Merge "Add wrapper for logging backup & restore metrics from Launcher" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 760d8ac..af175ce 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -76,3 +76,17 @@
     description: "Enables logging of Launcher restore metrics to the Backup & Restore team"
     bug: "307527314"
 }
+
+flag {
+    name: "enable_unfolded_two_pane_picker"
+    namespace: "launcher"
+    description: "Enables two pane widget picker for unfolded foldables"
+    bug: "313922374"
+}
+
+flag {
+    name: "enable_tablet_two_pane_picker_v2"
+    namespace: "launcher"
+    description: "Enables full width two pane widget picker for tablets in landscape and portrait"
+    bug: "315055849"
+}
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index 5a9e147..7c648b6 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -183,6 +183,7 @@
   ALL_APPS_SEARCH_RESULT_CHROMETAB = 24;
   ALL_APPS_SEARCH_RESULT_NAVVYSITE = 25 [deprecated = true];
   ALL_APPS_SEARCH_RESULT_TIPS = 26;
+  ALL_APPS_SEARCH_RESULT_QS_TILE = 27;
   ALL_APPS_SEARCH_RESULT_PEOPLE_TILE = 27 [deprecated = true];
   ALL_APPS_SEARCH_RESULT_LEGACY_SHORTCUT = 30;
   ALL_APPS_SEARCH_RESULT_ASSISTANT_MEMORY = 31;
@@ -192,7 +193,6 @@
   ALL_APPS_SEARCH_RESULT_LOCATION = 50;
   ALL_APPS_SEARCH_RESULT_TEXT_HEADER = 51;
   ALL_APPS_SEARCH_RESULT_NO_FULFILLMENT = 52;
-  ALL_APPS_SEARCH_RESULT_QS_TILE = 53;
 
   // Result sources
   DATA_SOURCE_APPSEARCH_APP_PREVIEW = 45;
@@ -200,6 +200,7 @@
   DATA_SOURCE_APPSEARCH_CATEGORY_SRP_PREVIEW = 48;
   DATA_SOURCE_APPSEARCH_ENTITY_SRP_PREVIEW = 49;
   DATA_SOURCE_AIAI_SEARCH_ROOT = 47;
+  DATA_SOURCE_LAUNCHER = 53;
 
   // Web suggestions provided by AGA
   ALL_APPS_SEARCH_RESULT_WEB_SUGGEST = 39;
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 82f8ebe..db46508 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -43,6 +43,10 @@
 
     <uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
 
+    <!-- Permission required to start a WidgetPickerActivity. -->
+    <permission android:name="${packageName}.permission.START_WIDGET_PICKER_ACTIVITY"
+        android:protectionLevel="signature|privileged" />
+
     <application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
          android:fullBackupOnly="true"
          android:fullBackupContent="@xml/backupscheme"
@@ -133,6 +137,20 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="com.android.launcher3.WidgetPickerActivity"
+            android:theme="@style/WidgetPickerActivityTheme"
+            android:excludeFromRecents="true"
+            android:autoRemoveFromRecents="true"
+            android:showOnLockScreen="true"
+            android:launchMode="singleTop"
+            android:exported="true"
+            android:permission="android.permission.START_WIDGET_PICKER_ACTIVITY">
+            <intent-filter>
+                <action android:name="android.intent.action.PICK" />
+                <category android:name="android.intent.category.DEFAULT" />
+            </intent-filter>
+        </activity>
+
     </application>
 
 </manifest>
diff --git a/quickstep/res/layout/widget_picker_activity.xml b/quickstep/res/layout/widget_picker_activity.xml
new file mode 100644
index 0000000..3388e40
--- /dev/null
+++ b/quickstep/res/layout/widget_picker_activity.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2023 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<com.android.launcher3.dragndrop.SimpleDragLayer
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/drag_layer"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:importantForAccessibility="no" />
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 75c6c60..a6da872 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Skermkiekie"</string>
     <string name="action_split" msgid="2098009717623550676">"Verdeel"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tik op ’n ander app om verdeelde skerm te gebruik"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Jou organisasie laat nie hierdie program toe nie"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Sleep ’n app na die kant toe om 2 apps tegelyk te gebruik"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Stadigswiep op om die Taakbalk te wys"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Kry appvoorstelle op grond van jou roetine"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Skakel gebaarnavigasie in Instellings aan om die Taakbalk outomaties te versteek"</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_close" msgid="887022990168191073">"Maak toe"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Klaar"</string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 2c39370..a825e3e 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"ቅጽበታዊ ገፅ ዕይታ"</string>
     <string name="action_split" msgid="2098009717623550676">"ክፈል"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"የተከፈለ ማያ ገጽን ለመጠቀም ሌላ መተግበሪያ መታ ያድርጉ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ይህ ድርጊት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"የተግባር አሞሌን በራስ ሰር ለመደበቅ የእጅ ምልክት ዳሰሳን በቅንብሮች ውስጥ ያብሩት"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"የተግባር አሞሌውን ፒን ለማድረግ በአከፋፋዩ ላይ በረጅሙ ይጫኑ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"በተግባር አሞሌው ተጨማሪ ነገር ያድርጉ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ዝጋ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ተጠናቅቋል"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 12f0363..09f146c 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"لقطة شاشة"</string>
     <string name="action_split" msgid="2098009717623550676">"تقسيم"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"انقر على تطبيق آخر لاستخدام وضع تقسيم الشاشة."</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"لا يسمح التطبيق أو لا تسمح مؤسستك بهذا الإجراء."</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"فعِّل خيار \"التنقُّل بالإيماءات\" في \"الإعدادات\" لإخفاء شريط التطبيقات تلقائيًا."</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"اضغط مع الاستمرار على المقسِّم لتثبيت \"شريط التطبيقات\""</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"إنجاز المزيد باستخدام شريط التطبيقات"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"إغلاق"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"تم"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 65c0a10..ea95d2c 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"স্ক্ৰীনশ্বট"</string>
     <string name="action_split" msgid="2098009717623550676">"বিভাজন কৰক"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপত টিপক"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"এপ্‌টোৱে অথবা আপোনাৰ প্ৰতিষ্ঠানে এই কাৰ্যটোৰ অনুমতি নিদিয়ে"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"টাস্কবাৰ স্বয়ংক্ৰিয়ভাৱে লুকুৱাবলৈ ছেটিঙত আঙুলিৰ স্পৰ্শৰ নিৰ্দেশেৰে কৰা নেভিগেশ্বন অন কৰক"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"টাস্কবাৰ পিন কৰিবলৈ বিভাজকত দীঘলীয়া সময় টিপি থাকক"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"টাস্কবাৰৰ জৰিয়তে অধিক কাৰ্য সম্পাদন কৰক"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"বন্ধ কৰক"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"হ’ল"</string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 01d61ee..510749c 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Skrinşot"</string>
     <string name="action_split" msgid="2098009717623550676">"Ayırın"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Bölünmüş ekran üçün başqa tətbiqə toxunun"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Bu əməliyyata tətbiq və ya təşkilatınız tərəfindən icazə verilmir"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Eyni anda 2 tətbiqi istifadə etmək üçün bir tətbiqi yan tərəfə çəkin"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Tapşırıq panelini göstərmək üçün astaca yuxarı sürüşdürün"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Rejiminizə əsasən tətbiq təklifləri alın"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Tapşırıq panelini avtomatik gizlətmək üçün Ayarlarda jest naviqasiyasını aktiv edin"</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_close" msgid="887022990168191073">"Bağlayın"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Hazırdır"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 805fc7f..79e3616 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
     <string name="action_split" msgid="2098009717623550676">"Podeli"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podeljeni ekran"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili organizacija ne dozvoljavaju ovu radnju"</string>
@@ -110,7 +109,7 @@
     <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_suggestions" msgid="8215044496435527982">"Dobijajte predloge aplikacija na osnovu rutine"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Uključite navigaciju pomoću pokreta u Podešavanjima radi automatskog skrivanja trake zadataka"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Dugo pritiskajte 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_close" msgid="887022990168191073">"Zatvori"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 1cc8c35..c164f95 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Здымак экрана"</string>
     <string name="action_split" msgid="2098009717623550676">"Падзелены экран"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Каб падзяліць экран, націсніце на іншую праграму"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Гэта дзеянне не дазволена праграмай ці вашай арганізацыяй"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Каб аўтаматычна схаваць панэль задач, уключыце ў Наладах навігацыю жэстамі"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Замацуйце панэль задач доўгім націсканнем на раздзяляльнік"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Выкарыстоўвайце магчымасці панэлі задач"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Закрыць"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Гатова"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index b0889df..9239089 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Екранна снимка"</string>
     <string name="action_split" msgid="2098009717623550676">"Разделяне на екрана"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Докоснете друго прил., за да ползвате разд. екран"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Това действие не е разрешено от приложението или организацията ви"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Включете навигирането с жестове от настройките с цел авт. скриване на лентата на задачите"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Натиснете продължително разделителя, за да фиксирате лентата на задачите"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Правете повече неща с лентата на задачите"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Затваряне"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index abc9603..80d0275 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"স্ক্রিনশট নিন"</string>
     <string name="action_split" msgid="2098009717623550676">"স্প্লিট"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"স্প্লিট স্ক্রিন ব্যবহারের জন্য অ্যাপে ট্যাপ করুন"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"এই অ্যাপ বা আপনার প্রতিষ্ঠান এই অ্যাকশনটি পারফর্ম করার অনুমতি দেয়নি"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"\'টাস্কবার\' অটোমেটিক লুকানোর জন্য, সেটিংসে জেসচার নেভিগেশন চালু করুন"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"টাস্কবার পিন করতে, ড্রাইভার বেশ কিছুক্ষণ প্রেস করে রাখুন"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"\'টাস্কবার\' ফিচারের সাহায্যে আরও অনেক কিছু করুন"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"বন্ধ করুন"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"হয়ে গেছে"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 2e4e442..e22e856 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
     <string name="action_split" msgid="2098009717623550676">"Podijeli"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu apl. da koristite podijeljeni ekran"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Ovu radnju ne dozvoljava aplikacija ili vaša organizacija"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Prevucite aplikaciju ustranu da odjednom koristite 2 aplikacije"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Sporo prevucite nagore da vidite traku zadataka"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Dobijajte prijedloge aplikacija zasnovane na vašoj rutini"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Uključite navigaciju pokretima u Postavkama da automatski sakrijete traku zadataka"</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_close" msgid="887022990168191073">"Zatvori"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 0964a93..df8cb36 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
     <string name="action_split" msgid="2098009717623550676">"Divideix"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toca una altra app per utilitzar pantalla dividida"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"L\'aplicació o la teva organització no permeten aquesta acció"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arrossega una aplicació al costat per utilitzar-ne dues alhora"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Llisca lentament cap amunt per mostrar la Barra de tasques"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Obtén suggeriments d\'aplicacions basats en la teva rutina"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"A Configuració, activa la navegació amb gestos per amagar la Barra de tasques automàticament"</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_close" msgid="887022990168191073">"Tanca"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Fet"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 6dd5526..1cd2ed9 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Snímek obrazovky"</string>
     <string name="action_split" msgid="2098009717623550676">"Rozdělit"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Obrazovku rozdělíte klepnutím na jinou aplikaci"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikace nebo organizace zakazuje tuto akci"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Pokud chcete panel aplikací automaticky skrýt, zapněte v Nastavení navigaci gesty"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Dlouhým stisknutím oddělovače připnete panel aplikací"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Více možností s panelem aplikací"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zavřít"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Hotovo"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 9571fed..d8f84dc 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Opdel"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tryk på en anden app for at bruge opdelt skærm"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller din organisation tillader ikke denne handling"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Træk en app til siden for at bruge 2 apps på én gang"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Stryg langsomt opad for at se proceslinjen"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Få appforslag baseret på din rutine"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Aktivér navigation med bevægelser under Indstillinger for automatisk at skjule proceslinjen"</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_close" msgid="887022990168191073">"Luk"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Luk"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 0c60f3a..3d4ce43 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Teilen"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Für Splitscreen auf weitere App tippen"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Die App oder deine Organisation lässt diese Aktion nicht zu"</string>
@@ -110,7 +109,7 @@
     <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_suggestions" msgid="8215044496435527982">"App-Vorschläge auf Grundlage deiner Nutzung erhalten"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Taskleiste automatisch ausblenden: Aktiviere in „Einstellungen“ die Bedienung über Gesten."</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_close" msgid="887022990168191073">"Schließen"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Fertig"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 103f55a..335ebac 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Στιγμιότυπο οθόνης"</string>
     <string name="action_split" msgid="2098009717623550676">"Διαχωρισμός"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Πατήστε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Αυτή η ενέργεια δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας."</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Ενεργοπ. την πλοήγηση με κινήσεις στις Ρυθμίσεις για αυτόμ. απόκρυψη της Γραμμής εργαλείων"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Παρατετ. πάτημα στο διαχωρ. για καρφ. της Γραμμής εργαλείων"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Κάντε περισσότερα με τη Γραμμή εργαλείων"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Κλείσιμο"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Τέλος"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index 5eb836b..04ec03f 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Split"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Drag an app to the side to use two apps at once"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Slow-swipe up to show the Taskbar"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Get app suggestions based on your routine"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Turn on gesture navigation in Settings to auto-hide the Taskbar"</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_close" msgid="887022990168191073">"Close"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index b7cc6f5..5c8d0f2 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Split"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organization"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Drag an app to the side to use 2 apps at once"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Slow-swipe up to show the Taskbar"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Get app suggestions based on your routine"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Turn on gesture navigation in Settings to auto-hide the Taskbar"</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_close" msgid="887022990168191073">"Close"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index 5eb836b..04ec03f 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Split"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Drag an app to the side to use two apps at once"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Slow-swipe up to show the Taskbar"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Get app suggestions based on your routine"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Turn on gesture navigation in Settings to auto-hide the Taskbar"</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_close" msgid="887022990168191073">"Close"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index 5eb836b..04ec03f 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Split"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tap another app to use split screen"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Drag an app to the side to use two apps at once"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Slow-swipe up to show the Taskbar"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Get app suggestions based on your routine"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Turn on gesture navigation in Settings to auto-hide the Taskbar"</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_close" msgid="887022990168191073">"Close"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Done"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index c0e3466..5d705ff 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‏‏‏‎‏‎‏‎‏‎‏‎‏‎‎‏‏‎‎‏‏‎‎‏‏‎‎‏‎‎‎‎‏‏‏‏‎‎‎‏‎‏‎Screenshot‎‏‎‎‏‎"</string>
     <string name="action_split" msgid="2098009717623550676">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‏‎‎‎‏‏‏‎‏‏‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‏‏‏‏‎‎‏‎‎‏‎‎‎‏‎‎‏‏‏‏‎‎‏‎‏‏‎‏‎‏‎‎‎Split‎‏‎‎‏‎"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‏‎‏‎‏‏‏‎‏‏‏‎‏‎‎‎‏‎‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‏‏‎‎‏‎‏‎‏‏‎‎‏‏‏‏‏‎‎‎‎‏‏‎‏‎‎Tap another app to use split screen‎‏‎‎‏‎"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‏‏‎‎‏‎‏‏‏‏‏‏‎‎‎‏‏‎‎‎‎‏‎‎‏‏‎‎‏‏‏‎‏‎‏‏‏‎‎‎‎‎‎‎‎‏‏‏‏‏‏‏‎‎‏‎‏‎‏‎‎This action isn\'t allowed by the app or your organization‎‏‎‎‏‎"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‎‏‏‏‎‎‏‎‏‎‏‏‎‎‎‏‏‏‏‏‏‎‎‏‏‎‏‎‎‎‏‏‏‎‎‎‏‏‎‎‏‎‎‎‎‎‏‎‏‎‏‏‏‎‎‏‏‎‎Drag an app to the side to use 2 apps at once‎‏‎‎‏‎"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‏‏‎‎‏‎‏‏‎‎‎‏‎‏‏‎‏‎‏‎‎‏‏‎‏‎‏‎‎‎‏‏‏‏‏‎‎‏‎‎‎‏‏‎‏‎‎‏‎‏‎‎‎‎‎‏‏‏‎‎Slow-swipe up to show the Taskbar‎‏‎‎‏‎"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‏‏‎‎‏‎‎‎‎‎‎‎‎‏‏‎‏‏‎‎‏‏‎‏‏‏‎‎‎‏‏‏‎‎‎‎‎‎‎‎‎‏‎‎‎‏‎‏‎‎‎‎‎‏‎‎‏‎‏‏‏‎‎Get app suggestions based on your routine‎‏‎‎‏‎"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‏‏‎‎‏‏‎‏‎‎‎‎‎‎‏‏‏‏‎‎‎‎‎‏‏‎‎‎‎‎‏‎‎‏‎‎‏‎‎‎‏‏‏‏‏‏‏‏‎‏‎‏‎‎‏‎‎‏‎‏‏‏‎Turn on gesture navigation in Settings to auto-hide the Taskbar‎‏‎‎‏‎"</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_close" msgid="887022990168191073">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‎Close‎‏‎‎‏‎"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‏‏‏‏‏‎‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‎‎‎‎‏‏‎‎‎‎‏‎‎‏‎‏‏‏‏‎‏‏‏‎‎‎‏‏‎‎‎‎‏‏‏‏‎‎‏‎Done‎‏‎‎‏‎"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 62aa6df..a25bd7c 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
     <string name="action_split" msgid="2098009717623550676">"Pantalla dividida"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Presiona otra app para usar la pantalla dividida"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"La app o tu organización no permiten realizar esta acción"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Activa la navegación por gestos en la Configuración y la Barra de tareas se ocultará sola"</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_close" msgid="887022990168191073">"Cerrar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Listo"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index d261a72..bb2f533 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Hacer captura"</string>
     <string name="action_split" msgid="2098009717623550676">"Dividir"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toca otra aplicación para usar la pantalla dividida"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"No puedes hacerlo porque la aplicación o tu organización no lo permiten"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Activa la navegación por gestos en Ajustes para ocultar la barra de tareas automáticamente"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Mantén pulsado el divisor para fijar 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_close" msgid="887022990168191073">"Cerrar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Hecho"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 601de1d..93fbd1c 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
     <string name="action_split" msgid="2098009717623550676">"Eralda"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Jagatud ekraanikuva kasutamiseks puudutage muud rakendust"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Rakendus või teie organisatsioon on selle toimingu keelanud"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"2 rakenduse korraga kasutamiseks lohistage rakendus kõrvale"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Tegumiriba kuvamiseks pühkige aeglaselt üles"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Hankige oma rutiini põhjal rakenduste soovitusi"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Tegumiriba automaatseks peitmiseks lülitage seadetes sisse liigutustega navigeerimine"</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_close" msgid="887022990168191073">"Sule"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Valmis"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 893973b..53b3390 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Atera pantaila-argazki bat"</string>
     <string name="action_split" msgid="2098009717623550676">"Zatitu"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Sakatu beste aplikazio bat pantaila zatitzeko"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikazioak edo erakundeak ez du eman ekintza hori gauzatzeko baimena"</string>
@@ -110,7 +109,7 @@
     <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_suggestions" msgid="8215044496435527982">"Jaso aplikazioen iradokizunak erabileran oinarrituta"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Zereginen barra automatikoki ezkutatzeko, aktibatu keinu bidezko nabigazioa ezarpenetan"</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_close" msgid="887022990168191073">"Itxi"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Eginda"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 448bd1c..c8da620 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"نماگرفت"</string>
     <string name="action_split" msgid="2098009717623550676">"دونیمه"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"زدن روی برنامه‌ای دیگر برای استفاده از صفحه دونیمه"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"برنامه یا سازمان شما اجازه نمی‌دهد این کنش انجام شود."</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"برای پنهان‌سازی خودکار «نوار وظیفه»، پیمایش اشاره‌ای را در «تنظیمات» روشن کنید"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"برای سنجاق کردن «نوار وظیفه»، جداکننده را چند ثانیه فشار دهید"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"با «نوار وظیفه» می‌توانید کارهای بیشتر انجام دهید"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"بستن"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"تمام"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 77e25ef..c8c3490 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Kuvakaappaus"</string>
     <string name="action_split" msgid="2098009717623550676">"Jaa"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Avaa jaettu näyttö napauttamalla toista sovellusta"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Sovellus tai organisaatio ei salli tätä toimintoa"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Vedä sovellus sivuun, ja voit käyttää 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_settings_persistent" msgid="1387372982791296151">"Laita eleillä navigointi päälle Asetuksista Tehtäväpalkin piilottamiseksi automaattisesti"</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_close" msgid="887022990168191073">"Sulje"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Valmis"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 7702acd..8a8a9aa 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
     <string name="action_split" msgid="2098009717623550676">"Partager"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toucher une autre appli pour partager l\'écran"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"L\'application ou votre organisation n\'autorise pas cette action"</string>
@@ -110,7 +109,7 @@
     <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_suggestions" msgid="8215044496435527982">"Obtenez des suggestions d\'applis en fonction de vos routines"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Activez la navigation par gestes dans Paramètres pour masquer auto. la barre des tâches"</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_features" msgid="3320337287472848162">"Faites-en plus avec la barre des tâches"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Fermer"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"OK"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 3876bc1..df6cad4 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
     <string name="action_split" msgid="2098009717623550676">"Partager"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Appuyez sur autre appli pour l\'écran partagé"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Cette action n\'est pas autorisée par l\'application ou par votre organisation"</string>
@@ -110,7 +109,7 @@
     <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_suggestions" msgid="8215044496435527982">"Obtenez des suggestions d\'applis basées sur vos habitudes"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Activez la navigation par gestes dans paramètres pour masquage auto de la barre des tâches"</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_features" msgid="3320337287472848162">"Faites-en plus avec la barre des tâches"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Fermer"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"OK"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index b5ed56b..2022573 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string>
     <string name="action_split" msgid="2098009717623550676">"Dividir"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Para usar a pantalla dividida, toca outra app"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"A aplicación ou a túa organización non permite realizar esta acción"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Activa navegación con xestos en Configuración e oculta automaticamente 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_close" msgid="887022990168191073">"Pechar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Listo"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index e3965a6..d1adf5c 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"સ્ક્રીનશૉટ"</string>
     <string name="action_split" msgid="2098009717623550676">"વિભાજિત કરો"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"વિભાજિત સ્ક્રીન વાપરવા, કોઈ અન્ય ઍપ પર ટૅપ કરો"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ઍપ કે તમારી સંસ્થા દ્વારા આ ક્રિયા કરવાની મંજૂરી નથી"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"ટાસ્કબારને ઑટોમૅટિક રીતે છુપાવવા માટે સેટિંગમાં સંકેતથી નૅવિગેશનની સુવિધા ચાલુ કરો"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ટાસ્કબારને પિન કરવા માટે, વિભાજકને થોડીવાર દબાવી રાખો"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ટાસ્કબાર વડે બીજું ઘણું કરો"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"બંધ કરો"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"થઈ ગયું"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 431d4dd..5ebe814 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट लें"</string>
     <string name="action_split" msgid="2098009717623550676">"स्प्लिट स्क्रीन मोड"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिट स्क्रीन के लिए दूसरे ऐप्लिकेशन पर टैप करें"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ऐप्लिकेशन या आपका संगठन इस कार्रवाई की अनुमति नहीं देता"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"टास्कबार अपने-आप छिपाने वाली सुविधा के लिए, सेटिंग में जाकर जेस्चर वाला नेविगेशन चालू करें"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"टास्कबार को पिन करने के लिए डिवाइडर को दबाकर रखें"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार की मदद से कई और काम करें"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"बंद करें"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"हो गया"</string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index be59184..ad0be8e 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Snimka zaslona"</string>
     <string name="action_split" msgid="2098009717623550676">"Podijeli"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podijeljeni zaslon"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili vaša organizacija ne dopuštaju ovu radnju"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Povucite aplikaciju u stranu radi istodobne upotrebe dviju aplikacija"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Polako prijeđite prstom prema gore za prikaz trake sa zadacima"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Primajte prijedloge aplikacija na temelju svoje rutine"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Uključite navigaciju pokretima u postavkama da bi se traka sa zadacima automatski sakrila"</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_close" msgid="887022990168191073">"Zatvori"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 1ef8389..b1298ce 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Képernyőkép"</string>
     <string name="action_split" msgid="2098009717623550676">"Felosztás"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Koppintson másik appra az osztott képernyőhöz"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Az alkalmazás vagy az Ön szervezete nem engedélyezi ezt a műveletet"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Húzzon egy appot oldalra, ha kettőt használna egyidejűleg"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Lassan csúsztassa fel az ujját a Feladatsáv megjelenítéséhez"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Alkalmazásjavaslatokat kaphat a rutinja alapján"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"A Feladatsáv automatikus elrejtéséhez aktiválja a navigációs kézmozdulatokat a beállításokban"</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_close" msgid="887022990168191073">"Bezárás"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Kész"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index af97be3..d896b51 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Սքրինշոթ անել"</string>
     <string name="action_split" msgid="2098009717623550676">"Տրոհել"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Հպեք այլ հավելվածի՝ տրոհված էկրանից օգտվելու համար"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Այս գործողությունն արգելված է հավելվածի կամ ձեր կազմակերպության կողմից"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Կարգավորումներում միացրեք ժեստերով նավիգացիան՝ հավելվածների վահանակը թաքցնելու համար"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Հավելվածների վահանակն ամրացնելու համար երկար սեղմեք բաժանարարի վրա"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Օգտվեք հավելվածների վահանակի բոլոր հնարավորություններից"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Փակել"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Պատրաստ է"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index cc4d06a..e6563ae 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Pisahkan"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Ketuk aplikasi lain untuk memakai layar terpisah"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak diizinkan oleh aplikasi atau organisasi Anda"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Tarik aplikasi ke samping untuk menggunakan 2 aplikasi sekaligus"</string>
     <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_settings_persistent" msgid="1387372982791296151">"Aktifkan navigasi gestur di Setelan untuk menyembunyikan otomatis Taskbar"</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_close" msgid="887022990168191073">"Tutup"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Selesai"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index 11d69bc..c297a6b 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Skjámynd"</string>
     <string name="action_split" msgid="2098009717623550676">"Skipta"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Ýttu á annað forrit til að nota skjáskiptingu"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Forritið eða fyrirtækið leyfir ekki þessa aðgerð"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Dragðu forrit til hliðar til að nota 2 forrit í einu"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Strjúktu hægt upp til að birta forritastikuna"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Fáðu forritatillögur sem byggjast á rútínunni þinni"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Kveiktu á bendingastjórnun í stillingunum til að fela forritastikuna sjálfkrafa"</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_close" msgid="887022990168191073">"Loka"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Lokið"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 20887ac..c028d26 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Dividi"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tocca un\'altra app per usare lo schermo diviso"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Questa azione non è consentita dall\'app o dall\'organizzazione"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Trascina un\'app di lato per usare due app contemporaneamente"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Scorri lentamente in su per mostrare la barra delle app"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Visualizza le app suggerite in base alla tua routine"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Per nascondere automaticamente la barra delle app, attiva la navigazione tramite gesti"</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_close" msgid="887022990168191073">"Chiudi"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Fine"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 9c07653..505096b 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"צילום מסך"</string>
     <string name="action_split" msgid="2098009717623550676">"פיצול"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"צריך להקיש על אפליקציה אחרת כדי להשתמש במסך מפוצל"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"האפליקציה או הארגון שלך אינם מתירים את הפעולה הזאת"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"אפשר להפעיל את הניווט באמצעות תנועות ב\'הגדרות\' כדי להסתיר אוטומטית את סרגל האפליקציות"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"כדי להצמיד את סרגל האפליקציות, לוחצים לחיצה ארוכה על המחיצה"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"פעולות נוספות שאפשר לעשות עם סרגל האפליקציות"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"סגירה"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"סיום"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index c753a0f..e9f1670 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"スクリーンショット"</string>
     <string name="action_split" msgid="2098009717623550676">"分割"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"分割画面を使用するには、他のアプリをタップします"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"この操作はアプリまたは組織で許可されていません"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"[設定] でジェスチャー ナビゲーションを ON にすると、タスクバーを自動的に非表示にできます"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"タスクバーを固定するには分割線を長押ししてください"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"タスクバーの各種機能"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"閉じる"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"完了"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 11a8900..5bcf856 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"ეკრანის ანაბეჭდი"</string>
     <string name="action_split" msgid="2098009717623550676">"გაყოფა"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"შეეხეთ სხვა აპს ეკრანის გასაყოფად"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ეს მოქმედება არ არის დაშვებული აპის ან თქვენი ორგანიზაციის მიერ"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"ჩართეთ ჟესტებით ნავიგაცია პარამეტრებში, რათა ავტომატურად დაიმალოთ სამუშაო ზოლი"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ხანგრძლივად დააჭირეთ გამყოფს ამოცანათა ზოლის ჩასამაგრებლად"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"გააკეთეთ მეტი ამოცანათა ზოლის მეშვეობით"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"დახურვა"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"მზადაა"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index d6efe1b..da3670e 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
     <string name="action_split" msgid="2098009717623550676">"Бөлу"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлу режимін пайдалану үшін басқа қолданбаны түртіңіз."</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Бұл әрекетке қолданба не ұйым рұқсат етпейді."</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Тапсырмалар жолағын автоматты түрде жасыру үшін параметрлерден қимылмен басқаруды қосыңыз."</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Тапсырмалар жолағын бекіту үшін бөлгішті ұзақ басып тұрыңыз"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Тапсырмалар жолағында мүмкіндік көп"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Жабу"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Дайын"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 3956722..4c3d732 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"រូបថតអេក្រង់"</string>
     <string name="action_split" msgid="2098009717623550676">"បំបែក"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ចុចកម្មវិធី​ផ្សេងទៀត ដើម្បីប្រើ​មុខងារបំបែកអេក្រង់"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"សកម្មភាពនេះ​មិនត្រូវបានអនុញ្ញាតដោយកម្មវិធី​ ឬ​ស្ថាប័ន​របស់អ្នកទេ"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"បើកការរុករក​ដោយប្រើចលនានៅក្នុងការកំណត់ ដើម្បីលាក់របារកិច្ចការដោយស្វ័យប្រវត្តិ"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ចុចឱ្យយូរនៅលើបន្ទាត់ខណ្ឌចែក ដើម្បីខ្ទាស់របារកិច្ចការ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ធ្វើបានកាន់តែច្រើនដោយប្រើរបារកិច្ចការ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"បិទ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"រួចរាល់"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index f8cdde0..c8efb7e 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
     <string name="action_split" msgid="2098009717623550676">"ವಿಭಜಿಸಿ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ಆ್ಯಪ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಕ್ರಿಯೆಯನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"ಟಾಸ್ಕ್‌ಬಾರ್ ಅನ್ನು ಸ್ವಯಂ-ಮರೆಮಾಡಲು ಸೆಟ್ಟಿಂಗ್‌ಗಳಲ್ಲಿ ಗೆಸ್ಚರ್ ನ್ಯಾವಿಗೇಶನ್ ಅನ್ನು ಆನ್ ಮಾಡಿ"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ಟಾಸ್ಕ್ ಬಾರ್ ಅನ್ನು ಪಿನ್ ಮಾಡಲು ಡಿವೈಡರ್ ಮೇಲೆ ದೀರ್ಘಕಾಲ ಒತ್ತಿರಿ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ಟಾಸ್ಕ್‌ಬಾರ್ ಮೂಲಕ ಹೆಚ್ಚಿನದನ್ನು ಮಾಡಿ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ಮುಚ್ಚಿರಿ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ಆಯಿತು"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index fb03677..5b5b728 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"스크린샷"</string>
     <string name="action_split" msgid="2098009717623550676">"분할"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"다른 앱을 탭하여 화면 분할 사용"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"이 작업은 앱 또는 조직에서 허용되지 않습니다."</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"태스크 바를 자동 숨김하려면 설정에서 동작 탐색을 켜세요."</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"구분선을 길게 눌러 태스크 바 고정하기"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"태스크 바 최대한 활용하기"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"닫기"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"완료"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 8020313..ea98e71 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
     <string name="action_split" msgid="2098009717623550676">"Бөлүү"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлүү үчүн башка колдонмону таптап коюңуз"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Бул аракетти аткарууга колдонмо же ишканаңыз тыюу салган"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Тапшырмалар тактасын автоматтык түрдө жашыруу үчүн Тууралоодон жаңсап чабыттоону күйгүзүңүз"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Тапшырмалар панелин кадап коюу үчүн бөлгүчтү коё бербей басып туруңуз"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Тапшырмалар тактасы менен көбүрөөк нерселерди аткарыңыз"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Жабуу"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Бүттү"</string>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index b0b4597..635523e 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"ຮູບໜ້າຈໍ"</string>
     <string name="action_split" msgid="2098009717623550676">"ແບ່ງ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ແຕະແອັບອື່ນເພື່ອໃຊ້ໜ້າຈໍແຍກ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ແອັບ ຫຼື ອົງການຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ໃຊ້ຄຳສັ່ງນີ້"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"ເປີດການນຳທາງແບບທ່າທາງໃນການຕັ້ງຄ່າເພື່ອເຊື່ອງແຖບໜ້າວຽກໄວ້ໂດຍອັດຕະໂນມັດ"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ກົດຕົວຂັ້ນຄ້າງໄວ້ເພື່ອປັກໝຸດແຖບໜ້າວຽກ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ເຮັດສິ່ງຕ່າງໆໄດ້ຫຼາຍຂຶ້ນດ້ວຍແຖບໜ້າວຽກ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ປິດ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ແລ້ວໆ"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index 34a2878..c5839e3 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Ekrano kopija"</string>
     <string name="action_split" msgid="2098009717623550676">"Išskaidymo režimas"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Išskaidyto ekrano režimas palietus kitą programą"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Jūsų organizacijoje arba naudojant šią programą neleidžiama atlikti šio veiksmo"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Nuvilkę programą į šoną vienu metu naudokite dvi programas"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Trumpai perbraukite, kad būtų rodoma Užduočių juosta"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Gaukite programų pasiūlymų pagal savo veiklą"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Įjungę naršymą gestais „Nustatymų“ skiltyje automatiškai paslėpkite Užduočių juostą"</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_close" msgid="887022990168191073">"Uždaryti"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Atlikta"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 5e7b550..063a626 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Veikt ekrānuzņēmumu"</string>
     <string name="action_split" msgid="2098009717623550676">"Sadalīt"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Lai sadalītu ekrānu, pieskarieties citai lietotnei"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Lietotne vai jūsu organizācija neatļauj veikt šo darbību."</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Velciet lietotni sānis, lai izmantotu 2 lietotnes vienlaikus"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Lai skatītu uzdevumu joslu, lēni velciet augšup"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Skatiet ieteiktās lietotnes, balstoties uz jūsu ieradumiem"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Lai Uzdevumu josla tiktu automātiski paslēpta, iestatījumos ieslēdziet žestu navigāciju."</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_close" msgid="887022990168191073">"Aizvērt"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gatavs"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index c4d2fb2..61d34dd 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Слика од екранот"</string>
     <string name="action_split" msgid="2098009717623550676">"Раздели"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Допрете друга аплик. за да користите поделен екран"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Апликацијата или вашата организација не го дозволува дејствово"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Вклучете навигација со движење во „Поставки“ за автоматско сокривање на „Лентата со задачи“"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Притиснете долго на разделникот за да ја закачите „Лентата со задачи“"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Правете повеќе со една лента со задачи"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 4316396..f9e7827 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"സ്ക്രീൻഷോട്ട്"</string>
     <string name="action_split" msgid="2098009717623550676">"വിഭജിക്കുക"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"സ്പ്ലിറ്റ് സ്ക്രീനിന് മറ്റൊരു ആപ്പിൽ ടാപ്പ് ചെയ്യൂ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ഈ നടപടി എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"ടാസ്‌ക്‌ബാർ സ്വയമേവ മറയ്‌ക്കാൻ ക്രമീകരണത്തിൽ ജെസ്ച്ചർ നാവിഗേഷൻ ഓണാക്കുക"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ടാസ്‌ക്ബാർ പിൻ ചെയ്യാൻ ഡിവൈഡറിൽ ദീർഘനേരം അമർത്തുക"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ടാസ്‌ക്‌ബാർ ഉപയോഗിച്ച് കൂടുതൽ ചെയ്യുക"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"അടയ്ക്കുക"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"പൂർത്തിയായി"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 98b2712..1b86948 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Дэлгэцийн агшин дарах"</string>
     <string name="action_split" msgid="2098009717623550676">"Хуваах"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Дэлгэцийг хуваахыг ашиглахын тулд өөр аппыг товш"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Энэ үйлдлийг апп эсвэл танай байгууллага зөвшөөрдөггүй"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Ажлын хэсгийг автоматаар хаахын тулд Тохиргоонд зангааны навигацыг асаана уу"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Ажлын хэсгийг бэхлэхийн тулд тусгаарлагчийг удаан дарна уу"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Ажлын хэсгийн тусламжтай илүү ихийг хийгээрэй"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Хаах"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Дууссан"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 4bbfc6b..722e17d 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट"</string>
     <string name="action_split" msgid="2098009717623550676">"स्प्लिट"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिट स्क्रीन वापरण्यासाठी दुसऱ्या ॲपवर टॅप करा"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"अ‍ॅप किंवा तुमच्या संस्थेद्वारे ही क्रिया करण्याची अनुमती नाही"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"टास्कबार ऑटो हाइड करण्यासाठी सेटिंग्ज मधून जेश्चर नेव्हिगेशन सुरू करा"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"टास्कबार पिन करण्यासाठी विभाजकावर प्रेस करून ठेवा"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार चा पुरेपूर वापर करा"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"बंद करा"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"पूर्ण झाले"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index aa0f535..1959cd7 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Tangkapan skrin"</string>
     <string name="action_split" msgid="2098009717623550676">"Pisah"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Ketik apl lain untuk menggunakan skrin pisah"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak dibenarkan oleh apl atau organisasi anda"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Seret apl ke tepi untuk menggunakan 2 apl serentak"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Leret perlahan ke atas untuk menunjukkan Bar Tugas"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Dapatkan cadangan apl berdasarkan rutin anda"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Hidupkan navigasi gerak isyarat dalam Tetapan untuk autosembunyi Bar Tugas"</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_close" msgid="887022990168191073">"Tutup"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Selesai"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 60d8247..96ef54a 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
     <string name="action_split" msgid="2098009717623550676">"ခွဲထုတ်ရန်"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"မျက်နှာပြင် ခွဲ၍ပြသရန် အက်ပ်နောက်တစ်ခုကို တို့ပါ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ဤလုပ်ဆောင်ချက်ကို အက်ပ် သို့မဟုတ် သင်၏အဖွဲ့အစည်းက ခွင့်မပြုပါ"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Taskbar ကို အော်တိုဝှက်ရန် ဆက်တင်များတွင် လက်ဟန်ဖြင့်လမ်းညွှန်ခြင်း ဖွင့်နိုင်သည်"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Taskbar ပင်ထိုးရန် ခွဲခြားမျဉ်းကို ဖိနှိပ်ပါ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Taskbar ဖြင့် ပိုမိုလုပ်ဆောင်နိုင်ခြင်း"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ပိတ်ရန်"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ပြီးပြီ"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 20ea562..f129361 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Skjermdump"</string>
     <string name="action_split" msgid="2098009717623550676">"Del opp"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Trykk på en annen app for å bruke delt skjerm"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisasjonen din tillater ikke denne handlingen"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Dra en app til siden for å bruke 2 apper samtidig"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Sveip langsomt opp for å vise oppgavelinjen"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Få appforslag som er basert på rutinene dine"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Slå på navigasjon med bevegelser i innstillingene for å skjule oppgavelinjen automatisk"</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_close" msgid="887022990168191073">"Lukk"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Ferdig"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 8b517be..7ff28f6 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"स्क्रिनसट"</string>
     <string name="action_split" msgid="2098009717623550676">"स्प्लिट गर्नुहोस्"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिटस्क्रिन प्रयोग गर्न अर्को एपमा ट्याप गर्नु…"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"यो एप वा तपाईंको सङ्गठनले यो कारबाही गर्ने अनुमति दिँदैन"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"टास्कबार स्वतः लुकाउन सेटिङमा गई इसारामार्फत गरिने नेभिगेसन अन गर्नुहोस्"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"टास्कबार पिन गर्न डिभाइडरमा केही बेरसम्म थिच्नुहोस्"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"टास्कबार प्रयोग गरेर अझ धेरै कार्य गर्नुहोस्"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"बन्द गर्नुहोस्"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"सम्पन्न भयो"</string>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 16d8c76..bf10bf2 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Splitsen"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tik op nog een app om je scherm te splitsen"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Deze actie wordt niet toegestaan door de app of je organisatie"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Sleep een app naar de zijkant om 2 apps tegelijk te gebruiken"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Swipe langzaam omhoog om de taakbalk te tonen"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Krijg app-suggesties op basis van je routine"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Zet navigatie met gebaren aan bij Instellingen om de Taakbalk automatisch te verbergen"</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_close" msgid="887022990168191073">"Sluiten"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Klaar"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 367af6b..d9f49e6 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"ସ୍କ୍ରିନସଟ୍"</string>
     <string name="action_split" msgid="2098009717623550676">"ସ୍ପ୍ଲିଟ୍"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ସ୍ପ୍ଲିଟସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପରେ ଟାପ କର"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ଆପ୍ କିମ୍ବା ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ଏହି କାର୍ଯ୍ୟକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"ଟାସ୍କବାରକୁ ସ୍ୱତଃ-ଲୁଚାଇବା ପାଇଁ ସେଟିଂସରେ ଜେଶ୍ଚର ନାଭିଗେସନକୁ ଚାଲୁ କରନ୍ତୁ"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ଟାସ୍କବାର ପିନ କରିବା ପାଇଁ ଡିଭାଇଡରକୁ ଅଧିକ ସମୟ ଦବାନ୍ତୁ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ଟାସ୍କବାର ମାଧ୍ୟମରେ ଆହୁରି ଅନେକ କିଛି କରନ୍ତୁ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ବନ୍ଦ କରନ୍ତୁ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ହୋଇଗଲା"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index c1f60d3..cdf4d29 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
     <string name="action_split" msgid="2098009717623550676">"ਸਪਲਿਟ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨੂੰ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਇਸ ਕਾਰਵਾਈ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"ਟਾਸਕਬਾਰ ਨੂੰ ਸਵੈ-ਲੁਕਾਉਣ ਲਈ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਇਸ਼ਾਰਾ ਨੈਵੀਗੇਸ਼ਨ ਨੂੰ ਚਾਲੂ ਕਰੋ"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ਟਾਸਕਬਾਰ \'ਤੇ ਪਿੰਨ ਕਰਨ ਲਈ ਵਿਭਾਜਕ \'ਤੇ ਦਬਾਈ ਰੱਖੋ"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ਟਾਸਕਬਾਰ ਦਾ ਹੋਰ ਲਾਹਾ ਲਓ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ਬੰਦ ਕਰੋ"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ਸਮਝ ਲਿਆ"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 30771f2..7cc04ec 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Zrzut ekranu"</string>
     <string name="action_split" msgid="2098009717623550676">"Podziel"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Aby podzielić ekran, kliknij drugą aplikację"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Nie możesz wykonać tego działania, bo nie zezwala na to aplikacja lub Twoja organizacja"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Włącz nawigację przy użyciu gestów w Ustawieniach, aby automatycznie ukrywać pasek aplikacji"</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_close" msgid="887022990168191073">"Zamknij"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotowe"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 7b548ae..b90863d 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Fazer captura de ecrã"</string>
     <string name="action_split" msgid="2098009717623550676">"Dividir"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toque noutra app para usar o ecrã dividido"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Esta ação não é permitida pela app ou a sua entidade."</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Ative a navegação por gestos em Definições para ocultar automaticamente a Barra de tarefas"</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_close" msgid="887022990168191073">"Fechar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Concluir"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 318da85..2e4e2f8 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Capturar tela"</string>
     <string name="action_split" msgid="2098009717623550676">"Dividir"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Toque em outro app para usar a tela dividida"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Essa ação não é permitida pelo app ou pela organização"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Arraste um app para o lado e use dois apps ao mesmo tempo"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Deslize para cima devagar para mostrar a Barra de tarefas"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Receba sugestões de apps com base na sua rotina"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Ative a navegação por gestos nas configs. para ocultar a Barra de tarefas automaticamente"</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_close" msgid="887022990168191073">"Fechar"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Concluído"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 2703997..2f40dc4 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Captură de ecran"</string>
     <string name="action_split" msgid="2098009717623550676">"Împărțit"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Atinge altă aplicație pentru ecranul împărțit"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Această acțiune nu este permisă de aplicație sau de organizația ta"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Trage în lateral o aplicație ca să folosești 2 aplicații deodată"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Glisează lent în sus pentru a afișa bara de activități"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Primește sugestii de aplicații în funcție de rutina ta"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Activează navigarea prin gesturi în Setări ca să ascunzi automat bara de activități"</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_close" msgid="887022990168191073">"Închide"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Gata"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 533b1a3..0b7a193 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
     <string name="action_split" msgid="2098009717623550676">"Разделить"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Для разделения экрана выберите другое приложение."</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Это действие заблокировано приложением или организацией."</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Чтобы панель задач скрывалась автоматически, включите навигацию с помощью жестов."</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Закрепите панель задач долгим нажатием на разделитель"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Используйте все возможности панели задач"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Закрыть"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index c8f350a..0801a53 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"තිර රුව"</string>
     <string name="action_split" msgid="2098009717623550676">"බෙදන්න"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"බෙදුම් තිරය භාවිතා කිරීමට තවත් යෙදුමක් තට්ටු කරන්න"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"මෙම ක්‍රියාව යෙදුම හෝ ඔබේ සංවිධානය මගින් ඉඩ නොදේ"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"කාර්ය තීරුව ස්වයංක්‍රීයව සැඟවීමට සැකසීම් තුළ අභින සංචලනය සක්‍රීය කරන්න"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"කාර්ය තීරුව ඇමිණීමට බෙදනය මත දිගු වේලාවක් ඔබන්න"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"කාර්ය තීරුව සමග තවත් කරන්න"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"වසන්න"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"නිමයි"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 5b99d42..7e16184 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Snímka obrazovky"</string>
     <string name="action_split" msgid="2098009717623550676">"Rozdeliť"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Obrazovku rozdelíte klepnutím na inú aplikáciu"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikácia alebo vaša organizácia túto akciu nepovoľuje"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Ak chcete použiť dve aplikácie naraz, presuňte aplikáciu nabok"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Panel aplikácií zobrazíte pomalým potiahnutím nahor"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Získavajte návrhy aplikácií na základe svojich zvykov"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Ak chcete, aby sa panel aplikácií autom. skrýval, zapnite v Nastaveniach navigáciu gestami"</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_close" msgid="887022990168191073">"Zavrieť"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Hotovo"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 5ab0c02..9df20c2 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Posnetek zaslona"</string>
     <string name="action_split" msgid="2098009717623550676">"Razdeli"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Za razdeljeni zaslon se dotaknite še 1 aplikacije"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ali vaša organizacija ne dovoljuje tega dejanja"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"V nastavitvah vklopite krmarjenje s potezami, da se bo opravilna vrstica samodejno skrila."</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_close" msgid="887022990168191073">"Zapri"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Končano"</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index fa83899..566a42d 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Pamja e ekranit"</string>
     <string name="action_split" msgid="2098009717623550676">"Ndaj"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Trokit një apl. tjetër; përdor ekranin e ndarë"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Ky veprim nuk lejohet nga aplikacioni ose organizata jote"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Zvarrit një aplikacion në anë për të përdorur 2 aplikacione njëherësh"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Rrëshqit lart ngadalë për të shfaqur \"Shiritin e detyrave\""</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Merr sugjerime për aplikacion bazuar në rutinën tënde"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Aktivizo navigimin me gjeste te \"Cilësimet\" për të fshehur \"Shiritin e detyrave\""</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_close" msgid="887022990168191073">"Mbyll"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"U krye"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index e074802..78ce2ab 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Снимак екрана"</string>
     <string name="action_split" msgid="2098009717623550676">"Подели"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Додирните другу апликацију за подељени екран"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Апликација или организација не дозвољавају ову радњу"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Укључите навигацију помоћу покрета у Подешавањима ради аутоматског скривања траке задатака"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Дуго притискајте разделник да бисте закачили траку задатака"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Урадите више помоћу траке задатака"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index c13b437..a1e2048 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Skärmbild"</string>
     <string name="action_split" msgid="2098009717623550676">"Delat"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Tryck på en annan app för att använda delad skärm"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisationen tillåter inte den här åtgärden"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Dra en app till sidan om du vill använda två appar samtidigt"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Svep långsamt uppåt för att visa aktivitetsfältet"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Få appförslag utifrån dina rutiner"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Slå på navigering med rörelser i Inställningar för att dölja aktivitetsfältet automatiskt"</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_close" msgid="887022990168191073">"Stäng"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Klar"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 48ba038..089672c 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Picha ya skrini"</string>
     <string name="action_split" msgid="2098009717623550676">"Iliyogawanywa"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Gusa programu nyingine ili utumie kipengele cha kugawa skrini"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Kitendo hiki hakiruhusiwi na programu au shirika lako"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Buruta programu pembeni ili utumie programu 2 kwa wakati mmoja"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Telezesha kidole juu taratibu ili ufungue Upauzana"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Pata mapendekezo ya programu kulingana na ratiba yako"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Washa usogezaji kwa kutumia ishara kwenye Mipangilio ili ufiche Upauzana kiotomatiki"</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_close" msgid="887022990168191073">"Funga"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Imemaliza"</string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index fe021fb..49ddb8c 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"ஸ்கிரீன்ஷாட்"</string>
     <string name="action_split" msgid="2098009717623550676">"பிரி"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"திரைப் பிரிப்பைப் பயன்படுத்த வேறு ஆப்ஸைத் தட்டவும்"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ஆப்ஸோ உங்கள் நிறுவனமோ இந்த செயலை அனுமதிப்பதில்லை"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"செயல் பட்டியைத் தானாக மறைக்க அமைப்புகளில் சைகை வழிசெலுத்தலை இயக்கவும்"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"பிரிப்பானை நீண்ட நேரம் அழுத்தி, செயல் பட்டியைப் பின் செய்க"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"செயல் பட்டி மூலம் மேலும் பலவற்றைச் செய்யுங்கள்"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"மூடுக"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"முடிந்தது"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 38b9636..d13764e 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"స్క్రీన్‌షాట్"</string>
     <string name="action_split" msgid="2098009717623550676">"స్ప్లిట్ చేయండి"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"స్ప్లిట్ స్క్రీన్ కోసం మరొక యాప్‌ను ట్యాప్ చేయండి"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ఈ చర్యను యాప్ గానీ, మీ సంస్థ గానీ అనుమతించవు"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"టాస్క్‌బార్‌ను ఆటోమేటిక్‌గా దాచడానికి, సెట్టింగ్‌లలో సంజ్ఞ నావిగేషన్‌ను ఆన్ చేయండి"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"టాస్క్‌బార్‌ను పిన్ చేయడానికి డివైడర్‌పై ఎక్కువసేపు నొక్కి, ఉంచడం"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"టాస్క్‌బార్‌తో మరిన్ని చేయండి"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"మూసివేయండి"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"పూర్తయింది"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index c51c794..7447b6d 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"ภาพหน้าจอ"</string>
     <string name="action_split" msgid="2098009717623550676">"แยก"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"แตะแอปอื่นเพื่อใช้การแยกหน้าจอ"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"แอปหรือองค์กรของคุณไม่อนุญาตการดำเนินการนี้"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"เปิดการนำทางด้วยท่าทางสัมผัสในการตั้งค่าเพื่อซ่อนแถบงานโดยอัตโนมัติ"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"กดตัวแบ่งค้างไว้เพื่อปักหมุดแถบงาน"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ทำสิ่งต่างๆ ได้มากขึ้นด้วยแถบงาน"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ปิด"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"เสร็จ"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 4bdb331..cd432cc 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Split"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Mag-tap ng ibang app para gamitin ang split screen"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Hindi pinapayagan ng app o ng iyong organisasyon ang pagkilos na ito"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Mag-drag ng app sa gilid para makagamit ng 2 app nang sabay"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Mag-swipe nang mabagal pataas para ipakita ang Taskbar"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Makakuha ng mga iminumungkahing app batay sa iyong routine"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"I-on ang navigation gamit ang galaw sa Mga Setting para i-auto hide ang Taskbar"</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_close" msgid="887022990168191073">"Isara"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Tapos na"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 04043ee..ed22286 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Ekran görüntüsü"</string>
     <string name="action_split" msgid="2098009717623550676">"Böl"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Bölünmüş ekran için başka bir uygulamaya dokunun"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Uygulamanız veya kuruluşunuz bu işleme izin vermiyor"</string>
@@ -110,7 +109,7 @@
     <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_suggestions" msgid="8215044496435527982">"Rutininize göre uygulama önerileri alın"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Görev çubuğunu otomatik olarak gizlemek için Ayarlar\'dan hareketle gezinmeyi etkinleştirin"</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_close" msgid="887022990168191073">"Kapat"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Bitti"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index ea0df1a..42fc6dd 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Знімок екрана"</string>
     <string name="action_split" msgid="2098009717623550676">"Розділити"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Щоб розділити екран, виберіть ще один додаток"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"Ця дія заборонена додатком або адміністратором організації"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Увімкніть навігацію жестами в налаштуваннях, щоб автоматично приховувати панель завдань"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"Утримуйте розділювач, щоб закріпити панель завдань"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"Більше можливостей завдяки панелі завдань"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Закрити"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 5bff0f6..0e5b602 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"اسکرین شاٹ"</string>
     <string name="action_split" msgid="2098009717623550676">"اسپلٹ"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"اسپلٹ اسکرین کا استعمال کرنے کیلئے دوسری ایپ پر تھپتھپائیں"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"ایپ یا آپ کی تنظیم کی جانب سے اس کارروائی کی اجازت نہیں ہے"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"ٹاسک بار کو خودکار طور پر چھپانے کیلئے \'ترتیبات\' میں اشاروں والی نیویگیشن آن کریں"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"ٹاسک بار کو پن کرنے کے لیے ڈیوائیڈر پر لانگ پریس کریں"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"ٹاسک بار سے بہت کچھ کریں"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"بند کریں"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"ہو گیا"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 4029408..7cc157b 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Skrinshot"</string>
     <string name="action_split" msgid="2098009717623550676">"Ajratish"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Ekranni ikkiga ajratish uchun boshqa ilovani bosing"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Bu amal ilova yoki tashkilotingiz tomonidan taqiqlangan"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Bitta ilovani yon tomonga sudrab, bir vaqtda 2 ta ilovadan foydalaning."</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Vazifalar panelini ochish uchun tepaga asta suring"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Harakatlaringiz asosida tavsiyalar oling."</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Vazifalar paneli avtomatik yopilishi uchun ishorali navigatsiyani yoqing"</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_close" msgid="887022990168191073">"Yopish"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Tayyor"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 3232527..bc9b348 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -95,8 +95,7 @@
     <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="toast_split_select_app" msgid="8464310533320556058">"Nhấn vào ứng dụng khác để chia đôi màn hình"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Ứng dụng hoặc tổ chức của bạn không cho phép thực hiện hành động này"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"Bật tính năng thao tác bằng cử chỉ trong phần Cài đặt để tự động ẩn Thanh tác vụ"</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_features" msgid="3320337287472848162">"Làm nhiều việc hơn qua Thanh tác vụ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Đóng"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Xong"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index d48d9b5..2c740b7 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"屏幕截图"</string>
     <string name="action_split" msgid="2098009717623550676">"拆分"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"点按另一个应用即可使用分屏"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"该应用或您所在的单位不允许执行此操作"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"在设置中开启手势导航后,任务栏会自动隐藏"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"长按分隔线即可固定任务栏"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"体验任务栏的更多功能"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"关闭"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"完成"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 5a4ec9e..af7c663 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"螢幕截圖"</string>
     <string name="action_split" msgid="2098009717623550676">"分割"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"輕按其他應用程式以使用分割螢幕"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"應用程式或你的機構不允許此操作"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"在「設定」中啟用手勢操作後,工作列就會自動隱藏"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"長按分隔線即可固定工作列"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"工作列助你事半功倍"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"完成"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 8ae4403..e4ca3d9 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"螢幕截圖"</string>
     <string name="action_split" msgid="2098009717623550676">"分割"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"輕觸另一個應用程式即可使用分割畫面"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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="blocked_by_policy" msgid="2071401072261365546">"這個應用程式或貴機構不允許執行這個動作"</string>
@@ -110,7 +109,7 @@
     <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_settings_persistent" msgid="1387372982791296151">"在設定中啟用手勢操作後,工作列就會自動隱藏"</string>
+    <string name="taskbar_edu_pinning" msgid="6708550858580071558">"長按分隔線即可固定工作列"</string>
     <string name="taskbar_edu_features" msgid="3320337287472848162">"充分發揮工作列的功用"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"完成"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 4763101..0526940 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -95,8 +95,7 @@
     <string name="action_screenshot" msgid="8171125848358142917">"Isithombe-skrini"</string>
     <string name="action_split" msgid="2098009717623550676">"Hlukanisa"</string>
     <string name="toast_split_select_app" msgid="8464310533320556058">"Thepha enye i-app ukuze usebenzise isikrini sokuhlukanisa"</string>
-    <!-- no translation found for toast_split_select_app_cancel (1532690483356445639) -->
-    <skip />
+    <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>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Lesi senzo asivunyelwanga uhlelo lokusebenza noma inhlangano yakho"</string>
@@ -110,7 +109,7 @@
     <string name="taskbar_edu_splitscreen" msgid="5605512479258053350">"Hudula i-app ukusebenzisa ama-app ama-2 ngesikhathi esisodwa"</string>
     <string name="taskbar_edu_stashing" msgid="5645461372669217294">"Swayiphela phezulu kancane ukuze ubonise i-Taskbar"</string>
     <string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Thola iziphakamiso ze-app ngokusekelwe kumjikelezo wakho"</string>
-    <string name="taskbar_edu_settings_persistent" msgid="1387372982791296151">"Vula ukufuna kokuthinta Kumasethingi ukuze ufihle ngokuzenzakalela ibha yomsebenzi"</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_close" msgid="887022990168191073">"Vala"</string>
     <string name="taskbar_edu_done" msgid="6880178093977704569">"Kwenziwe"</string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 2a1f39f..232c441 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -322,6 +322,7 @@
 
     <!-- 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. -->
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index ae62c26..bdc86b2 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -311,4 +311,9 @@
         <item name="android:letterSpacing">0.025</item>
         <item name="android:lineHeight">20sp</item>
     </style>
+
+    <style name="WidgetPickerActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
+        <item name="widgetsTheme">@style/WidgetContainerTheme</item>
+        <item name="android:windowBackground">@android:color/transparent</item>
+    </style>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index d6ab54e..4898761 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -55,6 +55,7 @@
 import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
 import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
+import static com.android.launcher3.testing.shared.TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE;
 import static com.android.launcher3.util.DisplayController.isTransientTaskbar;
 import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
 import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
@@ -120,6 +121,7 @@
 import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
 import com.android.launcher3.anim.AnimationSuccessListener;
 import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.model.data.ItemInfo;
@@ -1651,6 +1653,16 @@
         if (launcherIsForceInvisibleOrOpening) {
             addCujInstrumentation(anim, playFallBackAnimation
                     ? CUJ_APP_CLOSE_TO_HOME_FALLBACK : CUJ_APP_CLOSE_TO_HOME);
+
+            anim.addListener(new AnimatorListenerAdapter() {
+                @Override
+                public void onAnimationEnd(Animator animation) {
+                    super.onAnimationEnd(animation);
+                    AccessibilityManagerCompat.sendTestProtocolEventToTest(
+                            mLauncher, WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE);
+                }
+            });
+
             // Only register the content animation for cancellation when state changes
             mLauncher.getStateManager().setCurrentAnimation(anim);
 
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
new file mode 100644
index 0000000..43716ab
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -0,0 +1,93 @@
+/*
+ * 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 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.os.Bundle;
+import android.view.WindowInsetsController;
+import android.view.WindowManager;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.dragndrop.SimpleDragLayer;
+import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.widget.BaseWidgetSheet;
+import com.android.launcher3.widget.model.WidgetsListBaseEntry;
+import com.android.launcher3.widget.picker.WidgetsFullSheet;
+
+import java.util.ArrayList;
+
+/** An Activity that can host Launcher's widget picker. */
+public class WidgetPickerActivity extends BaseActivity {
+    private SimpleDragLayer<WidgetPickerActivity> mDragLayer;
+    private WidgetsModel mModel;
+    private final PopupDataProvider mPopupDataProvider = new PopupDataProvider(i -> {});
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
+        getWindow().clearFlags(WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER);
+
+        LauncherAppState app = LauncherAppState.getInstance(this);
+        InvariantDeviceProfile idp = app.getInvariantDeviceProfile();
+
+        mDeviceProfile = idp.getDeviceProfile(this);
+        mModel = new WidgetsModel();
+
+        setContentView(R.layout.widget_picker_activity);
+        mDragLayer = findViewById(R.id.drag_layer);
+        mDragLayer.recreateControllers();
+
+        WindowInsetsController wc = mDragLayer.getWindowInsetsController();
+        wc.hide(navigationBars() + statusBars());
+
+        BaseWidgetSheet widgetSheet = WidgetsFullSheet.show(this, true);
+        widgetSheet.disableNavBarScrim(true);
+        widgetSheet.addOnCloseListener(this::finish);
+
+        refreshAndBindWidgets();
+    }
+
+    @NonNull
+    @Override
+    public PopupDataProvider getPopupDataProvider() {
+        return mPopupDataProvider;
+    }
+
+    @Override
+    public SimpleDragLayer<WidgetPickerActivity> getDragLayer() {
+        return mDragLayer;
+    }
+
+    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));
+        });
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
index 29c5204..0a9dfff 100644
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopNavbarButtonsViewController.java
@@ -18,12 +18,15 @@
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_NOTIFICATIONS;
 import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_QUICK_SETTINGS;
 
+import android.content.Context;
 import android.content.pm.ActivityInfo.Config;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.R;
 
 /**
@@ -40,8 +43,8 @@
     private TaskbarControllers mControllers;
 
     public DesktopNavbarButtonsViewController(TaskbarActivityContext context,
-            FrameLayout navButtonsView) {
-        super(context, navButtonsView);
+            @Nullable Context navigationBarPanelContext, FrameLayout navButtonsView) {
+        super(context, navigationBarPanelContext, navButtonsView);
         mContext = context;
         mNavButtonsView = navButtonsView;
         mNavButtonContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons);
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index cbb991d..b29ce6b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -133,11 +133,20 @@
         GroupTask task = mControllerCallbacks.getTaskAt(index);
         if (task == null) {
             return Math.max(0, index);
-        } else if (mOnDesktop) {
+        }
+        Task task2 = task.task2;
+        int runningTaskId = ActivityManagerWrapper.getInstance().getRunningTask().taskId;
+        if (runningTaskId == task.task1.key.id
+                || (task2 != null && runningTaskId == task2.key.id)) {
+            // Ignore attempts to run the selected task if it is already running.
+            return -1;
+        }
+
+        if (mOnDesktop) {
             UI_HELPER_EXECUTOR.execute(() ->
                     SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
                             .showDesktopApp(task.task1.key.id));
-        } else if (task.task2 == null) {
+        } else if (task2 == null) {
             UI_HELPER_EXECUTOR.execute(() ->
                     ActivityManagerWrapper.getInstance().startActivityFromRecents(
                             task.task1.key,
@@ -145,8 +154,7 @@
                                     taskView == null ? mKeyboardQuickSwitchView : taskView, null)
                                     .options));
         } else {
-            mControllers.uiController.launchSplitTasks(
-                    taskView == null ? mKeyboardQuickSwitchView : taskView, task);
+            mControllers.uiController.launchSplitTasks(task);
         }
         return -1;
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index bbe73ff..159a6ef 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -26,7 +26,6 @@
 import android.os.RemoteException;
 import android.util.Log;
 import android.view.TaskTransitionSpec;
-import android.view.View;
 import android.view.WindowManagerGlobal;
 
 import androidx.annotation.NonNull;
@@ -205,6 +204,11 @@
     }
 
     @Override
+    public void onStateTransitionCompletedAfterSwipeToHome(LauncherState state) {
+        mTaskbarLauncherStateController.onStateTransitionCompletedAfterSwipeToHome(state);
+    }
+
+    @Override
     public void refreshResumedState() {
         onLauncherVisibilityChanged(mLauncher.hasBeenResumed());
     }
@@ -386,8 +390,8 @@
     }
 
     @Override
-    public void launchSplitTasks(@NonNull View taskView, @NonNull GroupTask groupTask) {
-        mLauncher.launchSplitTasks(taskView, groupTask);
+    public void launchSplitTasks(@NonNull GroupTask groupTask) {
+        mLauncher.launchSplitTasks(groupTask);
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 3514447..bed4c37 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -53,6 +53,7 @@
 import android.annotation.DrawableRes;
 import android.annotation.IdRes;
 import android.annotation.LayoutRes;
+import android.content.Context;
 import android.content.pm.ActivityInfo.Config;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
@@ -80,6 +81,8 @@
 import android.widget.ImageView;
 import android.widget.LinearLayout;
 
+import androidx.annotation.Nullable;
+
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.LauncherAnimUtils;
 import com.android.launcher3.R;
@@ -146,6 +149,7 @@
     private int mState;
 
     private final TaskbarActivityContext mContext;
+    private final @Nullable Context mNavigationBarPanelContext;
     private final WindowManagerProxy mWindowManagerProxy;
     private final FrameLayout mNavButtonsView;
     private final LinearLayout mNavButtonContainer;
@@ -203,8 +207,10 @@
     private final RecentsHitboxExtender mHitboxExtender = new RecentsHitboxExtender();
     private ImageView mRecentsButton;
 
-    public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) {
+    public NavbarButtonsViewController(TaskbarActivityContext context,
+            @Nullable Context navigationBarPanelContext, FrameLayout navButtonsView) {
         mContext = context;
+        mNavigationBarPanelContext = navigationBarPanelContext;
         mWindowManagerProxy = WindowManagerProxy.INSTANCE.get(mContext);
         mNavButtonsView = navButtonsView;
         mNavButtonContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons);
@@ -312,7 +318,8 @@
             rotationButton.hide();
             mControllers.rotationButtonController.setRotationButton(rotationButton, null);
         } else {
-            mFloatingRotationButton = new FloatingRotationButton(mContext,
+            mFloatingRotationButton = new FloatingRotationButton(
+                    ENABLE_TASKBAR_NAVBAR_UNIFICATION ? mNavigationBarPanelContext : mContext,
                     R.string.accessibility_rotate_button,
                     R.layout.rotate_suggestion,
                     R.id.rotate_suggestion,
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index c4255bf..da1f766 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -108,7 +108,7 @@
         DeviceProfile deviceProfile = mActivity.getDeviceProfile();
         Resources resources = mActivity.getResources();
         if (isPhoneGestureNavMode(mActivity.getDeviceProfile())) {
-            mTaskbarSize = resources.getDimensionPixelSize(R.dimen.taskbar_size);
+            mTaskbarSize = resources.getDimensionPixelSize(R.dimen.taskbar_phone_size);
             mStashedHandleWidth =
                     resources.getDimensionPixelSize(R.dimen.taskbar_stashed_small_screen);
         } else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 988ef80..4290948 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -74,9 +74,11 @@
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.LauncherPrefs;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dot.DotInfo;
 import com.android.launcher3.folder.Folder;
@@ -106,6 +108,7 @@
 import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy;
 import com.android.launcher3.util.ActivityOptionsWrapper;
+import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Executors;
 import com.android.launcher3.util.NavigationMode;
@@ -127,6 +130,7 @@
 
 import java.io.PrintWriter;
 import java.util.Collections;
+import java.util.List;
 import java.util.Optional;
 import java.util.function.Consumer;
 
@@ -143,6 +147,8 @@
 
     private static final String WINDOW_TITLE = "Taskbar";
 
+    private final @Nullable Context mNavigationBarPanelContext;
+
     private final TaskbarDragLayer mDragLayer;
     private final TaskbarControllers mControllers;
 
@@ -178,11 +184,15 @@
 
     private DeviceProfile mPersistentTaskbarDeviceProfile;
 
-    public TaskbarActivityContext(Context windowContext, DeviceProfile launcherDp,
+    private final LauncherPrefs mLauncherPrefs;
+
+    public TaskbarActivityContext(Context windowContext,
+            @Nullable Context navigationBarPanelContext, DeviceProfile launcherDp,
             TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
             unfoldTransitionProgressProvider) {
         super(windowContext);
 
+        mNavigationBarPanelContext = navigationBarPanelContext;
         applyDeviceProfile(launcherDp);
         final Resources resources = getResources();
 
@@ -203,11 +213,16 @@
         Display display = windowContext.getDisplay();
         Context c = getApplicationContext();
         mWindowManager = c.getSystemService(WindowManager.class);
-        mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
-        mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
+
+        boolean phoneMode = TaskbarManager.isPhoneMode(mDeviceProfile);
+        mLeftCorner = phoneMode
+                ? null
+                : display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
+        mRightCorner = phoneMode
+                ? null
+                : display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
 
         // Inflate views.
-        boolean phoneMode = TaskbarManager.isPhoneMode(mDeviceProfile);
         int taskbarLayout = DisplayController.isTransientTaskbar(this) && !phoneMode
                 ? R.layout.transient_taskbar
                 : R.layout.taskbar;
@@ -251,8 +266,10 @@
                 new TaskbarDragController(this),
                 buttonController,
                 isDesktopMode
-                        ? new DesktopNavbarButtonsViewController(this, navButtonsView)
-                        : new NavbarButtonsViewController(this, navButtonsView),
+                        ? new DesktopNavbarButtonsViewController(this, mNavigationBarPanelContext,
+                                navButtonsView)
+                        : new NavbarButtonsViewController(this, mNavigationBarPanelContext,
+                                navButtonsView),
                 rotationButtonController,
                 new TaskbarDragLayerController(this, mDragLayer),
                 new TaskbarViewController(this, taskbarView),
@@ -280,6 +297,8 @@
                 new KeyboardQuickSwitchController(),
                 new TaskbarPinningController(this),
                 bubbleControllersOptional);
+
+        mLauncherPrefs = LauncherPrefs.get(this);
     }
 
     /** Updates {@link DeviceProfile} instances for any Taskbar windows. */
@@ -397,6 +416,11 @@
                 getDeviceProfile().toSmallString());
     }
 
+    @NonNull
+    public LauncherPrefs getLauncherPrefs() {
+        return mLauncherPrefs;
+    }
+
     /**
      * Returns the View bounds of transient taskbar.
      */
@@ -861,7 +885,7 @@
 
         if (ENABLE_TASKBAR_NAVBAR_UNIFICATION && mDeviceProfile.isPhone) {
             return isThreeButtonNav() ?
-                    resources.getDimensionPixelSize(R.dimen.taskbar_size) :
+                    resources.getDimensionPixelSize(R.dimen.taskbar_phone_size) :
                     resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
         }
 
@@ -970,6 +994,8 @@
     }
 
     protected void onTaskbarIconClicked(View view) {
+        TaskbarUIController taskbarUIController = mControllers.uiController;
+        RecentsView recents = taskbarUIController.getRecentsView();
         boolean shouldCloseAllOpenViews = true;
         Object tag = view.getTag();
         if (tag instanceof Task) {
@@ -977,41 +1003,26 @@
             ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key,
                     ActivityOptions.makeBasic());
             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
-        } else if (tag instanceof FolderInfo) {
+        } else if (tag instanceof FolderInfo fi && fi.itemType == Favorites.ITEM_TYPE_FOLDER) {
+            // Tapping an expandable folder icon on Taskbar
             shouldCloseAllOpenViews = false;
-            FolderIcon folderIcon = (FolderIcon) view;
-            Folder folder = folderIcon.getFolder();
-
-            folder.setOnFolderStateChangedListener(newState -> {
-                if (newState == Folder.STATE_OPEN) {
-                    setTaskbarWindowFocusableForIme(true);
-                } else if (newState == Folder.STATE_CLOSED) {
-                    // Defer by a frame to ensure we're no longer fullscreen and thus won't jump.
-                    getDragLayer().post(() -> setTaskbarWindowFocusableForIme(false));
-                    folder.setOnFolderStateChangedListener(null);
-                }
-            });
-
-            setTaskbarWindowFullscreen(true);
-
-            getDragLayer().post(() -> {
-                folder.animateOpen();
-                getStatsLogManager().logger().withItemInfo(folder.mInfo).log(LAUNCHER_FOLDER_OPEN);
-
-                folder.iterateOverItems((itemInfo, itemView) -> {
-                    mControllers.taskbarViewController
-                            .setClickAndLongClickListenersForIcon(itemView);
-                    // To play haptic when dragging, like other Taskbar items do.
-                    itemView.setHapticFeedbackEnabled(true);
-                    return false;
-                });
-            });
+            expandFolder((FolderIcon) view);
+        } else if (tag instanceof FolderInfo fi && fi.itemType == Favorites.ITEM_TYPE_APP_PAIR) {
+            // 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);
+                mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
+            }
         } else if (tag instanceof WorkspaceItemInfo) {
             // Tapping a launchable icon on Taskbar
             WorkspaceItemInfo info = (WorkspaceItemInfo) tag;
             if (!info.isDisabled() || !ItemClickHandler.handleDisabledItemClicked(info, this)) {
-                TaskbarUIController taskbarUIController = mControllers.uiController;
-                RecentsView recents = taskbarUIController.getRecentsView();
                 if (recents != null && recents.isSplitSelectionActive()) {
                     // If we are selecting a second app for split, launch the split tasks
                     taskbarUIController.triggerSecondAppForSplit(info, info.intent, view);
@@ -1039,7 +1050,8 @@
                             getSystemService(LauncherApps.class)
                                     .startShortcut(packageName, id, null, null, info.user);
                         } else {
-                            launchFromTaskbarPreservingSplitIfVisible(recents, info);
+                            launchFromTaskbarPreservingSplitIfVisible(
+                                    recents, view, Collections.singletonList(info));
                         }
 
                     } catch (NullPointerException
@@ -1050,7 +1062,21 @@
                         Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e);
                         return;
                     }
+                }
 
+                // If the app was launched from a folder, stash the taskbar after it closes
+                Folder f = Folder.getOpen(this);
+                if (f != null && f.getInfo().id == info.container) {
+                    f.addOnFolderStateChangedListener(new Folder.OnFolderStateChangedListener() {
+                        @Override
+                        public void onFolderStateChanged(int newState) {
+                            if (newState == Folder.STATE_CLOSED) {
+                                f.removeOnFolderStateChangedListener(this);
+                                mControllers.taskbarStashController
+                                        .updateAndAnimateTransientTaskbar(true);
+                            }
+                        }
+                    });
                 }
                 mControllers.uiController.onTaskbarIconLaunched(info);
                 mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
@@ -1058,14 +1084,13 @@
         } else if (tag instanceof AppInfo) {
             // Tapping an item in AllApps
             AppInfo info = (AppInfo) tag;
-            TaskbarUIController taskbarUIController = mControllers.uiController;
-            RecentsView recents = taskbarUIController.getRecentsView();
             if (recents != null
                     && taskbarUIController.getRecentsView().isSplitSelectionActive()) {
                 // If we are selecting a second app for split, launch the split tasks
                 taskbarUIController.triggerSecondAppForSplit(info, info.intent, view);
             } else {
-                launchFromTaskbarPreservingSplitIfVisible(recents, info);
+                launchFromTaskbarPreservingSplitIfVisible(
+                        recents, view, Collections.singletonList(info));
             }
             mControllers.uiController.onTaskbarIconLaunched(info);
             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
@@ -1087,17 +1112,22 @@
      * (potentially breaking a split pair).
      */
     private void launchFromTaskbarPreservingSplitIfVisible(@Nullable RecentsView recents,
-            ItemInfo info) {
+            @Nullable View launchingIconView, List<? extends ItemInfo> itemInfos) {
         if (recents == null) {
             return;
         }
+
+        boolean findExactPairMatch = 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(
-                Collections.singletonList(info.getComponentKey()),
+                componentKeys,
+                findExactPairMatch,
                 foundTasks -> {
                     @Nullable Task foundTask = foundTasks.get(0);
                     if (foundTask != null) {
-                        TaskView foundTaskView =
-                                recents.getTaskViewByTaskId(foundTask.key.id);
+                        TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);
                         if (foundTaskView != null
                                 && foundTaskView.isVisibleToUser()) {
                             TestLogging.recordEvent(
@@ -1106,8 +1136,16 @@
                             return;
                         }
                     }
-                    startItemInfoActivity(info);
-                });
+
+                    if (findExactPairMatch) {
+                        // We did not find the app pair we were looking for, so launch one.
+                        recents.getSplitSelectController().getAppPairsController().launchAppPair(
+                                (AppPairIcon) launchingIconView);
+                    } else {
+                        startItemInfoActivity(itemInfos.get(0));
+                    }
+                }
+        );
     }
 
     private void startItemInfoActivity(ItemInfo info) {
@@ -1129,6 +1167,41 @@
         }
     }
 
+    /** Expands a folder icon when it is clicked */
+    private void expandFolder(FolderIcon folderIcon) {
+        Folder folder = folderIcon.getFolder();
+
+        folder.setPriorityOnFolderStateChangedListener(
+                new Folder.OnFolderStateChangedListener() {
+                    @Override
+                    public void onFolderStateChanged(int newState) {
+                        if (newState == Folder.STATE_OPEN) {
+                            setTaskbarWindowFocusableForIme(true);
+                        } else if (newState == Folder.STATE_CLOSED) {
+                            // Defer by a frame to ensure we're no longer fullscreen and thus
+                            // won't jump.
+                            getDragLayer().post(() -> setTaskbarWindowFocusableForIme(false));
+                            folder.setPriorityOnFolderStateChangedListener(null);
+                        }
+                    }
+                });
+
+        setTaskbarWindowFullscreen(true);
+
+        getDragLayer().post(() -> {
+            folder.animateOpen();
+            getStatsLogManager().logger().withItemInfo(folder.mInfo).log(LAUNCHER_FOLDER_OPEN);
+
+            folder.iterateOverItems((itemInfo, itemView) -> {
+                mControllers.taskbarViewController
+                        .setClickAndLongClickListenersForIcon(itemView);
+                // To play haptic when dragging, like other Taskbar items do.
+                itemView.setHapticFeedbackEnabled(true);
+                return false;
+            });
+        });
+    }
+
     /**
      * Returns whether the taskbar is currently visually stashed.
      */
@@ -1137,15 +1210,6 @@
     }
 
     /**
-     * Called when we detect a long press in the nav region before passing the gesture slop.
-     *
-     * @return Whether taskbar handled the long press, and thus should cancel the gesture.
-     */
-    public boolean onLongPressToUnstashTaskbar() {
-        return mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
-    }
-
-    /**
      * Called when we want to unstash taskbar when user performs swipes up gesture.
      */
     public void onSwipeToUnstashTaskbar() {
@@ -1200,28 +1264,7 @@
      * @param animateForward Whether to animate towards the unstashed hint state or back to stashed.
      */
     public void startTaskbarUnstashHint(boolean animateForward) {
-        // TODO(b/270395798): Clean up forceUnstash after removing long-press unstashing code.
-        startTaskbarUnstashHint(animateForward, /* forceUnstash = */ false);
-    }
-
-    /**
-     * Called when we detect a motion down or up/cancel in the nav region while stashed.
-     *
-     * @param animateForward Whether to animate towards the unstashed hint state or back to stashed.
-     * @param forceUnstash   Whether we force the unstash hint.
-     */
-    public void startTaskbarUnstashHint(boolean animateForward, boolean forceUnstash) {
-        // TODO(b/270395798): Clean up forceUnstash after removing long-press unstashing code.
-        mControllers.taskbarStashController.startUnstashHint(animateForward, forceUnstash);
-    }
-
-    /**
-     * Enables manual taskbar stashing. This method should only be used for tests that need to
-     * stash/unstash the taskbar.
-     */
-    @VisibleForTesting
-    public void enableManualStashingDuringTests(boolean enableManualStashing) {
-        mControllers.taskbarStashController.enableManualStashingDuringTests(enableManualStashing);
+        mControllers.taskbarStashController.startUnstashHint(animateForward);
     }
 
     /**
@@ -1234,15 +1277,12 @@
     }
 
     /**
-     * Unstashes the Taskbar if it is stashed. This method should only be used to unstash the
-     * taskbar at the end of a test.
+     * Unstashes the Taskbar if it is stashed.
      */
     @VisibleForTesting
     public void unstashTaskbarIfStashed() {
         if (DisplayController.isTransientTaskbar(this)) {
             mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
-        } else {
-            mControllers.taskbarStashController.onLongPressToUnstashTaskbar();
         }
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
index ffaee45..333c07b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
@@ -22,7 +22,7 @@
 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
 
 import static com.android.launcher3.taskbar.NavbarButtonsViewController.ALPHA_INDEX_IMMERSIVE_MODE;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IMMERSIVE_MODE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY;
 
 import android.os.Bundle;
 import android.os.Handler;
@@ -84,7 +84,7 @@
 
     /** Update values tracked via sysui flags. */
     public void updateSysuiFlags(int sysuiFlags) {
-        mIsImmersiveMode = (sysuiFlags & SYSUI_STATE_IMMERSIVE_MODE) != 0;
+        mIsImmersiveMode = (sysuiFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) == 0;
         if (mContext.isNavBarForceVisible()) {
             if (mIsImmersiveMode) {
                 startIconDimming();
@@ -158,8 +158,7 @@
 
     @Override
     public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
-        if (!isNavbarShownInImmersiveMode()
-                || mControllers.taskbarStashController.supportsManualStashing()) {
+        if (!isNavbarShownInImmersiveMode()) {
             return false;
         }
         return onControllerTouchEvent(ev);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 9a37bcb..057b71b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -205,13 +205,6 @@
                 public void onStateTransitionComplete(LauncherState finalState) {
                     mLauncherState = finalState;
                     updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, false);
-                    // 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
-                            && mLauncher.hasBeenResumed()) {
-                        updateStateForFlag(FLAG_VISIBLE, true);
-                    }
                     applyState();
                     boolean disallowLongClick =
                             FeatureFlags.enableSplitContextually()
@@ -223,6 +216,21 @@
                 }
             };
 
+    /**
+     * Callback for when launcher state transition completes after user swipes to home.
+     * @param finalState The final state of the transition.
+     */
+    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)
+                && mLauncher.hasBeenResumed()) {
+            updateStateForFlag(FLAG_VISIBLE, true);
+            applyState();
+        }
+    }
+
     /** Initializes the controller instance, and applies the initial state immediately. */
     public void init(TaskbarControllers controllers, QuickstepLauncher launcher,
             int sysuiStateFlags) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index c0b07e7..bbac116 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -106,6 +106,7 @@
             Settings.Secure.NAV_BAR_KIDS_MODE);
 
     private final Context mContext;
+    private final @Nullable Context mNavigationBarPanelContext;
     private WindowManager mWindowManager;
     private FrameLayout mTaskbarRootLayout;
     private boolean mAddedWindow;
@@ -198,6 +199,9 @@
         mContext = service.createWindowContext(display,
                 ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL,
                 null);
+        mNavigationBarPanelContext = ENABLE_TASKBAR_NAVBAR_UNIFICATION
+                ? service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null)
+                : null;
         if (enableTaskbarNoRecreate()) {
             mWindowManager = mContext.getSystemService(WindowManager.class);
             mTaskbarRootLayout = new FrameLayout(mContext) {
@@ -435,8 +439,9 @@
             }
 
             if (enableTaskbarNoRecreate() || mTaskbarActivityContext == null) {
-                mTaskbarActivityContext = new TaskbarActivityContext(mContext, dp,
-                        mNavButtonController, mUnfoldProgressProvider);
+                mTaskbarActivityContext = new TaskbarActivityContext(mContext,
+                        mNavigationBarPanelContext, dp, mNavButtonController,
+                        mUnfoldProgressProvider);
             } else {
                 mTaskbarActivityContext.updateDeviceProfile(dp);
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
index cbfa024..6cb28ee 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -16,7 +16,9 @@
 package com.android.launcher3.taskbar
 
 import android.animation.AnimatorSet
+import android.annotation.SuppressLint
 import android.view.View
+import androidx.annotation.VisibleForTesting
 import androidx.core.animation.doOnEnd
 import com.android.launcher3.LauncherPrefs
 import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
@@ -31,46 +33,68 @@
 
     private lateinit var controllers: TaskbarControllers
     private lateinit var taskbarSharedState: TaskbarSharedState
-    private val launcherPrefs = LauncherPrefs.get(context)
+    private lateinit var launcherPrefs: LauncherPrefs
     private val statsLogManager = context.statsLogManager
-    private var isAnimatingTaskbarPinning = false
+    @VisibleForTesting var isAnimatingTaskbarPinning = false
+    @VisibleForTesting lateinit var onCloseCallback: (preferenceChanged: Boolean) -> Unit
 
+    @SuppressLint("VisibleForTests")
     fun init(taskbarControllers: TaskbarControllers, sharedState: TaskbarSharedState) {
         controllers = taskbarControllers
         taskbarSharedState = sharedState
+        launcherPrefs = context.launcherPrefs
+        onCloseCallback =
+            fun(didPreferenceChange: Boolean) {
+                statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE)
+                context.dragLayer.post { context.onPopupVisibilityChanged(false) }
+
+                if (!didPreferenceChange) {
+                    return
+                }
+                val animateToValue =
+                    if (!launcherPrefs.get(TASKBAR_PINNING)) {
+                        PINNING_PERSISTENT
+                    } else {
+                        PINNING_TRANSIENT
+                    }
+                taskbarSharedState.taskbarWasPinned = animateToValue == PINNING_TRANSIENT
+                animateTaskbarPinning(animateToValue)
+            }
     }
 
     fun showPinningView(view: View) {
         context.isTaskbarWindowFullscreen = true
-
         view.post {
-            val popupView = createAndPopulate(view, context)
+            val popupView = getPopupView(view)
             popupView.requestFocus()
-
-            popupView.onCloseCallback =
-                callback@{ didPreferenceChange ->
-                    statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE)
-                    context.dragLayer.post { context.onPopupVisibilityChanged(false) }
-
-                    if (!didPreferenceChange) {
-                        return@callback
-                    }
-                    val animateToValue =
-                        if (!launcherPrefs.get(TASKBAR_PINNING)) {
-                            PINNING_PERSISTENT
-                        } else {
-                            PINNING_TRANSIENT
-                        }
-                    taskbarSharedState.taskbarWasPinned = animateToValue == PINNING_TRANSIENT
-                    animateTaskbarPinning(animateToValue)
-                }
+            popupView.onCloseCallback = onCloseCallback
             context.onPopupVisibilityChanged(true)
             popupView.show()
             statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN)
         }
     }
 
-    private fun animateTaskbarPinning(animateToValue: Float) {
+    @VisibleForTesting
+    fun getPopupView(view: View): TaskbarDividerPopupView<*> {
+        return createAndPopulate(view, context)
+    }
+
+    @VisibleForTesting
+    fun animateTaskbarPinning(animateToValue: Float) {
+        val taskbarViewController = controllers.taskbarViewController
+        val animatorSet =
+            getAnimatorSetForTaskbarPinningAnimation(animateToValue).apply {
+                doOnEnd { recreateTaskbarAndUpdatePinningValue() }
+                duration = PINNING_ANIMATION_DURATION
+            }
+        controllers.taskbarOverlayController.hideWindow()
+        updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(true)
+        taskbarViewController.animateAwayNotificationDotsDuringTaskbarPinningAnimation()
+        animatorSet.start()
+    }
+
+    @VisibleForTesting
+    fun getAnimatorSetForTaskbarPinningAnimation(animateToValue: Float): AnimatorSet {
         val animatorSet = AnimatorSet()
         val taskbarViewController = controllers.taskbarViewController
         val dragLayerController = controllers.taskbarDragLayerController
@@ -82,13 +106,7 @@
             taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue)
         )
 
-        controllers.taskbarOverlayController.hideWindow()
-
-        animatorSet.doOnEnd { recreateTaskbarAndUpdatePinningValue() }
-        animatorSet.duration = PINNING_ANIMATION_DURATION
-        updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(true)
-        taskbarViewController.animateAwayNotificationDotsDuringTaskbarPinningAnimation()
-        animatorSet.start()
+        return animatorSet
     }
 
     private fun updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(isAnimating: Boolean) {
@@ -96,7 +114,8 @@
         context.dragLayer.setAnimatingTaskbarPinning(isAnimating)
     }
 
-    private fun recreateTaskbarAndUpdatePinningValue() {
+    @VisibleForTesting
+    fun recreateTaskbarAndUpdatePinningValue() {
         updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(false)
         launcherPrefs.put(TASKBAR_PINNING, !launcherPrefs.get(TASKBAR_PINNING))
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index 176a8c5..d09f74c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -73,9 +73,21 @@
     };
 
     // Allows us to shift translation logic when doing taskbar pinning animation.
-    public Boolean startTaskbarVariantIsTransient = true;
+    public boolean startTaskbarVariantIsTransient = true;
 
     // To track if taskbar was pinned using taskbar pinning feature at the time of recreate,
     // so we can unstash transient taskbar when we un-pinning taskbar.
-    public Boolean taskbarWasPinned = false;
+    private boolean mTaskbarWasPinned = false;
+
+    public boolean getTaskbarWasPinned() {
+        return mTaskbarWasPinned;
+    }
+
+    public void setTaskbarWasPinned(boolean taskbarWasPinned) {
+        mTaskbarWasPinned = taskbarWasPinned;
+    }
+
+    // To track if taskbar was stashed / unstashed between configuration changes (which recreates
+    // the task bar).
+    public Boolean taskbarWasStashedAuto = true;
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java
index e8c8fc4..bfbecf3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarShortcutMenuAccessibilityDelegate.java
@@ -34,6 +34,7 @@
 import com.android.launcher3.accessibility.BaseAccessibilityDelegate;
 import com.android.launcher3.logging.StatsLogManager;
 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;
@@ -84,9 +85,9 @@
 
     @Override
     protected boolean performAction(View host, ItemInfo item, int action, boolean fromKeyboard) {
-        if (item instanceof WorkspaceItemInfo
+        if (item instanceof ItemInfoWithIcon
                 && (action == MOVE_TO_TOP_OR_LEFT || action == MOVE_TO_BOTTOM_OR_RIGHT)) {
-            WorkspaceItemInfo info = (WorkspaceItemInfo) item;
+            ItemInfoWithIcon info = (ItemInfoWithIcon) item;
             int side = action == MOVE_TO_TOP_OR_LEFT
                     ? STAGE_POSITION_TOP_OR_LEFT : STAGE_POSITION_BOTTOM_OR_RIGHT;
 
@@ -97,10 +98,11 @@
                     .withInstanceId(instanceIds.second)
                     .log(getLogEventForPosition(side));
 
-            if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+            if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
+                    && item instanceof WorkspaceItemInfo) {
                 SystemUiProxy.INSTANCE.get(mContext).startShortcut(
                         info.getIntent().getPackage(),
-                        info.getDeepShortcutId(),
+                        ((WorkspaceItemInfo) info).getDeepShortcutId(),
                         side,
                         /* bundleOpts= */ null,
                         info.user,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index a34df4f..9aaa80f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -15,17 +15,13 @@
  */
 package com.android.launcher3.taskbar;
 
-import static android.view.HapticFeedbackConstants.LONG_PRESS;
 import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_CONTROLS;
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
 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.LauncherPrefs.TASKBAR_PINNING;
-import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW;
+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;
 import static com.android.launcher3.taskbar.TaskbarKeyguardController.MASK_ANY_SYSUI_LOCKED;
@@ -44,7 +40,6 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.app.RemoteAction;
-import android.content.SharedPreferences;
 import android.graphics.drawable.Icon;
 import android.os.SystemClock;
 import android.util.Log;
@@ -62,9 +57,7 @@
 import com.android.internal.jank.InteractionJankMonitor;
 import com.android.launcher3.Alarm;
 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.AnimatedFloat;
 import com.android.launcher3.anim.AnimatorListeners;
 import com.android.launcher3.util.DisplayController;
@@ -86,27 +79,26 @@
     private static final boolean DEBUG = false;
 
     public static final int FLAG_IN_APP = 1 << 0;
-    public static final int FLAG_STASHED_IN_APP_MANUAL = 1 << 1; // long press, persisted
-    public static final int FLAG_STASHED_IN_APP_SYSUI = 1 << 2; // shade open, ...
-    public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 3; // setup wizard and AllSetActivity
-    public static final int FLAG_STASHED_IN_APP_IME = 1 << 4; // IME is visible
-    public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 5;
-    public static final int FLAG_STASHED_IN_TASKBAR_ALL_APPS = 1 << 6; // All apps is visible.
-    public static final int FLAG_IN_SETUP = 1 << 7; // In the Setup Wizard
-    public static final int FLAG_STASHED_SMALL_SCREEN = 1 << 8; // phone screen gesture nav, stashed
-    public static final int FLAG_STASHED_IN_APP_AUTO = 1 << 9; // Autohide (transient taskbar).
-    public static final int FLAG_STASHED_SYSUI = 1 << 10; //  app pinning,...
-    public static final int FLAG_STASHED_DEVICE_LOCKED = 1 << 11; // device is locked: keyguard, ...
-    public static final int FLAG_IN_OVERVIEW = 1 << 12; // launcher is in overview
+    public static final int FLAG_STASHED_IN_APP_SYSUI = 1 << 1; // shade open, ...
+    public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 2; // setup wizard and AllSetActivity
+    public static final int FLAG_STASHED_IN_APP_IME = 1 << 3; // IME is visible
+    public static final int FLAG_IN_STASHED_LAUNCHER_STATE = 1 << 4;
+    public static final int FLAG_STASHED_IN_TASKBAR_ALL_APPS = 1 << 5; // All apps is visible.
+    public static final int FLAG_IN_SETUP = 1 << 6; // In the Setup Wizard
+    public static final int FLAG_STASHED_SMALL_SCREEN = 1 << 7; // phone screen gesture nav, stashed
+    public static final int FLAG_STASHED_IN_APP_AUTO = 1 << 8; // Autohide (transient taskbar).
+    public static final int FLAG_STASHED_SYSUI = 1 << 9; //  app pinning,...
+    public static final int FLAG_STASHED_DEVICE_LOCKED = 1 << 10; // device is locked: keyguard, ...
+    public static final int FLAG_IN_OVERVIEW = 1 << 11; // launcher is in overview
 
     // If any of these flags are enabled, isInApp should return true.
     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_MANUAL
-            | 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;
+    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;
 
     // If any of these flags are enabled, inset apps by our stashed height instead of our unstashed
     // height. This way the reported insets are consistent even during transitions out of the app.
@@ -167,21 +159,11 @@
     private static final long TASKBAR_STASH_ICON_ALPHA_HOME_TO_APP_START_DELAY = 66;
 
     /**
-     * The scale that TaskbarView animates to when hinting towards the stashed state.
-     */
-    private static final float STASHED_TASKBAR_HINT_SCALE = 0.9f;
-
-    /**
      * The scale that the stashed handle animates to when hinting towards the unstashed state.
      */
     private static final float UNSTASHED_TASKBAR_HANDLE_HINT_SCALE = 1.1f;
 
     /**
-     * The SharedPreferences key for whether user has manually stashed the taskbar.
-     */
-    private static final String SHARED_PREFS_STASHED_KEY = "taskbar_is_stashed";
-
-    /**
      * Whether taskbar should be stashed out of the box.
      */
     private static final boolean DEFAULT_STASHED_PREF = false;
@@ -224,7 +206,6 @@
     private @interface StashAnimation {}
 
     private final TaskbarActivityContext mActivity;
-    private final SharedPreferences mPrefs;
     private final int mStashedHeight;
     private final int mUnstashedHeight;
     private final SystemUiProxy mSystemUiProxy;
@@ -253,8 +234,6 @@
     private boolean mIsImeShowing;
     private boolean mIsImeSwitcherShowing;
 
-    private boolean mEnableManualStashingDuringTests = false;
-
     private final Alarm mTimeoutAlarm = new Alarm();
     private boolean mEnableBlockingTimeoutDuringTests = false;
 
@@ -274,12 +253,12 @@
 
     public TaskbarStashController(TaskbarActivityContext activity) {
         mActivity = activity;
-        mPrefs = LauncherPrefs.getPrefs(mActivity);
         mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
         mAccessibilityManager = mActivity.getSystemService(AccessibilityManager.class);
 
         if (isPhoneMode()) {
-            mUnstashedHeight = mActivity.getResources().getDimensionPixelSize(R.dimen.taskbar_size);
+            mUnstashedHeight = mActivity.getResources().getDimensionPixelSize(
+                    R.dimen.taskbar_phone_size);
             mStashedHeight = mActivity.getResources().getDimensionPixelSize(
                     R.dimen.taskbar_stashed_size);
         } else {
@@ -328,17 +307,13 @@
         mTaskbarStashedHandleHintScale = stashedHandleController.getStashedHandleHintScale();
 
         boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
-        // We use supportsVisualStashing() here instead of supportsManualStashing() because we want
-        // it to work properly for tests that recreate taskbar. This check is here just to ensure
-        // that taskbar unstashes when going to 3 button mode (supportsVisualStashing() false).
-        boolean isManuallyStashedInApp = supportsVisualStashing()
-                && !isTransientTaskbar
-                && !enableTaskbarPinning()
-                && mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF);
         boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible;
-        updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
-        updateStateForFlag(FLAG_STASHED_IN_APP_AUTO,
-                isTransientTaskbar && !mTaskbarSharedState.taskbarWasPinned);
+        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()
@@ -347,7 +322,8 @@
         // us that we're paused until a bit later. This avoids flickering upon recreating taskbar.
         updateStateForFlag(FLAG_IN_APP, true);
         applyState(/* duration = */ 0);
-        if (mTaskbarSharedState.taskbarWasPinned) {
+        if (mTaskbarSharedState.getTaskbarWasPinned()
+                || !mTaskbarSharedState.taskbarWasStashedAuto) {
             tryStartTaskbarTimeout();
         }
         notifyStashChange(/* visible */ false, /* stashed */ isStashedInApp());
@@ -362,28 +338,6 @@
     }
 
     /**
-     * Returns whether the user can manually stash the taskbar based on the current device state.
-     */
-    protected boolean supportsManualStashing() {
-        if (enableTaskbarPinning() && LauncherPrefs.get(mActivity).get(TASKBAR_PINNING)) {
-            return false;
-        }
-        return supportsVisualStashing()
-                && isInApp()
-                && (!Utilities.isRunningInTestHarness() || mEnableManualStashingDuringTests)
-                && !DisplayController.isTransientTaskbar(mActivity);
-    }
-
-    /**
-     * Enables support for manual stashing. This should only be used to add this functionality
-     * to Launcher specific tests.
-     */
-    @VisibleForTesting
-    public void enableManualStashingDuringTests(boolean enableManualStashing) {
-        mEnableManualStashingDuringTests = enableManualStashing;
-    }
-
-    /**
      * Enables the auto timeout for taskbar stashing. This method should only be used for taskbar
      * testing.
      */
@@ -544,6 +498,7 @@
         }
 
         if (hasAnyFlag(FLAG_STASHED_IN_APP_AUTO) != stash) {
+            mTaskbarSharedState.taskbarWasStashedAuto = stash;
             updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, stash);
             applyState();
         }
@@ -577,53 +532,6 @@
                 /* shouldBubblesFollow= */ !bubbleBarExpanded);
     }
 
-    /**
-     * Should be called when long pressing the nav region when taskbar is present.
-     * @return Whether taskbar was stashed and now is unstashed.
-     */
-    public boolean onLongPressToUnstashTaskbar() {
-        if (!isStashed()) {
-            // We only listen for long press on the nav region to unstash the taskbar. To stash the
-            // taskbar, we use an OnLongClickListener on TaskbarView instead.
-            return false;
-        }
-        if (!canCurrentlyManuallyUnstash()) {
-            return false;
-        }
-        if (updateAndAnimateIsManuallyStashedInApp(false)) {
-            mControllers.taskbarActivityContext.getDragLayer().performHapticFeedback(LONG_PRESS);
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * Returns whether taskbar will unstash when long pressing it based on the current state. The
-     * only time this is true is if the user is in an app and the taskbar is only stashed because
-     * the user previously long pressed to manually stash (not due to other reasons like IME).
-     */
-    private boolean canCurrentlyManuallyUnstash() {
-        return (mState & (FLAG_IN_APP | FLAGS_STASHED_IN_APP))
-                == (FLAG_IN_APP | FLAG_STASHED_IN_APP_MANUAL);
-    }
-
-    /**
-     * Updates whether we should stash the taskbar when in apps, and animates to the changed state.
-     * @return Whether we started an animation to either be newly stashed or unstashed.
-     */
-    public boolean updateAndAnimateIsManuallyStashedInApp(boolean isManuallyStashedInApp) {
-        if (!supportsManualStashing()) {
-            return false;
-        }
-        if (hasAnyFlag(FLAG_STASHED_IN_APP_MANUAL) != isManuallyStashedInApp) {
-            mPrefs.edit().putBoolean(SHARED_PREFS_STASHED_KEY, isManuallyStashedInApp).apply();
-            updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
-            applyState();
-            return true;
-        }
-        return false;
-    }
-
     /** Toggles the Taskbar's stash state. */
     public void toggleTaskbarStash() {
         if (!DisplayController.isTransientTaskbar(mActivity) || !hasAnyFlag(FLAGS_IN_APP)) return;
@@ -910,21 +818,6 @@
             }
         });
     }
-    /**
-     * Creates and starts a partial stash animation, hinting at the new state that will trigger when
-     * long press is detected.
-     * @param animateForward Whether we are going towards the new stashed state or returning to the
-     *                       unstashed state.
-     */
-    public void startStashHint(boolean animateForward) {
-        if (isStashed() || !supportsManualStashing()) {
-            // Already stashed, no need to hint in that direction.
-            return;
-        }
-        mIconScaleForStash.animateToValue(
-                animateForward ? STASHED_TASKBAR_HINT_SCALE : 1)
-                .setDuration(TASKBAR_HINT_STASH_DURATION).start();
-    }
 
     /**
      * Creates and starts a partial unstash animation, hinting at the new state that will trigger
@@ -932,19 +825,12 @@
      *
      * @param animateForward Whether we are going towards the new unstashed state or returning to
      *                       the stashed state.
-     * @param forceUnstash Whether we force the unstash hint to animate.
      */
-    protected void startUnstashHint(boolean animateForward, boolean forceUnstash) {
+    protected void startUnstashHint(boolean animateForward) {
         if (!isStashed()) {
             // Already unstashed, no need to hint in that direction.
             return;
         }
-        // TODO(b/270395798): Clean up after removing long-press unstashing code path.
-        if (!canCurrentlyManuallyUnstash() && !forceUnstash) {
-            // If any other flags are causing us to be stashed, long press won't cause us to
-            // unstash, so don't hint that it will.
-            return;
-        }
         mTaskbarStashedHandleHintScale.animateToValue(
                 animateForward ? UNSTASHED_TASKBAR_HANDLE_HINT_SCALE : 1)
                 .setDuration(TASKBAR_HINT_STASH_DURATION).start();
@@ -1097,13 +983,6 @@
             mControllers.taskbarAutohideSuspendController.updateFlag(
                     TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER, !isInApp());
         }
-        if (hasAnyFlag(changedFlags, FLAG_STASHED_IN_APP_MANUAL)) {
-            if (hasAnyFlag(FLAG_STASHED_IN_APP_MANUAL)) {
-                mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_LONGPRESS_HIDE);
-            } else {
-                mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_LONGPRESS_SHOW);
-            }
-        }
         if (hasAnyFlag(changedFlags, FLAG_STASHED_IN_APP_AUTO)) {
             mActivity.getStatsLogManager().logger().log(hasAnyFlag(FLAG_STASHED_IN_APP_AUTO)
                     ? LAUNCHER_TRANSIENT_TASKBAR_HIDE
@@ -1227,7 +1106,6 @@
     private static String getStateString(int flags) {
         StringJoiner sj = new StringJoiner("|");
         appendFlag(sj, flags, FLAGS_IN_APP, "FLAG_IN_APP");
-        appendFlag(sj, flags, FLAG_STASHED_IN_APP_MANUAL, "FLAG_STASHED_IN_APP_MANUAL");
         appendFlag(sj, flags, FLAG_STASHED_IN_APP_SYSUI, "FLAG_STASHED_IN_APP_SYSUI");
         appendFlag(sj, flags, FLAG_STASHED_IN_APP_SETUP, "FLAG_STASHED_IN_APP_SETUP");
         appendFlag(sj, flags, FLAG_STASHED_IN_APP_IME, "FLAG_STASHED_IN_APP_IME");
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 445b312..df2a43b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -30,6 +30,7 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.LauncherState;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -216,6 +217,7 @@
 
         recentsView.getSplitSelectController().findLastActiveTasksAndRunCallback(
                 Collections.singletonList(splitSelectSource.itemInfo.getComponentKey()),
+                false /* findExactPairMatch */,
                 foundTasks -> {
                     @Nullable Task foundTask = foundTasks.get(0);
                     splitSelectSource.alreadyRunningTaskId = foundTask == null
@@ -234,6 +236,7 @@
         RecentsView recents = getRecentsView();
         recents.getSplitSelectController().findLastActiveTasksAndRunCallback(
                 Collections.singletonList(info.getComponentKey()),
+                false /* findExactPairMatch */,
                 foundTasks -> {
                     @Nullable Task foundTask = foundTasks.get(0);
                     if (foundTask != null) {
@@ -297,11 +300,9 @@
     }
 
     /**
-     * Launches the focused task in splitscreen.
-     *
-     * No-op if the view is not yet open.
+     * Launches the given task in split-screen.
      */
-    public void launchSplitTasks(@NonNull View taskview, @NonNull GroupTask groupTask) { }
+    public void launchSplitTasks(@NonNull GroupTask groupTask) { }
 
     /**
      * Returns the matching view (if any) in the taskbar.
@@ -330,6 +331,14 @@
     }
 
     /**
+     * Callback for when launcher state transition completes after user swipes to home.
+     * @param finalState The final state of the transition.
+     */
+    public void onStateTransitionCompletedAfterSwipeToHome(LauncherState finalState) {
+        // Overridden
+    }
+
+    /**
      * Refreshes the resumed state of this ui controller.
      */
     public void refreshResumedState() {}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 1be1798..2ab0066 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -19,6 +19,8 @@
 import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
 
 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;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR;
 import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
 import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
@@ -47,6 +49,7 @@
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
 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.model.data.FolderInfo;
@@ -261,8 +264,6 @@
         mIconClickListener = mControllerCallbacks.getIconOnClickListener();
         mIconLongClickListener = mControllerCallbacks.getIconOnLongClickListener();
 
-        setOnLongClickListener(mControllerCallbacks.getBackgroundOnLongClickListener());
-
         if (mAllAppsButton != null) {
             mAllAppsButton.setOnClickListener(mControllerCallbacks.getAllAppsButtonClickListener());
         }
@@ -309,12 +310,14 @@
 
             // Replace any Hotseat views with the appropriate type if it's not already that type.
             final int expectedLayoutResId;
-            boolean isFolder = false;
+            boolean isCollection = false;
             if (hotseatItemInfo.isPredictedItem()) {
                 expectedLayoutResId = R.layout.taskbar_predicted_app_icon;
-            } else if (hotseatItemInfo instanceof FolderInfo) {
-                expectedLayoutResId = R.layout.folder_icon;
-                isFolder = true;
+            } else if (hotseatItemInfo instanceof FolderInfo fi) {
+                expectedLayoutResId = fi.itemType == ITEM_TYPE_APP_PAIR
+                        ? R.layout.app_pair_icon
+                        : R.layout.folder_icon;
+                isCollection = true;
             } else {
                 expectedLayoutResId = R.layout.taskbar_app_icon;
             }
@@ -325,7 +328,7 @@
 
                 // see if the view can be reused
                 if ((hotseatView.getSourceLayoutResId() != expectedLayoutResId)
-                        || (isFolder && (hotseatView.getTag() != hotseatItemInfo))) {
+                        || (isCollection && (hotseatView.getTag() != hotseatItemInfo))) {
                     // Unlike for BubbleTextView, we can't reapply a new FolderInfo after inflation,
                     // so if the info changes we need to reinflate. This should only happen if a new
                     // folder is dragged to the position that another folder previously existed.
@@ -338,12 +341,23 @@
             }
 
             if (hotseatView == null) {
-                if (isFolder) {
+                if (isCollection) {
                     FolderInfo folderInfo = (FolderInfo) hotseatItemInfo;
-                    FolderIcon folderIcon = FolderIcon.inflateFolderAndIcon(expectedLayoutResId,
-                            mActivityContext, this, folderInfo);
-                    folderIcon.setTextVisible(false);
-                    hotseatView = folderIcon;
+                    switch (hotseatItemInfo.itemType) {
+                        case ITEM_TYPE_FOLDER:
+                            hotseatView = FolderIcon.inflateFolderAndIcon(
+                                    expectedLayoutResId, mActivityContext, this, folderInfo);
+                            ((FolderIcon) hotseatView).setTextVisible(false);
+                            break;
+                        case ITEM_TYPE_APP_PAIR:
+                            hotseatView = AppPairIcon.inflateIcon(
+                                    expectedLayoutResId, mActivityContext, this, folderInfo);
+                            ((AppPairIcon) hotseatView).setTextVisible(false);
+                            break;
+                        default:
+                            throw new IllegalStateException(
+                                    "Unexpected item type: " + hotseatItemInfo.itemType);
+                    }
                 } else {
                     hotseatView = inflate(expectedLayoutResId);
                 }
@@ -513,24 +527,6 @@
         }
     }
 
-    @Override
-    public boolean onTouchEvent(MotionEvent event) {
-        if (mIconLayoutBounds.left <= event.getX() && event.getX() <= mIconLayoutBounds.right) {
-            // Don't allow long pressing between icons, or above/below them.
-            return true;
-        }
-        if (mControllerCallbacks.onTouchEvent(event)) {
-            int oldAction = event.getAction();
-            try {
-                event.setAction(MotionEvent.ACTION_CANCEL);
-                return super.onTouchEvent(event);
-            } finally {
-                event.setAction(oldAction);
-            }
-        }
-        return super.onTouchEvent(event);
-    }
-
     /**
      * Returns whether the given MotionEvent, *in screen coorindates*, is within any Taskbar item's
      * touch bounds.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 8a7a98c..c0cbd45 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -22,7 +22,6 @@
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
 import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
 import static com.android.launcher3.Utilities.mapRange;
-import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.anim.AnimatedFloat.VALUE;
 import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
@@ -193,7 +192,7 @@
         mControllers = controllers;
         mTaskbarView.init(new TaskbarViewCallbacks());
         mTaskbarView.getLayoutParams().height = isPhoneMode(mActivity.getDeviceProfile())
-                ? mActivity.getResources().getDimensionPixelSize(R.dimen.taskbar_size)
+                ? mActivity.getResources().getDimensionPixelSize(R.dimen.taskbar_phone_size)
                 : mActivity.getDeviceProfile().taskbarHeight;
 
         mTaskbarIconScaleForStash.updateValue(1f);
@@ -899,53 +898,12 @@
             return mControllers.taskbarDragController::startDragOnLongClick;
         }
 
-        public View.OnLongClickListener getBackgroundOnLongClickListener() {
-            return view -> mControllers.taskbarStashController
-                    .updateAndAnimateIsManuallyStashedInApp(true);
-        }
-
         /** Gets the hover listener for the provided icon view. */
         public View.OnHoverListener getIconOnHoverListener(View icon) {
             return new TaskbarHoverToolTipController(mActivity, mTaskbarView, icon);
         }
 
         /**
-         * Get the first chance to handle TaskbarView#onTouchEvent, and return whether we want to
-         * consume the touch so TaskbarView treats it as an ACTION_CANCEL.
-         * TODO(b/270395798): We can remove this entirely once we remove the Transient Taskbar flag.
-         */
-        public boolean onTouchEvent(MotionEvent motionEvent) {
-            final float x = motionEvent.getRawX();
-            final float y = motionEvent.getRawY();
-            switch (motionEvent.getAction()) {
-                case MotionEvent.ACTION_DOWN:
-                    mDownX = x;
-                    mDownY = y;
-                    mControllers.taskbarStashController.startStashHint(/* animateForward = */ true);
-                    mCanceledStashHint = false;
-                    break;
-                case MotionEvent.ACTION_MOVE:
-                    if (!mCanceledStashHint
-                            && squaredHypot(mDownX - x, mDownY - y) > mSquaredTouchSlop) {
-                        mControllers.taskbarStashController.startStashHint(
-                                /* animateForward= */ false);
-                        mCanceledStashHint = true;
-                        return true;
-                    }
-                    break;
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_CANCEL:
-                    if (!mCanceledStashHint) {
-                        mControllers.taskbarStashController.startStashHint(
-                                /* animateForward= */ false);
-                    }
-                    break;
-            }
-
-            return false;
-        }
-
-        /**
          * Notifies launcher to update icon alignment.
          */
         public void notifyIconLayoutBoundsChanged() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 5ce2a7a..964d329 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -222,7 +222,7 @@
         if (ev.getAction() == MotionEvent.ACTION_DOWN) {
             mNoIntercept = !mAppsView.shouldContainerScroll(ev)
                     || getTopOpenViewWithType(
-                            mActivityContext, TYPE_ACCESSIBLE & ~TYPE_TASKBAR_OVERLAYS) != null;
+                            mActivityContext, TYPE_TOUCH_CONTROLLER_NO_INTERCEPT) != null;
         }
         return super.onControllerInterceptTouchEvent(ev);
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
index c4eeea7..adbec65 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.taskbar.overlay;
 
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_CONSUME_IME_INSETS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
 import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
@@ -187,6 +188,7 @@
         layoutParams.setFitInsetsTypes(0); // Handled by container view.
         layoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         layoutParams.setSystemApplicationOverlay(true);
+        layoutParams.privateFlags = PRIVATE_FLAG_CONSUME_IME_INSETS;
         return layoutParams;
     }
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 5b0c8c3..9438e00 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -19,6 +19,7 @@
 import static android.os.Trace.TRACE_TAG_APP;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
 import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
+
 import static com.android.app.animation.Interpolators.EMPHASIZED;
 import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.PENDING_SPLIT_SELECT_INFO;
 import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
@@ -34,8 +35,6 @@
 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.ENABLE_HOME_TRANSITION_LISTENER;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
 import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
@@ -107,6 +106,7 @@
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.appprediction.PredictionRowView;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.desktop.DesktopRecentsTransitionController;
@@ -117,7 +117,6 @@
 import com.android.launcher3.model.BgDataModel.FixedContainerItems;
 import com.android.launcher3.model.WellbeingModel;
 import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.SystemShortcut;
 import com.android.launcher3.proxy.ProxyActivityStarter;
 import com.android.launcher3.statehandlers.DepthController;
@@ -643,6 +642,7 @@
         // using that.
         mSplitSelectStateController.findLastActiveTasksAndRunCallback(
                 Collections.singletonList(splitSelectSource.itemInfo.getComponentKey()),
+                false /* findExactPairMatch */,
                 foundTasks -> {
                     @Nullable Task foundTask = foundTasks.get(0);
                     boolean taskWasFound = foundTask != null;
@@ -707,6 +707,13 @@
     }
 
     @Override
+    public void onStateTransitionCompletedAfterSwipeToHome(LauncherState finalState) {
+        if (mTaskbarUIController != null) {
+            mTaskbarUIController.onStateTransitionCompletedAfterSwipeToHome(finalState);
+        }
+    }
+
+    @Override
     protected void onResume() {
         super.onResume();
 
@@ -1263,24 +1270,19 @@
 
     /**
      * Launches the given {@link GroupTask} in splitscreen.
-     *
-     * If the second split task is missing, launches the first task normally.
      */
-    public void launchSplitTasks(@NonNull View taskView, @NonNull GroupTask groupTask) {
-        if (groupTask.task2 == null) {
-            UI_HELPER_EXECUTOR.execute(() ->
-                    ActivityManagerWrapper.getInstance().startActivityFromRecents(
-                            groupTask.task1.key,
-                            getActivityLaunchOptions(taskView, null).options));
-            return;
-        }
+    public void launchSplitTasks(@NonNull GroupTask groupTask) {
+        // 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
+        Task task2 = groupTask.task2;
         mSplitSelectStateController.launchExistingSplitPair(
                 null /* launchingTaskView */,
-                groupTask.task1.key.id,
-                groupTask.task2.key.id,
+                task1.key.id,
+                task2.key.id,
                 SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT,
                 /* callback= */ success -> mSplitSelectStateController.resetState(),
-                /* freezeTaskList= */ true,
+                /* freezeTaskList= */ false,
                 groupTask.mSplitBounds == null
                         ? SNAP_TO_50_50
                         : groupTask.mSplitBounds.snapPosition);
@@ -1289,8 +1291,8 @@
     /**
      * Launches two apps as an app pair.
      */
-    public void launchAppPair(WorkspaceItemInfo app1, WorkspaceItemInfo app2) {
-        mSplitSelectStateController.getAppPairsController().launchAppPair(app1, app2);
+    public void launchAppPair(AppPairIcon appPairIcon) {
+        mSplitSelectStateController.getAppPairsController().launchAppPair(appPairIcon);
     }
 
     public boolean canStartHomeSafely() {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
index 301fbe4..c1a85fa 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/flags/DeveloperOptionsUI.java
@@ -28,6 +28,7 @@
 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;
@@ -67,6 +68,7 @@
 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;
@@ -115,6 +117,9 @@
             addAllAppsFromOverviewCatergory();
         }
         addCustomLpnhCategory();
+        if (Flags.enablePrivateSpace()) {
+            addCustomPrivateAppsCategory();
+        }
     }
 
     private void filterPreferences(String query, PreferenceGroup pg) {
@@ -365,6 +370,12 @@
         }
     }
 
+    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.
      *
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index f6cd30a..82a9c05 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -45,6 +45,7 @@
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.TouchController;
@@ -194,7 +195,20 @@
             recentsView.switchToScreenshot(null,
                     () -> recentsView.finishRecentsAnimation(true /* toRecents */, null));
             if (mStartState.overviewUi) {
-                new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(mEndState),
+                Runnable onReachedHome = () -> {
+                    StateManager.StateListener<LauncherState> listener =
+                            new StateManager.StateListener<>() {
+                                @Override
+                                public void onStateTransitionComplete(LauncherState finalState) {
+                                    mLauncher.onStateTransitionCompletedAfterSwipeToHome(
+                                            finalState);
+                                    mLauncher.getStateManager().removeStateListener(this);
+                                }
+                            };
+                    mLauncher.getStateManager().addStateListener(listener);
+                    onSwipeInteractionCompleted(mEndState);
+                };
+                new OverviewToHomeAnim(mLauncher, onReachedHome,
                         FeatureFlags.enableSplitContextually()
                                 ? mCancelSplitRunnable
                                 : null)
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 8cbf239..2c937b0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -15,8 +15,7 @@
  */
 package com.android.launcher3.uioverrides.touchcontrollers;
 
-import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
-import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_APPS_EDU;
+import static com.android.launcher3.AbstractFloatingView.TYPE_TOUCH_CONTROLLER_NO_INTERCEPT;
 import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
 import static com.android.launcher3.LauncherState.ALL_APPS;
 import static com.android.launcher3.LauncherState.NORMAL;
@@ -84,7 +83,7 @@
                 return false;
             }
         }
-        if (getTopOpenViewWithType(mLauncher, TYPE_ACCESSIBLE | TYPE_ALL_APPS_EDU) != null) {
+        if (getTopOpenViewWithType(mLauncher, TYPE_TOUCH_CONTROLLER_NO_INTERCEPT) != null) {
             return false;
         }
         return true;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 3d94857..19bfe06 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -15,7 +15,7 @@
  */
 package com.android.launcher3.uioverrides.touchcontrollers;
 
-import static com.android.launcher3.AbstractFloatingView.TYPE_ACCESSIBLE;
+import static com.android.launcher3.AbstractFloatingView.TYPE_TOUCH_CONTROLLER_NO_INTERCEPT;
 import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
 import static com.android.launcher3.touch.SingleAxisSwipeDetector.DIRECTION_BOTH;
 
@@ -112,7 +112,8 @@
             // If we are already animating from a previous state, we can intercept.
             return true;
         }
-        if (AbstractFloatingView.getTopOpenViewWithType(mActivity, TYPE_ACCESSIBLE) != null) {
+        if (AbstractFloatingView.getTopOpenViewWithType(
+                mActivity, TYPE_TOUCH_CONTROLLER_NO_INTERCEPT) != null) {
             return false;
         }
         return isRecentsInteractive();
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 5568459..7c24ba8 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -23,6 +23,8 @@
 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;
@@ -52,9 +54,11 @@
 
 import com.android.internal.view.AppearanceRegion;
 import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.LauncherPrefs;
 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.quickstep.util.RectFSpringAnim;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -293,8 +297,12 @@
         mBackTarget = appTarget;
         mInitialTouchPos.set(backEvent.getTouchX(), backEvent.getTouchY());
 
-        // TODO(b/218916755): Offset start rectangle in multiwindow mode.
         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);
+        }
         mCurrentRect.set(mStartRect);
         addScrimLayer();
         mTransaction.apply();
@@ -416,6 +424,10 @@
         if (mLauncher.isDestroyed()) {
             return;
         }
+        LauncherTaskbarUIController taskbarUIController = mLauncher.getTaskbarUIController();
+        if (taskbarUIController != null) {
+            taskbarUIController.onLauncherVisibilityChanged(true);
+        }
         // TODO: Catch the moment when launcher becomes visible after the top app un-occludes
         //  launcher and start animating afterwards. Currently we occasionally get a flicker from
         //  animating when launcher is still invisible.
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 221ce48..0303791 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -82,34 +82,18 @@
                 return response;
             }
 
-            case TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING:
-                runOnTISBinder(tisBinder -> {
-                    enableManualTaskbarStashing(tisBinder, true);
-                });
-                return response;
-
-            case TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING:
-                runOnTISBinder(tisBinder -> {
-                    enableManualTaskbarStashing(tisBinder, false);
-                });
-                return response;
-
             case TestProtocol.REQUEST_UNSTASH_TASKBAR_IF_STASHED:
                 runOnTISBinder(tisBinder -> {
-                    enableManualTaskbarStashing(tisBinder, true);
-
                     // Allow null-pointer to catch illegal states.
                     tisBinder.getTaskbarManager().getCurrentActivityContext()
                             .unstashTaskbarIfStashed();
-
-                    enableManualTaskbarStashing(tisBinder, false);
                 });
                 return response;
 
-            case TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT: {
+            case TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD: {
                 final Resources resources = mContext.getResources();
                 response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
-                        resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size));
+                        resources.getDimensionPixelSize(R.dimen.taskbar_from_nav_threshold));
                 return response;
             }
 
@@ -187,13 +171,6 @@
         return super.isLauncherInitialized() && TouchInteractionService.isInitialized();
     }
 
-    private void enableManualTaskbarStashing(
-            TouchInteractionService.TISBinder tisBinder, boolean enable) {
-        // Allow null-pointer to catch illegal states.
-        tisBinder.getTaskbarManager().getCurrentActivityContext().enableManualStashingDuringTests(
-                enable);
-    }
-
     private void enableBlockingTimeout(
             TouchInteractionService.TISBinder tisBinder, boolean enable) {
         TaskbarActivityContext context = tisBinder.getTaskbarManager().getCurrentActivityContext();
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 39edd70..22163b9 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -18,9 +18,11 @@
 import static android.os.Trace.TRACE_TAG_APP;
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
+
 import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
 import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_DURATION;
 import static com.android.launcher3.QuickstepTransitionManager.STATUS_BAR_TRANSITION_PRE_DELAY;
+import static com.android.launcher3.testing.shared.TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE;
 import static com.android.launcher3.testing.shared.TestProtocol.OVERVIEW_STATE_ORDINAL;
 import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely;
 import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
@@ -344,6 +346,8 @@
         // Workaround for b/78520668, explicitly trim memory once UI is hidden
         onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
         mFallbackRecentsView.updateLocusId();
+        AccessibilityManagerCompat.sendTestProtocolEventToTest(
+                this, LAUNCHER_ACTIVITY_STOPPED_MESSAGE);
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 27de20c..94ed5b9 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -17,7 +17,6 @@
 
 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
 
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
@@ -102,6 +101,7 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.LinkedHashMap;
+import java.util.List;
 
 /**
  * Holds the reference to SystemUI.
@@ -147,6 +147,9 @@
     private IDesktopTaskListener mDesktopTaskListener;
     private final LinkedHashMap<RemoteTransition, TransitionFilter> mRemoteTransitions =
             new LinkedHashMap<>();
+
+    private final List<Runnable> mStateChangeCallbacks = new ArrayList<>();
+
     private IBinder mOriginalTransactionToken = null;
     private IOnBackInvokedCallback mBackToLauncherCallback;
     private IRemoteAnimationRunner mBackToLauncherRunner;
@@ -268,6 +271,7 @@
         setDesktopTaskListener(mDesktopTaskListener);
         setAssistantOverridesRequested(
                 AssistUtils.newInstance(mContext).getSysUiAssistOverrideInvocationTypes());
+        mStateChangeCallbacks.forEach(Runnable::run);
     }
 
     /**
@@ -278,6 +282,20 @@
         setProxy(null, null, null, null, null, null, null, null, null, null, null, null, null);
     }
 
+    /**
+     * Adds a callback to be notified whenever the active state changes
+     */
+    public void addOnStateChangeListener(Runnable callback) {
+        mStateChangeCallbacks.add(callback);
+    }
+
+    /**
+     * Removes a previously added state change callback
+     */
+    public void removeOnStateChangeListener(Runnable callback) {
+        mStateChangeCallbacks.remove(callback);
+    }
+
     // TODO(141886704): Find a way to remove this
     public void setLastSystemUiStateFlags(int stateFlags) {
         mLastSystemUiStateFlags = stateFlags;
@@ -1082,6 +1100,25 @@
     }
 
     /**
+     * Returns a surface which can be used to attach overlays to home task or null if
+     * the task doesn't exist or sysui is not connected
+     */
+    @Nullable
+    public SurfaceControl getHomeTaskOverlayContainer() {
+        // Use a local reference as this method can be called on a worker thread, which can lead
+        // to NullPointer exceptions if mShellTransitions is modified on the main thread.
+        IShellTransitions shellTransitions = mShellTransitions;
+        if (shellTransitions != null) {
+            try {
+                return mShellTransitions.getHomeTaskOverlayContainer();
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed call getOverlayContainerForTask", e);
+            }
+        }
+        return null;
+    }
+
+    /**
      * Use SystemUI's transaction-queue instead of Launcher's independent one. This is necessary
      * if Launcher and SystemUI need to coordinate transactions (eg. for shell transitions).
      */
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index 20a751b..1b3f598 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -31,7 +31,6 @@
 import android.os.UserHandle;
 import android.text.TextUtils;
 import android.util.SparseArray;
-import android.view.accessibility.AccessibilityManager;
 
 import androidx.annotation.WorkerThread;
 
@@ -45,6 +44,7 @@
 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;
@@ -62,7 +62,6 @@
 public class TaskIconCache implements DisplayInfoChangeListener {
 
     private final Executor mBgExecutor;
-    private final AccessibilityManager mAccessibilityManager;
 
     private final Context mContext;
     private final TaskKeyLruCache<TaskCacheEntry> mIconCache;
@@ -79,7 +78,6 @@
     public TaskIconCache(Context context, Executor bgExecutor, IconProvider iconProvider) {
         mContext = context;
         mBgExecutor = bgExecutor;
-        mAccessibilityManager = context.getSystemService(AccessibilityManager.class);
         mIconProvider = iconProvider;
 
         Resources res = context.getResources();
@@ -238,14 +236,11 @@
             if ((index = mDefaultIcons.indexOfKey(userId)) >= 0) {
                 return mDefaultIcons.valueAt(index).newIcon(mContext);
             } else {
-                try (BaseIconFactory li = getIconFactory()) {
-                    BitmapInfo info = mDefaultIconBase.withFlags(
-                            li.getBitmapFlagOp(new IconOptions()
-                                    .setUser(UserCache.INSTANCE.get(mContext)
-                                            .getUserInfo(UserHandle.of(userId)))));
-                    mDefaultIcons.put(userId, info);
-                    return info.newIcon(mContext);
-                }
+                BitmapInfo info = mDefaultIconBase.withFlags(
+                        UserCache.INSTANCE.get(mContext).getUserInfo(UserHandle.of(userId))
+                                .applyBitmapInfoFlags(FlagOp.NO_OP));
+                mDefaultIcons.put(userId, info);
+                return info.newIcon(mContext);
             }
         }
     }
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
index e5fca4b..9e21595 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -195,11 +195,15 @@
             return null;
         }
 
-        CancellableTask<ThumbnailData> request = new CancellableTask<ThumbnailData>() {
+        CancellableTask<ThumbnailData> request = new CancellableTask<>() {
             @Override
             public ThumbnailData getResultOnBg() {
-                return ActivityManagerWrapper.getInstance().getTaskThumbnail(
+                ThumbnailData thumbnailData = ActivityManagerWrapper.getInstance().getTaskThumbnail(
                         key.id, lowResolution);
+                if (thumbnailData.thumbnail != null) {
+                    return thumbnailData;
+                }
+                return ActivityManagerWrapper.getInstance().takeTaskThumbnail(key.id);
             }
 
             @Override
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index ddddc89..11c5ab4 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -18,8 +18,6 @@
 import static android.view.RemoteAnimationTarget.MODE_CLOSING;
 import static android.view.RemoteAnimationTarget.MODE_OPENING;
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
 
 import static com.android.app.animation.Interpolators.LINEAR;
 import static com.android.app.animation.Interpolators.TOUCH_RESPONSE;
@@ -421,106 +419,34 @@
      * Technically this case should be taken care of by
      * {@link #composeRecentsSplitLaunchAnimatorLegacy} below, but the way we launch tasks whether
      * it's a single task or multiple tasks results in different entry-points.
-     *
-     * If it is null, then it will simply fade in the starting apps and fade out launcher (for the
-     * case where launcher handles animating starting split tasks from app icon)
      */
     public static void composeRecentsSplitLaunchAnimator(GroupedTaskView launchingTaskView,
             @NonNull StateManager stateManager, @Nullable DepthController depthController,
-            int initialTaskId, int secondTaskId, @NonNull TransitionInfo transitionInfo,
-            SurfaceControl.Transaction t, @NonNull Runnable finishCallback) {
-        if (launchingTaskView != null) {
-            AnimatorSet animatorSet = new AnimatorSet();
-            animatorSet.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    finishCallback.run();
-                }
-            });
-
-            final RemoteAnimationTarget[] appTargets =
-                    RemoteAnimationTargetCompat.wrapApps(transitionInfo, t, null /* leashMap */);
-            final RemoteAnimationTarget[] wallpaperTargets =
-                    RemoteAnimationTargetCompat.wrapNonApps(
-                            transitionInfo, true /* wallpapers */, t, null /* leashMap */);
-            final RemoteAnimationTarget[] nonAppTargets =
-                    RemoteAnimationTargetCompat.wrapNonApps(
-                            transitionInfo, false /* wallpapers */, t, null /* leashMap */);
-            final RecentsView recentsView = launchingTaskView.getRecentsView();
-            composeRecentsLaunchAnimator(animatorSet, launchingTaskView,
-                    appTargets, wallpaperTargets, nonAppTargets,
-                    true, stateManager,
-                    recentsView, depthController);
-
-            t.apply();
-            animatorSet.start();
-            return;
-        }
-
-        TransitionInfo.Change splitRoot1 = null;
-        TransitionInfo.Change splitRoot2 = null;
-        final ArrayList<SurfaceControl> openingTargets = new ArrayList<>();
-        for (int i = 0; i < transitionInfo.getChanges().size(); ++i) {
-            final TransitionInfo.Change change = transitionInfo.getChanges().get(i);
-            if (change.getTaskInfo() == null) {
-                continue;
-            }
-            final int taskId = change.getTaskInfo().taskId;
-            final int mode = change.getMode();
-
-            // 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) {
-                if (!(mode == TRANSIT_OPEN || mode == TRANSIT_TO_FRONT)) {
-                    throw new IllegalStateException(
-                            "Expected task to be showing, but it is " + mode);
-                }
-            }
-            if (taskId == initialTaskId) {
-                splitRoot1 = change.getParent() == null ? change :
-                        transitionInfo.getChange(change.getParent());
-                openingTargets.add(splitRoot1.getLeash());
-            }
-            if (taskId == secondTaskId) {
-                splitRoot2 = change.getParent() == null ? change :
-                        transitionInfo.getChange(change.getParent());
-                openingTargets.add(splitRoot2.getLeash());
-            }
-        }
-
-        SurfaceControl.Transaction animTransaction = new SurfaceControl.Transaction();
-        ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
-        animator.setDuration(SPLIT_LAUNCH_DURATION);
-        animator.addUpdateListener(valueAnimator -> {
-            float progress = valueAnimator.getAnimatedFraction();
-            for (SurfaceControl leash: openingTargets) {
-                animTransaction.setAlpha(leash, progress);
-            }
-            animTransaction.apply();
-        });
-        animator.addListener(new AnimatorListenerAdapter() {
-            @Override
-            public void onAnimationStart(Animator animation) {
-                for (SurfaceControl leash: openingTargets) {
-                    animTransaction.show(leash)
-                            .setAlpha(leash, 0.0f);
-                }
-                animTransaction.apply();
-            }
-
+            @NonNull TransitionInfo transitionInfo, SurfaceControl.Transaction t,
+            @NonNull Runnable finishCallback) {
+        AnimatorSet animatorSet = new AnimatorSet();
+        animatorSet.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
                 finishCallback.run();
             }
         });
 
-        if (splitRoot1 != null && splitRoot1.getParent() != null) {
-            // Set the highest level split root alpha; we could technically use the parent of either
-            // splitRoot1 or splitRoot2
-            t.setAlpha(transitionInfo.getChange(splitRoot1.getParent()).getLeash(), 1f);
-        }
+        final RemoteAnimationTarget[] appTargets =
+                RemoteAnimationTargetCompat.wrapApps(transitionInfo, t, null /* leashMap */);
+        final RemoteAnimationTarget[] wallpaperTargets =
+                RemoteAnimationTargetCompat.wrapNonApps(
+                        transitionInfo, true /* wallpapers */, t, null /* leashMap */);
+        final RemoteAnimationTarget[] nonAppTargets =
+                RemoteAnimationTargetCompat.wrapNonApps(
+                        transitionInfo, false /* wallpapers */, t, null /* leashMap */);
+        final RecentsView recentsView = launchingTaskView.getRecentsView();
+        composeRecentsLaunchAnimator(animatorSet, launchingTaskView, appTargets, wallpaperTargets,
+                nonAppTargets, /* launcherClosing */ true, stateManager, recentsView,
+                depthController);
+
         t.apply();
-        animator.start();
+        animatorSet.start();
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
index 57c05e9..4d47f07 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressHandler.java
@@ -56,5 +56,5 @@
      * Called when nav handle gesture is finished by the user lifting their finger or the system
      * cancelling the touch for some other reason.
      */
-    public void onTouchFinished() {}
+    public void onTouchFinished(String reason) {}
 }
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index 0127cc9..0a558e2 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -81,7 +81,7 @@
         if (mDelegate.allowInterceptByParent()) {
             handleMotionEvent(ev);
         } else if (MAIN_EXECUTOR.getHandler().hasCallbacks(mTriggerLongPress)) {
-            cancelLongPress();
+            cancelLongPress("intercept disallowed by child input consumer");
         }
 
         if (mState != STATE_ACTIVE) {
@@ -113,10 +113,11 @@
                 float dy = ev.getY() - mCurrentDownEvent.getY();
                 double distanceSquared = (dx * dx) + (dy * dy);
                 if (distanceSquared > touchSlopSquared) {
-                    cancelLongPress();
+                    cancelLongPress("touch slop passed");
                 }
             }
-            case MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> cancelLongPress();
+            case MotionEvent.ACTION_UP -> cancelLongPress("touch action up");
+            case MotionEvent.ACTION_CANCEL -> cancelLongPress("touch action cancel");
         }
 
         // If the gesture is deep press then trigger long press asap
@@ -158,9 +159,9 @@
         }
     }
 
-    private void cancelLongPress() {
+    private void cancelLongPress(String reason) {
         MAIN_EXECUTOR.getHandler().removeCallbacks(mTriggerLongPress);
-        mNavHandleLongPressHandler.onTouchFinished();
+        mNavHandleLongPressHandler.onTouchFinished(reason);
     }
 
     private boolean isInNavBarHorizontalArea(float x) {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index 12a8bd9..cd180ba 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -22,15 +22,12 @@
 
 import static com.android.launcher3.Flags.enableCursorHoverStates;
 import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
-import static com.android.launcher3.Utilities.squaredHypot;
 import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TOUCHING;
 
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.PointF;
 import android.graphics.Rect;
-import android.view.GestureDetector;
-import android.view.GestureDetector.SimpleOnGestureListener;
 import android.view.InputDevice;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
@@ -39,7 +36,6 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
 import com.android.launcher3.taskbar.TaskbarActivityContext;
 import com.android.launcher3.taskbar.TaskbarThresholdUtils;
 import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
@@ -51,22 +47,13 @@
 import com.android.systemui.shared.system.InputMonitorCompat;
 
 /**
- * Listens for touch and hover events to unstash the Taskbar.
- *
- * <p>Cancels the current gesture if the long press causes the Taskbar to be unstashed.
+ * Listens for touch (swipe) and hover events to unstash the Taskbar.
  */
 public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
 
     private final TaskbarActivityContext mTaskbarActivityContext;
     private final OverviewCommandHelper mOverviewCommandHelper;
-    private final GestureDetector mLongPressDetector;
-    private final float mSquaredTouchSlop;
-
-    private float mLongPressDownX, mLongPressDownY;
-    private boolean mCanceledUnstashHint;
     private final float mUnstashArea;
-    private final float mScreenWidth;
-
     private final int mTaskbarNavThreshold;
     private final int mTaskbarNavThresholdY;
     private final boolean mIsTaskbarAllAppsOpen;
@@ -96,10 +83,7 @@
         super(delegate, inputMonitor);
         mTaskbarActivityContext = taskbarActivityContext;
         mOverviewCommandHelper = overviewCommandHelper;
-        // TODO(b/270395798): remove this when cleaning up old Persistent Taskbar code.
-        mSquaredTouchSlop = Utilities.squaredTouchSlop(context);
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
-        mScreenWidth = taskbarActivityContext.getDeviceProfile().widthPx;
 
         Resources res = context.getResources();
         mUnstashArea = res.getDimensionPixelSize(R.dimen.taskbar_unstash_input_area);
@@ -111,13 +95,6 @@
 
         mIsTransientTaskbar = DisplayController.isTransientTaskbar(context);
 
-        mLongPressDetector = new GestureDetector(context, new SimpleOnGestureListener() {
-            @Override
-            public void onLongPress(MotionEvent motionEvent) {
-                onLongPressDetected(motionEvent);
-            }
-        });
-
         mBottomScreenEdge = res.getDimensionPixelSize(
                 R.dimen.taskbar_stashed_screen_edge_hover_deadzone_height);
         mStashedTaskbarBottomEdge =
@@ -135,7 +112,6 @@
 
     @Override
     public void onMotionEvent(MotionEvent ev) {
-        mLongPressDetector.onTouchEvent(ev);
         if (mState != STATE_ACTIVE) {
             boolean isStashedTaskbarHovered = isMouseEvent(ev)
                     && isStashedTaskbarHovered((int) ev.getX(), (int) ev.getY());
@@ -152,15 +128,6 @@
                         mHasPassedTaskbarNavThreshold = false;
                         mTaskbarActivityContext.setAutohideSuspendFlag(
                                 FLAG_AUTOHIDE_SUSPEND_TOUCHING, true);
-                        if (isInTaskbarArea(x)) {
-                            if (!mIsTransientTaskbar) {
-                                mLongPressDownX = x;
-                                mLongPressDownY = y;
-                                mTaskbarActivityContext.startTaskbarUnstashHint(
-                                        /* animateForward = */ true);
-                                mCanceledUnstashHint = false;
-                            }
-                        }
                         if (mTransitionCallback != null && !mIsTaskbarAllAppsOpen) {
                             mTransitionCallback.onActionDown();
                         }
@@ -181,15 +148,6 @@
                         }
                         break;
                     case MotionEvent.ACTION_MOVE:
-                        if (!mIsTransientTaskbar
-                                && !mCanceledUnstashHint
-                                && squaredHypot(mLongPressDownX - x, mLongPressDownY - y)
-                                > mSquaredTouchSlop) {
-                            mTaskbarActivityContext.startTaskbarUnstashHint(
-                                    /* animateForward = */ false);
-                            mCanceledUnstashHint = true;
-                        }
-
                         int pointerIndex = ev.findPointerIndex(mActivePointerId);
                         if (pointerIndex == INVALID_POINTER_ID) {
                             break;
@@ -283,10 +241,6 @@
     }
 
     private void cleanupAfterMotionEvent() {
-        if (!mIsTransientTaskbar && !mCanceledUnstashHint) {
-            mTaskbarActivityContext.startTaskbarUnstashHint(
-                    /* animateForward = */ false);
-        }
         mTaskbarActivityContext.setAutohideSuspendFlag(
                 FLAG_AUTOHIDE_SUSPEND_TOUCHING, false);
         if (mTransitionCallback != null) {
@@ -298,12 +252,6 @@
         mIsPassedBubbleBarSlop = false;
     }
 
-    private boolean isInTaskbarArea(float x) {
-        float areaFromMiddle = mUnstashArea / 2.0f;
-        float distFromMiddle = Math.abs(mScreenWidth / 2.0f - x);
-        return distFromMiddle < areaFromMiddle;
-    }
-
     private boolean isInBubbleBarArea(float x) {
         if (mTaskbarActivityContext == null || !mIsTransientTaskbar) {
             return false;
@@ -320,17 +268,6 @@
         }
     }
 
-    private void onLongPressDetected(MotionEvent motionEvent) {
-        if (mTaskbarActivityContext != null
-                && isInTaskbarArea(motionEvent.getRawX())
-                && !mIsTransientTaskbar) {
-            boolean taskBarPressed = mTaskbarActivityContext.onLongPressToUnstashTaskbar();
-            if (taskBarPressed) {
-                setActive(motionEvent);
-            }
-        }
-    }
-
     /**
      * Listen for hover events for the stashed taskbar.
      *
@@ -389,7 +326,7 @@
     }
 
     private void startStashedTaskbarHover(boolean isHovered) {
-        mTaskbarActivityContext.startTaskbarUnstashHint(isHovered, /* forceUnstash = */ true);
+        mTaskbarActivityContext.startTaskbarUnstashHint(isHovered);
         mIsStashedTaskbarHovered = isHovered;
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/AnimUtils.java b/quickstep/src/com/android/quickstep/util/AnimUtils.java
index b7b7825..7fbbb6e 100644
--- a/quickstep/src/com/android/quickstep/util/AnimUtils.java
+++ b/quickstep/src/com/android/quickstep/util/AnimUtils.java
@@ -39,4 +39,13 @@
                 ? SplitAnimationTimings.TABLET_SPLIT_TO_CONFIRM
                 : SplitAnimationTimings.PHONE_SPLIT_TO_CONFIRM;
     }
+
+    /**
+     * Fetches device-specific timings for the app pair launch animation.
+     */
+    public static SplitAnimationTimings getDeviceAppPairLaunchTimings(boolean isTablet) {
+        return isTablet
+                ? SplitAnimationTimings.TABLET_APP_PAIR_LAUNCH
+                : SplitAnimationTimings.PHONE_APP_PAIR_LAUNCH;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/AppPairLaunchTimings.kt b/quickstep/src/com/android/quickstep/util/AppPairLaunchTimings.kt
new file mode 100644
index 0000000..086c8af
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/AppPairLaunchTimings.kt
@@ -0,0 +1,72 @@
+/*
+ * 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 com.android.app.animation.Interpolators
+
+/** Timings for the app pair launch animation. */
+abstract class AppPairLaunchTimings : SplitAnimationTimings {
+    protected abstract val STAGED_RECT_SLIDE_DURATION: Int
+
+    // Common timings that apply to app pair launches on any type of device
+    override fun getStagedRectSlideStart() = 0
+    override fun getStagedRectSlideEnd() = stagedRectSlideStart + STAGED_RECT_SLIDE_DURATION
+    override fun getPlaceholderFadeInStart() = 0
+    override fun getPlaceholderFadeInEnd() = 0
+    override fun getPlaceholderIconFadeInStart() = 0
+    override fun getPlaceholderIconFadeInEnd() = 0
+
+    private val iconFadeStart: Int
+        get() = getStagedRectSlideEnd()
+    private val iconFadeEnd: Int
+        get() = iconFadeStart + 83
+    private val appRevealStart: Int
+        get() = getStagedRectSlideEnd() + 67
+    private val appRevealEnd: Int
+        get() = appRevealStart + 217
+    private val cellSplitStart: Int
+        get() = (getStagedRectSlideEnd() * 0.83f).toInt()
+    private val cellSplitEnd: Int
+        get() = cellSplitStart + 500
+
+    override fun getStagedRectXInterpolator() = Interpolators.EMPHASIZED_COMPLEMENT
+    override fun getStagedRectYInterpolator() = Interpolators.EMPHASIZED
+    override fun getStagedRectScaleXInterpolator() = Interpolators.EMPHASIZED
+    override fun getStagedRectScaleYInterpolator() = Interpolators.EMPHASIZED
+    override fun getCellSplitInterpolator() = Interpolators.EMPHASIZED
+    override fun getIconFadeInterpolator() = Interpolators.LINEAR
+
+    override fun getCellSplitStartOffset(): Float {
+        return cellSplitStart.toFloat() / getDuration()
+    }
+    override fun getCellSplitEndOffset(): Float {
+        return cellSplitEnd.toFloat() / getDuration()
+    }
+    override fun getIconFadeStartOffset(): Float {
+        return iconFadeStart.toFloat() / getDuration()
+    }
+    override fun getIconFadeEndOffset(): Float {
+        return iconFadeEnd.toFloat() / getDuration()
+    }
+    override fun getAppRevealStartOffset(): Float {
+        return appRevealStart.toFloat() / getDuration()
+    }
+    override fun getAppRevealEndOffset(): Float {
+        return appRevealEnd.toFloat() / getDuration()
+    }
+    abstract override fun getDuration(): Int
+}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index cc3b54b..3ca2531 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -36,6 +36,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.R;
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
+import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.FolderInfo;
@@ -120,11 +121,14 @@
      * 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.
      */
-    public void launchAppPair(WorkspaceItemInfo app1, WorkspaceItemInfo app2) {
+    public void launchAppPair(AppPairIcon appPairIcon) {
+        WorkspaceItemInfo app1 = appPairIcon.getInfo().contents.get(0);
+        WorkspaceItemInfo app2 = appPairIcon.getInfo().contents.get(1);
         ComponentKey app1Key = new ComponentKey(app1.getTargetComponent(), app1.user);
         ComponentKey app2Key = new ComponentKey(app2.getTargetComponent(), app2.user);
         mSplitSelectStateController.findLastActiveTasksAndRunCallback(
                 Arrays.asList(app1Key, app2Key),
+                false /* findExactPairMatch */,
                 foundTasks -> {
                     @Nullable Task foundTask1 = foundTasks.get(0);
                     Intent task1Intent;
@@ -151,9 +155,12 @@
                                 app2.intent, app2.user);
                     }
 
+                    mSplitSelectStateController.setLaunchingIconView(appPairIcon);
+
                     mSplitSelectStateController.launchSplitTasks(
                             AppPairsController.convertRankToSnapPosition(app1.rank));
-                });
+                }
+        );
     }
 
     /**
diff --git a/quickstep/src/com/android/quickstep/util/AssistStateManager.java b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
index a0bb76d..f7437eb 100644
--- a/quickstep/src/com/android/quickstep/util/AssistStateManager.java
+++ b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
@@ -31,6 +31,11 @@
 
     public AssistStateManager() {}
 
+    /** Whether search supports haptic on invocation. */
+    public boolean supportsCommitHaptic() {
+        return false;
+    }
+
     /** Whether search is available. */
     public boolean isSearchAvailable() {
         return false;
diff --git a/quickstep/src/com/android/quickstep/util/PhoneAppPairLaunchTimings.kt b/quickstep/src/com/android/quickstep/util/PhoneAppPairLaunchTimings.kt
new file mode 100644
index 0000000..beab90f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/PhoneAppPairLaunchTimings.kt
@@ -0,0 +1,23 @@
+/*
+ * 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
+
+/** Timings for the app pair launch animation on phones. */
+class PhoneAppPairLaunchTimings : AppPairLaunchTimings(), SplitAnimationTimings {
+    override val STAGED_RECT_SLIDE_DURATION = 500
+    override fun getDuration() = SplitAnimationTimings.PHONE_APP_PAIR_LAUNCH_DURATION
+}
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index dfbd32c..ade8074 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -21,20 +21,37 @@
 import android.animation.AnimatorListenerAdapter
 import android.animation.AnimatorSet
 import android.animation.ObjectAnimator
+import android.animation.ValueAnimator
+import android.app.ActivityManager.RunningTaskInfo
 import android.graphics.Bitmap
 import android.graphics.Rect
 import android.graphics.RectF
 import android.graphics.drawable.Drawable
+import android.view.RemoteAnimationTarget
+import android.view.SurfaceControl
+import android.view.SurfaceControl.Transaction
 import android.view.View
+import android.view.WindowManager
+import android.window.TransitionInfo
+import android.window.TransitionInfo.Change
+import androidx.annotation.VisibleForTesting
 import com.android.app.animation.Interpolators
 import com.android.launcher3.DeviceProfile
+import com.android.launcher3.Launcher
+import com.android.launcher3.QuickstepTransitionManager
 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.statehandlers.DepthController
+import com.android.launcher3.statemanager.StateManager
 import com.android.launcher3.statemanager.StatefulActivity
 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.RecentsView
 import com.android.quickstep.views.SplitInstructionsView
 import com.android.quickstep.views.TaskThumbnailView
@@ -308,6 +325,407 @@
         pendingAnimation.buildAnim().start()
     }
 
+    /**
+     * Called when launching a specific pair of apps, e.g. when tapping a pair of apps in Overview,
+     * or launching an app pair from its Home icon. Selects the appropriate launch animation and
+     * plays it.
+     */
+    fun playSplitLaunchAnimation(
+        launchingTaskView: GroupedTaskView?,
+        launchingIconView: AppPairIcon?,
+        initialTaskId: Int,
+        secondTaskId: Int,
+        apps: Array<RemoteAnimationTarget>?,
+        wallpapers: Array<RemoteAnimationTarget>?,
+        nonApps: Array<RemoteAnimationTarget>?,
+        stateManager: StateManager<*>,
+        depthController: DepthController?,
+        info: TransitionInfo?,
+        t: Transaction?,
+        finishCallback: Runnable
+    ) {
+        if (info == null && t == null) {
+            // (Legacy animation) Tapping a split tile in Overview
+            // TODO (b/315490678): Ensure that this works with app pairs flow
+            check(apps != null && wallpapers != null && nonApps != null) {
+                "trying to call composeRecentsSplitLaunchAnimatorLegacy, but encountered an " +
+                    "unexpected null"
+            }
+
+            composeRecentsSplitLaunchAnimatorLegacy(
+                launchingTaskView,
+                initialTaskId,
+                secondTaskId,
+                apps,
+                wallpapers,
+                nonApps,
+                stateManager,
+                depthController,
+                finishCallback
+            )
+
+            return
+        }
+
+        if (launchingTaskView != null) {
+            // Tapping a split tile in Overview
+            check(info != null && t != null) {
+                "trying to launch a GroupedTaskView, but encountered an unexpected null"
+            }
+
+            composeRecentsSplitLaunchAnimator(
+                launchingTaskView,
+                stateManager,
+                depthController,
+                info,
+                t,
+                finishCallback
+            )
+        } else if (launchingIconView != null) {
+            // Tapping an app pair icon
+            check(info != null && t != null) {
+                "trying to launch an app pair icon, but encountered an unexpected null"
+            }
+
+            composeIconSplitLaunchAnimator(
+                launchingIconView,
+                initialTaskId,
+                secondTaskId,
+                info,
+                t,
+                finishCallback
+            )
+        } else {
+            // Fallback case: simple fade-in animation
+            check(info != null && t != null) {
+                "trying to call composeFadeInSplitLaunchAnimator, but encountered an " +
+                    "unexpected null"
+            }
+
+            composeFadeInSplitLaunchAnimator(initialTaskId, secondTaskId, info, t, finishCallback)
+        }
+    }
+
+    /**
+     * When the user taps a split tile in Overview, this will play the tasks' launch animation from
+     * the position of the tapped tile.
+     */
+    @VisibleForTesting
+    fun composeRecentsSplitLaunchAnimator(
+        launchingTaskView: GroupedTaskView,
+        stateManager: StateManager<*>,
+        depthController: DepthController?,
+        info: TransitionInfo,
+        t: Transaction,
+        finishCallback: Runnable
+    ) {
+        TaskViewUtils.composeRecentsSplitLaunchAnimator(
+            launchingTaskView,
+            stateManager,
+            depthController,
+            info,
+            t,
+            finishCallback
+        )
+    }
+
+    /**
+     * LEGACY VERSION: When the user taps a split tile in Overview, this will play the tasks' launch
+     * animation from the position of the tapped tile.
+     */
+    @VisibleForTesting
+    fun composeRecentsSplitLaunchAnimatorLegacy(
+        launchingTaskView: GroupedTaskView?,
+        initialTaskId: Int,
+        secondTaskId: Int,
+        apps: Array<RemoteAnimationTarget>,
+        wallpapers: Array<RemoteAnimationTarget>,
+        nonApps: Array<RemoteAnimationTarget>,
+        stateManager: StateManager<*>,
+        depthController: DepthController?,
+        finishCallback: Runnable
+    ) {
+        TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(
+            launchingTaskView,
+            initialTaskId,
+            secondTaskId,
+            apps,
+            wallpapers,
+            nonApps,
+            stateManager,
+            depthController,
+            finishCallback
+        )
+    }
+
+    /**
+     * When the user taps an app pair icon to launch split, this will play the tasks' launch
+     * animation from the position of the icon.
+     */
+    @VisibleForTesting
+    fun composeIconSplitLaunchAnimator(
+        launchingIconView: AppPairIcon,
+        initialTaskId: Int,
+        secondTaskId: Int,
+        transitionInfo: TransitionInfo,
+        t: Transaction,
+        finishCallback: Runnable
+    ) {
+        val launcher = Launcher.getLauncher(launchingIconView.context)
+        val dp = launcher.deviceProfile
+
+        // Create an AnimatorSet that will run both shell and launcher transitions together
+        val launchAnimation = AnimatorSet()
+        val progressUpdater = ValueAnimator.ofFloat(0f, 1f)
+        val timings = AnimUtils.getDeviceAppPairLaunchTimings(dp.isTablet)
+        progressUpdater.setDuration(timings.getDuration().toLong())
+        progressUpdater.interpolator = Interpolators.LINEAR
+
+        // 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
+
+        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"
+                }
+            }
+
+            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"
+        }
+
+        // Shell animation: the apps are revealed toward end of the launch animation
+        progressUpdater.addUpdateListener { valueAnimator: ValueAnimator ->
+            val progress =
+                Interpolators.clampToProgress(
+                    Interpolators.LINEAR,
+                    valueAnimator.animatedFraction,
+                    timings.appRevealStartOffset,
+                    timings.appRevealEndOffset
+                )
+
+            // Set the alpha of the shell layer (2 apps + divider)
+            t.setAlpha(rootShellLayer, 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)
+        appIcon1.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
+        appIcon2.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
+        val floatingView =
+            FloatingAppPairView.getFloatingAppPairView(
+                launcher,
+                drawableArea,
+                appIcon1,
+                appIcon2,
+                dividerPos
+            )
+
+        // Launcher animation: animate the floating view, expanding to fill the display surface
+        progressUpdater.addUpdateListener(
+            object : MultiValueUpdateListener() {
+                var mDx =
+                    FloatProp(
+                        floatingView.startingPosition.left,
+                        dp.widthPx / 2f - floatingView.startingPosition.width() / 2f,
+                        0f /* delay */,
+                        timings.getDuration().toFloat(),
+                        Interpolators.clampToProgress(
+                            timings.getStagedRectXInterpolator(),
+                            timings.stagedRectSlideStartOffset,
+                            timings.stagedRectSlideEndOffset
+                        )
+                    )
+                var mDy =
+                    FloatProp(
+                        floatingView.startingPosition.top,
+                        dp.heightPx / 2f - floatingView.startingPosition.height() / 2f,
+                        0f /* delay */,
+                        timings.getDuration().toFloat(),
+                        Interpolators.clampToProgress(
+                            Interpolators.EMPHASIZED,
+                            timings.stagedRectSlideStartOffset,
+                            timings.stagedRectSlideEndOffset
+                        )
+                    )
+                var mScaleX =
+                    FloatProp(
+                        1f /* start */,
+                        dp.widthPx / floatingView.startingPosition.width(),
+                        0f /* delay */,
+                        timings.getDuration().toFloat(),
+                        Interpolators.clampToProgress(
+                            Interpolators.EMPHASIZED,
+                            timings.stagedRectSlideStartOffset,
+                            timings.stagedRectSlideEndOffset
+                        )
+                    )
+                var mScaleY =
+                    FloatProp(
+                        1f /* start */,
+                        dp.heightPx / floatingView.startingPosition.height(),
+                        0f /* delay */,
+                        timings.getDuration().toFloat(),
+                        Interpolators.clampToProgress(
+                            Interpolators.EMPHASIZED,
+                            timings.stagedRectSlideStartOffset,
+                            timings.stagedRectSlideEndOffset
+                        )
+                    )
+
+                override fun onUpdate(percent: Float, initOnly: Boolean) {
+                    floatingView.progress = percent
+                    floatingView.x = mDx.value
+                    floatingView.y = mDy.value
+                    floatingView.scaleX = mScaleX.value
+                    floatingView.scaleY = mScaleY.value
+                    floatingView.invalidate()
+                }
+            }
+        )
+
+        // When animation ends, remove the floating view and run finishCallback
+        progressUpdater.addListener(
+            object : AnimatorListenerAdapter() {
+                override fun onAnimationEnd(animation: Animator) {
+                    safeRemoveViewFromDragLayer(launcher, floatingView)
+                    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.
+     */
+    @VisibleForTesting
+    fun composeFadeInSplitLaunchAnimator(
+        initialTaskId: Int,
+        secondTaskId: Int,
+        transitionInfo: TransitionInfo,
+        t: Transaction,
+        finishCallback: Runnable
+    ) {
+        var splitRoot1: Change? = null
+        var splitRoot2: Change? = null
+        val openingTargets = ArrayList<SurfaceControl>()
+        for (change in transitionInfo.changes) {
+            val taskInfo: RunningTaskInfo = change.taskInfo ?: continue
+            val taskId = taskInfo.taskId
+            val mode = change.mode
+
+            // 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
+                ) {
+                    "Expected task to be showing, but it is $mode"
+                }
+            }
+
+            if (taskId == initialTaskId) {
+                splitRoot1 = change
+                val parentToken1 = change.parent
+                if (parentToken1 != null) {
+                    splitRoot1 = transitionInfo.getChange(parentToken1) ?: change
+                }
+
+                if (splitRoot1?.leash != null) {
+                    openingTargets.add(splitRoot1.leash)
+                }
+            }
+
+            if (taskId == secondTaskId) {
+                splitRoot2 = change
+                val parentToken2 = change.parent
+                if (parentToken2 != null) {
+                    splitRoot2 = transitionInfo.getChange(parentToken2) ?: change
+                }
+
+                if (splitRoot2?.leash != null) {
+                    openingTargets.add(splitRoot2.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
+            for (leash in openingTargets) {
+                animTransaction.setAlpha(leash, progress)
+            }
+            animTransaction.apply()
+        }
+
+        animator.addListener(
+            object : AnimatorListenerAdapter() {
+                override fun onAnimationStart(animation: Animator) {
+                    for (leash in openingTargets) {
+                        animTransaction.show(leash).setAlpha(leash, 0.0f)
+                    }
+                    animTransaction.apply()
+                }
+
+                override fun onAnimationEnd(animation: Animator) {
+                    finishCallback.run()
+                }
+            }
+        )
+
+        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?) {
         if (view != null) {
             launcher.dragLayer.removeView(view)
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationTimings.java b/quickstep/src/com/android/quickstep/util/SplitAnimationTimings.java
index 93f2255..b618546 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationTimings.java
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationTimings.java
@@ -21,31 +21,44 @@
 import android.view.animation.Interpolator;
 
 /**
- * An interface that supports the centralization of timing information for splitscreen animations.
+ * Organizes timing information for split screen animations.
  */
 public interface SplitAnimationTimings {
+    /** Total duration (ms) for initiating split screen (staging the first app) on tablets. */
     int TABLET_ENTER_DURATION = 866;
+    /** Total duration (ms) for confirming split screen (selecting the second app) on tablets. */
     int TABLET_CONFIRM_DURATION = 500;
-
+    /** Total duration (ms) for initiating split screen (staging the first app) on phones. */
     int PHONE_ENTER_DURATION = 517;
+    /** Total duration (ms) for confirming split screen (selecting the second app) on phones. */
     int PHONE_CONFIRM_DURATION = 333;
-
+    /** Total duration (ms) for aborting split screen (before selecting the second app). */
     int ABORT_DURATION = 500;
+    /** Total duration (ms) for launching an app pair from its icon on tablets. */
+    int TABLET_APP_PAIR_LAUNCH_DURATION = 998;
+    /** Total duration (ms) for launching an app pair from its icon on phones. */
+    int PHONE_APP_PAIR_LAUNCH_DURATION = 915;
 
+    // Initialize timing classes so they can be accessed statically
     SplitAnimationTimings TABLET_OVERVIEW_TO_SPLIT = new TabletOverviewToSplitTimings();
     SplitAnimationTimings TABLET_HOME_TO_SPLIT = new TabletHomeToSplitTimings();
     SplitAnimationTimings TABLET_SPLIT_TO_CONFIRM = new TabletSplitToConfirmTimings();
-
     SplitAnimationTimings PHONE_OVERVIEW_TO_SPLIT = new PhoneOverviewToSplitTimings();
     SplitAnimationTimings PHONE_SPLIT_TO_CONFIRM = new PhoneSplitToConfirmTimings();
+    SplitAnimationTimings TABLET_APP_PAIR_LAUNCH = new TabletAppPairLaunchTimings();
+    SplitAnimationTimings PHONE_APP_PAIR_LAUNCH = new PhoneAppPairLaunchTimings();
 
-    // Shared methods
+    // Shared methods: all split animations have these parameters
     int getDuration();
+    /** Start fading in the floating view tile at this time (in ms). */
     int getPlaceholderFadeInStart();
     int getPlaceholderFadeInEnd();
+    /** Start fading in the app icon at this time (in ms). */
     int getPlaceholderIconFadeInStart();
     int getPlaceholderIconFadeInEnd();
+    /** Start translating the floating view tile at this time (in ms). */
     int getStagedRectSlideStart();
+    /** The floating tile has reached its final position at this time (in ms). */
     int getStagedRectSlideEnd();
     Interpolator getStagedRectXInterpolator();
     Interpolator getStagedRectYInterpolator();
@@ -70,6 +83,11 @@
         return (float) getStagedRectSlideEnd() / getDuration();
     }
 
+    // DEFAULT VALUES: We define default values here so that SplitAnimationTimings can be used
+    // flexibly in animation-running functions, e.g. a single function that handles 2 types of split
+    // animations. The values are not intended to be used, and can safely be removed if refactoring
+    // these classes.
+
     // Defaults for OverviewToSplit
     default float getGridSlideStartOffset() { return 0; }
     default float getGridSlideStaggerOffset() { return 0; }
@@ -94,5 +112,13 @@
     // Defaults for SplitToConfirm
     default float getInstructionsFadeStartOffset() { return 0; }
     default float getInstructionsFadeEndOffset() { return 0; }
+
+    // Defaults for AppPair
+    default float getCellSplitStartOffset() { return 0; }
+    default float getCellSplitEndOffset() { return 0; }
+    default float getAppRevealStartOffset() { return 0; }
+    default float getAppRevealEndOffset() { return 0; }
+    default Interpolator getCellSplitInterpolator() { return LINEAR; }
+    default Interpolator getIconFadeInterpolator() { return LINEAR; }
 }
 
diff --git a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
index 596bb47..38bbe60 100644
--- a/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitScreenUtils.kt
@@ -56,4 +56,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
index 423ba43..c013483 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt
@@ -93,6 +93,7 @@
     private var secondTaskId: Int = INVALID_TASK_ID
     private var initialIntent: Intent? = null
     private var secondIntent: Intent? = null
+    private var widgetSecondIntent: Intent? = null
     private var initialUser: UserHandle? = null
     private var secondUser: UserHandle? = null
     private var initialPendingIntent: PendingIntent? = null
@@ -167,6 +168,16 @@
         secondUser = pendingIntent.creatorUserHandle
     }
 
+    /**
+     * Similar to [setSecondTask] except this is to be called for widgets which can pass through
+     * an extra intent from their RemoteResponse.
+     * See [android.widget.RemoteViews.RemoteResponse.getLaunchOptions].first
+     */
+    fun setSecondWidget(pendingIntent: PendingIntent, widgetIntent: Intent?) {
+        setSecondTask(pendingIntent)
+        widgetSecondIntent = widgetIntent
+    }
+
     private fun getShortcutInfo(intent: Intent?, user: UserHandle?): ShortcutInfo? {
         val intentPackage = intent?.getPackage() ?: return null
         val shortcutId = intent.getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID)
@@ -241,6 +252,7 @@
                 secondTaskId,
                 initialPendingIntent,
                 secondPendingIntent,
+                widgetSecondIntent,
                 initialUser?.identifier ?: -1,
                 secondUser?.identifier ?: -1,
                 initialShortcut,
@@ -257,7 +269,8 @@
      * Note that both [initialIntent] and [secondIntent] will be nullified on method return
      *
      * One caveat is that if [secondPendingIntent] is set, we will use that and *not* attempt to
-     * convert [secondIntent]
+     * convert [secondIntent].
+     * This also leaves [widgetSecondIntent] untouched.
      */
     private fun convertIntentsToFinalTypes() {
         initialShortcut = getShortcutInfo(initialIntent, initialUser)
@@ -343,6 +356,7 @@
             var secondTaskId: Int = INVALID_TASK_ID,
             var initialPendingIntent: PendingIntent? = null,
             var secondPendingIntent: PendingIntent? = null,
+            var widgetSecondIntent: Intent? = null,
             var initialUserId: Int = -1,
             var secondUserId: Int = -1,
             var initialShortcut: ShortcutInfo? = null,
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 145707b..d5899e4 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -32,6 +32,7 @@
 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;
 
 import android.animation.Animator;
@@ -70,6 +71,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.apppairs.AppPairIcon;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.IconProvider;
 import com.android.launcher3.logging.StatsLogManager;
@@ -91,7 +93,6 @@
 import com.android.quickstep.SplitSelectionListener;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskAnimationManager;
-import com.android.quickstep.TaskViewUtils;
 import com.android.quickstep.views.FloatingTaskView;
 import com.android.quickstep.views.GroupedTaskView;
 import com.android.quickstep.views.RecentsView;
@@ -140,6 +141,8 @@
     /** If not null, this is the TaskView we want to launch from */
     @Nullable
     private GroupedTaskView mLaunchingTaskView;
+    /** If not null, this is the icon we want to launch from */
+    private AppPairIcon mLaunchingIconView;
 
     /** True when the first selected split app is being launched in fullscreen. */
     private boolean mLaunchingFirstAppFullscreen;
@@ -213,15 +216,16 @@
     }
 
     /**
-     * Maps a List<ComponentKey> to List<@Nullable Task>, searching through active Tasks in
-     * RecentsModel. If found, the Task will be the most recently-interacted-with instance of that
-     * Task. Then runs the given callback on that List.
-     * <p>
-     * Used in various task-switching or splitscreen operations when we need to check if there is a
-     * currently running Task of a certain type and use the most recent one.
+     * Given a list of task keys, searches through active Tasks in RecentsModel to find the last
+     * active instances of these tasks. Returns an empty array if there is no such running task.
+     *
+     * @param componentKeys The list of ComponentKeys to search for.
+     * @param callback The callback that will be executed on the list of found tasks.
+     * @param findExactPairMatch If {@code true}, only finds tasks that contain BOTH of the wanted
+     *                           tasks (i.e. searching for a running pair of tasks.)
      */
-    public void findLastActiveTasksAndRunCallback(
-            @Nullable List<ComponentKey> componentKeys, Consumer<List<Task>> callback) {
+    public void findLastActiveTasksAndRunCallback(@Nullable List<ComponentKey> componentKeys,
+            boolean findExactPairMatch, Consumer<List<Task>> callback) {
         mRecentTasksModel.getTasks(taskGroups -> {
             if (componentKeys == null || componentKeys.isEmpty()) {
                 callback.accept(Collections.emptyList());
@@ -229,27 +233,40 @@
             }
 
             List<Task> lastActiveTasks = new ArrayList<>();
-            // For each key we are looking for, add to lastActiveTasks with the corresponding Task
-            // (or null if not found).
-            for (ComponentKey key : componentKeys) {
-                Task lastActiveTask = null;
+
+            if (findExactPairMatch) {
                 // Loop through tasks in reverse, since they are ordered with most-recent tasks last
                 for (int i = taskGroups.size() - 1; i >= 0; i--) {
                     GroupTask groupTask = taskGroups.get(i);
-                    Task task1 = groupTask.task1;
-                    // Don't add duplicate Tasks
-                    if (isInstanceOfComponent(task1, key) && !lastActiveTasks.contains(task1)) {
-                        lastActiveTask = task1;
-                        break;
-                    }
-                    Task task2 = groupTask.task2;
-                    if (isInstanceOfComponent(task2, key) && !lastActiveTasks.contains(task2)) {
-                        lastActiveTask = task2;
+                    if (isInstanceOfAppPair(
+                            groupTask, componentKeys.get(0), componentKeys.get(1))) {
+                        lastActiveTasks.add(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) {
+                    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);
+                        Task task1 = groupTask.task1;
+                        // Don't add duplicate Tasks
+                        if (isInstanceOfComponent(task1, key) && !lastActiveTasks.contains(task1)) {
+                            lastActiveTask = task1;
+                            break;
+                        }
+                        Task task2 = groupTask.task2;
+                        if (isInstanceOfComponent(task2, key) && !lastActiveTasks.contains(task2)) {
+                            lastActiveTask = task2;
+                            break;
+                        }
+                    }
 
-                lastActiveTasks.add(lastActiveTask);
+                    lastActiveTasks.add(lastActiveTask);
+                }
             }
 
             callback.accept(lastActiveTasks);
@@ -271,6 +288,19 @@
     }
 
     /**
+     * Checks if a given GroupTask is a pair of apps that matches two given ComponentKeys. We check
+     * both permutations because task order is not guaranteed in GroupTasks.
+     */
+    public boolean isInstanceOfAppPair(GroupTask groupTask, @NonNull ComponentKey componentKey1,
+            @NonNull ComponentKey componentKey2) {
+        return ((isInstanceOfComponent(groupTask.task1, componentKey1)
+                && isInstanceOfComponent(groupTask.task2, componentKey2))
+                ||
+                (isInstanceOfComponent(groupTask.task1, componentKey2)
+                        && isInstanceOfComponent(groupTask.task2, componentKey1)));
+    }
+
+    /**
      * Listener will only get callbacks going forward from the point of registration. No
      * methods will be fired upon registering.
      */
@@ -355,6 +385,10 @@
         mSplitSelectDataHolder.setSecondTask(pendingIntent);
     }
 
+    public void setSecondWidget(PendingIntent pendingIntent, Intent widgetIntent) {
+        mSplitSelectDataHolder.setSecondWidget(pendingIntent, widgetIntent);
+    }
+
     /**
      * To be called when we want to launch split pairs from Overview. Split can be initiated from
      * either Overview or home, or all apps. Either both taskIds are set, or a pending intent + a
@@ -380,11 +414,13 @@
         ShortcutInfo secondShortcut = launchData.getSecondShortcut();
         PendingIntent firstPI = launchData.getInitialPendingIntent();
         PendingIntent secondPI = launchData.getSecondPendingIntent();
+        Intent widgetIntent = launchData.getWidgetSecondIntent();
         int firstUserId = launchData.getInitialUserId();
         int secondUserId = launchData.getSecondUserId();
         int initialStagePosition = launchData.getInitialStagePosition();
         Bundle optionsBundle = options1.toBundle();
-
+        Bundle extrasBundle = new Bundle(1);
+        extrasBundle.putParcelable(KEY_EXTRA_WIDGET_INTENT, widgetIntent);
         if (TaskAnimationManager.ENABLE_SHELL_TRANSITIONS) {
             final RemoteTransition remoteTransition = getShellRemoteTransition(firstTaskId,
                     secondTaskId, callback, "LaunchSplitPair");
@@ -396,7 +432,7 @@
 
                 case SPLIT_TASK_PENDINGINTENT ->
                         mSystemUiProxy.startIntentAndTask(secondPI, secondUserId, optionsBundle,
-                                firstTaskId, null /*options2*/, initialStagePosition, snapPosition,
+                                firstTaskId, extrasBundle, initialStagePosition, snapPosition,
                                 remoteTransition, shellInstanceId);
 
                 case SPLIT_TASK_SHORTCUT ->
@@ -411,9 +447,9 @@
 
                 case SPLIT_PENDINGINTENT_PENDINGINTENT ->
                         mSystemUiProxy.startIntents(firstPI, firstUserId, firstShortcut,
-                                optionsBundle, secondPI, secondUserId, secondShortcut,
-                                null /*options2*/, initialStagePosition, snapPosition,
-                                remoteTransition, shellInstanceId);
+                                optionsBundle, secondPI, secondUserId, secondShortcut, extrasBundle,
+                                initialStagePosition, snapPosition, remoteTransition,
+                                shellInstanceId);
 
                 case SPLIT_SHORTCUT_TASK ->
                         mSystemUiProxy.startShortcutAndTask(firstShortcut, optionsBundle,
@@ -627,8 +663,20 @@
             };
 
             MAIN_EXECUTOR.execute(() -> {
-                TaskViewUtils.composeRecentsSplitLaunchAnimator(mLaunchingTaskView, mStateManager,
-                        mDepthController, mInitialTaskId, mSecondTaskId, info, t, () -> {
+                // Only animate from taskView if it's already visible
+                boolean shouldLaunchFromTaskView = mLaunchingTaskView != null &&
+                        mLaunchingTaskView.getRecentsView().isTaskViewVisible(mLaunchingTaskView);
+                mSplitAnimationController.playSplitLaunchAnimation(
+                        shouldLaunchFromTaskView ? mLaunchingTaskView : null,
+                        mLaunchingIconView,
+                        mInitialTaskId,
+                        mSecondTaskId,
+                        null /* apps */,
+                        null /* wallpapers */,
+                        null /* nonApps */,
+                        mStateManager,
+                        mDepthController,
+                        info, t, () -> {
                             finishAdapter.run();
                             cleanup(true /*success*/);
                         });
@@ -684,9 +732,10 @@
                 RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
                 Runnable finishedCallback) {
             postAsyncCallback(mHandler,
-                    () -> TaskViewUtils.composeRecentsSplitLaunchAnimatorLegacy(
-                            mLaunchingTaskView, mInitialTaskId, mSecondTaskId, apps, wallpapers,
-                            nonApps, mStateManager, mDepthController, () -> {
+                    () -> mSplitAnimationController.playSplitLaunchAnimation(mLaunchingTaskView,
+                            mLaunchingIconView, mInitialTaskId, mSecondTaskId, apps, wallpapers,
+                            nonApps, mStateManager, mDepthController, null /* info */, null /* t */,
+                            () -> {
                                 finishedCallback.run();
                                 if (mSuccessCallback != null) {
                                     mSuccessCallback.accept(true);
@@ -719,6 +768,7 @@
         dispatchOnSplitSelectionExit();
         mRecentsAnimationRunning = false;
         mLaunchingTaskView = null;
+        mLaunchingIconView = null;
         mAnimateCurrentTaskDismissal = false;
         mDismissingFromSplitPair = false;
         mFirstFloatingTaskView = null;
@@ -779,6 +829,10 @@
         return mAppPairsController;
     }
 
+    public void setLaunchingIconView(AppPairIcon launchingIconView) {
+        mLaunchingIconView = launchingIconView;
+    }
+
     public BackPressHandler getSplitBackHandler() {
         return mSplitBackHandler;
     }
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index 9313342..e705285 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -72,7 +72,8 @@
      * @return {@code true} if we can attempt launch the widget into split, {@code false} otherwise
      *         to allow launcher to handle the click
      */
-    public boolean handleSecondWidgetSelectionForSplit(View view, PendingIntent pendingIntent) {
+    public boolean handleSecondWidgetSelectionForSplit(View view, PendingIntent pendingIntent,
+            Intent remoteResponseIntent) {
         if (shouldIgnoreSecondSplitLaunch()) {
             return false;
         }
@@ -86,7 +87,7 @@
             Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
 
             view.post(() -> {
-                mController.setSecondTask(pendingIntent);
+                mController.setSecondWidget(pendingIntent, remoteResponseIntent);
                 // Convert original widgetView into bitmap to use for animation
                 Canvas canvas = new Canvas(bitmap);
                 view.draw(canvas);
diff --git a/quickstep/src/com/android/quickstep/util/TabletAppPairLaunchTimings.kt b/quickstep/src/com/android/quickstep/util/TabletAppPairLaunchTimings.kt
new file mode 100644
index 0000000..fb2d63f
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/TabletAppPairLaunchTimings.kt
@@ -0,0 +1,23 @@
+/*
+ * 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
+
+/** Timings for the app pair launch animation on tablets. */
+class TabletAppPairLaunchTimings : AppPairLaunchTimings(), SplitAnimationTimings {
+    override val STAGED_RECT_SLIDE_DURATION = 600
+    override fun getDuration() = SplitAnimationTimings.TABLET_APP_PAIR_LAUNCH_DURATION
+}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt b/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt
new file mode 100644
index 0000000..3a5873b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/FloatingAppPairBackground.kt
@@ -0,0 +1,358 @@
+/*
+ * 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.views
+
+import android.content.Context
+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 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
+import com.android.systemui.shared.system.QuickStepContract
+
+/**
+ * A Drawable that is drawn onto [FloatingAppPairView] every frame during the app pair launch
+ * animation. Consists of a rectangular background that splits into two, and two app icons that
+ * increase in size during the animation.
+ */
+class FloatingAppPairBackground(
+    context: Context,
+    private val floatingView: FloatingAppPairView, // the view that we will draw this background on
+    private val appIcon1: Drawable,
+    private val appIcon2: Drawable,
+    dividerPos: Int
+) : Drawable() {
+    companion object {
+        // Design specs -- app icons start small and expand during the animation
+        private val STARTING_ICON_SIZE_PX = Utilities.dpToPx(22f)
+        private val ENDING_ICON_SIZE_PX = Utilities.dpToPx(66f)
+
+        // Null values to use with drawDoubleRoundRect(), since there doesn't seem to be any other
+        // API for drawing rectangles with 4 different corner radii.
+        private val EMPTY_RECT = RectF()
+        private val ARRAY_OF_ZEROES = FloatArray(8)
+    }
+
+    private val launcher: Launcher
+    private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG)
+
+    // Animation interpolators
+    private val expandXInterpolator: Interpolator
+    private val expandYInterpolator: Interpolator
+    private val cellSplitInterpolator: Interpolator
+    private val iconFadeInterpolator: Interpolator
+
+    // Device-specific measurements
+    private val deviceCornerRadius: Float
+    private val deviceHalfDividerSize: Float
+    private val desiredSplitRatio: Float
+
+    init {
+        launcher = Launcher.getLauncher(context)
+        val dp = launcher.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)
+        expandXInterpolator =
+            Interpolators.clampToProgress(
+                timings.getStagedRectScaleXInterpolator(),
+                timings.stagedRectSlideStartOffset,
+                timings.stagedRectSlideEndOffset
+            )
+        expandYInterpolator =
+            Interpolators.clampToProgress(
+                timings.getStagedRectScaleYInterpolator(),
+                timings.stagedRectSlideStartOffset,
+                timings.stagedRectSlideEndOffset
+            )
+        cellSplitInterpolator =
+            Interpolators.clampToProgress(
+                timings.cellSplitInterpolator,
+                timings.cellSplitStartOffset,
+                timings.cellSplitEndOffset
+            )
+        iconFadeInterpolator =
+            Interpolators.clampToProgress(
+                timings.iconFadeInterpolator,
+                timings.iconFadeStartOffset,
+                timings.iconFadeEndOffset
+            )
+
+        // Find device-specific measurements
+        deviceCornerRadius = QuickStepContract.getWindowCornerRadius(launcher)
+        deviceHalfDividerSize =
+            launcher.resources.getDimensionPixelSize(R.dimen.multi_window_task_divider_size) / 2f
+        val dividerCenterPos = dividerPos + deviceHalfDividerSize
+        desiredSplitRatio =
+            if (dp.isLeftRightSplit) dividerCenterPos / dp.widthPx
+            else dividerCenterPos / dp.heightPx
+    }
+
+    override fun draw(canvas: Canvas) {
+        if (launcher.deviceProfile.isLandscape) {
+            drawLeftRightSplit(canvas)
+        } else {
+            drawTopBottomSplit(canvas)
+        }
+    }
+
+    /** When device is in landscape, we draw the rectangles with a left-right split. */
+    private fun drawLeftRightSplit(canvas: Canvas) {
+        val progress = floatingView.progress
+
+        // Since the entire floating app pair surface is scaling up during this animation, we
+        // scale down most of these drawn elements so that they appear the proper size on-screen.
+        val scaleFactorX = floatingView.scaleX
+        val scaleFactorY = floatingView.scaleY
+
+        // Get the bounds where we will draw the background image
+        val width = bounds.width().toFloat()
+        val height = bounds.height().toFloat()
+
+        // Get device-specific measurements
+        val cornerRadiusX = deviceCornerRadius / scaleFactorX
+        val cornerRadiusY = deviceCornerRadius / scaleFactorY
+        val halfDividerSize = deviceHalfDividerSize / scaleFactorX
+
+        // Calculate changing measurements for background
+        // We add one pixel to some measurements to create a smooth edge with no gaps
+        val onePixel = 1f / scaleFactorX
+        val changingDividerSize =
+            (cellSplitInterpolator.getInterpolation(progress) * halfDividerSize) - onePixel
+        val changingInnerRadiusX = cellSplitInterpolator.getInterpolation(progress) * cornerRadiusX
+        val changingInnerRadiusY = cellSplitInterpolator.getInterpolation(progress) * cornerRadiusY
+        val dividerCenterPos = width * desiredSplitRatio
+
+        // The left half of the background image
+        val leftSide = RectF(
+            0f,
+            0f,
+            dividerCenterPos - changingDividerSize,
+            height
+        )
+        // The right half of the background image
+        val rightSide = RectF(
+            dividerCenterPos + changingDividerSize,
+            0f,
+            width,
+            height
+        )
+
+        // Draw background
+        drawCustomRoundedRect(
+            canvas,
+            leftSide,
+            floatArrayOf(
+                cornerRadiusX, cornerRadiusY,
+                changingInnerRadiusX, changingInnerRadiusY,
+                changingInnerRadiusX, changingInnerRadiusY,
+                cornerRadiusX, cornerRadiusY
+            )
+        )
+        drawCustomRoundedRect(
+            canvas,
+            rightSide,
+            floatArrayOf(
+                changingInnerRadiusX, changingInnerRadiusY,
+                cornerRadiusX, cornerRadiusY,
+                cornerRadiusX, cornerRadiusY,
+                changingInnerRadiusX, changingInnerRadiusY
+            )
+        )
+
+        // Calculate changing measurements for icons.
+        val changingIconSizeX =
+            (STARTING_ICON_SIZE_PX +
+                ((ENDING_ICON_SIZE_PX - STARTING_ICON_SIZE_PX) *
+                    expandXInterpolator.getInterpolation(progress))) / scaleFactorX
+        val changingIconSizeY =
+            (STARTING_ICON_SIZE_PX +
+                ((ENDING_ICON_SIZE_PX - STARTING_ICON_SIZE_PX) *
+                    expandYInterpolator.getInterpolation(progress))) / scaleFactorY
+
+        val changingIcon1Left = ((width / 2f - halfDividerSize) / 2f) - (changingIconSizeX / 2f)
+        val changingIcon2Left =
+            (width - ((width / 2f - halfDividerSize) / 2f)) - (changingIconSizeX / 2f)
+        val changingIconTop = (height / 2f) - (changingIconSizeY / 2f)
+        val changingIconScaleX = changingIconSizeX / appIcon1.bounds.width()
+        val changingIconScaleY = changingIconSizeY / appIcon1.bounds.height()
+        val changingIconAlpha =
+            (255 - (255 * iconFadeInterpolator.getInterpolation(progress))).toInt()
+
+        // Draw first icon
+        canvas.save()
+        canvas.translate(changingIcon1Left, changingIconTop)
+        canvas.scale(changingIconScaleX, changingIconScaleY)
+        appIcon1.alpha = changingIconAlpha
+        appIcon1.draw(canvas)
+        canvas.restore()
+
+        // Draw second icon
+        canvas.save()
+        canvas.translate(changingIcon2Left, changingIconTop)
+        canvas.scale(changingIconScaleX, changingIconScaleY)
+        appIcon2.alpha = changingIconAlpha
+        appIcon2.draw(canvas)
+        canvas.restore()
+    }
+
+    /** When device is in portrait, we draw the rectangles with a top-bottom split. */
+    private fun drawTopBottomSplit(canvas: Canvas) {
+        val progress = floatingView.progress
+
+        // Since the entire floating app pair surface is scaling up during this animation, we
+        // scale down most of these drawn elements so that they appear the proper size on-screen.
+        val scaleFactorX = floatingView.scaleX
+        val scaleFactorY = floatingView.scaleY
+
+        // Get the bounds where we will draw the background image
+        val width = bounds.width().toFloat()
+        val height = bounds.height().toFloat()
+
+        // Get device-specific measurements
+        val cornerRadiusX = deviceCornerRadius / scaleFactorX
+        val cornerRadiusY = deviceCornerRadius / scaleFactorY
+        val halfDividerSize = deviceHalfDividerSize / scaleFactorY
+
+        // Calculate changing measurements for background
+        // We add one pixel to some measurements to create a smooth edge with no gaps
+        val onePixel = 1f / scaleFactorY
+        val changingDividerSize =
+            (cellSplitInterpolator.getInterpolation(progress) * halfDividerSize) - onePixel
+        val changingInnerRadiusX = cellSplitInterpolator.getInterpolation(progress) * cornerRadiusX
+        val changingInnerRadiusY = cellSplitInterpolator.getInterpolation(progress) * cornerRadiusY
+        val dividerCenterPos = height * desiredSplitRatio
+
+        // The top half of the background image
+        val topSide = RectF(
+            0f,
+            0f,
+            width,
+            dividerCenterPos - changingDividerSize
+        )
+        // The bottom half of the background image
+        val bottomSide = RectF(
+            0f,
+            dividerCenterPos + changingDividerSize,
+            width,
+            height
+        )
+
+        // Draw background
+        drawCustomRoundedRect(
+            canvas,
+            topSide,
+            floatArrayOf(
+                cornerRadiusX, cornerRadiusY,
+                cornerRadiusX, cornerRadiusY,
+                changingInnerRadiusX, changingInnerRadiusY,
+                changingInnerRadiusX, changingInnerRadiusY
+            )
+        )
+        drawCustomRoundedRect(
+            canvas,
+            bottomSide,
+            floatArrayOf(
+                changingInnerRadiusX, changingInnerRadiusY,
+                changingInnerRadiusX, changingInnerRadiusY,
+                cornerRadiusX, cornerRadiusY,
+                cornerRadiusX, cornerRadiusY
+            )
+        )
+
+        // Calculate changing measurements for icons.
+        val changingIconSizeX =
+            (STARTING_ICON_SIZE_PX +
+                ((ENDING_ICON_SIZE_PX - STARTING_ICON_SIZE_PX) *
+                    expandXInterpolator.getInterpolation(progress))) / scaleFactorX
+        val changingIconSizeY =
+            (STARTING_ICON_SIZE_PX +
+                ((ENDING_ICON_SIZE_PX - STARTING_ICON_SIZE_PX) *
+                    expandYInterpolator.getInterpolation(progress))) / scaleFactorY
+
+        val changingIconLeft = (width / 2f) - (changingIconSizeX / 2f)
+        val changingIcon1Top = (((height / 2f) - halfDividerSize) / 2f) - (changingIconSizeY / 2f)
+        val changingIcon2Top =
+            (height - (((height / 2f) - halfDividerSize) / 2f)) - (changingIconSizeY / 2f)
+        val changingIconScaleX = changingIconSizeX / appIcon1.bounds.width()
+        val changingIconScaleY = changingIconSizeY / appIcon1.bounds.height()
+        val changingIconAlpha =
+            (255 - 255 * iconFadeInterpolator.getInterpolation(progress)).toInt()
+
+        // Draw first icon
+        canvas.save()
+        canvas.translate(changingIconLeft, changingIcon1Top)
+        canvas.scale(changingIconScaleX, changingIconScaleY)
+        appIcon1.alpha = changingIconAlpha
+        appIcon1.draw(canvas)
+        canvas.restore()
+
+        // Draw second icon
+        canvas.save()
+        canvas.translate(changingIconLeft, changingIcon2Top)
+        canvas.scale(changingIconScaleX, changingIconScaleY)
+        appIcon2.alpha = changingIconAlpha
+        appIcon2.draw(canvas)
+        canvas.restore()
+    }
+
+    /**
+     * 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 fun drawCustomRoundedRect(c: Canvas, rect: RectF, radii: FloatArray) {
+        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+            // Canvas.drawDoubleRoundRect is supported from Q onward
+            c.drawDoubleRoundRect(rect, radii, EMPTY_RECT, ARRAY_OF_ZEROES, backgroundPaint)
+        } else {
+            // 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
+            c.drawRoundRect(rect, cornerRadiusX, cornerRadiusY, backgroundPaint)
+        }
+    }
+
+    override fun getOpacity(): Int {
+        return PixelFormat.OPAQUE
+    }
+
+    override fun setAlpha(i: Int) {
+        // Required by Drawable but not used.
+    }
+
+    override fun setColorFilter(colorFilter: ColorFilter?) {
+        // Required by Drawable but not used.
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingAppPairView.kt b/quickstep/src/com/android/quickstep/views/FloatingAppPairView.kt
new file mode 100644
index 0000000..e90aa13
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/FloatingAppPairView.kt
@@ -0,0 +1,103 @@
+/*
+ * 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.views
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import android.widget.FrameLayout
+import com.android.launcher3.R
+import com.android.launcher3.Utilities
+import com.android.launcher3.statemanager.StatefulActivity
+import com.android.launcher3.views.BaseDragLayer
+
+/**
+ * A temporary View that is created for the app pair launch animation and destroyed at the end.
+ * Matches the size & position of the app pair icon graphic, and expands to full screen.
+ */
+class FloatingAppPairView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
+    FrameLayout(context, attrs) {
+    companion object {
+        fun getFloatingAppPairView(
+            launcher: StatefulActivity<*>,
+            originalView: View,
+            appIcon1: Drawable,
+            appIcon2: Drawable,
+            dividerPos: Int
+        ): FloatingAppPairView {
+            val dragLayer: ViewGroup = launcher.getDragLayer()
+            val floatingView =
+                launcher
+                    .getLayoutInflater()
+                    .inflate(R.layout.floating_app_pair_view, dragLayer, false)
+                    as FloatingAppPairView
+            floatingView.init(launcher, originalView, appIcon1, appIcon2, dividerPos)
+            dragLayer.addView(floatingView, dragLayer.childCount - 1)
+            return floatingView
+        }
+    }
+
+    val startingPosition = RectF()
+    private lateinit var background: FloatingAppPairBackground
+    var progress = 0f
+
+    /** Initializes the view, copying the bounds and location of the original icon view. */
+    fun init(
+        launcher: StatefulActivity<*>,
+        originalView: View,
+        appIcon1: Drawable,
+        appIcon2: Drawable,
+        dividerPos: Int
+    ) {
+        val viewBounds = Rect(0, 0, originalView.width, originalView.height)
+        Utilities.getBoundsForViewInDragLayer(
+            launcher.getDragLayer(),
+            originalView,
+            viewBounds,
+            false /* ignoreTransform */,
+            null /* recycle */,
+            startingPosition
+        )
+        val lp =
+            BaseDragLayer.LayoutParams(
+                Math.round(startingPosition.width()),
+                Math.round(startingPosition.height())
+            )
+        lp.ignoreInsets = true
+
+        // Position the floating view exactly on top of the original
+        lp.topMargin = Math.round(startingPosition.top)
+        lp.leftMargin = Math.round(startingPosition.left)
+
+        layout(lp.leftMargin, lp.topMargin, lp.leftMargin + lp.width, lp.topMargin + lp.height)
+        layoutParams = lp
+
+        // Prepare to draw app pair icon background
+        background = FloatingAppPairBackground(context, this, appIcon1, appIcon2, dividerPos)
+        background.setBounds(0, 0, lp.width, lp.height)
+    }
+
+    override fun dispatchDraw(canvas: Canvas) {
+        super.dispatchDraw(canvas)
+        background.draw(canvas)
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 7e1034b..87cee63 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2124,8 +2124,7 @@
         for (int i = 0; i < taskCount; i++) {
             TaskView taskView = requireTaskViewAt(i);
             taskView.updateTaskSize();
-            taskView.getPrimaryNonGridTranslationProperty().set(taskView, accumulatedTranslationX);
-            taskView.getSecondaryNonGridTranslationProperty().set(taskView, 0f);
+            taskView.setNonGridTranslationX(accumulatedTranslationX);
             taskView.setNonGridPivotTranslationX(translateXToMiddle);
             // Compensate space caused by TaskView scaling.
             float widthDiff =
@@ -2642,23 +2641,25 @@
         if (endState.displayOverviewTasksAsGrid(mActivity.getDeviceProfile())) {
             TaskView runningTaskView = getRunningTaskView();
             float runningTaskPrimaryGridTranslation = 0;
+            float runningTaskSecondaryGridTranslation = 0;
             if (runningTaskView != null) {
                 // Apply the grid translation to running task unless it's being snapped to
                 // and removes the current translation applied to the running task.
-                runningTaskPrimaryGridTranslation = mOrientationHandler.getPrimaryValue(
-                        runningTaskView.getGridTranslationX(),
-                        runningTaskView.getGridTranslationY())
-                        - runningTaskView.getPrimaryNonGridTranslationProperty().get(
-                        runningTaskView);
+                runningTaskPrimaryGridTranslation = runningTaskView.getGridTranslationX()
+                        - runningTaskView.getNonGridTranslationX();
+                runningTaskSecondaryGridTranslation = runningTaskView.getGridTranslationY();
             }
             for (TaskViewSimulator tvs : taskViewSimulators) {
                 if (animatorSet == null) {
                     setGridProgress(1);
                     tvs.taskPrimaryTranslation.value = runningTaskPrimaryGridTranslation;
+                    tvs.taskSecondaryTranslation.value = runningTaskSecondaryGridTranslation;
                 } else {
                     animatorSet.play(ObjectAnimator.ofFloat(this, RECENTS_GRID_PROGRESS, 1));
                     animatorSet.play(tvs.taskPrimaryTranslation.animateToValue(
                             runningTaskPrimaryGridTranslation));
+                    animatorSet.play(tvs.taskSecondaryTranslation.animateToValue(
+                            runningTaskSecondaryGridTranslation));
                 }
             }
         }
@@ -3123,6 +3124,14 @@
                     + snappedTaskNonGridScrollAdjustment);
         }
 
+        final TaskView runningTask = getRunningTaskView();
+        if (showAsGrid() && enableGridOnlyOverview() && runningTask != null) {
+            runActionOnRemoteHandles(
+                    remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
+                            .taskSecondaryTranslation.value = runningTask.getGridTranslationY()
+            );
+        }
+
         mClearAllButton.setGridTranslationPrimary(
                 clearAllTotalTranslationX - snappedTaskGridTranslationX);
         mClearAllButton.setGridScrollOffset(
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index af4f402..b42f055 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -119,6 +119,8 @@
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 
+import kotlin.Unit;
+
 import java.lang.annotation.Retention;
 import java.util.Arrays;
 import java.util.Collections;
@@ -127,8 +129,6 @@
 import java.util.function.Consumer;
 import java.util.stream.Stream;
 
-import kotlin.Unit;
-
 /**
  * A task in the Recents view.
  */
@@ -304,32 +304,6 @@
                 }
             };
 
-    private static final FloatProperty<TaskView> NON_GRID_TRANSLATION_X =
-            new FloatProperty<TaskView>("nonGridTranslationX") {
-                @Override
-                public void setValue(TaskView taskView, float v) {
-                    taskView.setNonGridTranslationX(v);
-                }
-
-                @Override
-                public Float get(TaskView taskView) {
-                    return taskView.mNonGridTranslationX;
-                }
-            };
-
-    private static final FloatProperty<TaskView> NON_GRID_TRANSLATION_Y =
-            new FloatProperty<TaskView>("nonGridTranslationY") {
-                @Override
-                public void setValue(TaskView taskView, float v) {
-                    taskView.setNonGridTranslationY(v);
-                }
-
-                @Override
-                public Float get(TaskView taskView) {
-                    return taskView.mNonGridTranslationY;
-                }
-            };
-
     public static final FloatProperty<TaskView> GRID_END_TRANSLATION_X =
             new FloatProperty<TaskView>("gridEndTranslationX") {
                 @Override
@@ -386,7 +360,6 @@
     // Applied as a complement to gridTranslation, for adjusting the carousel overview and quick
     // switch.
     private float mNonGridTranslationX;
-    private float mNonGridTranslationY;
     private float mNonGridPivotTranslationX;
     // Used when in SplitScreenSelectState
     private float mSplitSelectTranslationY;
@@ -1323,7 +1296,7 @@
     }
 
     protected void resetPersistentViewTransforms() {
-        mNonGridTranslationX = mNonGridTranslationY = mGridTranslationX =
+        mNonGridTranslationX = mGridTranslationX =
                 mGridTranslationY = mBoxTranslationY = mNonGridPivotTranslationX = 0f;
         resetViewTransforms();
     }
@@ -1494,14 +1467,16 @@
         applyTranslationY();
     }
 
-    private void setNonGridTranslationX(float nonGridTranslationX) {
-        mNonGridTranslationX = nonGridTranslationX;
-        applyTranslationX();
+    public float getNonGridTranslationX() {
+        return mNonGridTranslationX;
     }
 
-    private void setNonGridTranslationY(float nonGridTranslationY) {
-        mNonGridTranslationY = nonGridTranslationY;
-        applyTranslationY();
+    /**
+     * Updates X coordinate of non-grid translation.
+     */
+    public void setNonGridTranslationX(float nonGridTranslationX) {
+        mNonGridTranslationX = nonGridTranslationX;
+        applyTranslationX();
     }
 
     public void setGridTranslationX(float gridTranslationX) {
@@ -1540,7 +1515,7 @@
         if (gridEnabled) {
             scrollAdjustment += mGridTranslationX;
         } else {
-            scrollAdjustment += getPrimaryNonGridTranslationProperty().get(this);
+            scrollAdjustment += getNonGridTranslationX();
         }
         return scrollAdjustment;
     }
@@ -1586,9 +1561,7 @@
      * change according to a temporary state (e.g. task offset).
      */
     public float getPersistentTranslationY() {
-        return mBoxTranslationY
-                + getNonGridTrans(mNonGridTranslationY)
-                + getGridTrans(mGridTranslationY);
+        return mBoxTranslationY + getGridTrans(mGridTranslationY);
     }
 
     public FloatProperty<TaskView> getPrimarySplitTranslationProperty() {
@@ -1626,16 +1599,6 @@
                 TASK_RESISTANCE_TRANSLATION_X, TASK_RESISTANCE_TRANSLATION_Y);
     }
 
-    public FloatProperty<TaskView> getPrimaryNonGridTranslationProperty() {
-        return getPagedOrientationHandler().getPrimaryValue(
-                NON_GRID_TRANSLATION_X, NON_GRID_TRANSLATION_Y);
-    }
-
-    public FloatProperty<TaskView> getSecondaryNonGridTranslationProperty() {
-        return getPagedOrientationHandler().getSecondaryValue(
-                NON_GRID_TRANSLATION_X, NON_GRID_TRANSLATION_Y);
-    }
-
     @Override
     public boolean hasOverlappingRendering() {
         // TODO: Clip-out the icon region from the thumbnail, since they are overlapping.
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index eced5a9..8d54dce 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -144,7 +144,7 @@
                 .around(new TestStabilityRule())
                 .around(new NavigationModeSwitchRule(mLauncher))
                 .around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
-                .around(viewCaptureRule)
+                // .around(viewCaptureRule) b/315482167
                 .around(new TestIsolationRule(mLauncher, false))
                 .around(setLauncherCommand);
 
diff --git a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
similarity index 83%
rename from quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
rename to quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
index 1129a33..728fe67 100644
--- a/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
@@ -1,3 +1,18 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package com.android.quickstep;
 
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
@@ -27,7 +42,7 @@
 
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class DigitalWellBeingToastTest extends AbstractQuickStepTest {
+public class TaplDigitalWellBeingToastTest extends AbstractQuickStepTest {
     private static final String CALCULATOR_PACKAGE =
             resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
 
diff --git a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
similarity index 96%
rename from quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
rename to quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
index 85440e9..7e274e8 100644
--- a/quickstep/tests/src/com/android/quickstep/StartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
@@ -32,7 +32,7 @@
 
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class StartLauncherViaGestureTests extends AbstractQuickStepTest {
+public class TaplStartLauncherViaGestureTests extends AbstractQuickStepTest {
 
     static final int STRESS_REPEAT_COUNT = 10;
 
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
index 9a2826d..c9e536a 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java
@@ -20,9 +20,10 @@
 import androidx.test.filters.LargeTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
 import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
 
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
@@ -32,17 +33,10 @@
 
     @Test
     @TaskbarModeSwitch(mode = PERSISTENT)
-    public void testHideShowTaskbar() {
-        getTaskbar().hide();
-        mLauncher.getLaunchedAppState().showTaskbar();
-    }
-
-    @Test
-    @TaskbarModeSwitch(mode = PERSISTENT)
-    @Ignore // b/301575789
-    public void testHideTaskbarPersistsOnRecreate() {
-        getTaskbar().hide();
-        mLauncher.recreateTaskbar();
-        mLauncher.getLaunchedAppState().assertTaskbarHidden();
+    @PortraitLandscape
+    @NavigationModeSwitch
+    public void testTaskbarFillsWidth() {
+        // Width check is performed inside TAPL whenever getTaskbar() is called.
+        getTaskbar();
     }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index b3cc215..6cbe171 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -18,7 +18,6 @@
 
 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 static com.android.quickstep.TaskbarModeSwitchRule.Mode.TRANSIENT;
 
 import static org.junit.Assert.assertEquals;
@@ -295,7 +294,8 @@
     }
 
     @Test
-    @TaskbarModeSwitch(mode = PERSISTENT)
+    @TaskbarModeSwitch
+    @Ignore // b/314873201
     public void testQuickSwitchToPreviousAppForTablet() throws Exception {
         assumeTrue(mLauncher.isTablet());
         startTestActivity(2);
@@ -304,22 +304,33 @@
         // Set ignoreTaskbarVisibility to true to verify the task bar visibility explicitly.
         mLauncher.setIgnoreTaskbarVisibility(true);
 
-        // Expect task bar invisible when the launched app was the IME activity.
-        LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
-        if (isHardwareKeyboard()) {
-            launchedAppState.assertTaskbarVisible();
-        } else {
-            launchedAppState.assertTaskbarHidden();
+
+        try {
+            boolean isTransientTaskbar = mLauncher.isTransientTaskbar();
+            // Expect task bar invisible when the launched app was the IME activity.
+            LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
+            if (!isTransientTaskbar && isHardwareKeyboard()) {
+                launchedAppState.assertTaskbarVisible();
+            } else {
+                launchedAppState.assertTaskbarHidden();
+            }
+
+            // Quick-switch to the test app with swiping to right.
+            quickSwitchToPreviousAppAndAssert(true /* toRight */);
+
+            assertTestActivityIsRunning(2,
+                    "The first app we should have quick switched to is not running");
+            launchedAppState = getAndAssertLaunchedApp();
+            if (isTransientTaskbar) {
+                launchedAppState.assertTaskbarHidden();
+            } else {
+                // Expect taskbar visible when the launched app was the test activity.
+                launchedAppState.assertTaskbarVisible();
+            }
+        } finally {
+            // Reset ignoreTaskbarVisibility to ensure other tests still verify it.
+            mLauncher.setIgnoreTaskbarVisibility(false);
         }
-
-        // Quick-switch to the test app with swiping to right.
-        quickSwitchToPreviousAppAndAssert(true /* toRight */);
-
-        assertTestActivityIsRunning(2,
-                "The first app we should have quick switched to is not running");
-        // Expect task bar visible when the launched app was the test activity.
-        launchedAppState = getAndAssertLaunchedApp();
-        launchedAppState.assertTaskbarVisible();
     }
 
     private boolean isHardwareKeyboard() {
@@ -344,6 +355,8 @@
     public void testPressBack() throws Exception {
         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
                 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();
@@ -358,7 +371,7 @@
 
     @Test
     @PortraitLandscape
-    @TaskbarModeSwitch(mode = PERSISTENT)
+    @TaskbarModeSwitch()
     @PlatinumTest(focusArea = "launcher")
     @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/309820115
     @ScreenRecord // b/309820115
@@ -454,6 +467,7 @@
 
     @Test
     @PortraitLandscape
+    @TaskbarModeSwitch
     public void testTaskbarDeadzonesForTablet() throws Exception {
         assumeTrue(mLauncher.isTablet());
 
@@ -466,15 +480,29 @@
                 launcher -> assertTrue("Should have at least 3 tasks",
                         getTaskCount(launcher) >= 3));
 
-        // On persistent taskbar, it should not dismiss when tapping the taskbar
-        overview.touchTaskbarBottomCorner(/* tapRight= */ false);
-        assertTrue("Launcher internal state should be Overview",
-                isInState(() -> LauncherState.OVERVIEW));
+        if (mLauncher.isTransientTaskbar()) {
+            // On transient taskbar, it should dismiss when tapping outside taskbar bounds.
+            overview.touchTaskbarBottomCorner(/* tapRight= */ false);
+            assertTrue("Launcher internal state should be Normal",
+                    isInState(() -> LauncherState.NORMAL));
 
-        // On persistent taskbar, it should not dismiss when tapping the taskbar
-        overview.touchTaskbarBottomCorner(/* tapRight= */ true);
-        assertTrue("Launcher internal state should be Overview",
-                isInState(() -> LauncherState.OVERVIEW));
+            overview = mLauncher.getWorkspace().switchToOverview();
+
+            // On transient taskbar, it should dismiss when tapping outside taskbar bounds.
+            overview.touchTaskbarBottomCorner(/* tapRight= */ true);
+            assertTrue("Launcher internal state should be Normal",
+                    isInState(() -> LauncherState.NORMAL));
+        } else {
+            // On persistent taskbar, it should not dismiss when tapping the taskbar
+            overview.touchTaskbarBottomCorner(/* tapRight= */ false);
+            assertTrue("Launcher internal state should be Overview",
+                    isInState(() -> LauncherState.OVERVIEW));
+
+            // On persistent taskbar, it should not dismiss when tapping the taskbar
+            overview.touchTaskbarBottomCorner(/* tapRight= */ true);
+            assertTrue("Launcher internal state should be Overview",
+                    isInState(() -> LauncherState.OVERVIEW));
+        }
     }
 
     @Test
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
index 0eec8b7..3465f23 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -86,7 +86,7 @@
             mLauncher.setTrackpadGestureType(TrackpadGestureType.THREE_FINGER);
 
             startTestActivity(2);
-            mLauncher.pressBack();
+            mLauncher.getLaunchedAppState().pressBackToWorkspace();
         } finally {
             instrumentation.getUiAutomation().dropShellPermissionIdentity();
         }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
index db23cc0..7109bbf 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTransientTaskbar.java
@@ -24,6 +24,7 @@
 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;
@@ -64,4 +65,12 @@
         getTaskbar().getAppIcon(TEST_APP_NAME).launch(TEST_APP_PACKAGE);
         mLauncher.getLaunchedAppState().clickStashedTaskbarToGoHome();
     }
+
+    @Test
+    @TaskbarModeSwitch(mode = TRANSIENT)
+    @PortraitLandscape
+    public void testSwipeToStashAndUnstash() {
+        getTaskbar().swipeDownToStash();
+        mLauncher.getLaunchedAppState().swipeUpToUnstashTaskbar();
+    }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java b/quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java
similarity index 99%
rename from quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
rename to quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java
index 2318f54..f76e17a 100644
--- a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java
@@ -85,7 +85,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class ViewInflationDuringSwipeUp extends AbstractQuickStepTest {
+public class TaplViewInflationDuringSwipeUp extends AbstractQuickStepTest {
 
     private SparseArray<ViewConfiguration> mConfigMap;
     private InitTracker mInitTracker;
diff --git a/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
new file mode 100644
index 0000000..dbe4624
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt
@@ -0,0 +1,202 @@
+/*
+ * 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.taskbar.controllers
+
+import android.animation.AnimatorSet
+import android.animation.ObjectAnimator
+import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
+import com.android.launcher3.logging.StatsLogManager
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.TaskbarBaseTestCase
+import com.android.launcher3.taskbar.TaskbarDividerPopupView
+import com.android.launcher3.taskbar.TaskbarDragLayer
+import com.android.launcher3.taskbar.TaskbarPinningController
+import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_PERSISTENT
+import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_TRANSIENT
+import com.android.launcher3.taskbar.TaskbarSharedState
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+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
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class TaskbarPinningControllerTest : TaskbarBaseTestCase() {
+    private val taskbarDragLayer = mock<TaskbarDragLayer>()
+    private val taskbarSharedState = mock<TaskbarSharedState>()
+    private val launcherPrefs = mock<LauncherPrefs> { on { get(TASKBAR_PINNING) } doReturn false }
+    private val statsLogger = mock<StatsLogManager.StatsLogger>()
+    private val statsLogManager = mock<StatsLogManager> { on { logger() } doReturn statsLogger }
+    private lateinit var pinningController: TaskbarPinningController
+
+    @Before
+    override fun setup() {
+        super.setup()
+        whenever(taskbarActivityContext.launcherPrefs).thenReturn(launcherPrefs)
+        whenever(taskbarActivityContext.dragLayer).thenReturn(taskbarDragLayer)
+        whenever(taskbarActivityContext.statsLogManager).thenReturn(statsLogManager)
+        pinningController = spy(TaskbarPinningController(taskbarActivityContext))
+        pinningController.init(taskbarControllers, taskbarSharedState)
+    }
+
+    @Test
+    fun testOnCloseCallback_whenClosingPopupView_shouldLogStatsForClosingPopupMenu() {
+        pinningController.onCloseCallback(false)
+        verify(statsLogger, times(1)).log(LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE)
+    }
+
+    @Test
+    fun testOnCloseCallback_whenClosingPopupView_shouldPostVisibilityChangedToDragLayer() {
+        val argumentCaptor = argumentCaptor<Runnable>()
+        pinningController.onCloseCallback(false)
+        verify(taskbarDragLayer, times(1)).post(argumentCaptor.capture())
+
+        val runnable = argumentCaptor.lastValue
+        assertThat(runnable).isNotNull()
+
+        runnable.run()
+        verify(taskbarActivityContext, times(1)).onPopupVisibilityChanged(false)
+    }
+
+    @Test
+    fun testOnCloseCallback_whenPreferenceUnchanged_shouldNotAnimateTaskbarPinning() {
+        pinningController.onCloseCallback(false)
+        verify(taskbarSharedState, never()).taskbarWasPinned = true
+        verify(pinningController, never()).animateTaskbarPinning(any())
+    }
+
+    @Test
+    fun testOnCloseCallback_whenPreferenceChanged_shouldAnimateToPinnedTaskbar() {
+        whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false)
+        doNothing().whenever(pinningController).animateTaskbarPinning(any())
+
+        pinningController.onCloseCallback(true)
+
+        verify(taskbarSharedState, times(1)).taskbarWasPinned = false
+        verify(pinningController, times(1)).animateTaskbarPinning(PINNING_PERSISTENT)
+    }
+
+    @Test
+    fun testOnCloseCallback_whenPreferenceChanged_shouldAnimateToTransientTaskbar() {
+        whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(true)
+        doNothing().whenever(pinningController).animateTaskbarPinning(any())
+
+        pinningController.onCloseCallback(true)
+
+        verify(taskbarSharedState, times(1)).taskbarWasPinned = true
+        verify(pinningController, times(1)).animateTaskbarPinning(PINNING_TRANSIENT)
+    }
+
+    @Test
+    fun testShowPinningView_whenShowingPinningView_shouldSetTaskbarWindowFullscreenAndPostRunnableToView() {
+        val popupView =
+            mock<TaskbarDividerPopupView<TaskbarActivityContext>> {
+                on { requestFocus() } doReturn true
+            }
+        val view = mock<View>()
+        val argumentCaptor = argumentCaptor<Runnable>()
+        doReturn(popupView).whenever(pinningController).getPopupView(view)
+
+        pinningController.showPinningView(view)
+
+        verify(view, times(1)).post(argumentCaptor.capture())
+
+        val runnable = argumentCaptor.lastValue
+        assertThat(runnable).isNotNull()
+        runnable.run()
+
+        verify(pinningController, times(1)).getPopupView(view)
+        verify(popupView, times(1)).requestFocus()
+        verify(popupView, times(1)).onCloseCallback = any()
+        verify(taskbarActivityContext, times(1)).onPopupVisibilityChanged(true)
+        verify(popupView, times(1)).show()
+        verify(statsLogger, times(1)).log(LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN)
+    }
+
+    @Test
+    fun testAnimateTaskbarPinning_whenAnimationEnds_shouldInvokeCallbackDoOnEnd() {
+        val animatorSet = spy(AnimatorSet())
+        doReturn(animatorSet)
+            .whenever(pinningController)
+            .getAnimatorSetForTaskbarPinningAnimation(PINNING_PERSISTENT)
+        doNothing().whenever(animatorSet).start()
+        pinningController.animateTaskbarPinning(PINNING_PERSISTENT)
+        animatorSet.listeners[0].onAnimationEnd(ObjectAnimator())
+        verify(pinningController, times(1)).recreateTaskbarAndUpdatePinningValue()
+    }
+
+    @Test
+    fun testAnimateTaskbarPinning_whenAnimatingToPersistentTaskbar_shouldAnimateToPinnedTaskbar() {
+        val animatorSet = spy(AnimatorSet())
+        doReturn(animatorSet)
+            .whenever(pinningController)
+            .getAnimatorSetForTaskbarPinningAnimation(PINNING_PERSISTENT)
+        doNothing().whenever(animatorSet).start()
+        pinningController.animateTaskbarPinning(PINNING_PERSISTENT)
+
+        verify(taskbarOverlayController, times(1)).hideWindow()
+        verify(pinningController, times(1))
+            .getAnimatorSetForTaskbarPinningAnimation(PINNING_PERSISTENT)
+        verify(taskbarViewController, times(1))
+            .animateAwayNotificationDotsDuringTaskbarPinningAnimation()
+        verify(taskbarDragLayer, times(1)).setAnimatingTaskbarPinning(true)
+        assertThat(pinningController.isAnimatingTaskbarPinning).isTrue()
+        assertThat(animatorSet.listeners).isNotNull()
+    }
+
+    @Test
+    fun testAnimateTaskbarPinning_whenAnimatingToTransientTaskbar_shouldAnimateToTransientTaskbar() {
+        val animatorSet = spy(AnimatorSet())
+        doReturn(animatorSet)
+            .whenever(pinningController)
+            .getAnimatorSetForTaskbarPinningAnimation(PINNING_TRANSIENT)
+        doNothing().whenever(animatorSet).start()
+        pinningController.animateTaskbarPinning(PINNING_TRANSIENT)
+
+        verify(taskbarOverlayController, times(1)).hideWindow()
+        verify(pinningController, times(1))
+            .getAnimatorSetForTaskbarPinningAnimation(PINNING_TRANSIENT)
+        verify(taskbarDragLayer, times(1)).setAnimatingTaskbarPinning(true)
+        assertThat(pinningController.isAnimatingTaskbarPinning).isTrue()
+        verify(taskbarViewController, times(1))
+            .animateAwayNotificationDotsDuringTaskbarPinningAnimation()
+        assertThat(animatorSet.listeners).isNotNull()
+    }
+
+    @Test
+    fun testRecreateTaskbarAndUpdatePinningValue_whenAnimationEnds_shouldUpdateTaskbarPinningLauncherPref() {
+        pinningController.recreateTaskbarAndUpdatePinningValue()
+        verify(taskbarDragLayer, times(1)).setAnimatingTaskbarPinning(false)
+        assertThat(pinningController.isAnimatingTaskbarPinning).isFalse()
+        verify(launcherPrefs, times(1)).put(TASKBAR_PINNING, true)
+    }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
index 50803fe..86018b1 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -19,8 +19,13 @@
 
 import android.graphics.Bitmap
 import android.graphics.drawable.Drawable
+import android.view.SurfaceControl.Transaction
 import android.view.View
+import android.window.TransitionInfo
 import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.apppairs.AppPairIcon
+import com.android.launcher3.statehandlers.DepthController
+import com.android.launcher3.statemanager.StateManager
 import com.android.launcher3.util.SplitConfigurationOptions
 import com.android.quickstep.views.GroupedTaskView
 import com.android.quickstep.views.IconView
@@ -32,13 +37,18 @@
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doNothing
 import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
 @RunWith(AndroidJUnit4::class)
 class SplitAnimationControllerTest {
 
     private val taskId = 9
+    private val taskId2 = 10
 
     private val mockSplitSelectStateController: SplitSelectStateController = mock()
     // TaskView
@@ -52,12 +62,19 @@
     private val mockTask: Task = mock()
     private val mockTaskKey: Task.TaskKey = mock()
     private val mockTaskIdAttributeContainer: TaskIdAttributeContainer = mock()
+    // AppPairIcon
+    private val mockAppPairIcon: AppPairIcon = mock()
 
     // SplitSelectSource
     private val splitSelectSource: SplitConfigurationOptions.SplitSelectSource = mock()
     private val mockSplitSourceDrawable: Drawable = mock()
     private val mockSplitSourceView: View = mock()
 
+    private val stateManager: StateManager<*> = mock()
+    private val depthController: DepthController = mock()
+    private val transitionInfo: TransitionInfo = mock()
+    private val transaction: Transaction = mock()
+
     lateinit var splitAnimationController: SplitAnimationController
 
     @Before
@@ -172,4 +189,110 @@
             splitAnimInitProps.iconDrawable
         )
     }
+
+    @Test
+    fun playsAppropriateSplitLaunchAnimation_playsLegacyLaunchCorrectly() {
+        val spySplitAnimationController = spy(splitAnimationController)
+        doNothing()
+            .whenever(spySplitAnimationController)
+            .composeRecentsSplitLaunchAnimatorLegacy(
+                any(), any(), any(), any(), any(), any(), any(), any(), any())
+
+        spySplitAnimationController.playSplitLaunchAnimation(
+            mockGroupedTaskView,
+            null /* launchingIconView */,
+            taskId,
+            taskId2,
+            arrayOf() /* apps */,
+            arrayOf() /* wallpapers */,
+            arrayOf() /* nonApps */,
+            stateManager,
+            depthController,
+            null /* info */,
+            null /* t */,
+            {} /* finishCallback */
+        )
+
+        verify(spySplitAnimationController)
+            .composeRecentsSplitLaunchAnimatorLegacy(
+                any(), any(), any(), any(), any(), any(), any(), any(), any())
+    }
+
+    @Test
+    fun playsAppropriateSplitLaunchAnimation_playsRecentsLaunchCorrectly() {
+        val spySplitAnimationController = spy(splitAnimationController)
+        doNothing()
+            .whenever(spySplitAnimationController)
+            .composeRecentsSplitLaunchAnimator(any(), any(), any(), any(), any(), any())
+
+        spySplitAnimationController.playSplitLaunchAnimation(
+            mockGroupedTaskView,
+            null /* launchingIconView */,
+            taskId,
+            taskId2,
+            null /* apps */,
+            null /* wallpapers */,
+            null /* nonApps */,
+            stateManager,
+            depthController,
+            transitionInfo,
+            transaction,
+            {} /* finishCallback */
+        )
+
+        verify(spySplitAnimationController)
+            .composeRecentsSplitLaunchAnimator(any(), any(), any(), any(), any(), any())
+    }
+
+    @Test
+    fun playsAppropriateSplitLaunchAnimation_playsIconLaunchCorrectly() {
+        val spySplitAnimationController = spy(splitAnimationController)
+        doNothing()
+            .whenever(spySplitAnimationController)
+            .composeIconSplitLaunchAnimator(any(), any(), any(), any(), any(), any())
+
+        spySplitAnimationController.playSplitLaunchAnimation(
+            null /* launchingTaskView */,
+            mockAppPairIcon,
+            taskId,
+            taskId2,
+            null /* apps */,
+            null /* wallpapers */,
+            null /* nonApps */,
+            stateManager,
+            depthController,
+            transitionInfo,
+            transaction,
+            {} /* finishCallback */
+        )
+
+        verify(spySplitAnimationController)
+            .composeIconSplitLaunchAnimator(any(), any(), any(), any(), any(), any())
+    }
+
+    @Test
+    fun playsAppropriateSplitLaunchAnimation_playsFadeInLaunchCorrectly() {
+        val spySplitAnimationController = spy(splitAnimationController)
+        doNothing()
+            .whenever(spySplitAnimationController)
+            .composeFadeInSplitLaunchAnimator(any(), any(), any(), any(), any())
+
+        spySplitAnimationController.playSplitLaunchAnimation(
+            null /* launchingTaskView */,
+            null /* launchingIconView */,
+            taskId,
+            taskId2,
+            null /* apps */,
+            null /* wallpapers */,
+            null /* nonApps */,
+            stateManager,
+            depthController,
+            transitionInfo,
+            transaction,
+            {} /* finishCallback */
+        )
+
+        verify(spySplitAnimationController)
+            .composeFadeInSplitLaunchAnimator(any(), any(), any(), any(), any())
+    }
 }
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index f292f9a..f41ac48 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -114,6 +114,7 @@
             argumentCaptor<Consumer<ArrayList<GroupTask>>> {
                     splitSelectStateController.findLastActiveTasksAndRunCallback(
                         listOf(nonMatchingComponent),
+                        false /* findExactPairMatch */,
                         taskConsumer
                     )
                     verify(recentsModel).getTasks(capture())
@@ -166,6 +167,7 @@
             argumentCaptor<Consumer<ArrayList<GroupTask>>> {
                     splitSelectStateController.findLastActiveTasksAndRunCallback(
                         listOf(matchingComponent),
+                        false /* findExactPairMatch */,
                         taskConsumer
                     )
                     verify(recentsModel).getTasks(capture())
@@ -206,6 +208,7 @@
             argumentCaptor<Consumer<ArrayList<GroupTask>>> {
                     splitSelectStateController.findLastActiveTasksAndRunCallback(
                         listOf(nonPrimaryUserComponent),
+                        false /* findExactPairMatch */,
                         taskConsumer
                     )
                     verify(recentsModel).getTasks(capture())
@@ -261,6 +264,7 @@
             argumentCaptor<Consumer<ArrayList<GroupTask>>> {
                     splitSelectStateController.findLastActiveTasksAndRunCallback(
                         listOf(nonPrimaryUserComponent),
+                        false /* findExactPairMatch */,
                         taskConsumer
                     )
                     verify(recentsModel).getTasks(capture())
@@ -313,6 +317,7 @@
             argumentCaptor<Consumer<ArrayList<GroupTask>>> {
                     splitSelectStateController.findLastActiveTasksAndRunCallback(
                         listOf(matchingComponent),
+                        false /* findExactPairMatch */,
                         taskConsumer
                     )
                     verify(recentsModel).getTasks(capture())
@@ -366,6 +371,7 @@
             argumentCaptor<Consumer<ArrayList<GroupTask>>> {
                     splitSelectStateController.findLastActiveTasksAndRunCallback(
                         listOf(nonMatchingComponent, matchingComponent),
+                        false /* findExactPairMatch */,
                         taskConsumer
                     )
                     verify(recentsModel).getTasks(capture())
@@ -418,6 +424,7 @@
             argumentCaptor<Consumer<ArrayList<GroupTask>>> {
                     splitSelectStateController.findLastActiveTasksAndRunCallback(
                         listOf(matchingComponent, matchingComponent),
+                        false /* findExactPairMatch */,
                         taskConsumer
                     )
                     verify(recentsModel).getTasks(capture())
@@ -483,6 +490,59 @@
             argumentCaptor<Consumer<ArrayList<GroupTask>>> {
                     splitSelectStateController.findLastActiveTasksAndRunCallback(
                         listOf(matchingComponent, matchingComponent),
+                        false /* findExactPairMatch */,
+                        taskConsumer
+                    )
+                    verify(recentsModel).getTasks(capture())
+                }
+                .lastValue
+
+        // Send our mocked tasks
+        consumer.accept(tasks)
+    }
+
+    @Test
+    fun activeTasks_multipleSearchShouldFindExactPairMatch() {
+        val matchingPackage = "hotdog"
+        val matchingClass = "juice"
+        val matchingComponent =
+            ComponentKey(ComponentName(matchingPackage, matchingClass), primaryUserHandle)
+        val matchingPackage2 = "pomegranate"
+        val matchingClass2 = "juice"
+        val matchingComponent2 =
+            ComponentKey(ComponentName(matchingPackage2, matchingClass2), primaryUserHandle)
+
+        val groupTask1 =
+            generateGroupTask(ComponentName("hotdog", "pie"), ComponentName("pumpkin", "pie"))
+        val groupTask2 =
+            generateGroupTask(
+                ComponentName(matchingPackage2, matchingClass2),
+                ComponentName(matchingPackage, matchingClass)
+            )
+        val groupTask3 =
+            generateGroupTask(
+                ComponentName("hotdog", "pie"),
+                ComponentName(matchingPackage, matchingClass)
+            )
+        val tasks: ArrayList<GroupTask> = ArrayList()
+        tasks.add(groupTask3)
+        tasks.add(groupTask2)
+        tasks.add(groupTask1)
+
+        // 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)
+                assertEquals("Found wrong task", it[0], groupTask2.task1)
+            }
+
+        // Capture callback from recentsModel#getTasks()
+        val consumer =
+            argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+                    splitSelectStateController.findLastActiveTasksAndRunCallback(
+                        listOf(matchingComponent2, matchingComponent),
+                        true /* findExactPairMatch */,
                         taskConsumer
                     )
                     verify(recentsModel).getTasks(capture())
diff --git a/res/layout/add_item_confirmation_activity.xml b/res/layout/add_item_confirmation_activity.xml
index e29e1b1..d113a38 100644
--- a/res/layout/add_item_confirmation_activity.xml
+++ b/res/layout/add_item_confirmation_activity.xml
@@ -16,7 +16,7 @@
 ** limitations under the License.
 */
 -->
-<com.android.launcher3.dragndrop.AddItemDragLayer
+<com.android.launcher3.dragndrop.SimpleDragLayer
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/add_item_drag_layer"
     android:layout_width="match_parent"
@@ -121,6 +121,6 @@
         </LinearLayout>
     </com.android.launcher3.widget.AddItemWidgetsBottomSheet>
 
-</com.android.launcher3.dragndrop.AddItemDragLayer>
+</com.android.launcher3.dragndrop.SimpleDragLayer>
 
 
diff --git a/res/layout/app_pair_icon.xml b/res/layout/app_pair_icon.xml
index 2b9a98b..4e2dd58 100644
--- a/res/layout/app_pair_icon.xml
+++ b/res/layout/app_pair_icon.xml
@@ -20,6 +20,11 @@
     android:layout_height="match_parent"
     android:orientation="vertical"
     android:focusable="true" >
+    <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.views.DoubleShadowBubbleTextView
         style="@style/BaseIcon.Workspace"
         android:id="@+id/app_pair_icon_name"
diff --git a/res/layout/floating_app_pair_view.xml b/res/layout/floating_app_pair_view.xml
new file mode 100644
index 0000000..88ec655
--- /dev/null
+++ b/res/layout/floating_app_pair_view.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<com.android.quickstep.views.FloatingAppPairView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent">
+</com.android.quickstep.views.FloatingAppPairView>
\ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 20e7089..8d84c90 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -164,7 +164,19 @@
 
         <!-- numFolderRows & numFolderColumns defaults to numRows & numColumns, if not specified -->
         <attr name="numFolderRows" format="integer" />
+        <!-- defaults to numFolderRows, if not specified -->
+        <attr name="numFolderRowsLandscape" format="integer" />
+        <!-- defaults to numFolderRows, if not specified -->
+        <attr name="numFolderRowsTwoPanelLandscape" format="integer" />
+        <!-- defaults to numFolderRows, if not specified -->
+        <attr name="numFolderRowsTwoPanelPortrait" format="integer" />
         <attr name="numFolderColumns" format="integer" />
+        <!-- defaults to numFolderColumns, if not specified -->
+        <attr name="numFolderColumnsLandscape" format="integer" />
+        <!-- defaults to numFolderColumns, if not specified -->
+        <attr name="numFolderColumnsTwoPanelLandscape" format="integer" />
+        <!-- defaults to numFolderColumns, if not specified -->
+        <attr name="numFolderColumnsTwoPanelPortrait" format="integer" />
         <!-- Support attributes in FolderStyle -->
         <attr name="folderStyle" format="reference" />
 
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 025003b..0a57127 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -125,6 +125,9 @@
     <dimen name="all_apps_tip_bottom_margin">8dp</dimen>
     <dimen name="all_apps_height_extra">6dp</dimen>
     <dimen name="all_apps_paged_view_top_padding">40dp</dimen>
+    <dimen name="all_apps_recycler_view_decorator_padding">1dp</dimen>
+    <dimen name="all_apps_recycler_view_decorator_group_radius">28dp</dimen>
+    <dimen name="all_apps_recycler_view_decorator_result_radius">4dp</dimen>
 
     <dimen name="all_apps_icon_drawable_padding">8dp</dimen>
     <dimen name="all_apps_predicted_icon_vertical_padding">8dp</dimen>
@@ -176,6 +179,7 @@
     <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>
 
@@ -363,6 +367,7 @@
 
     <!-- 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_stashed_size">0dp</dimen>
     <dimen name="qsb_widget_height">0dp</dimen>
     <dimen name="qsb_shadow_height">0dp</dimen>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index b845c88..f72c556 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -104,6 +104,7 @@
     public static final int TYPE_ADD_TO_HOME_CONFIRMATION = 1 << 19;
     public static final int TYPE_TASKBAR_OVERLAY_PROXY = 1 << 20;
     public static final int TYPE_TASKBAR_PINNING_POPUP = 1 << 21;
+    public static final int TYPE_PIN_IME_POPUP = 1 << 22;
 
     public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
             | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
@@ -112,17 +113,18 @@
             | TYPE_ICON_SURFACE | TYPE_DRAG_DROP_POPUP | TYPE_PIN_WIDGET_FROM_EXTERNAL_POPUP
             | TYPE_WIDGETS_EDUCATION_DIALOG | TYPE_TASKBAR_EDUCATION_DIALOG | TYPE_TASKBAR_ALL_APPS
             | TYPE_OPTIONS_POPUP_DIALOG | TYPE_ADD_TO_HOME_CONFIRMATION
-            | TYPE_TASKBAR_OVERLAY_PROXY | TYPE_TASKBAR_PINNING_POPUP;
+            | TYPE_TASKBAR_OVERLAY_PROXY | TYPE_TASKBAR_PINNING_POPUP | TYPE_PIN_IME_POPUP;
 
     // Type of popups which should be kept open during launcher rebind
     public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
             | TYPE_WIDGETS_BOTTOM_SHEET | TYPE_ON_BOARD_POPUP | TYPE_DISCOVERY_BOUNCE
             | TYPE_ALL_APPS_EDU | TYPE_ICON_SURFACE | TYPE_WIDGETS_EDUCATION_DIALOG
             | TYPE_TASKBAR_EDUCATION_DIALOG | TYPE_TASKBAR_ALL_APPS | TYPE_OPTIONS_POPUP_DIALOG
-            | TYPE_TASKBAR_OVERLAY_PROXY;
+            | TYPE_TASKBAR_OVERLAY_PROXY | TYPE_PIN_IME_POPUP;
 
+    /** Type of popups that should get exclusive accessibility focus. */
     public static final int TYPE_ACCESSIBLE = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE & ~TYPE_LISTENER
-            & ~TYPE_ALL_APPS_EDU;
+            & ~TYPE_ALL_APPS_EDU & ~TYPE_TASKBAR_ALL_APPS & ~TYPE_PIN_IME_POPUP;
 
     // 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 |
@@ -133,7 +135,12 @@
     public static final int TYPE_TASKBAR_OVERLAYS =
             TYPE_TASKBAR_ALL_APPS | TYPE_TASKBAR_EDUCATION_DIALOG;
 
-    public static final int TYPE_ALL_EXCEPT_ON_BOARD_POPUP = TYPE_ALL & ~TYPE_ON_BOARD_POPUP;
+    // Floating views that a TouchController should not try to intercept touches from.
+    public static final int TYPE_TOUCH_CONTROLLER_NO_INTERCEPT = TYPE_ALL & ~TYPE_DISCOVERY_BOUNCE
+            & ~TYPE_LISTENER & ~TYPE_TASKBAR_OVERLAYS;
+
+    public static final int TYPE_ALL_EXCEPT_ON_BOARD_POPUP = TYPE_ALL & ~TYPE_ON_BOARD_POPUP
+            & ~TYPE_PIN_IME_POPUP;
 
     protected boolean mIsOpen;
 
diff --git a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
index 641fd83..429978e 100644
--- a/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
+++ b/src/com/android/launcher3/AppWidgetsRestoredReceiver.java
@@ -9,9 +9,13 @@
 import android.content.Intent;
 import android.util.Log;
 
+import com.android.launcher3.logging.FileLog;
+import com.android.launcher3.provider.RestoreDbTask;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.widget.LauncherWidgetHolder;
 
+import java.util.Arrays;
+
 public class AppWidgetsRestoredReceiver extends BroadcastReceiver {
 
     private static final String TAG = "AppWidgetsRestoredReceiver";
@@ -20,8 +24,11 @@
     public void onReceive(final Context context, Intent intent) {
         if (AppWidgetManager.ACTION_APPWIDGET_HOST_RESTORED.equals(intent.getAction())) {
             int hostId = intent.getIntExtra(AppWidgetManager.EXTRA_HOST_ID, 0);
-            Log.d(TAG, "Widget ID map received for host:" + hostId);
+            Log.d(TAG, "onReceive: Widget ID map received for host:" + hostId);
             if (hostId != LauncherWidgetHolder.APPWIDGET_HOST_ID) {
+                Log.w(TAG,  "onReceive: hostId does not match Launcher."
+                        + " Expected: " + LauncherWidgetHolder.APPWIDGET_HOST_ID
+                        + ", Actual: " + hostId);
                 return;
             }
 
@@ -31,8 +38,18 @@
                 LauncherPrefs.get(context).putSync(
                         OLD_APP_WIDGET_IDS.to(IntArray.wrap(oldIds).toConcatString()),
                         APP_WIDGET_IDS.to(IntArray.wrap(newIds).toConcatString()));
+                FileLog.d(TAG, "onReceive: Valid Widget IDs received."
+                        + " old IDs=" + Arrays.toString(oldIds)
+                        + ", new IDs=" + Arrays.toString(newIds));
+                if (!RestoreDbTask.isPending(context)) {
+                    FileLog.w(TAG, "onReceive: Restored App Widget Ids received but Launcher"
+                            + " restore is not pending. New widget Ids might not get restored.");
+                }
             } else {
-                Log.e(TAG, "Invalid host restored received");
+                Log.e(TAG, "onReceive: Invalid widget ids received for Launcher"
+                        + ", skipping restore of widget ids."
+                        + " newIds=" + Arrays.toString(newIds)
+                        + ", oldIds=" + Arrays.toString(oldIds));
             }
         }
     }
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index e2e528c..91da7e6 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -175,6 +175,7 @@
     @ViewDebug.ExportedProperty(category = "launcher")
     private DotInfo mDotInfo;
     private DotRenderer mDotRenderer;
+    private Locale mCurrentLocale;
     @ViewDebug.ExportedProperty(category = "launcher", deepExport = true)
     protected DotRenderer.DrawParams mDotParams;
     private Animator mDotScaleAnim;
@@ -250,6 +251,7 @@
 
         mDotParams = new DotRenderer.DrawParams();
 
+        mCurrentLocale = context.getResources().getConfiguration().locale;
         setEllipsize(TruncateAt.END);
         setAccessibilityDelegate(mActivity.getAccessibilityDelegate());
         setTextAlpha(1f);
@@ -411,10 +413,12 @@
      *  Only if actual text can be displayed in two line, the {@code true} value will be effective.
      */
     protected boolean shouldUseTwoLine() {
-        return ((FeatureFlags.enableTwolineAllapps())
-                && (mDisplay == DISPLAY_ALL_APPS || mDisplay == DISPLAY_PREDICTION_ROW))
-                || (FeatureFlags.ENABLE_TWOLINE_DEVICESEARCH.get()
-                && mDisplay == DISPLAY_SEARCH_RESULT);
+        return (FeatureFlags.enableTwolineAllapps() && isCurrentLanguageEnglish())
+                && (mDisplay == DISPLAY_ALL_APPS || mDisplay == DISPLAY_PREDICTION_ROW);
+    }
+
+    protected boolean isCurrentLanguageEnglish() {
+        return mCurrentLocale.equals(Locale.US);
     }
 
     @UiThread
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index 7d15f7b..5443ff9 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -70,6 +70,7 @@
 import com.android.launcher3.celllayout.DelegatedCellDrawing;
 import com.android.launcher3.celllayout.ItemConfiguration;
 import com.android.launcher3.celllayout.ReorderAlgorithm;
+import com.android.launcher3.celllayout.ReorderParameters;
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.dragndrop.DraggableView;
 import com.android.launcher3.folder.PreviewBackground;
@@ -1748,8 +1749,11 @@
     protected ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX,
             int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX,
             ItemConfiguration solution) {
-        return createReorderAlgorithm().findReorderSolution(pixelX, pixelY, minSpanX, minSpanY,
-                spanX, spanY, direction, dragView, decX, solution);
+        ItemConfiguration configuration = new ItemConfiguration();
+        copyCurrentStateToSolution(configuration);
+        ReorderParameters parameters = new ReorderParameters(pixelX, pixelY, spanX, spanY, minSpanX,
+                minSpanY, dragView, configuration);
+        return createReorderAlgorithm().findReorderSolution(parameters, decX);
     }
 
     public void copyCurrentStateToSolution(ItemConfiguration solution) {
@@ -1779,8 +1783,12 @@
      */
     public ItemConfiguration calculateReorder(int pixelX, int pixelY, int minSpanX, int minSpanY,
             int spanX, int spanY, View dragView) {
-        return createReorderAlgorithm().calculateReorder(pixelX, pixelY, minSpanX, minSpanY,
-                spanX, spanY, dragView);
+        ItemConfiguration configuration = new ItemConfiguration();
+        copyCurrentStateToSolution(configuration);
+        return createReorderAlgorithm().calculateReorder(
+                new ReorderParameters(pixelX, pixelY, spanX, spanY,  minSpanX, minSpanY, dragView,
+                        configuration)
+        );
     }
 
     int[] performReorder(int pixelX, int pixelY, int minSpanX, int minSpanY, int spanX, int spanY,
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 1451b98..b6e8ec3 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -182,6 +182,8 @@
     public int cellYPaddingPx = -1;
 
     // Folder
+    public final int numFolderRows;
+    public final int numFolderColumns;
     public final float folderLabelTextScale;
     public int folderLabelTextSizePx;
     public int folderFooterHeightPx;
@@ -439,6 +441,8 @@
         }
 
         folderLabelTextScale = res.getFloat(R.dimen.folder_label_text_scale);
+        numFolderRows = inv.numFolderRows[mTypeIndex];
+        numFolderColumns = inv.numFolderColumns[mTypeIndex];
 
         if (mIsScalableGrid && inv.folderStyle != INVALID_RESOURCE_HANDLE) {
             TypedArray folderStyle = context.obtainStyledAttributes(inv.folderStyle,
@@ -645,11 +649,11 @@
                             isTwoPanels ? inv.folderSpecsTwoPanelId : inv.folderSpecsId),
                     ResponsiveSpecType.Folder);
             mResponsiveFolderWidthSpec = folderSpecs.getCalculatedSpec(responsiveAspectRatio,
-                    DimensionType.WIDTH, inv.numFolderColumns,
+                    DimensionType.WIDTH, numFolderColumns,
                     mResponsiveWorkspaceWidthSpec.getAvailableSpace(),
                     mResponsiveWorkspaceWidthSpec);
             mResponsiveFolderHeightSpec = folderSpecs.getCalculatedSpec(responsiveAspectRatio,
-                    DimensionType.HEIGHT, inv.numFolderRows,
+                    DimensionType.HEIGHT, numFolderRows,
                     mResponsiveWorkspaceHeightSpec.getAvailableSpace(),
                     mResponsiveWorkspaceHeightSpec);
 
@@ -1406,16 +1410,16 @@
         Point totalWorkspacePadding = getTotalWorkspacePadding();
 
         // Check if the folder fit within the available height.
-        float contentUsedHeight = folderCellHeightPx * inv.numFolderRows
-                + ((inv.numFolderRows - 1) * folderCellLayoutBorderSpacePx.y)
+        float contentUsedHeight = folderCellHeightPx * numFolderRows
+                + ((numFolderRows - 1) * folderCellLayoutBorderSpacePx.y)
                 + folderFooterHeightPx
                 + folderContentPaddingTop;
         int contentMaxHeight = availableHeightPx - totalWorkspacePadding.y;
         float scaleY = contentMaxHeight / contentUsedHeight;
 
         // Check if the folder fit within the available width.
-        float contentUsedWidth = folderCellWidthPx * inv.numFolderColumns
-                + ((inv.numFolderColumns - 1) * folderCellLayoutBorderSpacePx.x)
+        float contentUsedWidth = folderCellWidthPx * numFolderColumns
+                + ((numFolderColumns - 1) * folderCellLayoutBorderSpacePx.x)
                 + folderContentPaddingLeftRight * 2;
         int contentMaxWidth = availableWidthPx - totalWorkspacePadding.x;
         float scaleX = contentMaxWidth / contentUsedWidth;
@@ -1451,7 +1455,7 @@
             }
 
             // Recalculating padding and cell height
-            folderChildDrawablePaddingPx = getNormalizedFolderChildDrawablePaddingPx(textHeight);
+            folderChildDrawablePaddingPx = mResponsiveWorkspaceCellSpec.getIconDrawablePadding();
 
             CellContentDimensions cellContentDimensions = new CellContentDimensions(
                     folderChildIconSizePx,
@@ -2045,8 +2049,8 @@
         writer.println(prefix + pxToDpStr("iconTextSizePx", iconTextSizePx));
         writer.println(prefix + pxToDpStr("iconDrawablePaddingPx", iconDrawablePaddingPx));
 
-        writer.println(prefix + "\tinv.numFolderRows: " + inv.numFolderRows);
-        writer.println(prefix + "\tinv.numFolderColumns: " + inv.numFolderColumns);
+        writer.println(prefix + "\tnumFolderRows: " + numFolderRows);
+        writer.println(prefix + "\tnumFolderColumns: " + numFolderColumns);
         writer.println(prefix + pxToDpStr("folderCellWidthPx", folderCellWidthPx));
         writer.println(prefix + pxToDpStr("folderCellHeightPx", folderCellHeightPx));
         writer.println(prefix + pxToDpStr("folderChildIconSizePx", folderChildIconSizePx));
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 567d0c5..5721ed3 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -122,8 +122,8 @@
     /**
      * Number of icons per row and column in the folder.
      */
-    public int numFolderRows;
-    public int numFolderColumns;
+    public int[] numFolderRows;
+    public int[] numFolderColumns;
     public float[] iconSize;
     public float[] iconTextSize;
     public int iconBitmapSize;
@@ -298,11 +298,15 @@
      * Reinitialize the current grid after a restore, where some grids might now be disabled.
      */
     public void reinitializeAfterRestore(Context context) {
-        FileLog.d(TAG, "Reinitializing grid after restore");
         String currentGridName = getCurrentGridName(context);
         String currentDbFile = dbFile;
         String newGridName = initGrid(context, currentGridName);
         String newDbFile = dbFile;
+        FileLog.d(TAG, "Reinitializing grid after restore."
+                + " currentGridName=" + currentGridName
+                + ", currentDbFile=" + currentDbFile
+                + ", newGridName=" + newGridName
+                + ", newDbFile=" + newDbFile);
         if (!newDbFile.equals(currentDbFile)) {
             FileLog.d(TAG, "Restored grid is disabled : " + currentGridName
                     + ", migrating to: " + newGridName
@@ -810,8 +814,8 @@
         public final int numSearchContainerColumns;
         public final int deviceCategory;
 
-        private final int numFolderRows;
-        private final int numFolderColumns;
+        private final int[] numFolderRows = new int[COUNT_SIZES];
+        private final int[] numFolderColumns = new int[COUNT_SIZES];
         private final @StyleRes int folderStyle;
         private final @StyleRes int cellStyle;
 
@@ -888,11 +892,39 @@
                     a.getResourceId(R.styleable.GridDisplayOption_inlineNavButtonsEndSpacing,
                             R.dimen.taskbar_button_margin_default);
 
-            numFolderRows = a.getInt(
+            numFolderRows[INDEX_DEFAULT] = a.getInt(
                     R.styleable.GridDisplayOption_numFolderRows, numRows);
-            numFolderColumns = a.getInt(
+            numFolderColumns[INDEX_DEFAULT] = a.getInt(
                     R.styleable.GridDisplayOption_numFolderColumns, numColumns);
 
+            if (FeatureFlags.enableResponsiveWorkspace()) {
+                numFolderRows[INDEX_LANDSCAPE] = a.getInt(
+                        R.styleable.GridDisplayOption_numFolderRowsLandscape,
+                        numFolderRows[INDEX_DEFAULT]);
+                numFolderColumns[INDEX_LANDSCAPE] = a.getInt(
+                        R.styleable.GridDisplayOption_numFolderColumnsLandscape,
+                        numFolderColumns[INDEX_DEFAULT]);
+                numFolderRows[INDEX_TWO_PANEL_PORTRAIT] = a.getInt(
+                        R.styleable.GridDisplayOption_numFolderRowsTwoPanelPortrait,
+                        numFolderRows[INDEX_DEFAULT]);
+                numFolderColumns[INDEX_TWO_PANEL_PORTRAIT] = a.getInt(
+                        R.styleable.GridDisplayOption_numFolderColumnsTwoPanelPortrait,
+                        numFolderColumns[INDEX_DEFAULT]);
+                numFolderRows[INDEX_TWO_PANEL_LANDSCAPE] = a.getInt(
+                        R.styleable.GridDisplayOption_numFolderRowsTwoPanelLandscape,
+                        numFolderRows[INDEX_DEFAULT]);
+                numFolderColumns[INDEX_TWO_PANEL_LANDSCAPE] = a.getInt(
+                        R.styleable.GridDisplayOption_numFolderColumnsTwoPanelLandscape,
+                        numFolderColumns[INDEX_DEFAULT]);
+            } else {
+                numFolderRows[INDEX_LANDSCAPE] = numFolderRows[INDEX_DEFAULT];
+                numFolderColumns[INDEX_LANDSCAPE] = numFolderColumns[INDEX_DEFAULT];
+                numFolderRows[INDEX_TWO_PANEL_PORTRAIT] = numFolderRows[INDEX_DEFAULT];
+                numFolderColumns[INDEX_TWO_PANEL_PORTRAIT] = numFolderColumns[INDEX_DEFAULT];
+                numFolderRows[INDEX_TWO_PANEL_LANDSCAPE] = numFolderRows[INDEX_DEFAULT];
+                numFolderColumns[INDEX_TWO_PANEL_LANDSCAPE] = numFolderColumns[INDEX_DEFAULT];
+            }
+
             folderStyle = a.getResourceId(R.styleable.GridDisplayOption_folderStyle,
                     INVALID_RESOURCE_HANDLE);
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0278e4f..e41a8a5 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -22,7 +22,6 @@
 import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
 
 import static com.android.app.animation.Interpolators.EMPHASIZED;
-import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
 import static com.android.launcher3.AbstractFloatingView.TYPE_FOLDER;
 import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE;
 import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
@@ -81,7 +80,6 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_ACTIVITY_ON_CREATE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION;
 import static com.android.launcher3.logging.StatsLogManager.LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_VIEW_INFLATION;
-import static com.android.launcher3.logging.StatsLogManager.LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_WORKSPACE_LOADER_ASYNC;
 import static com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.LatencyType.COLD;
 import static com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.LatencyType.COLD_DEVICE_REBOOTING;
 import static com.android.launcher3.logging.StatsLogManager.StatsLatencyLogger.LatencyType.WARM;
@@ -140,7 +138,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewTreeObserver;
 import android.view.ViewTreeObserver.OnPreDrawListener;
 import android.view.WindowManager.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
@@ -160,7 +157,6 @@
 import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
 import com.android.launcher3.allapps.ActivityAllAppsContainerView;
 import com.android.launcher3.allapps.AllAppsRecyclerView;
-import com.android.launcher3.allapps.AllAppsStore;
 import com.android.launcher3.allapps.AllAppsTransitionController;
 import com.android.launcher3.allapps.DiscoveryBounce;
 import com.android.launcher3.anim.AnimationSuccessListener;
@@ -190,6 +186,7 @@
 import com.android.launcher3.logging.InstanceIdSequence;
 import com.android.launcher3.logging.StartupLatencyLogger;
 import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.logging.StatsLogManager.LauncherLatencyEvent;
 import com.android.launcher3.model.BgDataModel.Callbacks;
 import com.android.launcher3.model.ItemInstallQueue;
 import com.android.launcher3.model.ModelWriter;
@@ -351,14 +348,9 @@
     // UI and state for the overview panel
     private View mOverviewPanel;
 
-    @Thunk
-    boolean mWorkspaceLoading = true;
-
     // Used to notify when an activity launch has been deferred because launcher is not yet resumed
     // TODO: See if we can remove this later
     private Runnable mOnDeferredActivityLaunchCallback;
-
-    private ViewOnDrawExecutor mPendingExecutor;
     private OnPreDrawListener mOnInitialBindListener;
 
     private LauncherModel mModel;
@@ -797,7 +789,7 @@
         if (info.container >= 0) {
             View folderIcon = getWorkspace().getHomescreenIconByItemId(info.container);
             if (folderIcon instanceof FolderIcon && folderIcon.getTag() instanceof FolderInfo) {
-                if (new FolderGridOrganizer(getDeviceProfile().inv)
+                if (new FolderGridOrganizer(getDeviceProfile())
                         .setFolderInfo((FolderInfo) folderIcon.getTag())
                         .isItemInPreview(info.rank)) {
                     folderIcon.invalidate();
@@ -853,6 +845,17 @@
         return screenId;
     }
 
+    /**
+     * Process any pending activity result if it was put on hold for any reason like item binding.
+     */
+    public void processActivityResult() {
+        if (mPendingActivityResult != null) {
+            handleActivityResult(mPendingActivityResult.requestCode,
+                    mPendingActivityResult.resultCode, mPendingActivityResult.data);
+            mPendingActivityResult = null;
+        }
+    }
+
     private void handleActivityResult(
             final int requestCode, final int resultCode, final Intent data) {
         if (isWorkspaceLoading()) {
@@ -1075,7 +1078,7 @@
     }
 
     private void logStopAndResume(boolean isResume) {
-        if (mPendingExecutor != null) return;
+        if (mModelCallbacks.getPendingExecutor() != null) return;
         int pageIndex = mWorkspace.isOverlayShown() ? -1 : mWorkspace.getCurrentPage();
         int statsLogOrdinal = mStateManager.getState().statsLogOrdinal;
 
@@ -1715,9 +1718,13 @@
         mAppWidgetHolder.destroy();
 
         TextKeyListener.getInstance().release();
-        clearPendingBinds();
+        mModelCallbacks.clearPendingBinds();
         LauncherAppState.getIDP(this).removeOnChangeListener(this);
-
+        // if Launcher activity is recreated, {@link Window} including {@link ViewTreeObserver}
+        // could be preserved in {@link ActivityThread#scheduleRelaunchActivity(IBinder)} if the
+        // previous activity has not stopped, which could happen when wallpaper detects a color
+        // changes while launcher is still loading.
+        getRootView().getViewTreeObserver().removeOnPreDrawListener(mOnInitialBindListener);
         mOverlayManager.onActivityDestroyed();
     }
 
@@ -2077,48 +2084,9 @@
         return mModelCallbacks.getPagesToBindSynchronously(orderedScreenIds);
     }
 
-    /**
-     * Clear any pending bind callbacks. This is called when is loader is planning to
-     * perform a full rebind from scratch.
-     */
-    @Override
-    public void clearPendingBinds() {
-        if (mPendingExecutor != null) {
-            mPendingExecutor.cancel();
-            mPendingExecutor = null;
-
-            // We might have set this flag previously and forgot to clear it.
-            mAppsView.getAppsStore()
-                    .disableDeferUpdatesSilently(AllAppsStore.DEFER_UPDATES_NEXT_DRAW);
-        }
-    }
-
-    /**
-     * Refreshes the shortcuts shown on the workspace.
-     * <p>
-     * Implementation of the method from LauncherModel.Callbacks.
-     */
     @Override
     public void startBinding() {
-        TraceHelper.INSTANCE.beginSection("startBinding");
-        // Floating panels (except the full widget sheet) are associated with individual icons. If
-        // we are starting a fresh bind, close all such panels as all the icons are about
-        // to go away.
-        AbstractFloatingView.closeOpenViews(this, true, TYPE_ALL & ~TYPE_REBIND_SAFE);
-
-        setWorkspaceLoading(true);
-
-        // Clear the workspace because it's going to be rebound
-        mDragController.cancelDrag();
-
-        mWorkspace.clearDropTargets();
-        mWorkspace.removeAllWorkspaceScreens();
-        mAppWidgetHolder.clearViews();
-
-        if (mHotseat != null) {
-            mHotseat.resetLayout(getDeviceProfile().isVerticalBarLayout());
-        }
-        TraceHelper.INSTANCE.endSection();
+        mModelCallbacks.startBinding();
     }
 
     @Override
@@ -2500,44 +2468,25 @@
     }
 
     public void clearPendingExecutor(ViewOnDrawExecutor executor) {
-        if (mPendingExecutor == executor) {
-            mPendingExecutor = null;
+        if (mModelCallbacks.getPendingExecutor() == executor) {
+            mModelCallbacks.setPendingExecutor(null);
         }
     }
 
-    @Override
+    /**
+     * Call back when ModelCallbacks finish binding the Launcher data.
+     */
     @TargetApi(Build.VERSION_CODES.S)
-    public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks,
-            int workspaceItemCount, boolean isBindSync) {
-        mModelCallbacks.setSynchronouslyBoundPages(boundPages);
-        mModelCallbacks.setPagesToBindSynchronously(new IntSet());
-
-        clearPendingBinds();
-        ViewOnDrawExecutor executor = new ViewOnDrawExecutor(pendingTasks);
-        mPendingExecutor = executor;
-        if (!isInState(ALL_APPS)) {
-            mAppsView.getAppsStore().enableDeferUpdates(AllAppsStore.DEFER_UPDATES_NEXT_DRAW);
-            pendingTasks.add(() -> mAppsView.getAppsStore().disableDeferUpdates(
-                    AllAppsStore.DEFER_UPDATES_NEXT_DRAW));
-        }
-
+    public void bindComplete(int workspaceItemCount, boolean isBindSync) {
         if (mOnInitialBindListener != null) {
             getRootView().getViewTreeObserver().removeOnPreDrawListener(mOnInitialBindListener);
             mOnInitialBindListener = null;
         }
-
-        executor.onLoadAnimationCompleted();
-        executor.attachTo(this);
-        if (Utilities.ATLEAST_S) {
-            Trace.endAsyncSection(DISPLAY_WORKSPACE_TRACE_METHOD_NAME,
-                    DISPLAY_WORKSPACE_TRACE_COOKIE);
-        }
         if (!isBindSync) {
             mStartupLatencyLogger
                     .logCardinality(workspaceItemCount)
-                    .logEnd(LAUNCHER_LATENCY_STARTUP_WORKSPACE_LOADER_ASYNC);
+                    .logEnd(LauncherLatencyEvent.LAUNCHER_LATENCY_STARTUP_WORKSPACE_LOADER_ASYNC);
         }
-
         MAIN_EXECUTOR.getHandler().postAtFrontOfQueue(() -> {
             mStartupLatencyLogger
                     .logEnd(LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION)
@@ -2548,15 +2497,13 @@
                         COLD_STARTUP_TRACE_COOKIE);
             }
         });
-        getRootView().getViewTreeObserver().addOnDrawListener(
-                new ViewTreeObserver.OnDrawListener() {
-                    @Override
-                    public void onDraw() {
-                        MAIN_EXECUTOR.getHandler().postAtFrontOfQueue(
-                                () -> getRootView().getViewTreeObserver()
-                                        .removeOnDrawListener(this));
-                    }
-                });
+    }
+
+    @Override
+    public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks,
+            int workspaceItemCount, boolean isBindSync) {
+        mModelCallbacks.onInitialBindComplete(boundPages, pendingTasks, workspaceItemCount,
+                isBindSync);
     }
 
     /**
@@ -2565,34 +2512,7 @@
      * Implementation of the method from LauncherModel.Callbacks.
      */
     public void finishBindingItems(IntSet pagesBoundFirst) {
-        TraceHelper.INSTANCE.beginSection("finishBindingItems");
-        mWorkspace.restoreInstanceStateForRemainingPages();
-
-        setWorkspaceLoading(false);
-
-        if (mPendingActivityResult != null) {
-            handleActivityResult(mPendingActivityResult.requestCode,
-                    mPendingActivityResult.resultCode, mPendingActivityResult.data);
-            mPendingActivityResult = null;
-        }
-
-        int currentPage = pagesBoundFirst != null && !pagesBoundFirst.isEmpty()
-                ? mWorkspace.getPageIndexForScreenId(pagesBoundFirst.getArray().get(0))
-                : PagedView.INVALID_PAGE;
-        // When undoing the removal of the last item on a page, return to that page.
-        // Since we are just resetting the current page without user interaction,
-        // override the previous page so we don't log the page switch.
-        mWorkspace.setCurrentPage(currentPage, currentPage /* overridePrevPage */);
-        mModelCallbacks.setPagesToBindSynchronously(new IntSet());
-
-        // Cache one page worth of icons
-        getViewCache().setCacheSize(R.layout.folder_application,
-                mDeviceProfile.inv.numFolderColumns * mDeviceProfile.inv.numFolderRows);
-        getViewCache().setCacheSize(R.layout.folder_page, 2);
-
-        TraceHelper.INSTANCE.endSection();
-        mWorkspace.removeExtraEmptyScreen(/* stripEmptyScreens= */ true);
-        mWorkspace.mPageIndicator.setAreScreensBinding(false, mDeviceProfile.isTwoPanels);
+        mModelCallbacks.finishBindingItems(pagesBoundFirst);
     }
 
     private boolean canAnimatePageChange() {
@@ -2851,7 +2771,7 @@
 
         writer.println(prefix + "Misc:");
         dumpMisc(prefix + "\t", writer);
-        writer.println(prefix + "\tmWorkspaceLoading=" + mWorkspaceLoading);
+        writer.println(prefix + "\tmWorkspaceLoading=" + mModelCallbacks.getWorkspaceLoading());
         writer.println(prefix + "\tmPendingRequestArgs=" + mPendingRequestArgs
                 + " mPendingActivityResult=" + mPendingActivityResult);
         writer.println(prefix + "\tmRotationHelper: " + mRotationHelper);
@@ -2985,6 +2905,14 @@
         // Overridden; move this into ActivityContext if necessary for Taskbar
     }
 
+    /**
+     * Callback for when launcher state transition completes after user swipes to home.
+     * @param finalState The final state of the transition.
+     */
+    public void onStateTransitionCompletedAfterSwipeToHome(LauncherState finalState) {
+        // Overridden
+    }
+
     @Override
     public void returnToHomescreen() {
         super.returnToHomescreen();
@@ -3079,21 +3007,17 @@
 
     // Getters and Setters
 
-    private void setWorkspaceLoading(boolean value) {
-        mWorkspaceLoading = value;
-    }
-
     public boolean isWorkspaceLocked() {
-        return mWorkspaceLoading || mPendingRequestArgs != null;
+        return isWorkspaceLoading() || mPendingRequestArgs != null;
     }
 
     public boolean isWorkspaceLoading() {
-        return mWorkspaceLoading;
+        return mModelCallbacks.getWorkspaceLoading();
     }
 
     @Override
     public boolean isBindingItems() {
-        return mWorkspaceLoading;
+        return isWorkspaceLoading();
     }
 
     /**
@@ -3273,7 +3197,7 @@
      * Handles an app pair launch; overridden in
      * {@link com.android.launcher3.uioverrides.QuickstepLauncher}
      */
-    public void launchAppPair(WorkspaceItemInfo app1, WorkspaceItemInfo app2) {
+    public void launchAppPair(AppPairIcon appPairIcon) {
         // Overridden
     }
 
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index a05b0f5..78056e6 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -364,6 +364,13 @@
                         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)
         @JvmField val PROMISE_ICON_IDS = backedUpItem(InstallSessionHelper.PROMISE_ICON_IDS, "")
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index bcd30d3..5172999 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -1,7 +1,13 @@
 package com.android.launcher3
 
+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
+import com.android.launcher3.allapps.AllAppsStore
 import com.android.launcher3.config.FeatureFlags
 import com.android.launcher3.config.FeatureFlags.shouldShowFirstPageWidget
 import com.android.launcher3.model.BgDataModel
@@ -12,12 +18,14 @@
 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.IntArray
 import com.android.launcher3.util.IntSet as LIntSet
-import com.android.launcher3.util.IntSet
 import com.android.launcher3.util.PackageUserKey
 import com.android.launcher3.util.Preconditions
+import com.android.launcher3.util.RunnableList
+import com.android.launcher3.util.TraceHelper
+import com.android.launcher3.util.ViewOnDrawExecutor
 import com.android.launcher3.widget.PendingAddWidgetInfo
 import com.android.launcher3.widget.model.WidgetsListBaseEntry
 import java.util.function.Predicate
@@ -27,11 +35,127 @@
     var synchronouslyBoundPages = LIntSet()
     var pagesToBindSynchronously = LIntSet()
 
-    var isFirstPagePinnedItemEnabled =
+    private var isFirstPagePinnedItemEnabled =
         (BuildConfig.QSB_ON_FIRST_SCREEN && !FeatureFlags.ENABLE_SMARTSPACE_REMOVAL.get())
 
     var stringCache: StringCache? = null
 
+    var pendingExecutor: ViewOnDrawExecutor? = null
+
+    var workspaceLoading = true
+
+    /**
+     * Refreshes the shortcuts shown on the workspace.
+     *
+     * Implementation of the method from LauncherModel.Callbacks.
+     */
+    override fun startBinding() {
+        TraceHelper.INSTANCE.beginSection("startBinding")
+        // Floating panels (except the full widget sheet) are associated with individual icons. If
+        // we are starting a fresh bind, close all such panels as all the icons are about
+        // to go away.
+        AbstractFloatingView.closeOpenViews(
+            launcher,
+            true,
+            AbstractFloatingView.TYPE_ALL and AbstractFloatingView.TYPE_REBIND_SAFE.inv()
+        )
+        workspaceLoading = true
+
+        // Clear the workspace because it's going to be rebound
+        launcher.dragController.cancelDrag()
+        launcher.workspace.clearDropTargets()
+        launcher.workspace.removeAllWorkspaceScreens()
+        launcher.appWidgetHolder.clearViews()
+        launcher.hotseat?.resetLayout(launcher.deviceProfile.isVerticalBarLayout)
+        TraceHelper.INSTANCE.endSection()
+    }
+
+    @TargetApi(Build.VERSION_CODES.S)
+    override fun onInitialBindComplete(
+        boundPages: LIntSet,
+        pendingTasks: RunnableList,
+        workspaceItemCount: Int,
+        isBindSync: Boolean
+    ) {
+        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 {
+                launcher.appsView.appsStore.disableDeferUpdates(
+                    AllAppsStore.DEFER_UPDATES_NEXT_DRAW
+                )
+            }
+        }
+        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)
+                    }
+                }
+            }
+        )
+    }
+
+    /**
+     * Callback saying that there aren't any more items to bind.
+     *
+     * Implementation of the method from LauncherModel.Callbacks.
+     */
+    override fun finishBindingItems(pagesBoundFirst: LIntSet?) {
+        TraceHelper.INSTANCE.beginSection("finishBindingItems")
+        val deviceProfile = launcher.deviceProfile
+        launcher.workspace.restoreInstanceStateForRemainingPages()
+        workspaceLoading = false
+        launcher.processActivityResult()
+        val currentPage =
+            if (pagesBoundFirst != null && !pagesBoundFirst.isEmpty)
+                launcher.workspace.getPageIndexForScreenId(pagesBoundFirst.array[0])
+            else PagedView.INVALID_PAGE
+        // When undoing the removal of the last item on a page, return to that page.
+        // Since we are just resetting the current page without user interaction,
+        // override the previous page so we don't log the page switch.
+        launcher.workspace.setCurrentPage(currentPage, currentPage /* overridePrevPage */)
+        pagesToBindSynchronously = LIntSet()
+
+        // Cache one page worth of icons
+        launcher.viewCache.setCacheSize(
+            R.layout.folder_application,
+            deviceProfile.numFolderColumns * deviceProfile.numFolderRows
+        )
+        launcher.viewCache.setCacheSize(R.layout.folder_page, 2)
+        TraceHelper.INSTANCE.endSection()
+        launcher.workspace.removeExtraEmptyScreen(/* stripEmptyScreens= */ true)
+        launcher.workspace.pageIndicator.setAreScreensBinding(false, deviceProfile.isTwoPanels)
+    }
+
+    /**
+     * Clear any pending bind callbacks. This is called when is loader is planning to perform a full
+     * rebind from scratch.
+     */
+    override fun clearPendingBinds() {
+        pendingExecutor?.cancel() ?: return
+        pendingExecutor = null
+
+        // We might have set this flag previously and forgot to clear it.
+        launcher.appsView.appsStore.disableDeferUpdatesSilently(
+            AllAppsStore.DEFER_UPDATES_NEXT_DRAW
+        )
+    }
+
     override fun preAddApps() {
         // If there's an undo snackbar, force it to complete to ensure empty screens are removed
         // before trying to add new items.
@@ -119,7 +243,7 @@
         val visibleIds =
             when {
                 !pagesToBindSynchronously.isEmpty -> pagesToBindSynchronously
-                !launcher.isWorkspaceLoading -> launcher.workspace.currentPageScreenIds
+                !workspaceLoading -> launcher.workspace.currentPageScreenIds
                 else -> synchronouslyBoundPages
             }
         // Launcher IntArray has the same name as Kotlin IntArray
@@ -178,7 +302,7 @@
         )
     }
 
-    override fun bindScreens(orderedScreenIds: IntArray) {
+    override fun bindScreens(orderedScreenIds: LIntArray) {
         launcher.workspace.pageIndicator.setAreScreensBinding(
             true,
             launcher.deviceProfile.isTwoPanels
@@ -208,7 +332,7 @@
     }
 
     override fun bindAppsAdded(
-        newScreens: IntArray?,
+        newScreens: LIntArray?,
         addNotAnimated: java.util.ArrayList<ItemInfo?>?,
         addAnimated: java.util.ArrayList<ItemInfo?>?
     ) {
@@ -233,7 +357,7 @@
         launcher.workspace.removeExtraEmptyScreen(false)
     }
 
-    private fun bindAddScreens(orderedScreenIdsArg: IntArray) {
+    private fun bindAddScreens(orderedScreenIdsArg: LIntArray) {
         var orderedScreenIds = orderedScreenIdsArg
         if (launcher.deviceProfile.isTwoPanels) {
             if (FeatureFlags.FOLDABLE_SINGLE_PAGE.get()) {
@@ -241,7 +365,7 @@
             } else {
                 // Some empty pages might have been removed while the phone was in a single panel
                 // mode, so we want to add those empty pages back.
-                val screenIds = IntSet.wrap(orderedScreenIds)
+                val screenIds = LIntSet.wrap(orderedScreenIds)
                 orderedScreenIds.forEach { screenId: Int ->
                     screenIds.add(launcher.workspace.getScreenPair(screenId))
                 }
@@ -264,8 +388,8 @@
      * Remove odd number because they are already included when isTwoPanels and add the pair screen
      * if not present.
      */
-    private fun filterTwoPanelScreenIds(orderedScreenIds: IntArray): IntArray {
-        val screenIds = IntSet.wrap(orderedScreenIds)
+    private fun filterTwoPanelScreenIds(orderedScreenIds: LIntArray): LIntArray {
+        val screenIds = LIntSet.wrap(orderedScreenIds)
         orderedScreenIds
             .filter { screenId -> screenId % 2 == 1 }
             .forEach { screenId ->
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index b74699a..e0f6101 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -79,7 +79,6 @@
 
 import com.android.launcher3.dragndrop.FolderAdaptiveIcon;
 import com.android.launcher3.graphics.TintedDrawableSpan;
-import com.android.launcher3.icons.BaseIconFactory;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.LauncherIcons;
 import com.android.launcher3.icons.ShortcutCachingLogic;
@@ -91,6 +90,7 @@
 import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.shortcuts.ShortcutRequest;
 import com.android.launcher3.testing.shared.ResourceUtils;
+import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.IntArray;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
 import com.android.launcher3.util.Themes;
@@ -676,12 +676,11 @@
         }
 
         if (badge == null) {
-            try (LauncherIcons li = LauncherIcons.obtain(context)) {
-                badge = BitmapInfo.LOW_RES_INFO.withFlags(
-                                li.getBitmapFlagOp(new BaseIconFactory.IconOptions().setUser(
-                                        UserCache.INSTANCE.get(context).getUserInfo(info.user))))
-                        .getBadgeDrawable(context, useTheme);
-            }
+            badge = BitmapInfo.LOW_RES_INFO.withFlags(
+                            UserCache.INSTANCE.get(context)
+                                    .getUserInfo(info.user)
+                                    .applyBitmapInfoFlags(FlagOp.NO_OP))
+                    .getBadgeDrawable(context, useTheme);
             if (badge == null) {
                 badge = new ColorDrawable(Color.TRANSPARENT);
             }
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index e5a223a..7f1d216 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -407,7 +407,7 @@
             // If exiting search, revert predictive back scale on all apps
             mAllAppsTransitionController.animateAllAppsToNoScale();
         }
-        mSearchTransitionController.animateToSearchState(goingToSearch, durationMs,
+        mSearchTransitionController.animateToState(goingToSearch, durationMs,
                 /* onEndRunnable = */ () -> {
                     mIsSearching = goingToSearch;
                     updateSearchResultsVisibility();
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index b0f13ef..36a44cc 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -36,7 +36,11 @@
 import android.graphics.Canvas;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.View;
 
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.core.util.Consumer;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.DeviceProfile;
@@ -57,6 +61,7 @@
     protected static final String TAG = "AllAppsRecyclerView";
     private static final boolean DEBUG = false;
     private static final boolean DEBUG_LATENCY = Utilities.isPropertyEnabled(SEARCH_LOGGING);
+    private Consumer<View> mChildAttachedConsumer;
 
     protected final int mNumAppsPerRow;
     private final AllAppsFastScrollHelper mFastScrollHelper;
@@ -282,6 +287,22 @@
         }
     }
 
+    /**
+     * This will be called just before a new child is attached to the window. Passing in null will
+     * remove the consumer.
+     */
+    protected void setChildAttachedConsumer(@Nullable Consumer<View> childAttachedConsumer) {
+        mChildAttachedConsumer = childAttachedConsumer;
+    }
+
+    @Override
+    public void onChildAttachedToWindow(@NonNull View child) {
+        if (mChildAttachedConsumer != null) {
+            mChildAttachedConsumer.accept(child);
+        }
+        super.onChildAttachedToWindow(child);
+    }
+
     @Override
     public int getScrollBarTop() {
         return ActivityContext.lookupContext(getContext()).getAppsView().isSearchSupported()
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 328516e..1782791 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -15,6 +15,10 @@
  */
 package com.android.launcher3.allapps;
 
+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 android.content.Context;
 
 import androidx.annotation.Nullable;
@@ -318,6 +322,10 @@
                 case PrivateProfileManager.STATE_ENABLED:
                     // Add PS Apps only in Enabled State.
                     addAppsWithSections(mPrivateApps, position);
+                    if (mActivityContext.getAppsView() != null) {
+                        mActivityContext.getAppsView().getActiveRecyclerView()
+                                .scrollToBottomWithMotion();
+                    }
                     break;
             }
         }
@@ -325,8 +333,34 @@
 
     private void addAppsWithSections(List<AppInfo> appList, int startPosition) {
         String lastSectionName = null;
+        boolean hasPrivateApps = false;
+        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) {
-            mAdapterItems.add(AdapterItem.asApp(info));
+            // 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,
+                                true /* decorateTogether */)));
+                privateAppCount += 1;
+            } else {
+                mAdapterItems.add(AdapterItem.asApp(info));
+            }
 
             String sectionName = info.sectionName;
             // Create a new section if the section names do not match
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 5e26ea5..5eeb259 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -15,6 +15,12 @@
  */
 package com.android.launcher3.allapps;
 
+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_TOP_LEFT;
+import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_TOP_RIGHT;
+import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED;
+
 import android.content.Context;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -25,6 +31,7 @@
 import android.widget.RelativeLayout;
 import android.widget.TextView;
 
+import androidx.annotation.Nullable;
 import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.BubbleTextView;
@@ -92,7 +99,8 @@
         public int rowAppIndex;
         // The associated ItemInfoWithIcon for the item
         public AppInfo itemInfo = null;
-
+        // Private App Decorator
+        public SectionDecorationInfo decorationInfo = null;
         public AdapterItem(int viewType) {
             this.viewType = viewType;
         }
@@ -106,6 +114,13 @@
             return item;
         }
 
+        public static AdapterItem asAppWithDecorationInfo(AppInfo appInfo,
+                SectionDecorationInfo decorationInfo) {
+            AdapterItem item = asApp(appInfo);
+            item.decorationInfo = decorationInfo;
+            return item;
+        }
+
         protected boolean isCountedForAccessibility() {
             return viewType == VIEW_TYPE_ICON;
         }
@@ -125,9 +140,17 @@
             return itemInfo == null && other.itemInfo == null;
         }
 
-        /** Sets the alpha of the decorator for this item. Returns true if successful. */
-        public boolean setDecorationFillAlpha(int alpha) {
-            return false;
+        @Nullable
+        public SectionDecorationInfo getDecorationInfo() {
+            return decorationInfo;
+        }
+
+        /** Sets the alpha of the decorator for this item. */
+        protected void setDecorationFillAlpha(int alpha) {
+            if (decorationInfo == null || decorationInfo.getDecorationHandler() == null) {
+                return;
+            }
+            decorationInfo.getDecorationHandler().setFillAlpha(alpha);
         }
     }
 
@@ -249,6 +272,15 @@
                 assert mPrivateSpaceHeaderViewController != null;
                 assert psHeaderLayout != null;
                 mPrivateSpaceHeaderViewController.addPrivateSpaceHeaderViewElements(psHeaderLayout);
+                AdapterItem adapterItem = mApps.getAdapterItems().get(position);
+                int roundRegions = ROUND_TOP_LEFT | ROUND_TOP_RIGHT;
+                if (mPrivateSpaceHeaderViewController.getPrivateProfileManager().getCurrentState()
+                        == STATE_DISABLED) {
+                    roundRegions |= (ROUND_BOTTOM_LEFT | ROUND_BOTTOM_RIGHT);
+                }
+                adapterItem.decorationInfo =
+                        new SectionDecorationInfo(mActivityContext, roundRegions,
+                                false /* decorateTogether */);
                 break;
             case VIEW_TYPE_ALL_APPS_DIVIDER:
             case VIEW_TYPE_WORK_DISABLED_CARD:
diff --git a/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java b/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java
index f4ed754..8712b84 100644
--- a/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java
+++ b/src/com/android/launcher3/allapps/PrivateAppsSectionDecorator.java
@@ -16,97 +16,55 @@
 
 package com.android.launcher3.allapps;
 
-import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON;
-import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
-
-import android.content.Context;
 import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
 import android.view.View;
 
-import androidx.core.content.ContextCompat;
 import androidx.recyclerview.widget.RecyclerView;
 
-import com.android.launcher3.R;
-import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.views.ActivityContext;
+import java.util.HashMap;
 
 /**
  * Decorator which changes the background color for Private Space Icon Rows in AllAppsContainer.
  */
 public class PrivateAppsSectionDecorator extends RecyclerView.ItemDecoration {
 
-    private final Path mTmpPath = new Path();
-    private final RectF mTmpRect = new RectF();
-    private final Context mContext;
+    private static final String PRIVATE_APP_SECTION = "private_apps";
     private final AlphabeticalAppsList<?> mAppsList;
-    private final UserCache mUserCache;
-    private final Paint mPaint;
-    private final int mCornerRadius;
 
-    public PrivateAppsSectionDecorator(Context context, AlphabeticalAppsList<?> appsList) {
-        mContext = context;
+    public PrivateAppsSectionDecorator(AlphabeticalAppsList<?> appsList) {
         mAppsList = appsList;
-        mUserCache = UserCache.getInstance(context);
-        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mPaint.setColor(ContextCompat.getColor(context,
-                R.color.material_color_surface_container_high));
-        mCornerRadius = context.getResources().getDimensionPixelSize(
-                R.dimen.ps_container_corner_radius);
     }
 
     /** Decorates Private Space Header and Icon Rows to give the shape of a container. */
     @Override
     public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
-        mTmpPath.reset();
-        mTmpRect.setEmpty();
-        int numCol = ActivityContext.lookupContext(mContext).getDeviceProfile()
-                .numShownAllAppsColumns;
+        HashMap<String, SectionDecorationHandler.UnionDecorationHandler> deferredDecorations =
+                new HashMap<>();
         for (int i = 0; i < parent.getChildCount(); i++) {
             View view = parent.getChildAt(i);
             int position = parent.getChildAdapterPosition(view);
             BaseAllAppsAdapter.AdapterItem adapterItem = mAppsList.getAdapterItems().get(position);
-            // Rectangle that covers the bottom half of the PS Header View when Space is unlocked.
-            if (adapterItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
-                // We flatten the bottom corners of the rectangle, so that it merges with
-                // the private space app row decorator.
-                mTmpRect.set(
-                        view.getLeft(),
-                        view.getTop() + (float) (view.getBottom() - view.getTop()) / 2,
-                        view.getRight(),
-                        view.getBottom());
-                mTmpPath.addRect(mTmpRect, Path.Direction.CW);
-                c.drawPath(mTmpPath, mPaint);
-            } else if (adapterItem.viewType == VIEW_TYPE_ICON
-                    && mUserCache.getUserInfo(adapterItem.itemInfo.user).isPrivate()
-                    // No decoration for any private space app icon other than those at first row.
-                    && adapterItem.rowAppIndex == 0) {
-                c.drawPath(getPrivateAppRowPath(parent, view, position, numCol), mPaint);
+            SectionDecorationInfo info = adapterItem.decorationInfo;
+            if (info == null) {
+                continue;
+            }
+            SectionDecorationHandler decorationHandler = info.getDecorationHandler();
+            if (info.shouldDecorateItemsTogether()) {
+                SectionDecorationHandler.UnionDecorationHandler unionHandler =
+                        deferredDecorations.getOrDefault(
+                                PRIVATE_APP_SECTION,
+                                new SectionDecorationHandler.UnionDecorationHandler(
+                                        decorationHandler, parent.getPaddingLeft(),
+                                        parent.getPaddingRight()));
+                unionHandler.addChild(decorationHandler, view, true /* applyBackground */);
+                deferredDecorations.put(PRIVATE_APP_SECTION, unionHandler);
+            } else {
+                decorationHandler.onFocusDraw(c, view);
             }
         }
-    }
-
-    /** Returns the path to be decorated for Private Space App Row */
-    private Path getPrivateAppRowPath(RecyclerView parent, View iconView, int adapterPosition,
-            int numCol) {
-        // We always decorate the entire app row here.
-        // As the iconView just represents the first icon of the row, we get the right margin of
-        // our decorator using the parent view.
-        mTmpRect.set(iconView.getLeft(),
-                iconView.getTop(),
-                parent.getRight() - parent.getPaddingRight(),
-                iconView.getBottom());
-        // Decorates last app row with rounded bottom corners.
-        if (adapterPosition + numCol >= mAppsList.getAdapterItems().size()) {
-            float[] mCornersBot = new float[]{0, 0, 0, 0, mCornerRadius, mCornerRadius,
-                    mCornerRadius, mCornerRadius};
-            mTmpPath.addRoundRect(mTmpRect, mCornersBot, Path.Direction.CW);
-        } else {
-            // Decorate other rows as a plain rectangle
-            mTmpPath.addRect(mTmpRect, Path.Direction.CW);
+        for (SectionDecorationHandler.UnionDecorationHandler decorationHandler
+                : deferredDecorations.values()) {
+            decorationHandler.onGroupDecorate(c);
         }
-        return mTmpPath;
     }
 }
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 77eb07e..693681b 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -30,6 +30,7 @@
 
 import androidx.annotation.VisibleForTesting;
 
+import com.android.launcher3.Flags;
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.util.Preconditions;
@@ -47,6 +48,7 @@
     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 final ActivityAllAppsContainerView<?> mAllApps;
     private final Predicate<UserHandle> mPrivateProfileMatcher;
     private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
@@ -71,13 +73,11 @@
 
     /** Disables quiet mode for Private Space User Profile. */
     public void unlockPrivateProfile() {
-        // TODO (b/302666597): Log this event to WW.
         enableQuietMode(false);
     }
 
     /** Enables quiet mode for Private Space User Profile. */
     public void lockPrivateProfile() {
-        // TODO (b/302666597): Log this event to WW.
         enableQuietMode(true);
     }
 
@@ -98,7 +98,6 @@
 
     /** Opens the Private Space Settings Entry Point. */
     public void openPrivateSpaceSettings() {
-        // TODO (b/302666597): Log this event to WW.
         Intent psSettingsIntent = new Intent(SAFETY_CENTER_INTENT);
         psSettingsIntent.putExtra(PS_SETTINGS_FRAGMENT_KEY, PS_SETTINGS_FRAGMENT_VALUE);
         mAllApps.getContext().startActivity(psSettingsIntent);
@@ -128,7 +127,6 @@
             // Create a new decorator instance if not already available.
             if (mPrivateAppsSectionDecorator == null) {
                 mPrivateAppsSectionDecorator = new PrivateAppsSectionDecorator(
-                        mAllApps.mActivityContext,
                         mainAdapterHolder.mAppsList);
             }
             for (int i = 0; i < mainAdapterHolder.mRecyclerView.getItemDecorationCount(); i++) {
@@ -140,6 +138,13 @@
             }
             // 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) {
diff --git a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
index 79e0cce..568ce32 100644
--- a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
+++ b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
@@ -19,6 +19,9 @@
 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;
@@ -63,13 +66,19 @@
                 quietModeButton.setVisibility(View.VISIBLE);
                 quietModeButton.setImageResource(R.drawable.bg_ps_lock_button);
                 quietModeButton.setOnClickListener(
-                        view -> mPrivateProfileManager.lockPrivateProfile());
+                        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.unlockPrivateProfile());
+                        view -> {
+                            mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP);
+                            mPrivateProfileManager.unlockPrivateProfile();
+                        });
             }
             default -> quietModeButton.setVisibility(View.GONE);
         }
@@ -79,8 +88,11 @@
         if (mPrivateProfileManager.getCurrentState() == STATE_ENABLED
                 && mPrivateProfileManager.isPrivateSpaceSettingsAvailable()) {
             settingsButton.setVisibility(View.VISIBLE);
-            settingsButton.setOnClickListener(view ->
-                    mPrivateProfileManager.openPrivateSpaceSettings());
+            settingsButton.setOnClickListener(
+                    view -> {
+                        mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
+                        mPrivateProfileManager.openPrivateSpaceSettings();
+                    });
         } else {
             settingsButton.setVisibility(View.GONE);
         }
@@ -93,4 +105,8 @@
             transitionImage.setVisibility(View.GONE);
         }
     }
+
+    PrivateProfileManager getPrivateProfileManager() {
+        return mPrivateProfileManager;
+    }
 }
diff --git a/src/com/android/launcher3/allapps/RecyclerViewAnimationController.java b/src/com/android/launcher3/allapps/RecyclerViewAnimationController.java
new file mode 100644
index 0000000..6209393
--- /dev/null
+++ b/src/com/android/launcher3/allapps/RecyclerViewAnimationController.java
@@ -0,0 +1,309 @@
+/*
+ * 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.recyclerview.widget.RecyclerView.NO_POSITION;
+
+import static com.android.app.animation.Interpolators.DECELERATE_1_7;
+import static com.android.app.animation.Interpolators.INSTANT;
+import static com.android.app.animation.Interpolators.clampToProgress;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
+import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
+
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.graphics.drawable.Drawable;
+import android.util.FloatProperty;
+import android.util.Log;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.model.data.ItemInfo;
+
+import java.util.List;
+
+public class RecyclerViewAnimationController {
+
+    private static final String LOG_TAG = "AnimationCtrl";
+
+    /**
+     * These values represent points on the [0, 1] animation progress spectrum. They are used to
+     * animate items in the {@link SearchRecyclerView} and private space container in
+     * {@link AllAppsRecyclerView}.
+     */
+    protected static final float TOP_CONTENT_FADE_PROGRESS_START = 0.133f;
+    protected static final float CONTENT_FADE_PROGRESS_DURATION = 0.083f;
+    protected static final float TOP_BACKGROUND_FADE_PROGRESS_START = 0.633f;
+    protected static final float BACKGROUND_FADE_PROGRESS_DURATION = 0.15f;
+    // Progress before next item starts fading.
+    protected static final float CONTENT_STAGGER = 0.01f;
+
+    protected static final FloatProperty<RecyclerViewAnimationController> PROGRESS =
+            new FloatProperty<RecyclerViewAnimationController>("expansionProgress") {
+                @Override
+                public Float get(RecyclerViewAnimationController controller) {
+                    return controller.getAnimationProgress();
+                }
+
+                @Override
+                public void setValue(RecyclerViewAnimationController controller, float progress) {
+                    controller.setAnimationProgress(progress);
+                }
+            };
+
+    protected final ActivityAllAppsContainerView<?> mAllAppsContainerView;
+    protected ObjectAnimator mAnimator = null;
+    private float mAnimatorProgress = 1f;
+
+    public RecyclerViewAnimationController(ActivityAllAppsContainerView<?> allAppsContainerView) {
+        mAllAppsContainerView = allAppsContainerView;
+    }
+
+    /**
+     * Updates the children views of the current recyclerView based on the current animation
+     * progress.
+     *
+     * @return the total height of animating views (may exclude at most one row of app icons
+     * depending on which recyclerView is being acted upon).
+     */
+    protected int onProgressUpdated(float expansionProgress) {
+        int numItemsAnimated = 0;
+        int totalHeight = 0;
+        int appRowHeight = 0;
+        boolean appRowComplete = false;
+        Integer top = null;
+        AllAppsRecyclerView allAppsRecyclerView = getRecyclerView();
+
+        for (int i = 0; i < allAppsRecyclerView.getChildCount(); i++) {
+            View currentView = allAppsRecyclerView.getChildAt(i);
+            if (currentView == null) {
+                continue;
+            }
+            if (top == null) {
+                top = currentView.getTop();
+            }
+            int adapterPosition = allAppsRecyclerView.getChildAdapterPosition(currentView);
+            List<BaseAllAppsAdapter.AdapterItem> allAppsAdapters = allAppsRecyclerView.getApps()
+                    .getAdapterItems();
+            if (adapterPosition < 0 || adapterPosition >= allAppsAdapters.size()) {
+                continue;
+            }
+            BaseAllAppsAdapter.AdapterItem adapterItemAtPosition =
+                    allAppsAdapters.get(adapterPosition);
+            int spanIndex = getSpanIndex(allAppsRecyclerView, adapterPosition);
+            appRowComplete |= appRowHeight > 0 && spanIndex == 0;
+
+            float backgroundAlpha = 1f;
+            boolean hasDecorationInfo = adapterItemAtPosition.getDecorationInfo() != null;
+            boolean shouldAnimate = shouldAnimate(currentView, hasDecorationInfo, appRowComplete);
+
+            if (shouldAnimate) {
+                if (spanIndex > 0) {
+                    // Animate this item with the previous item on the same row.
+                    numItemsAnimated--;
+                }
+                // Adjust background (or decorator) alpha based on start progress and stagger.
+                backgroundAlpha = getAdjustedBackgroundAlpha(numItemsAnimated);
+            }
+
+            Drawable background = currentView.getBackground();
+            if (background != null && currentView instanceof ViewGroup currentViewGroup) {
+                currentView.setAlpha(1f);
+                // Apply content alpha to each child, since the view needs to be fully opaque for
+                // the background to show properly.
+                for (int j = 0; j < currentViewGroup.getChildCount(); j++) {
+                    setViewAdjustedContentAlpha(currentViewGroup.getChildAt(j), numItemsAnimated,
+                            shouldAnimate);
+                }
+
+                // Apply background alpha to the background drawable directly.
+                background.setAlpha((int) (255 * backgroundAlpha));
+            } else {
+                // Adjust content alpha based on start progress and stagger.
+                setViewAdjustedContentAlpha(currentView, numItemsAnimated, shouldAnimate);
+
+                // Apply background alpha to decorator if possible.
+                setAdjustedAdapterItemDecorationBackgroundAlpha(
+                        allAppsRecyclerView.getApps().getAdapterItems().get(adapterPosition),
+                        numItemsAnimated);
+
+                // Apply background alpha to view's background (e.g. for Search Edu card).
+                if (background != null) {
+                    background.setAlpha((int) (255 * backgroundAlpha));
+                }
+            }
+
+            float scaleY = 1;
+            if (shouldAnimate) {
+                scaleY = 1 - getAnimationProgress();
+                // Update number of search results that has been animated.
+                numItemsAnimated++;
+            }
+            int scaledHeight = (int) (currentView.getHeight() * scaleY);
+            currentView.setScaleY(scaleY);
+
+            // For rows with multiple elements, only count the height once and translate elements to
+            // the same y position.
+            int y = top + totalHeight;
+            if (spanIndex > 0) {
+                // Continuation of an existing row; move this item into the row.
+                y -= scaledHeight;
+            } else {
+                // Start of a new row contributes to total height.
+                totalHeight += scaledHeight;
+                if (!shouldAnimate) {
+                    appRowHeight = scaledHeight;
+                }
+            }
+            currentView.setY(y);
+        }
+        return totalHeight - appRowHeight;
+    }
+
+    protected void animateToState(boolean expand, long duration, Runnable onEndRunnable) {
+        float targetProgress = expand ? 0 : 1;
+        if (mAnimator != null) {
+            mAnimator.cancel();
+        }
+        mAnimator = ObjectAnimator.ofFloat(this, PROGRESS, targetProgress);
+
+        TimeInterpolator timeInterpolator = getInterpolator();
+        if (timeInterpolator == INSTANT) {
+            duration = 0;
+        }
+
+        mAnimator.addListener(forEndCallback(() -> mAnimator = null));
+        mAnimator.setDuration(duration).setInterpolator(timeInterpolator);
+        mAnimator.addListener(forSuccessCallback(onEndRunnable));
+        mAnimator.start();
+        getRecyclerView().setChildAttachedConsumer(this::onChildAttached);
+    }
+
+    /** Called just before a child is attached to the RecyclerView. */
+    private void onChildAttached(View child) {
+        // Avoid allocating hardware layers for alpha changes.
+        child.forceHasOverlappingRendering(false);
+        child.setPivotY(0);
+        if (getAnimationProgress() > 0 && getAnimationProgress() < 1) {
+            // Before the child is rendered, apply the animation including it to avoid flicker.
+            onProgressUpdated(getAnimationProgress());
+        } else {
+            // Apply default states without processing the full layout.
+            child.setAlpha(1);
+            child.setScaleY(1);
+            child.setTranslationY(0);
+            int adapterPosition = getRecyclerView().getChildAdapterPosition(child);
+            List<BaseAllAppsAdapter.AdapterItem> allAppsAdapters =
+                    getRecyclerView().getApps().getAdapterItems();
+            if (adapterPosition >= 0 && adapterPosition < allAppsAdapters.size()) {
+                allAppsAdapters.get(adapterPosition).setDecorationFillAlpha(255);
+            }
+            if (child instanceof ViewGroup childGroup) {
+                for (int i = 0; i < childGroup.getChildCount(); i++) {
+                    childGroup.getChildAt(i).setAlpha(1f);
+                }
+            }
+            if (child.getBackground() != null) {
+                child.getBackground().setAlpha(255);
+            }
+        }
+    }
+
+    /** @return the column that the view at this position is found (0 assumed if indeterminate). */
+    protected int getSpanIndex(AllAppsRecyclerView appsRecyclerView, int adapterPosition) {
+        if (adapterPosition == NO_POSITION) {
+            Log.w(LOG_TAG, "Can't determine span index - child not found in adapter");
+            return 0;
+        }
+        if (!(appsRecyclerView.getAdapter() instanceof AllAppsGridAdapter<?>)) {
+            Log.e(LOG_TAG, "Search RV doesn't have an AllAppsGridAdapter?");
+            // This case shouldn't happen, but for debug devices we will continue to create a more
+            // visible crash.
+            if (!Utilities.IS_DEBUG_DEVICE) {
+                return 0;
+            }
+        }
+        AllAppsGridAdapter<?> adapter = (AllAppsGridAdapter<?>) appsRecyclerView.getAdapter();
+        return adapter.getSpanIndex(adapterPosition);
+    }
+
+    protected TimeInterpolator getInterpolator() {
+        return DECELERATE_1_7;
+    }
+
+    protected AllAppsRecyclerView getRecyclerView() {
+        return mAllAppsContainerView.mAH.get(ActivityAllAppsContainerView.AdapterHolder.MAIN)
+                .mRecyclerView;
+    }
+
+    /** Returns true if a transition animation is currently in progress. */
+    protected boolean isRunning() {
+        return mAnimator != null;
+    }
+
+    /** Should only animate if the view is an app icon and if it has a decoration info. */
+    protected boolean shouldAnimate(View view, boolean hasDecorationInfo,
+            boolean firstAppRowComplete) {
+        return isAppIcon(view) && hasDecorationInfo;
+    }
+
+    private float getAdjustedContentAlpha(int itemsAnimated) {
+        float startContentFadeProgress = Math.max(0,
+                TOP_CONTENT_FADE_PROGRESS_START - CONTENT_STAGGER * itemsAnimated);
+        float endContentFadeProgress = Math.min(1,
+                startContentFadeProgress + CONTENT_FADE_PROGRESS_DURATION);
+        return 1 - clampToProgress(mAnimatorProgress,
+                startContentFadeProgress, endContentFadeProgress);
+    }
+
+    private float getAdjustedBackgroundAlpha(int itemsAnimated) {
+        float startBackgroundFadeProgress = Math.max(0,
+                TOP_BACKGROUND_FADE_PROGRESS_START - CONTENT_STAGGER * itemsAnimated);
+        float endBackgroundFadeProgress = Math.min(1,
+                startBackgroundFadeProgress + BACKGROUND_FADE_PROGRESS_DURATION);
+        return 1 - clampToProgress(mAnimatorProgress,
+                startBackgroundFadeProgress, endBackgroundFadeProgress);
+    }
+
+    private void setViewAdjustedContentAlpha(View view, int numberOfItemsAnimated,
+            boolean shouldAnimate) {
+        view.setAlpha(shouldAnimate ? getAdjustedContentAlpha(numberOfItemsAnimated) : 1f);
+    }
+
+    private void setAdjustedAdapterItemDecorationBackgroundAlpha(
+            BaseAllAppsAdapter.AdapterItem adapterItem, int numberOfItemsAnimated) {
+        adapterItem.setDecorationFillAlpha((int)
+                (255 * getAdjustedBackgroundAlpha(numberOfItemsAnimated)));
+    }
+
+    private float getAnimationProgress() {
+        return mAnimatorProgress;
+    }
+
+    private void setAnimationProgress(float expansionProgress) {
+        mAnimatorProgress = expansionProgress;
+        onProgressUpdated(expansionProgress);
+    }
+
+    protected boolean isAppIcon(View item) {
+        return item instanceof BubbleTextView && item.getTag() instanceof ItemInfo
+                && ((ItemInfo) item.getTag()).itemType == ITEM_TYPE_APPLICATION;
+    }
+}
diff --git a/src/com/android/launcher3/allapps/SearchRecyclerView.java b/src/com/android/launcher3/allapps/SearchRecyclerView.java
index 9d1dfc0..68f9f11 100644
--- a/src/com/android/launcher3/allapps/SearchRecyclerView.java
+++ b/src/com/android/launcher3/allapps/SearchRecyclerView.java
@@ -27,8 +27,6 @@
 /** A RecyclerView for AllApps Search results. */
 public class SearchRecyclerView extends AllAppsRecyclerView {
 
-    private Consumer<View> mChildAttachedConsumer;
-
     public SearchRecyclerView(Context context) {
         this(context, null);
     }
@@ -46,11 +44,6 @@
         super(context, attrs, defStyleAttr, defStyleRes);
     }
 
-    /** This will be called just before a new child is attached to the window. */
-    public void setChildAttachedConsumer(Consumer<View> childAttachedConsumer) {
-        mChildAttachedConsumer = childAttachedConsumer;
-    }
-
     @Override
     protected void updatePoolSize() {
         RecycledViewPool pool = getRecycledViewPool();
@@ -67,12 +60,4 @@
     public RecyclerViewFastScroller getScrollbar() {
         return null;
     }
-
-    @Override
-    public void onChildAttachedToWindow(@NonNull View child) {
-        if (mChildAttachedConsumer != null) {
-            mChildAttachedConsumer.accept(child);
-        }
-        super.onChildAttachedToWindow(child);
-    }
 }
diff --git a/src/com/android/launcher3/allapps/SearchTransitionController.java b/src/com/android/launcher3/allapps/SearchTransitionController.java
index eb1bc0a..d5c3b57 100644
--- a/src/com/android/launcher3/allapps/SearchTransitionController.java
+++ b/src/com/android/launcher3/allapps/SearchTransitionController.java
@@ -18,34 +18,21 @@
 
 import static android.view.View.VISIBLE;
 
-import static androidx.recyclerview.widget.RecyclerView.NO_POSITION;
-
 import static com.android.app.animation.Interpolators.DECELERATE_1_7;
 import static com.android.app.animation.Interpolators.INSTANT;
 import static com.android.app.animation.Interpolators.clampToProgress;
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
 import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
 import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
 
 import android.animation.ObjectAnimator;
 import android.animation.TimeInterpolator;
-import android.graphics.drawable.Drawable;
-import android.util.FloatProperty;
-import android.util.Log;
 import android.view.View;
-import android.view.ViewGroup;
 import android.view.animation.Interpolator;
 
-import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.model.data.ItemInfo;
 
 /** Coordinates the transition between Search and A-Z in All Apps. */
-public class SearchTransitionController {
-
-    private static final String LOG_TAG = "SearchTransitionCtrl";
+public class SearchTransitionController extends RecyclerViewAnimationController {
 
     // Interpolator when the user taps the QSB while already in All Apps.
     private static final Interpolator INTERPOLATOR_WITHIN_ALL_APPS = DECELERATE_1_7;
@@ -53,42 +40,10 @@
     // happening simultaneously.
     private static final Interpolator INTERPOLATOR_TRANSITIONING_TO_ALL_APPS = INSTANT;
 
-    /**
-     * These values represent points on the [0, 1] animation progress spectrum. They are used to
-     * animate items in the {@link SearchRecyclerView}.
-     */
-    private static final float TOP_CONTENT_FADE_PROGRESS_START = 0.133f;
-    private static final float CONTENT_FADE_PROGRESS_DURATION = 0.083f;
-    private static final float TOP_BACKGROUND_FADE_PROGRESS_START = 0.633f;
-    private static final float BACKGROUND_FADE_PROGRESS_DURATION = 0.15f;
-    private static final float CONTENT_STAGGER = 0.01f;  // Progress before next item starts fading.
-
-    private static final FloatProperty<SearchTransitionController> SEARCH_TO_AZ_PROGRESS =
-            new FloatProperty<SearchTransitionController>("searchToAzProgress") {
-                @Override
-                public Float get(SearchTransitionController controller) {
-                    return controller.getSearchToAzProgress();
-                }
-
-                @Override
-                public void setValue(SearchTransitionController controller, float progress) {
-                    controller.setSearchToAzProgress(progress);
-                }
-            };
-
-    private final ActivityAllAppsContainerView<?> mAllAppsContainerView;
-
-    private ObjectAnimator mSearchToAzAnimator = null;
-    private float mSearchToAzProgress = 1f;
     private boolean mSkipNextAnimationWithinAllApps;
 
     public SearchTransitionController(ActivityAllAppsContainerView<?> allAppsContainerView) {
-        mAllAppsContainerView = allAppsContainerView;
-    }
-
-    /** Returns true if a transition animation is currently in progress. */
-    public boolean isRunning() {
-        return mSearchToAzAnimator != null;
+        super(allAppsContainerView);
     }
 
     /**
@@ -101,51 +56,31 @@
      * @param onEndRunnable will be called when the animation finishes, unless another animation is
      *                      scheduled in the meantime
      */
-    public void animateToSearchState(boolean goingToSearch, long duration, Runnable onEndRunnable) {
-        float targetProgress = goingToSearch ? 0 : 1;
-
-        if (mSearchToAzAnimator != null) {
-            mSearchToAzAnimator.cancel();
-        }
-
-        mSearchToAzAnimator = ObjectAnimator.ofFloat(this, SEARCH_TO_AZ_PROGRESS, targetProgress);
-        boolean inAllApps = mAllAppsContainerView.isInAllApps();
-        TimeInterpolator timeInterpolator =
-                inAllApps ? INTERPOLATOR_WITHIN_ALL_APPS : INTERPOLATOR_TRANSITIONING_TO_ALL_APPS;
-        if (mSkipNextAnimationWithinAllApps) {
-            timeInterpolator = INSTANT;
-            mSkipNextAnimationWithinAllApps = false;
-        }
-        if (timeInterpolator == INSTANT) {
-            duration = 0;  // Don't want to animate when coming from QSB.
-        }
-        mSearchToAzAnimator.setDuration(duration).setInterpolator(timeInterpolator);
-        mSearchToAzAnimator.addListener(forEndCallback(() -> mSearchToAzAnimator = null));
+    @Override
+    protected void animateToState(boolean goingToSearch, long duration, Runnable onEndRunnable) {
+        super.animateToState(goingToSearch, duration, onEndRunnable);
         if (!goingToSearch) {
-            mSearchToAzAnimator.addListener(forSuccessCallback(() -> {
+            mAnimator.addListener(forSuccessCallback(() -> {
                 mAllAppsContainerView.getFloatingHeaderView().setFloatingRowsCollapsed(false);
                 mAllAppsContainerView.getFloatingHeaderView().reset(false /* animate */);
                 mAllAppsContainerView.getAppsRecyclerViewContainer().setTranslationY(0);
             }));
         }
-        mSearchToAzAnimator.addListener(forSuccessCallback(onEndRunnable));
-
         mAllAppsContainerView.getFloatingHeaderView().setFloatingRowsCollapsed(true);
         mAllAppsContainerView.getFloatingHeaderView().setVisibility(VISIBLE);
         mAllAppsContainerView.getFloatingHeaderView().maybeSetTabVisibility(VISIBLE);
         mAllAppsContainerView.getAppsRecyclerViewContainer().setVisibility(VISIBLE);
-        getSearchRecyclerView().setVisibility(VISIBLE);
-        getSearchRecyclerView().setChildAttachedConsumer(this::onSearchChildAttached);
-        mSearchToAzAnimator.start();
+        getRecyclerView().setVisibility(VISIBLE);
     }
 
-    private SearchRecyclerView getSearchRecyclerView() {
+    @Override
+    protected SearchRecyclerView getRecyclerView() {
         return mAllAppsContainerView.getSearchRecyclerView();
     }
 
-    private void setSearchToAzProgress(float searchToAzProgress) {
-        mSearchToAzProgress = searchToAzProgress;
-        int searchHeight = updateSearchRecyclerViewProgress();
+    @Override
+    protected int onProgressUpdated(float searchToAzProgress) {
+        int searchHeight = super.onProgressUpdated(searchToAzProgress);
 
         FloatingHeaderView headerView = mAllAppsContainerView.getFloatingHeaderView();
 
@@ -171,179 +106,27 @@
         appsContainer.setTranslationY(appsTranslationY);
         // Fade apps out with tabs (in 20% of the total animation).
         appsContainer.setAlpha(clampToProgress(searchToAzProgress, 0.8f, 1f));
+        return searchHeight;
     }
 
     /**
-     * Updates the children views of SearchRecyclerView based on the current animation progress.
-     *
-     * @return the total height of animating views (excluding at most one row of app icons).
+     * Should only animate if the view is not an app icon or if the app row is complete.
      */
-    private int updateSearchRecyclerViewProgress() {
-        int numSearchResultsAnimated = 0;
-        int totalHeight = 0;
-        int appRowHeight = 0;
-        boolean appRowComplete = false;
-        Integer top = null;
-        SearchRecyclerView searchRecyclerView = getSearchRecyclerView();
-
-        for (int i = 0; i < searchRecyclerView.getChildCount(); i++) {
-            View searchResultView = searchRecyclerView.getChildAt(i);
-            if (searchResultView == null) {
-                continue;
-            }
-
-            if (top == null) {
-                top = searchResultView.getTop();
-            }
-
-            int adapterPosition = searchRecyclerView.getChildAdapterPosition(searchResultView);
-            int spanIndex = getSpanIndex(searchRecyclerView, adapterPosition);
-            appRowComplete |= appRowHeight > 0 && spanIndex == 0;
-            // We don't animate the first (currently only) app row we see, as that is assumed to be
-            // predicted/prefix-matched apps.
-            boolean shouldAnimate = !isAppIcon(searchResultView) || appRowComplete;
-
-            float contentAlpha = 1f;
-            float backgroundAlpha = 1f;
-            if (shouldAnimate) {
-                if (spanIndex > 0) {
-                    // Animate this item with the previous item on the same row.
-                    numSearchResultsAnimated--;
-                }
-
-                // Adjust content alpha based on start progress and stagger.
-                float startContentFadeProgress = Math.max(0,
-                        TOP_CONTENT_FADE_PROGRESS_START
-                                - CONTENT_STAGGER * numSearchResultsAnimated);
-                float endContentFadeProgress = Math.min(1,
-                        startContentFadeProgress + CONTENT_FADE_PROGRESS_DURATION);
-                contentAlpha = 1 - clampToProgress(mSearchToAzProgress,
-                        startContentFadeProgress, endContentFadeProgress);
-
-                // Adjust background (or decorator) alpha based on start progress and stagger.
-                float startBackgroundFadeProgress = Math.max(0,
-                        TOP_BACKGROUND_FADE_PROGRESS_START
-                                - CONTENT_STAGGER * numSearchResultsAnimated);
-                float endBackgroundFadeProgress = Math.min(1,
-                        startBackgroundFadeProgress + BACKGROUND_FADE_PROGRESS_DURATION);
-                backgroundAlpha = 1 - clampToProgress(mSearchToAzProgress,
-                        startBackgroundFadeProgress, endBackgroundFadeProgress);
-
-                numSearchResultsAnimated++;
-            }
-
-            Drawable background = searchResultView.getBackground();
-            if (background != null
-                    && searchResultView instanceof ViewGroup
-                    && FeatureFlags.ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES.get()) {
-                searchResultView.setAlpha(1f);
-
-                // Apply content alpha to each child, since the view needs to be fully opaque for
-                // the background to show properly.
-                ViewGroup searchResultViewGroup = (ViewGroup) searchResultView;
-                for (int j = 0; j < searchResultViewGroup.getChildCount(); j++) {
-                    searchResultViewGroup.getChildAt(j).setAlpha(contentAlpha);
-                }
-
-                // Apply background alpha to the background drawable directly.
-                background.setAlpha((int) (255 * backgroundAlpha));
-            } else {
-                searchResultView.setAlpha(contentAlpha);
-
-                // Apply background alpha to decorator if possible.
-                if (adapterPosition != NO_POSITION) {
-                    searchRecyclerView.getApps().getAdapterItems().get(adapterPosition)
-                            .setDecorationFillAlpha((int) (255 * backgroundAlpha));
-                }
-
-                // Apply background alpha to view's background (e.g. for Search Edu card).
-                if (background != null) {
-                    background.setAlpha((int) (255 * backgroundAlpha));
-                }
-            }
-
-            float scaleY = 1;
-            if (shouldAnimate) {
-                scaleY = 1 - mSearchToAzProgress;
-            }
-            int scaledHeight = (int) (searchResultView.getHeight() * scaleY);
-            searchResultView.setScaleY(scaleY);
-
-            // For rows with multiple elements, only count the height once and translate elements to
-            // the same y position.
-            int y = top + totalHeight;
-            if (spanIndex > 0) {
-                // Continuation of an existing row; move this item into the row.
-                y -= scaledHeight;
-            } else {
-                // Start of a new row contributes to total height.
-                totalHeight += scaledHeight;
-                if (!shouldAnimate) {
-                    appRowHeight = scaledHeight;
-                }
-            }
-            searchResultView.setY(y);
-        }
-
-        return totalHeight - appRowHeight;
+    @Override
+    protected boolean shouldAnimate(View view, boolean hasDecorationInfo, boolean appRowComplete) {
+        return !isAppIcon(view) || appRowComplete;
     }
 
-    /** @return the column that the view at this position is found (0 assumed if indeterminate). */
-    private int getSpanIndex(SearchRecyclerView searchRecyclerView, int adapterPosition) {
-        if (adapterPosition == NO_POSITION) {
-            Log.w(LOG_TAG, "Can't determine span index - child not found in adapter");
-            return 0;
+    @Override
+    protected TimeInterpolator getInterpolator() {
+        TimeInterpolator timeInterpolator =
+                mAllAppsContainerView.isInAllApps()
+                        ? INTERPOLATOR_WITHIN_ALL_APPS : INTERPOLATOR_TRANSITIONING_TO_ALL_APPS;
+        if (mSkipNextAnimationWithinAllApps) {
+            timeInterpolator = INSTANT;
+            mSkipNextAnimationWithinAllApps = false;
         }
-        if (!(searchRecyclerView.getAdapter() instanceof AllAppsGridAdapter<?>)) {
-            Log.e(LOG_TAG, "Search RV doesn't have an AllAppsGridAdapter?");
-            // This case shouldn't happen, but for debug devices we will continue to create a more
-            // visible crash.
-            if (!Utilities.IS_DEBUG_DEVICE) {
-                return 0;
-            }
-        }
-        AllAppsGridAdapter<?> adapter = (AllAppsGridAdapter<?>) searchRecyclerView.getAdapter();
-        return adapter.getSpanIndex(adapterPosition);
-    }
-
-    private boolean isAppIcon(View item) {
-        return item instanceof BubbleTextView && item.getTag() instanceof ItemInfo
-                && ((ItemInfo) item.getTag()).itemType == ITEM_TYPE_APPLICATION;
-    }
-
-    /** Called just before a child is attached to the SearchRecyclerView. */
-    private void onSearchChildAttached(View child) {
-        // Avoid allocating hardware layers for alpha changes.
-        child.forceHasOverlappingRendering(false);
-        child.setPivotY(0);
-        if (mSearchToAzProgress > 0) {
-            // Before the child is rendered, apply the animation including it to avoid flicker.
-            updateSearchRecyclerViewProgress();
-        } else {
-            // Apply default states without processing the full layout.
-            child.setAlpha(1);
-            child.setScaleY(1);
-            child.setTranslationY(0);
-            int adapterPosition = getSearchRecyclerView().getChildAdapterPosition(child);
-            if (adapterPosition != NO_POSITION) {
-                getSearchRecyclerView().getApps().getAdapterItems().get(adapterPosition)
-                        .setDecorationFillAlpha(255);
-            }
-            if (child instanceof ViewGroup
-                    && FeatureFlags.ENABLE_SEARCH_RESULT_BACKGROUND_DRAWABLES.get()) {
-                ViewGroup childGroup = (ViewGroup) child;
-                for (int i = 0; i < childGroup.getChildCount(); i++) {
-                    childGroup.getChildAt(i).setAlpha(1f);
-                }
-            }
-            if (child.getBackground() != null) {
-                child.getBackground().setAlpha(255);
-            }
-        }
-    }
-
-    private float getSearchToAzProgress() {
-        return mSearchToAzProgress;
+        return timeInterpolator;
     }
 
     /**
diff --git a/src/com/android/launcher3/allapps/SectionDecorationHandler.java b/src/com/android/launcher3/allapps/SectionDecorationHandler.java
new file mode 100644
index 0000000..f79b82c
--- /dev/null
+++ b/src/com/android/launcher3/allapps/SectionDecorationHandler.java
@@ -0,0 +1,206 @@
+/*
+ * 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 android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Path;
+import android.graphics.RectF;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.InsetDrawable;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+import androidx.core.content.ContextCompat;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.Themes;
+
+public class SectionDecorationHandler {
+
+    protected final Path mTmpPath = new Path();
+    protected final RectF mTmpRect = new RectF();
+
+    protected final int mCornerGroupRadius;
+    protected final int mCornerResultRadius;
+    protected final RectF mBounds = new RectF();
+    protected final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+    protected final int mFocusAlpha = 255; // main focused item alpha
+    protected int mFillColor; // grouping color
+    protected int mFocusColor; // main focused item color
+    protected float mFillSpacing;
+    protected int mInlineRadius;
+    protected Context mContext;
+    protected float[] mCorners;
+    protected int mFillAlpha;
+    protected boolean mIsTopLeftRound;
+    protected boolean mIsTopRightRound;
+    protected boolean mIsBottomLeftRound;
+    protected boolean mIsBottomRightRound;
+    protected boolean mIsBottomRound;
+    protected boolean mIsTopRound;
+
+    public SectionDecorationHandler(Context context, int fillAlpha, boolean isTopLeftRound,
+            boolean isTopRightRound, boolean isBottomLeftRound,
+            boolean isBottomRightRound) {
+
+        mContext = context;
+        mFillAlpha = fillAlpha;
+        mFocusColor = ContextCompat.getColor(context,
+                R.color.material_color_surface_bright); // UX recommended
+        mFillColor = ContextCompat.getColor(context,
+                R.color.material_color_surface_container_high); // UX recommended
+
+        mIsTopLeftRound = isTopLeftRound;
+        mIsTopRightRound = isTopRightRound;
+        mIsBottomLeftRound = isBottomLeftRound;
+        mIsBottomRightRound = isBottomRightRound;
+        mIsBottomRound = mIsBottomLeftRound && mIsBottomRightRound;
+        mIsTopRound = mIsTopLeftRound && mIsTopRightRound;
+
+        mCornerGroupRadius = context.getResources().getDimensionPixelSize(
+                R.dimen.all_apps_recycler_view_decorator_group_radius);
+        mCornerResultRadius = context.getResources().getDimensionPixelSize(
+                R.dimen.all_apps_recycler_view_decorator_result_radius);
+
+        mInlineRadius = 0;
+        mFillSpacing = 0;
+        initCorners();
+    }
+
+    protected void initCorners() {
+        mCorners = new float[]{
+                mIsTopLeftRound ? mCornerGroupRadius : 0,
+                mIsTopLeftRound ? mCornerGroupRadius : 0, // Top left radius in px
+                mIsTopRightRound ? mCornerGroupRadius : 0,
+                mIsTopRightRound ? mCornerGroupRadius : 0, // Top right radius in px
+                mIsBottomRightRound ? mCornerGroupRadius : 0,
+                mIsBottomRightRound ? mCornerGroupRadius : 0, // Bottom right
+                mIsBottomLeftRound ? mCornerGroupRadius : 0,
+                mIsBottomLeftRound ? mCornerGroupRadius : 0 // Bottom left
+        };
+    }
+
+    protected void setFillAlpha(int fillAlpha) {
+        mFillAlpha = fillAlpha;
+        mPaint.setAlpha(mFillAlpha);
+    }
+
+    protected void onFocusDraw(Canvas canvas, @Nullable View view) {
+        if (view == null) {
+            return;
+        }
+        mPaint.setColor(mFillColor);
+        mPaint.setAlpha(mFillAlpha);
+        int scaledHeight = (int) (view.getHeight() * view.getScaleY());
+        mBounds.set(view.getLeft(), view.getY(), view.getRight(), view.getY() + scaledHeight);
+        onDraw(canvas);
+    }
+
+    protected void onDraw(Canvas canvas) {
+        mTmpPath.reset();
+        mTmpRect.set(mBounds.left + mFillSpacing,
+                mBounds.top + mFillSpacing,
+                mBounds.right - mFillSpacing,
+                mBounds.bottom - mFillSpacing);
+        mTmpPath.addRoundRect(mTmpRect, mCorners, Path.Direction.CW);
+        canvas.drawPath(mTmpPath, mPaint);
+    }
+
+    /** Sets the right background drawable to the view based on the give decoration info. */
+    public void applyBackground(View view, Context context,
+           @Nullable SectionDecorationInfo decorationInfo, boolean isHighlighted) {
+        int inset = context.getResources().getDimensionPixelSize(
+                R.dimen.all_apps_recycler_view_decorator_padding);
+        float radiusBottom = (decorationInfo == null || decorationInfo.isBottomRound()) ?
+                mCornerGroupRadius : mCornerResultRadius;
+        float radiusTop =
+                (decorationInfo == null || decorationInfo.isTopRound()) ?
+                        mCornerGroupRadius : mCornerResultRadius;
+        int color = isHighlighted ? mFocusColor : mFillColor;
+
+        GradientDrawable shape = new GradientDrawable();
+        shape.setShape(GradientDrawable.RECTANGLE);
+        shape.setCornerRadii(new float[] {
+                radiusTop, radiusTop, // top-left
+                radiusTop, radiusTop, // top-right
+                radiusBottom, radiusBottom, // bottom-right
+                radiusBottom, radiusBottom // bottom-left
+        });
+        shape.setColor(color);
+
+        // Setting the background resets the padding, so we cache it and reset it afterwards.
+        int paddingLeft = view.getPaddingLeft();
+        int paddingTop = view.getPaddingTop();
+        int paddingRight = view.getPaddingRight();
+        int paddingBottom = view.getPaddingBottom();
+
+        view.setBackground(new InsetDrawable(shape, inset));
+
+        view.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
+    }
+
+    /**
+     * Section decorator that combines views and draws a single block decoration
+     */
+    public static class UnionDecorationHandler extends SectionDecorationHandler {
+
+        private final int mPaddingLeft;
+        private final int mPaddingRight;
+
+        public UnionDecorationHandler(
+                SectionDecorationHandler decorationHandler,
+                int paddingLeft, int paddingRight) {
+            super(decorationHandler.mContext, decorationHandler.mFillAlpha,
+                    decorationHandler.mIsTopLeftRound, decorationHandler.mIsTopRightRound,
+                    decorationHandler.mIsBottomLeftRound, decorationHandler.mIsBottomRightRound);
+            mPaddingLeft = paddingLeft;
+            mPaddingRight = paddingRight;
+        }
+
+        /**
+         * Expands decoration bounds to include child {@link PrivateAppsSectionDecorator}
+         */
+        public void addChild(SectionDecorationHandler child, View view, boolean applyBackground) {
+            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;
+            mIsTopRound |= child.mIsTopRound;
+            mIsTopLeftRound |= child.mIsTopLeftRound;
+            mIsTopRightRound |= child.mIsTopRightRound;
+        }
+
+        /**
+         * Draws group decoration to canvas
+         */
+        public void onGroupDecorate(Canvas canvas) {
+            initCorners();
+            mBounds.left = mPaddingLeft;
+            mBounds.right = canvas.getWidth() - mPaddingRight;
+            mPaint.setColor(mFillColor);
+            mPaint.setAlpha(mFillAlpha);
+            onDraw(canvas);
+        }
+    }
+}
diff --git a/src/com/android/launcher3/allapps/SectionDecorationInfo.java b/src/com/android/launcher3/allapps/SectionDecorationInfo.java
new file mode 100644
index 0000000..1fed2b6
--- /dev/null
+++ b/src/com/android/launcher3/allapps/SectionDecorationInfo.java
@@ -0,0 +1,77 @@
+/*
+ * 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 android.content.Context;
+import android.os.Bundle;
+
+import androidx.annotation.NonNull;
+
+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 DECORATOR_ALPHA = 255;
+
+    protected boolean mShouldDecorateItemsTogether;
+    private SectionDecorationHandler mDecorationHandler;
+    protected boolean mIsTopRound;
+    protected boolean mIsBottomRound;
+
+    public SectionDecorationInfo(Context context, int roundRegions, boolean decorateTogether) {
+        mDecorationHandler =
+                new SectionDecorationHandler(context, DECORATOR_ALPHA,
+                        isFlagEnabled(roundRegions, ROUND_TOP_LEFT),
+                        isFlagEnabled(roundRegions, ROUND_TOP_RIGHT),
+                        isFlagEnabled(roundRegions, ROUND_BOTTOM_LEFT),
+                        isFlagEnabled(roundRegions, ROUND_BOTTOM_RIGHT));
+        mShouldDecorateItemsTogether = decorateTogether;
+        mIsTopRound = isFlagEnabled(roundRegions, ROUND_TOP_LEFT) &&
+                isFlagEnabled(roundRegions, ROUND_TOP_RIGHT);
+        mIsBottomRound = isFlagEnabled(roundRegions, ROUND_BOTTOM_LEFT) &&
+                isFlagEnabled(roundRegions, ROUND_BOTTOM_RIGHT);
+    }
+
+    public SectionDecorationInfo(Context context, @NonNull Bundle target,
+            String targetLayoutType, @NonNull Bundle prevTarget, @NonNull Bundle nextTarget) {}
+
+    public SectionDecorationHandler getDecorationHandler() {
+        return mDecorationHandler;
+    }
+
+    private boolean isFlagEnabled(int canonicalFlag, int comparison) {
+        return (canonicalFlag & comparison) != 0;
+    }
+
+    /**
+     * Returns whether multiple {@link SectionDecorationInfo}s with the same sectionId should
+     * be grouped together.
+     */
+    public boolean shouldDecorateItemsTogether() {
+        return mShouldDecorateItemsTogether;
+    }
+
+    public boolean isTopRound() {
+        return mIsTopRound;
+    }
+
+    public boolean isBottomRound() {
+        return mIsBottomRound;
+    }
+}
diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java
index 4cf6471..1d73441 100644
--- a/src/com/android/launcher3/apppairs/AppPairIcon.java
+++ b/src/com/android/launcher3/apppairs/AppPairIcon.java
@@ -17,11 +17,10 @@
 package com.android.launcher3.apppairs;
 
 import android.content.Context;
-import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
+import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
 
@@ -30,9 +29,10 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.DeviceProfile;
 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.model.data.WorkspaceItemInfo;
+import com.android.launcher3.util.MultiTranslateDelegate;
 import com.android.launcher3.views.ActivityContext;
 
 import java.util.Collections;
@@ -44,39 +44,18 @@
  * The app pair icon is two parallel background rectangles with rounded corners. Icons of the two
  * member apps are set into these rectangles.
  */
-public class AppPairIcon extends FrameLayout implements DraggableView {
-    /**
-     * Design specs -- the below ratios are in relation to the size of a standard app icon.
-     */
-    private static final float OUTER_PADDING_SCALE = 1 / 30f;
-    private static final float INNER_PADDING_SCALE = 1 / 24f;
-    private static final float MEMBER_ICON_SCALE = 11 / 30f;
-    private static final float CENTER_CHANNEL_SCALE = 1 / 30f;
-    private static final float BIG_RADIUS_SCALE = 1 / 5f;
-    private static final float SMALL_RADIUS_SCALE = 1 / 15f;
-
-    // App pair icons are slightly smaller than regular icons, so we pad the icon by this much on
-    // each side.
-    float mOuterPadding;
-    // Inside of the icon, the two member apps are padded by this much.
-    float mInnerPadding;
-    // The two member apps have icons that are this big (in diameter).
-    float mMemberIconSize;
-    // The size of the center channel.
-    float mCenterChannelSize;
-    // The large outer radius of the background rectangles.
-    float mBigRadius;
-    // The small inner radius of the background rectangles.
-    float mSmallRadius;
-    // The app pairs icon appears differently in portrait and landscape.
-    boolean mIsLandscape;
-
-    private ActivityContext mActivity;
+public class AppPairIcon extends FrameLayout implements DraggableView, Reorderable {
+    // 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;
 
+    // Required for Reorderable -- handles translation and bouncing movements
+    private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this);
+    private float mScaleForReorderBounce = 1f;
+
     public AppPairIcon(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -103,7 +82,10 @@
         icon.setTag(appPairInfo);
         icon.setOnClickListener(activity.getItemOnClickListener());
         icon.mInfo = appPairInfo;
-        icon.mActivity = activity;
+
+        // Set up icon drawable area
+        icon.mIconGraphic = icon.findViewById(R.id.app_pair_icon_graphic);
+        icon.mIconGraphic.init(activity.getDeviceProfile(), icon);
 
         // Set up app pair title
         icon.mAppPairName = icon.findViewById(R.id.app_pair_icon_name);
@@ -121,85 +103,6 @@
         return icon;
     }
 
-    @Override
-    protected void dispatchDraw(Canvas canvas) {
-        super.dispatchDraw(canvas);
-
-        // Calculate device-specific measurements
-        DeviceProfile grid = mActivity.getDeviceProfile();
-        int defaultIconSize = grid.iconSizePx;
-        mOuterPadding = OUTER_PADDING_SCALE * defaultIconSize;
-        mInnerPadding = INNER_PADDING_SCALE * defaultIconSize;
-        mMemberIconSize = MEMBER_ICON_SCALE * defaultIconSize;
-        mCenterChannelSize = CENTER_CHANNEL_SCALE * defaultIconSize;
-        mBigRadius = BIG_RADIUS_SCALE * defaultIconSize;
-        mSmallRadius = SMALL_RADIUS_SCALE * defaultIconSize;
-        mIsLandscape = grid.isLeftRightSplit;
-
-        // Calculate drawable area position
-        float leftBound = (canvas.getWidth() / 2f) - (defaultIconSize / 2f);
-        float topBound = getPaddingTop();
-
-        // Prepare to draw app pair icon background
-        Drawable background = new AppPairIconBackground(getContext(), this);
-        background.setBounds(0, 0, defaultIconSize, defaultIconSize);
-
-        // Draw background
-        canvas.save();
-        canvas.translate(leftBound, topBound);
-        background.draw(canvas);
-        canvas.restore();
-
-        // Prepare to draw icons
-        WorkspaceItemInfo app1 = mInfo.contents.get(0);
-        WorkspaceItemInfo app2 = mInfo.contents.get(1);
-        Drawable app1Icon = app1.newIcon(getContext());
-        Drawable app2Icon = app2.newIcon(getContext());
-        app1Icon.setBounds(0, 0, defaultIconSize, defaultIconSize);
-        app2Icon.setBounds(0, 0, defaultIconSize, defaultIconSize);
-
-        // Draw first icon
-        canvas.save();
-        canvas.translate(leftBound, topBound);
-        // The app icons are placed differently depending on device orientation.
-        if (mIsLandscape) {
-            canvas.translate(
-                    (defaultIconSize / 2f) - (mCenterChannelSize / 2f) - mInnerPadding
-                            - mMemberIconSize,
-                    (defaultIconSize / 2f) - (mMemberIconSize / 2f)
-            );
-        } else {
-            canvas.translate(
-                    (defaultIconSize / 2f) - (mMemberIconSize / 2f),
-                    (defaultIconSize / 2f) - (mCenterChannelSize / 2f) - mInnerPadding
-                            - mMemberIconSize
-            );
-
-        }
-        canvas.scale(MEMBER_ICON_SCALE, MEMBER_ICON_SCALE);
-        app1Icon.draw(canvas);
-        canvas.restore();
-
-        // Draw second icon
-        canvas.save();
-        canvas.translate(leftBound, topBound);
-        // The app icons are placed differently depending on device orientation.
-        if (mIsLandscape) {
-            canvas.translate(
-                    (defaultIconSize / 2f) + (mCenterChannelSize / 2f) + mInnerPadding,
-                    (defaultIconSize / 2f) - (mMemberIconSize / 2f)
-            );
-        } else {
-            canvas.translate(
-                    (defaultIconSize / 2f) - (mMemberIconSize / 2f),
-                    (defaultIconSize / 2f) + (mCenterChannelSize / 2f) + mInnerPadding
-            );
-        }
-        canvas.scale(MEMBER_ICON_SCALE, MEMBER_ICON_SCALE);
-        app2Icon.draw(canvas);
-        canvas.restore();
-    }
-
     /**
      * Returns a formatted accessibility title for app pairs.
      */
@@ -207,17 +110,52 @@
         return getContext().getString(R.string.app_pair_name_format, app1, app2);
     }
 
+    // Required for DraggableView
     @Override
     public int getViewType() {
         return DRAGGABLE_ICON;
     }
 
+    // Required for DraggableView
     @Override
-    public void getWorkspaceVisualDragBounds(Rect bounds) {
-        mAppPairName.getIconBounds(bounds);
+    public void getWorkspaceVisualDragBounds(Rect outBounds) {
+        mIconGraphic.getIconBounds(outBounds);
+    }
+
+    /** Sets the visibility of the icon's title text */
+    public void setTextVisible(boolean visible) {
+        if (visible) {
+            mAppPairName.setVisibility(VISIBLE);
+        } else {
+            mAppPairName.setVisibility(INVISIBLE);
+        }
+    }
+
+    // Required for Reorderable
+    @Override
+    public MultiTranslateDelegate getTranslateDelegate() {
+        return mTranslateDelegate;
+    }
+
+    // Required for Reorderable
+    @Override
+    public void setReorderBounceScale(float scale) {
+        mScaleForReorderBounce = scale;
+        super.setScaleX(scale);
+        super.setScaleY(scale);
+    }
+
+    // Required for Reorderable
+    @Override
+    public float getReorderBounceScale() {
+        return mScaleForReorderBounce;
     }
 
     public FolderInfo getInfo() {
         return mInfo;
     }
+
+    public View getIconDrawableArea() {
+        return mIconGraphic;
+    }
 }
diff --git a/src/com/android/launcher3/apppairs/AppPairIconBackground.java b/src/com/android/launcher3/apppairs/AppPairIconBackground.java
index 735c82f..4e60ece 100644
--- a/src/com/android/launcher3/apppairs/AppPairIconBackground.java
+++ b/src/com/android/launcher3/apppairs/AppPairIconBackground.java
@@ -32,8 +32,8 @@
  * A Drawable for the background behind the twin app icons (looks like two rectangles).
  */
 class AppPairIconBackground extends Drawable {
-    // The icon that we will draw this background on.
-    private final AppPairIcon icon;
+    // The underlying view that we are drawing this background on.
+    private final AppPairIconGraphic icon;
     private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
 
     /**
@@ -44,8 +44,8 @@
     private static final RectF EMPTY_RECT = new RectF();
     private static final float[] ARRAY_OF_ZEROES = new float[8];
 
-    AppPairIconBackground(Context context, AppPairIcon appPairIcon) {
-        icon = appPairIcon;
+    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);
@@ -56,7 +56,7 @@
 
     @Override
     public void draw(Canvas canvas) {
-        if (icon.mIsLandscape) {
+        if (icon.isLeftRightSplit()) {
             drawLeftRightSplit(canvas);
         } else {
             drawTopBottomSplit(canvas);
@@ -73,29 +73,29 @@
 
         // The left half of the background image, excluding center channel
         RectF leftSide = new RectF(
-                icon.mOuterPadding,
-                icon.mOuterPadding,
-                (width / 2f) - (icon.mCenterChannelSize / 2f),
-                height - icon.mOuterPadding
+                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.mCenterChannelSize / 2f),
-                icon.mOuterPadding,
-                width - icon.mOuterPadding,
-                height - icon.mOuterPadding
+                (width / 2f) + (icon.getCenterChannelSize() / 2f),
+                0,
+                width,
+                height
         );
 
         drawCustomRoundedRect(canvas, leftSide, new float[]{
-                icon.mBigRadius, icon.mBigRadius,
-                icon.mSmallRadius, icon.mSmallRadius,
-                icon.mSmallRadius, icon.mSmallRadius,
-                icon.mBigRadius, icon.mBigRadius});
+                icon.getBigRadius(), icon.getBigRadius(),
+                icon.getSmallRadius(), icon.getSmallRadius(),
+                icon.getSmallRadius(), icon.getSmallRadius(),
+                icon.getBigRadius(), icon.getBigRadius()});
         drawCustomRoundedRect(canvas, rightSide, new float[]{
-                icon.mSmallRadius, icon.mSmallRadius,
-                icon.mBigRadius, icon.mBigRadius,
-                icon.mBigRadius, icon.mBigRadius,
-                icon.mSmallRadius, icon.mSmallRadius});
+                icon.getSmallRadius(), icon.getSmallRadius(),
+                icon.getBigRadius(), icon.getBigRadius(),
+                icon.getBigRadius(), icon.getBigRadius(),
+                icon.getSmallRadius(), icon.getSmallRadius()});
     }
 
     /**
@@ -108,29 +108,29 @@
 
         // The top half of the background image, excluding center channel
         RectF topSide = new RectF(
-                icon.mOuterPadding,
-                icon.mOuterPadding,
-                width - icon.mOuterPadding,
-                (height / 2f) - (icon.mCenterChannelSize / 2f)
+                0,
+                0,
+                width,
+                (height / 2f) - (icon.getCenterChannelSize() / 2f)
         );
         // The bottom half of the background image, excluding center channel
         RectF bottomSide = new RectF(
-                icon.mOuterPadding,
-                (height / 2f) + (icon.mCenterChannelSize / 2f),
-                width - icon.mOuterPadding,
-                height - icon.mOuterPadding
+                0,
+                (height / 2f) + (icon.getCenterChannelSize() / 2f),
+                width,
+                height
         );
 
         drawCustomRoundedRect(canvas, topSide, new float[]{
-                icon.mBigRadius, icon.mBigRadius,
-                icon.mBigRadius, icon.mBigRadius,
-                icon.mSmallRadius, icon.mSmallRadius,
-                icon.mSmallRadius, icon.mSmallRadius});
+                icon.getBigRadius(), icon.getBigRadius(),
+                icon.getBigRadius(), icon.getBigRadius(),
+                icon.getSmallRadius(), icon.getSmallRadius(),
+                icon.getSmallRadius(), icon.getSmallRadius()});
         drawCustomRoundedRect(canvas, bottomSide, new float[]{
-                icon.mSmallRadius, icon.mSmallRadius,
-                icon.mSmallRadius, icon.mSmallRadius,
-                icon.mBigRadius, icon.mBigRadius,
-                icon.mBigRadius, icon.mBigRadius});
+                icon.getSmallRadius(), icon.getSmallRadius(),
+                icon.getSmallRadius(), icon.getSmallRadius(),
+                icon.getBigRadius(), icon.getBigRadius(),
+                icon.getBigRadius(), icon.getBigRadius()});
     }
 
     /**
@@ -146,7 +146,7 @@
             c.drawDoubleRoundRect(rect, radii, EMPTY_RECT, ARRAY_OF_ZEROES, mBackgroundPaint);
         } else {
             // Fallback rectangle with uniform rounded corners
-            c.drawRoundRect(rect, icon.mBigRadius, icon.mBigRadius, mBackgroundPaint);
+            c.drawRoundRect(rect, icon.getBigRadius(), icon.getBigRadius(), mBackgroundPaint);
         }
     }
 
diff --git a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
new file mode 100644
index 0000000..2945979
--- /dev/null
+++ b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
@@ -0,0 +1,141 @@
+/*
+ * 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.graphics.Canvas
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import android.util.AttributeSet
+import android.view.Gravity
+import android.widget.FrameLayout
+import com.android.launcher3.DeviceProfile
+
+/**
+ * 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
+    }
+
+    // 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
+
+    private lateinit var parentIcon: AppPairIcon
+    private lateinit var appPairBackground: Drawable
+    private lateinit var appIcon1: Drawable
+    private lateinit var appIcon2: Drawable
+
+    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
+        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)
+
+        // 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()
+        layoutParams = lp
+
+        // Draw background
+        appPairBackground.draw(canvas)
+
+        // 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()
+
+        // 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()
+    }
+}
diff --git a/src/com/android/launcher3/celllayout/MulticellReorderAlgorithm.java b/src/com/android/launcher3/celllayout/MulticellReorderAlgorithm.java
index 7deb653..8d0cf13 100644
--- a/src/com/android/launcher3/celllayout/MulticellReorderAlgorithm.java
+++ b/src/com/android/launcher3/celllayout/MulticellReorderAlgorithm.java
@@ -48,28 +48,24 @@
     }
 
     @Override
-    public ItemConfiguration closestEmptySpaceReorder(int pixelX, int pixelY, int minSpanX,
-            int minSpanY, int spanX, int spanY) {
+    public ItemConfiguration closestEmptySpaceReorder(ReorderParameters reorderParameters) {
         return removeSeamFromSolution(simulateSeam(
-                () -> super.closestEmptySpaceReorder(pixelX, pixelY, minSpanX, minSpanY, spanX,
-                        spanY)));
+                () -> super.closestEmptySpaceReorder(reorderParameters))
+        );
     }
 
     @Override
-    public ItemConfiguration findReorderSolution(int pixelX, int pixelY, int minSpanX,
-            int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX,
-            ItemConfiguration solution) {
+    public ItemConfiguration findReorderSolution(ReorderParameters reorderParameters,
+            boolean decX) {
         return removeSeamFromSolution(simulateSeam(
-                () -> super.findReorderSolution(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY,
-                        direction, dragView, decX, solution)));
+                () -> super.findReorderSolution(reorderParameters, decX)));
     }
 
     @Override
-    public ItemConfiguration dropInPlaceSolution(int pixelX, int pixelY, int spanX,
-            int spanY,
-            View dragView) {
-        return removeSeamFromSolution(simulateSeam(
-                () -> super.dropInPlaceSolution(pixelX, pixelY, spanX, spanY, dragView)));
+    public ItemConfiguration dropInPlaceSolution(ReorderParameters reorderParameters) {
+        return removeSeamFromSolution(
+                simulateSeam(() -> super.dropInPlaceSolution(reorderParameters))
+        );
     }
 
     void addSeam() {
diff --git a/src/com/android/launcher3/celllayout/ReorderAlgorithm.java b/src/com/android/launcher3/celllayout/ReorderAlgorithm.java
index 7385c0a..8754b74 100644
--- a/src/com/android/launcher3/celllayout/ReorderAlgorithm.java
+++ b/src/com/android/launcher3/celllayout/ReorderAlgorithm.java
@@ -45,36 +45,28 @@
      * 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 pixelX    X coordinate in pixels in the screen
-     * @param pixelY    Y coordinate in pixels in the screen
-     * @param minSpanX  minimum possible horizontal span it will try to find a solution for.
-     * @param minSpanY  minimum possible vertical span it will try to find a solution for.
-     * @param spanX     horizontal cell span
-     * @param spanY     vertical cell span
-     * @param direction direction in which it will try to push the items intersecting the desired
-     *                  view
-     * @param dragView  view being dragged in reorder
-     * @param decX      whether it will decrease the horizontal or vertical span if it can't find a
-     *                  solution for the current span.
-     * @param solution  variable to store the solution
+     * @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(int pixelX, int pixelY, int minSpanX,
-            int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX,
-            ItemConfiguration solution) {
-        return findReorderSolutionRecursive(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY,
-                direction, dragView, decX, solution);
+    public ItemConfiguration findReorderSolution(ReorderParameters reorderParameters,
+            boolean decX) {
+        return findReorderSolutionRecursive(reorderParameters.getPixelX(),
+                reorderParameters.getPixelY(), reorderParameters.getMinSpanX(),
+                reorderParameters.getMinSpanY(), reorderParameters.getSpanX(),
+                reorderParameters.getSpanY(), mCellLayout.mDirectionVector,
+                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) {
+    private ItemConfiguration findReorderSolutionRecursive(int pixelX, int pixelY, int minSpanX,
+            int minSpanY, int spanX, int spanY, int[] direction, View dragView, boolean decX,
+            ItemConfiguration solution) {
         // Copy the current state into the solution. This solution will be manipulated as necessary.
         mCellLayout.copyCurrentStateToSolution(solution);
         // Copy the current occupied array into the temporary occupied array. This array will be
@@ -89,8 +81,8 @@
         boolean success;
         // First we try the exact nearest position of the item being dragged,
         // we will then want to try to move this around to other neighbouring positions
-        success = rearrangementExists(result[0], result[1], spanX, spanY, direction,
-                dragView, solution);
+        success = rearrangementExists(result[0], result[1], spanX, spanY, direction, dragView,
+                solution);
 
         if (!success) {
             // We try shrinking the widget down to size in an alternating pattern, shrink 1 in
@@ -135,10 +127,11 @@
         // and not by the views hash which is "random".
         // The views are sorted twice, once for the X position and a second time for the Y position
         // to ensure same order everytime.
-        Comparator comparator = Comparator.comparing(view ->
-                        ((CellLayoutLayoutParams) ((View) view).getLayoutParams()).getCellX())
-                .thenComparing(view ->
-                        ((CellLayoutLayoutParams) ((View) view).getLayoutParams()).getCellY());
+        Comparator comparator = Comparator.comparing(
+                view -> ((CellLayoutLayoutParams) ((View) view).getLayoutParams()).getCellX()
+        ).thenComparing(
+                view -> ((CellLayoutLayoutParams) ((View) view).getLayoutParams()).getCellY()
+        );
         List<View> views = solution.map.keySet().stream().sorted(comparator).toList();
         for (View child : views) {
             if (child == ignoreView) continue;
@@ -158,15 +151,13 @@
         // First we try to find a solution which respects the push mechanic. That is,
         // we try to find a solution such that no displaced item travels through another item
         // without also displacing that item.
-        if (attemptPushInDirection(intersectingViews, occupiedRect, direction,
-                ignoreView,
+        if (attemptPushInDirection(intersectingViews, occupiedRect, direction, ignoreView,
                 solution)) {
             return true;
         }
 
         // Next we try moving the views as a block, but without requiring the push mechanic.
-        if (addViewsToTempLocation(intersectingViews, occupiedRect, direction,
-                ignoreView,
+        if (addViewsToTempLocation(intersectingViews, occupiedRect, direction, ignoreView,
                 solution)) {
             return true;
         }
@@ -180,8 +171,8 @@
         return true;
     }
 
-    private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop,
-            int[] direction, ItemConfiguration currentState) {
+    private boolean addViewToTempLocation(View v, Rect rectOccupiedByPotentialDrop, int[] direction,
+            ItemConfiguration currentState) {
         CellAndSpan c = currentState.map.get(v);
         boolean success = false;
         mCellLayout.mTmpOccupied.markCells(c, false);
@@ -294,6 +285,11 @@
         return foundSolution;
     }
 
+    private void revertDir(int[] direction) {
+        direction[0] *= -1;
+        direction[1] *= -1;
+    }
+
     // This method tries to find a reordering solution which satisfies the push mechanic by trying
     // to push items in each of the cardinal directions, in an order based on the direction vector
     // passed.
@@ -302,91 +298,36 @@
         if ((Math.abs(direction[0]) + Math.abs(direction[1])) > 1) {
             // If the direction vector has two non-zero components, we try pushing
             // separately in each of the components.
-            int temp = direction[1];
-            direction[1] = 0;
-
-            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
-                    ignoreView, solution)) {
-                return true;
+            int temp;
+            for (int j = 0; j < 2; j++) {
+                for (int i = 1; i >= 0; i--) {
+                    temp = direction[i];
+                    direction[i] = 0;
+                    if (pushViewsToTempLocation(intersectingViews, occupied, direction, ignoreView,
+                            solution)) {
+                        return true;
+                    }
+                    direction[i] = temp;
+                }
+                revertDir(direction);
             }
-            direction[1] = temp;
-            temp = direction[0];
-            direction[0] = 0;
-
-            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
-                    ignoreView, solution)) {
-                return true;
-            }
-            // Revert the direction
-            direction[0] = temp;
-
-            // Now we try pushing in each component of the opposite direction
-            direction[0] *= -1;
-            direction[1] *= -1;
-            temp = direction[1];
-            direction[1] = 0;
-            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
-                    ignoreView, solution)) {
-                return true;
-            }
-
-            direction[1] = temp;
-            temp = direction[0];
-            direction[0] = 0;
-            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
-                    ignoreView, solution)) {
-                return true;
-            }
-            // revert the direction
-            direction[0] = temp;
-            direction[0] *= -1;
-            direction[1] *= -1;
-
         } else {
             // If the direction vector has a single non-zero component, we push first in the
             // direction of the vector
-            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
-                    ignoreView, solution)) {
-                return true;
+            int temp;
+            for (int j = 0; j < 2; j++) {
+                for (int i = 0; i < 2; i++) {
+                    if (pushViewsToTempLocation(intersectingViews, occupied, direction, ignoreView,
+                            solution)) {
+                        return true;
+                    }
+                    revertDir(direction);
+                }
+                // Swap the components
+                temp = direction[1];
+                direction[1] = direction[0];
+                direction[0] = temp;
             }
-            // Then we try the opposite direction
-            direction[0] *= -1;
-            direction[1] *= -1;
-            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
-                    ignoreView, solution)) {
-                return true;
-            }
-            // Switch the direction back
-            direction[0] *= -1;
-            direction[1] *= -1;
-
-            // If we have failed to find a push solution with the above, then we try
-            // to find a solution by pushing along the perpendicular axis.
-
-            // Swap the components
-            int temp = direction[1];
-            direction[1] = direction[0];
-            direction[0] = temp;
-            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
-                    ignoreView, solution)) {
-                return true;
-            }
-
-            // Then we try the opposite direction
-            direction[0] *= -1;
-            direction[1] *= -1;
-            if (pushViewsToTempLocation(intersectingViews, occupied, direction,
-                    ignoreView, solution)) {
-                return true;
-            }
-            // Switch the direction back
-            direction[0] *= -1;
-            direction[1] *= -1;
-
-            // Swap the components back
-            temp = direction[1];
-            direction[1] = direction[0];
-            direction[0] = temp;
         }
         return false;
     }
@@ -446,63 +387,59 @@
     /**
      * Returns a "reorder" if there is empty space without rearranging anything.
      *
-     * @param pixelX   X coordinate in pixels in the screen
-     * @param pixelY   Y coordinate in pixels in the screen
-     * @param spanX    horizontal cell span
-     * @param spanY    vertical cell span
-     * @param dragView view being dragged in reorder
      * @return the configuration that represents the found reorder
      */
-    public ItemConfiguration dropInPlaceSolution(int pixelX, int pixelY, int spanX,
-            int spanY, View dragView) {
-        int[] result = mCellLayout.findNearestAreaIgnoreOccupied(pixelX, pixelY, spanX, spanY,
-                new int[2]);
+    public ItemConfiguration dropInPlaceSolution(ReorderParameters reorderParameters) {
+        int[] result = mCellLayout.findNearestAreaIgnoreOccupied(reorderParameters.getPixelX(),
+                reorderParameters.getPixelY(), reorderParameters.getSpanX(),
+                reorderParameters.getSpanY(), new int[2]);
         ItemConfiguration solution = new ItemConfiguration();
         mCellLayout.copyCurrentStateToSolution(solution);
 
         solution.isSolution = !isConfigurationRegionOccupied(
-                new Rect(result[0], result[1], result[0] + spanX, result[1] + spanY),
-                solution,
-                dragView
-        );
+                new Rect(result[0], result[1], result[0] + reorderParameters.getSpanX(),
+                        result[1] + reorderParameters.getSpanY()), solution,
+                reorderParameters.getDragView());
         if (!solution.isSolution) {
             return solution;
         }
         solution.cellX = result[0];
         solution.cellY = result[1];
-        solution.spanX = spanX;
-        solution.spanY = spanY;
+        solution.spanX = reorderParameters.getSpanX();
+        solution.spanY = reorderParameters.getSpanY();
         return solution;
     }
 
-    private boolean isConfigurationRegionOccupied(Rect region,
-            ItemConfiguration configuration, View ignoreView) {
-        return configuration.map.entrySet()
+    private boolean isConfigurationRegionOccupied(Rect region, ItemConfiguration configuration,
+            View ignoreView) {
+        return configuration.map
+                .entrySet()
                 .stream()
                 .filter(entry -> entry.getKey() != ignoreView)
                 .map(Entry::getValue)
-                .anyMatch(cellAndSpan -> region.intersect(cellAndSpan.cellX, cellAndSpan.cellY,
+                .anyMatch(cellAndSpan -> region.intersect(
+                        cellAndSpan.cellX,
+                        cellAndSpan.cellY,
                         cellAndSpan.cellX + cellAndSpan.spanX,
-                        cellAndSpan.cellY + cellAndSpan.spanY));
+                        cellAndSpan.cellY + cellAndSpan.spanY
+                        )
+                );
     }
 
     /**
      * Returns a "reorder" where we simply drop the item in the closest empty space, without moving
      * any other item in the way.
      *
-     * @param pixelX X coordinate in pixels in the screen
-     * @param pixelY Y coordinate in pixels in the screen
-     * @param spanX  horizontal cell span
-     * @param spanY  vertical cell span
      * @return the configuration that represents the found reorder
      */
-    public ItemConfiguration closestEmptySpaceReorder(int pixelX, int pixelY,
-            int minSpanX, int minSpanY, int spanX, int spanY) {
+    public ItemConfiguration closestEmptySpaceReorder(ReorderParameters reorderParameters) {
         ItemConfiguration solution = new ItemConfiguration();
         int[] result = new int[2];
         int[] resultSpan = new int[2];
-        mCellLayout.findNearestVacantArea(pixelX, pixelY, minSpanX, minSpanY, spanX, spanY, result,
-                resultSpan);
+        mCellLayout.findNearestVacantArea(reorderParameters.getPixelX(),
+                reorderParameters.getPixelY(), reorderParameters.getMinSpanX(),
+                reorderParameters.getMinSpanY(), reorderParameters.getSpanX(),
+                reorderParameters.getSpanY(), result, resultSpan);
         if (result[0] >= 0 && result[1] >= 0) {
             mCellLayout.copyCurrentStateToSolution(solution);
             solution.cellX = result[0];
@@ -521,32 +458,19 @@
      * the workspace to make space for the new item, this function return a solution for that
      * reorder.
      *
-     * @param pixelX   X coordinate in the screen of the dragView in pixels
-     * @param pixelY   Y coordinate in the screen of the dragView in pixels
-     * @param minSpanX minimum horizontal span the item can be shrunk to
-     * @param minSpanY minimum vertical span the item can be shrunk to
-     * @param spanX    occupied horizontal span
-     * @param spanY    occupied vertical span
-     * @param dragView the view of the item being draged
      * @return returns a solution for the given parameters, the solution contains all the icons and
      * the locations they should be in the given solution.
      */
-    public ItemConfiguration calculateReorder(int pixelX, int pixelY, int minSpanX,
-            int minSpanY, int spanX, int spanY, View dragView) {
-        getDirectionVectorForDrop(pixelX, pixelY, spanX, spanY, dragView,
-                mCellLayout.mDirectionVector);
+    public ItemConfiguration calculateReorder(ReorderParameters reorderParameters) {
+        getDirectionVectorForDrop(reorderParameters, mCellLayout.mDirectionVector);
 
-        ItemConfiguration dropInPlaceSolution = dropInPlaceSolution(pixelX, pixelY, spanX, spanY,
-                dragView);
+        ItemConfiguration dropInPlaceSolution = dropInPlaceSolution(reorderParameters);
 
         // Find a solution involving pushing / displacing any items in the way
-        ItemConfiguration swapSolution = findReorderSolution(pixelX, pixelY, minSpanX,
-                minSpanY, spanX, spanY, mCellLayout.mDirectionVector, dragView, true,
-                new ItemConfiguration());
+        ItemConfiguration swapSolution = findReorderSolution(reorderParameters, true);
 
         // We attempt the approach which doesn't shuffle views at all
-        ItemConfiguration closestSpaceSolution = closestEmptySpaceReorder(pixelX, pixelY, minSpanX,
-                minSpanY, spanX, spanY);
+        ItemConfiguration closestSpaceSolution = closestEmptySpaceReorder(reorderParameters);
 
         // If the reorder solution requires resizing (shrinking) the item being dropped, we instead
         // favor a solution in which the item is not resized, but
@@ -586,21 +510,26 @@
      * those cells. Instead we use some heuristics to often lock the vector to up, down, left
      * or right, which helps make pushing feel right.
      */
-    private void getDirectionVectorForDrop(int dragViewCenterX, int dragViewCenterY, int spanX,
-            int spanY, View dragView, int[] resultDirection) {
+    public void getDirectionVectorForDrop(ReorderParameters reorderParameters,
+            int[] resultDirection) {
 
         //TODO(adamcohen) b/151776141 use the items visual center for the direction vector
         int[] targetDestination = new int[2];
 
-        mCellLayout.findNearestAreaIgnoreOccupied(dragViewCenterX, dragViewCenterY, spanX, spanY,
-                targetDestination);
+        mCellLayout.findNearestAreaIgnoreOccupied(reorderParameters.getPixelX(),
+                reorderParameters.getPixelY(), reorderParameters.getSpanX(),
+                reorderParameters.getSpanY(), targetDestination);
         Rect dragRect = new Rect();
-        mCellLayout.cellToRect(targetDestination[0], targetDestination[1], spanX, spanY, dragRect);
-        dragRect.offset(dragViewCenterX - dragRect.centerX(), dragViewCenterY - dragRect.centerY());
+        mCellLayout.cellToRect(targetDestination[0], targetDestination[1],
+                reorderParameters.getSpanX(), reorderParameters.getSpanY(), dragRect);
+        dragRect.offset(reorderParameters.getPixelX() - dragRect.centerX(),
+                reorderParameters.getPixelY() - dragRect.centerY());
 
         Rect region = new Rect(targetDestination[0], targetDestination[1],
-                targetDestination[0] + spanX, targetDestination[1] + spanY);
-        Rect dropRegionRect = mCellLayout.getIntersectingRectanglesInRegion(region, dragView);
+                targetDestination[0] + reorderParameters.getSpanX(),
+                targetDestination[1] + reorderParameters.getSpanY());
+        Rect dropRegionRect = mCellLayout.getIntersectingRectanglesInRegion(region,
+                reorderParameters.getDragView());
         if (dropRegionRect == null) dropRegionRect = new Rect(region);
 
         int dropRegionSpanX = dropRegionRect.width();
@@ -609,13 +538,17 @@
         mCellLayout.cellToRect(dropRegionRect.left, dropRegionRect.top, dropRegionRect.width(),
                 dropRegionRect.height(), dropRegionRect);
 
-        int deltaX = (dropRegionRect.centerX() - dragViewCenterX) / spanX;
-        int deltaY = (dropRegionRect.centerY() - dragViewCenterY) / spanY;
+        int deltaX = (dropRegionRect.centerX() - reorderParameters.getPixelX())
+                / reorderParameters.getSpanX();
+        int deltaY = (dropRegionRect.centerY() - reorderParameters.getPixelY())
+                / reorderParameters.getSpanY();
 
-        if (dropRegionSpanX == mCellLayout.getCountX() || spanX == mCellLayout.getCountX()) {
+        if (dropRegionSpanX == mCellLayout.getCountX()
+                || reorderParameters.getSpanX() == mCellLayout.getCountX()) {
             deltaX = 0;
         }
-        if (dropRegionSpanY == mCellLayout.getCountY() || spanY == mCellLayout.getCountY()) {
+        if (dropRegionSpanY == mCellLayout.getCountY()
+                || reorderParameters.getSpanY() == mCellLayout.getCountY()) {
             deltaY = 0;
         }
 
diff --git a/src/com/android/launcher3/celllayout/ReorderParameters.kt b/src/com/android/launcher3/celllayout/ReorderParameters.kt
new file mode 100644
index 0000000..3fdf35c
--- /dev/null
+++ b/src/com/android/launcher3/celllayout/ReorderParameters.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.celllayout
+
+import android.view.View
+
+class ReorderParameters(
+    val pixelX: Int,
+    val pixelY: Int,
+    val spanX: Int,
+    val spanY: Int,
+    val minSpanX: Int,
+    val minSpanY: Int,
+    val dragView: View?,
+    val solution: ItemConfiguration
+) {}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index bed6efb..2f62840 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -219,9 +219,6 @@
     public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag(270393108, "NOTIFY_CRASHES",
             TEAMFOOD, "Sends a notification whenever launcher encounters an uncaught exception.");
 
-    public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(270395798,
-            "ENABLE_TRANSIENT_TASKBAR", ENABLED, "Enables transient taskbar.");
-
     public static final boolean ENABLE_TASKBAR_NAVBAR_UNIFICATION =
             enableTaskbarNavbarUnification();
 
@@ -270,10 +267,6 @@
     public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693,
             "IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps");
 
-    public static final BooleanFlag ENABLE_PEOPLE_TILE_PREVIEW = getDebugFlag(270391653,
-            "ENABLE_PEOPLE_TILE_PREVIEW", DISABLED,
-            "Experimental: Shows conversation shortcuts on home screen as search results");
-
     public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag(270391638,
             "FOLDER_NAME_MAJORITY_RANKING", ENABLED,
             "Suggests folder names based on majority based ranking.");
@@ -491,10 +484,10 @@
 
     // TODO(Block 33): Clean up flags
     public static final BooleanFlag ENABLE_ALL_APPS_RV_PREINFLATION = getDebugFlag(288161355,
-            "ENABLE_ALL_APPS_RV_PREINFLATION", ENABLED,
+            "ENABLE_ALL_APPS_RV_PREINFLATION", TEAMFOOD,
             "Enables preinflating all apps icons to avoid scrolling jank.");
     public static final BooleanFlag ALL_APPS_GONE_VISIBILITY = getDebugFlag(291651514,
-            "ALL_APPS_GONE_VISIBILITY", ENABLED,
+            "ALL_APPS_GONE_VISIBILITY", TEAMFOOD,
             "Set all apps container view's hidden visibility to GONE instead of INVISIBLE.");
 
     // TODO(Block 34): Empty block
diff --git a/src/com/android/launcher3/dragndrop/AddItemDragLayer.java b/src/com/android/launcher3/dragndrop/SimpleDragLayer.java
similarity index 70%
rename from src/com/android/launcher3/dragndrop/AddItemDragLayer.java
rename to src/com/android/launcher3/dragndrop/SimpleDragLayer.java
index 5b52c3d..e42ba72 100644
--- a/src/com/android/launcher3/dragndrop/AddItemDragLayer.java
+++ b/src/com/android/launcher3/dragndrop/SimpleDragLayer.java
@@ -20,18 +20,20 @@
 import android.util.AttributeSet;
 
 import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
 
 /**
- * Drag layer for {@link AddItemActivity}.
+ * A concrete {@link BaseDragLayer} that creates an empty list of {@link TouchController}s.
+ * @param <T> The {@link ActivityContext} hosting the drag layer.
  */
-public class AddItemDragLayer extends BaseDragLayer<AddItemActivity> {
+public class SimpleDragLayer<T extends Context & ActivityContext> extends BaseDragLayer<T> {
 
-    public AddItemDragLayer(Context context, AttributeSet attrs) {
+    public SimpleDragLayer(Context context, AttributeSet attrs) {
         this(context, attrs, /*alphaChannelCount= */ 1);
     }
 
-    public AddItemDragLayer(Context context, AttributeSet attrs, int alphaChannelCount) {
+    public SimpleDragLayer(Context context, AttributeSet attrs, int alphaChannelCount) {
         super(context, attrs, alphaChannelCount);
     }
 
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 8bf7ec2..084f829 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -210,7 +210,9 @@
                     @ViewDebug.IntToString(from = STATE_OPEN, to = "STATE_OPEN"),
             })
     private int mState = STATE_CLOSED;
-    private OnFolderStateChangedListener mOnFolderStateChangedListener;
+    private final List<OnFolderStateChangedListener> mOnFolderStateChangedListeners =
+            new ArrayList<>();
+    private OnFolderStateChangedListener mPriorityOnFolderStateChangedListener;
     @ViewDebug.ExportedProperty(category = "launcher")
     private boolean mRearrangeOnClose = false;
     boolean mItemsInvalidated = false;
@@ -1082,7 +1084,7 @@
 
     private void updateItemLocationsInDatabaseBatch(boolean isBind) {
         FolderGridOrganizer verifier = new FolderGridOrganizer(
-                mActivityContext.getDeviceProfile().inv).setFolderInfo(mInfo);
+                mActivityContext.getDeviceProfile()).setFolderInfo(mInfo);
 
         ArrayList<ItemInfo> items = new ArrayList<>();
         int total = mInfo.contents.size();
@@ -1381,7 +1383,7 @@
     @Override
     public void onAdd(WorkspaceItemInfo item, int rank) {
         FolderGridOrganizer verifier = new FolderGridOrganizer(
-                mActivityContext.getDeviceProfile().inv).setFolderInfo(mInfo);
+                mActivityContext.getDeviceProfile()).setFolderInfo(mInfo);
         verifier.updateRankAndPos(item, rank);
         mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase(item, mInfo.id, 0, item.cellX,
                 item.cellY);
@@ -1665,18 +1667,43 @@
         return windowBottomPx - folderBottomPx;
     }
 
+    /**
+     * Save this listener for the special case of when we update the state and concurrently
+     * add another listener to {@link #mOnFolderStateChangedListeners} to avoid a
+     * ConcurrentModificationException
+     */
+    public void setPriorityOnFolderStateChangedListener(OnFolderStateChangedListener listener) {
+        mPriorityOnFolderStateChangedListener = listener;
+    }
+
     private void setState(@FolderState int newState) {
         mState = newState;
-        if (mOnFolderStateChangedListener != null) {
-            mOnFolderStateChangedListener.onFolderStateChanged(mState);
+        if (mPriorityOnFolderStateChangedListener != null) {
+            mPriorityOnFolderStateChangedListener.onFolderStateChanged(mState);
+        }
+        for (OnFolderStateChangedListener listener : mOnFolderStateChangedListeners) {
+            if (listener != null) {
+                listener.onFolderStateChanged(mState);
+            }
         }
     }
 
-    public void setOnFolderStateChangedListener(@Nullable OnFolderStateChangedListener listener) {
-        mOnFolderStateChangedListener = listener;
+    /**
+     * Adds the provided listener to the running list of Folder listeners
+     * {@link #mOnFolderStateChangedListeners}
+     */
+    public void addOnFolderStateChangedListener(@Nullable OnFolderStateChangedListener listener) {
+        if (listener != null) {
+            mOnFolderStateChangedListeners.add(listener);
+        }
     }
 
-    /** Listener that can be registered via {@link Folder#setOnFolderStateChangedListener} */
+    /** Removes the provided listener from the running list of Folder listeners */
+    public void removeOnFolderStateChangedListener(OnFolderStateChangedListener listener) {
+        mOnFolderStateChangedListeners.remove(listener);
+    }
+
+    /** Listener that can be registered via {@link #addOnFolderStateChangedListener} */
     public interface OnFolderStateChangedListener {
         /** See {@link Folder.FolderState} */
         void onFolderStateChanged(@FolderState int newState);
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 9e2e2bf..a91373b 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -96,7 +96,7 @@
 
         mContext = folder.getContext();
         mDeviceProfile = folder.mActivityContext.getDeviceProfile();
-        mPreviewVerifier = new FolderGridOrganizer(mDeviceProfile.inv);
+        mPreviewVerifier = new FolderGridOrganizer(mDeviceProfile);
 
         mIsOpening = isOpening;
 
diff --git a/src/com/android/launcher3/folder/FolderGridOrganizer.java b/src/com/android/launcher3/folder/FolderGridOrganizer.java
index 4be82ed..cc24761 100644
--- a/src/com/android/launcher3/folder/FolderGridOrganizer.java
+++ b/src/com/android/launcher3/folder/FolderGridOrganizer.java
@@ -20,7 +20,7 @@
 
 import android.graphics.Point;
 
-import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 
@@ -41,11 +41,13 @@
     private int mCountX;
     private int mCountY;
     private boolean mDisplayingUpperLeftQuadrant = false;
+    private static final int PREVIEW_MAX_ROWS = 2;
+    private static final int PREVIEW_MAX_COLUMNS = 2;
 
     /**
      * Note: must call {@link #setFolderInfo(FolderInfo)} manually for verifier to work.
      */
-    public FolderGridOrganizer(InvariantDeviceProfile profile) {
+    public FolderGridOrganizer(DeviceProfile profile) {
         mMaxCountX = profile.numFolderColumns;
         mMaxCountY = profile.numFolderRows;
         mMaxItemsPerPage = mMaxCountX * mMaxCountY;
@@ -127,6 +129,7 @@
 
     /**
      * Updates the item's cellX, cellY and rank corresponding to the provided rank.
+     *
      * @return true if there was any change
      */
     public boolean updateRankAndPos(ItemInfo item, int rank) {
@@ -189,7 +192,7 @@
         if (page > 0 || mDisplayingUpperLeftQuadrant) {
             int col = rank % mCountX;
             int row = rank / mCountX;
-            return col < 2 && row < 2;
+            return col < PREVIEW_MAX_COLUMNS && row < PREVIEW_MAX_ROWS;
         }
         return rank < MAX_NUM_ITEMS_IN_PREVIEW;
     }
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index cb1dc4f..f058ae4 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -86,7 +86,6 @@
 import java.util.List;
 import java.util.function.Predicate;
 
-
 /**
  * An icon that can appear on in the workspace representing an {@link Folder}.
  */
@@ -221,7 +220,7 @@
 
         icon.setAccessibilityDelegate(activity.getAccessibilityDelegate());
 
-        icon.mPreviewVerifier = new FolderGridOrganizer(activity.getDeviceProfile().inv);
+        icon.mPreviewVerifier = new FolderGridOrganizer(activity.getDeviceProfile());
         icon.mPreviewVerifier.setFolderInfo(folderInfo);
         icon.updatePreviewItems(false);
 
@@ -634,6 +633,7 @@
         }
     }
 
+    /** Sets the visibility of the icon's title text */
     public void setTextVisible(boolean visible) {
         if (visible) {
             mFolderName.setVisibility(VISIBLE);
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index 36e5e1b..f2bed92 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -37,8 +37,6 @@
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.PagedView;
 import com.android.launcher3.R;
 import com.android.launcher3.ShortcutAndWidgetContainer;
@@ -101,14 +99,15 @@
 
     public FolderPagedView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        InvariantDeviceProfile profile = LauncherAppState.getIDP(context);
+        ActivityContext activityContext = ActivityContext.lookupContext(context);
+        DeviceProfile profile = activityContext.getDeviceProfile();
         mOrganizer = new FolderGridOrganizer(profile);
 
         mIsRtl = Utilities.isRtl(getResources());
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
 
         mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
-        mViewCache = ActivityContext.lookupContext(context).getViewCache();
+        mViewCache = activityContext.getViewCache();
     }
 
     public void setFolder(Folder folder) {
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index f90779c..d8388c2 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -549,12 +549,6 @@
         @UiEvent(doc = "Launcher item drop failed since there was not enough room on the screen.")
         LAUNCHER_ITEM_DROP_FAILED_INSUFFICIENT_SPACE(872),
 
-        @UiEvent(doc = "User long pressed on the taskbar background to hide the taskbar")
-        LAUNCHER_TASKBAR_LONGPRESS_HIDE(896),
-
-        @UiEvent(doc = "User long pressed on the taskbar gesture handle to show the taskbar")
-        LAUNCHER_TASKBAR_LONGPRESS_SHOW(897),
-
         @UiEvent(doc = "User clicks on the search icon on header to launch search in app.")
         LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH(913),
 
@@ -693,7 +687,16 @@
         LAUNCHER_TASKBAR_PINNED(1490),
 
         @UiEvent(doc = "User has unpinned taskbar using taskbar divider menu")
-        LAUNCHER_TASKBAR_UNPINNED(1491)
+        LAUNCHER_TASKBAR_UNPINNED(1491),
+
+        @UiEvent(doc = "User tapped private space lock button")
+        LAUNCHER_PRIVATE_SPACE_LOCK_TAP(1548),
+
+        @UiEvent(doc = "User tapped private space unlock button")
+        LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP(1549),
+
+        @UiEvent(doc = "User tapped private space settings button")
+        LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP(1550),
 
         // ADD MORE
         ;
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index f4ce360..a98ec64 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -411,7 +411,7 @@
                     mSessionHelper.getActiveSessions();
             installingPkgs.forEach(mApp.getIconCache()::updateSessionCache);
             FileLog.d(TAG, "loadWorkspace: Packages with active install sessions: "
-                    + installingPkgs.values());
+                    + installingPkgs.keySet().stream().map(info -> info.mPackageName).toList());
 
             final PackageUserKey tempPackageKey = new PackageUserKey(null, null);
             mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs);
@@ -440,10 +440,15 @@
                                 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;
                         }
                     }
@@ -481,16 +486,17 @@
             mItemsDeleted = c.commitDeleted();
 
             // Sort the folder items, update ranks, and make sure all preview items are high res.
-            FolderGridOrganizer verifier =
-                    new FolderGridOrganizer(mApp.getInvariantDeviceProfile());
+            List<FolderGridOrganizer> verifiers =
+                    mApp.getInvariantDeviceProfile().supportedProfiles.stream().map(
+                            FolderGridOrganizer::new).toList();
             for (FolderInfo folder : mBgDataModel.folders) {
                 Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR);
-                verifier.setFolderInfo(folder);
+                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.
+                // 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
@@ -498,9 +504,9 @@
                         info.rank = rank;
                     }
 
-                    if (info.usingLowResIcon()
-                            && info.itemType == Favorites.ITEM_TYPE_APPLICATION
-                            && verifier.isItemInPreview(info.rank)) {
+                    if (info.usingLowResIcon() && info.itemType == Favorites.ITEM_TYPE_APPLICATION
+                            && verifiers.stream().anyMatch(
+                                verifier -> verifier.isItemInPreview(info.rank))) {
                         mIconCache.getTitleAndIcon(info, false);
                     }
                 }
@@ -589,17 +595,17 @@
                             // 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;
-                                c.updater().put(Favorites.RESTORED,
-                                        c.restoreFlag).commit();
+                                FileLog.d(TAG, "restore started for installing app: " + targetPkg);
+                                c.updater().put(Favorites.RESTORED, c.restoreFlag).commit();
                             } else {
-                                c.markDeleted("Unrestored app removed: " + targetPkg);
+                                c.markDeleted("removing app that is not restored and not "
+                                        + "installing. package: " + targetPkg);
                                 return;
                             }
                         } else if (pmHelper.isAppOnSdcard(targetPkg, c.user)) {
@@ -610,7 +616,7 @@
                         } else if (!isSdCardReady) {
                             // SdCard is not ready yet. Package might get available,
                             // once it is ready.
-                            Log.d(TAG, "Missing pkg, will check later: " + targetPkg);
+                            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;
@@ -646,7 +652,8 @@
                             ShortcutInfo pinnedShortcut = mShortcutKeyToPinnedShortcuts.get(key);
                             if (pinnedShortcut == null) {
                                 // The shortcut is no longer valid.
-                                c.markDeleted("Pinned shortcut not found");
+                                c.markDeleted("Pinned shortcut not found for package: "
+                                        + key.getPackageName());
                                 return;
                             }
                             info = new WorkspaceItemInfo(pinnedShortcut, mApp.getContext());
@@ -816,7 +823,7 @@
                         } else {
                             Log.v(TAG, "Widget restore pending id=" + c.id
                                     + " appWidgetId=" + appWidgetId
-                                    + " status =" + c.restoreFlag);
+                                    + " status=" + c.restoreFlag);
                             appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId, component);
                             appWidgetInfo.restoreStatus = c.restoreFlag;
 
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index 139efc3..d2b7161 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -62,6 +62,7 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherSettings.Favorites;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.logging.FileLog;
 import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.provider.LauncherDbUtils;
 import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
@@ -262,7 +263,7 @@
      */
     public void tryMigrateDB() {
         if (!migrateGridIfNeeded()) {
-            Log.d(TAG, "Migration failed: resetting launcher database");
+            FileLog.d(TAG, "Migration failed: resetting launcher database");
             createEmptyDB();
             LauncherPrefs.get(mContext).putSync(
                     getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
@@ -282,15 +283,17 @@
         createDbIfNotExists();
         if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) {
             // If we have already create a new DB, ignore migration
+            Log.d(TAG, "migrateGridIfNeeded: new DB already created, skipping migration");
             return false;
         }
         InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
         if (!GridSizeMigrationUtil.needsToMigrate(mContext, idp)) {
+            Log.d(TAG, "migrateGridIfNeeded: no grid migration needed");
             return true;
         }
         String targetDbName = new DeviceGridState(idp).getDbFile();
         if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) {
-            Log.e(TAG, "migrateGridIfNeeded - target db is same as current: " + targetDbName);
+            Log.e(TAG, "migrateGridIfNeeded: target db is same as current: " + targetDbName);
             return false;
         }
         DatabaseHelper oldHelper = mOpenHelper;
@@ -299,6 +302,9 @@
         try {
             return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, idp, mOpenHelper,
                    oldHelper.getWritableDatabase());
+        } catch (Exception e) {
+            FileLog.e(TAG, "Failed to migrate grid", e);
+            return false;
         } finally {
             if (mOpenHelper != oldHelper) {
                 oldHelper.close();
diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java
index 9bf6d43..5b541d0 100644
--- a/src/com/android/launcher3/model/data/FolderInfo.java
+++ b/src/com/android/launcher3/model/data/FolderInfo.java
@@ -46,7 +46,6 @@
 import java.util.OptionalInt;
 import java.util.stream.IntStream;
 
-
 /**
  * Represents a folder containing shortcuts or apps.
  */
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index dbd13b3..dc8cd3a 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -89,9 +89,9 @@
 
     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",
-            "container", "cellX", "cellY", "spanX", "spanY", "intent"};
+            "container", "cellX", "cellY", "spanX", "spanY", "intent", "appWidgetProvider",
+            "appWidgetId", "restored"};
 
     /**
      * Tries to restore the backup DB if needed
@@ -141,16 +141,17 @@
      *   4. If restored from a single display backup, remove gaps between screenIds
      *   5. Override shortcuts that need to be replaced.
      *
-     * @return number of items deleted.
+     * @return number of items deleted
      */
     @VisibleForTesting
     protected int sanitizeDB(Context context, ModelDbController controller, SQLiteDatabase db,
             BackupManager backupManager) throws Exception {
-        FileLog.d(TAG, "Old Launcher Database before sanitizing:");
+        logFavoritesTable(db, "Old Launcher Database before sanitizing:", null, null);
         // Primary user ids
         long myProfileId = controller.getSerialNumberForUser(myUserHandle());
         long oldProfileId = getDefaultProfileId(db);
-        FileLog.d(TAG, "sanitizeDB: myProfileId=" + myProfileId + " oldProfileId=" + oldProfileId);
+        FileLog.d(TAG, "sanitizeDB: myProfileId= " + myProfileId
+                + ", oldProfileId= " + oldProfileId);
         LongSparseArray<Long> oldManagedProfileIds = getManagedProfileIds(db, oldProfileId);
         LongSparseArray<Long> profileMapping = new LongSparseArray<>(oldManagedProfileIds.size()
                 + 1);
@@ -182,7 +183,7 @@
         final String[] args = new String[profileIds.length];
         Arrays.fill(args, "?");
         final String where = "profileId NOT IN (" + TextUtils.join(", ", Arrays.asList(args)) + ")";
-        logUnrestoredItems(db, where, profileIds);
+        logFavoritesTable(db, "items to delete from unrestored profiles:", where, profileIds);
         int itemsDeletedCount = db.delete(Favorites.TABLE_NAME, where, profileIds);
         FileLog.d(TAG, itemsDeletedCount + " total items from unrestored user(s) were deleted");
 
@@ -242,47 +243,6 @@
     }
 
     /**
-     * Queries and logs the items we will delete from unrestored profiles in the launcher db.
-     * This is to understand why items might be missing during the restore process for Launcher.
-     * @param database the Launcher db to query from.
-     * @param where the SELECT statement to query items that will be deleted.
-     * @param profileIds the profile ID's the user will be migrating to.
-     */
-    private void logUnrestoredItems(SQLiteDatabase database, String where, String[] profileIds) {
-        try (Cursor itemsToDelete = database.query(
-                /* table */ Favorites.TABLE_NAME,
-                /* columns */ DB_COLUMNS_TO_LOG,
-                /* selection */ where,
-                /* selection args */ profileIds,
-                /* groupBy */ null,
-                /* having */ null,
-                /* orderBy */ null
-        )) {
-            if (itemsToDelete.moveToFirst()) {
-                String[] columnNames = itemsToDelete.getColumnNames();
-                StringBuilder stringBuilder = new StringBuilder(
-                        "items to be deleted from the Favorites Table during restore:\n"
-                );
-                do {
-                    for (String columnName : columnNames) {
-                        stringBuilder.append(columnName)
-                            .append("=")
-                            .append(itemsToDelete.getString(
-                                        itemsToDelete.getColumnIndex(columnName)))
-                            .append(" ");
-                    }
-                    stringBuilder.append("\n");
-                } while (itemsToDelete.moveToNext());
-                FileLog.d(TAG, stringBuilder.toString());
-            } else {
-                FileLog.d(TAG, "logDeletedItems: No items found to delete");
-            }
-        } catch (Exception e) {
-            FileLog.e(TAG, "logDeletedItems: Error reading from database", e);
-        }
-    }
-
-    /**
      * Remove gaps between screenIds to make sure no empty pages are left in between.
      *
      * e.g. [0, 3, 4, 6, 7] -> [0, 1, 2, 3, 4]
@@ -396,7 +356,7 @@
                     IntArray.fromConcatString(lp.get(APP_WIDGET_IDS)).toArray(),
                     host);
         } else {
-            FileLog.d(TAG, "No app widget ids to restore.");
+            FileLog.d(TAG, "No app widget ids were received from backup to restore.");
         }
 
         lp.remove(APP_WIDGET_IDS, OLD_APP_WIDGET_IDS);
@@ -409,16 +369,16 @@
     private void restoreAppWidgetIds(Context context, ModelDbController controller,
             int[] oldWidgetIds, int[] newWidgetIds, @NonNull AppWidgetHost host) {
         if (WidgetsModel.GO_DISABLE_WIDGETS) {
-            Log.e(TAG, "Skipping widget ID remap as widgets not supported");
+            FileLog.e(TAG, "Skipping widget ID remap as widgets not supported");
             host.deleteHost();
             return;
         }
         if (!RestoreDbTask.isPending(context)) {
             // Someone has already gone through our DB once, probably LoaderTask. Skip any further
             // modifications of the DB.
-            Log.e(TAG, "Skipping widget ID remap as DB already in use");
+            FileLog.e(TAG, "Skipping widget ID remap as DB already in use");
             for (int widgetId : newWidgetIds) {
-                Log.d(TAG, "Deleting widgetId: " + widgetId);
+                FileLog.d(TAG, "Deleting widgetId: " + widgetId);
                 host.deleteAppWidgetId(widgetId);
             }
             return;
@@ -426,7 +386,7 @@
 
         final AppWidgetManager widgets = AppWidgetManager.getInstance(context);
 
-        Log.d(TAG, "restoreAppWidgetIds: "
+        FileLog.d(TAG, "restoreAppWidgetIds: "
                 + "oldWidgetIds=" + IntArray.wrap(oldWidgetIds).toConcatString()
                 + ", newWidgetIds=" + IntArray.wrap(newWidgetIds).toConcatString());
 
@@ -434,7 +394,7 @@
         logDatabaseWidgetInfo(controller);
 
         for (int i = 0; i < oldWidgetIds.length; i++) {
-            Log.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
+            FileLog.i(TAG, "Widget state restore id " + oldWidgetIds[i] + " => " + newWidgetIds[i]);
 
             final AppWidgetProviderInfo provider = widgets.getAppWidgetInfo(newWidgetIds[i]);
             final int state;
@@ -454,7 +414,7 @@
             final String where = "appWidgetId=? and (restored & 1) = 1 and profileId=?";
             String profileId = Long.toString(mainProfileId);
             final String[] args = new String[] { oldWidgetId, profileId };
-            Log.d(TAG, "restoreAppWidgetIds: querying profile id=" + profileId
+            FileLog.d(TAG, "restoreAppWidgetIds: querying profile id=" + profileId
                     + " with controller profile ID=" + controllerProfileId);
             int result = new ContentWriter(context,
                     new ContentWriter.CommitParams(controller, where, args))
@@ -463,7 +423,7 @@
                     .commit();
             if (result == 0) {
                 // TODO(b/234700507): Remove the logs after the bug is fixed
-                Log.e(TAG, "restoreAppWidgetIds: remapping failed since the widget is not in"
+                FileLog.e(TAG, "restoreAppWidgetIds: remapping failed since the widget is not in"
                         + " the database anymore");
                 try (Cursor cursor = controller.getDb().query(
                         Favorites.TABLE_NAME,
@@ -471,7 +431,7 @@
                         "appWidgetId=?", new String[]{oldWidgetId}, null, null, null)) {
                     if (!cursor.moveToFirst()) {
                         // The widget no long exists.
-                        Log.d(TAG, "Deleting widgetId: " + newWidgetIds[i] + " with old id: "
+                        FileLog.d(TAG, "Deleting widgetId: " + newWidgetIds[i] + " with old id: "
                                 + oldWidgetId);
                         host.deleteAppWidgetId(newWidgetIds[i]);
                     }
@@ -523,7 +483,7 @@
             }
             builder.append("]");
             Log.d(TAG, "restoreAppWidgetIds: all widget ids in database: "
-                    + builder.toString());
+                    + builder);
         } catch (Exception ex) {
             Log.e(TAG, "Getting widget ids from the database failed", ex);
         }
@@ -572,4 +532,45 @@
                 Collectors.joining(" OR "));
     }
 
+    /**
+     * Queries and logs the items from the Favorites table in the launcher db.
+     * This is to understand why items might be missing during the restore process for Launcher.
+     * @param database The Launcher db to query from.
+     * @param logHeader First line in log statement, used to explain what is being logged.
+     * @param where The SELECT statement to query items.
+     * @param profileIds The profile ID's for each user profile.
+     */
+    public static void logFavoritesTable(SQLiteDatabase database, @NonNull String logHeader,
+            String where, String[] profileIds) {
+        try (Cursor itemsToDelete = database.query(
+                /* table */ Favorites.TABLE_NAME,
+                /* columns */ DB_COLUMNS_TO_LOG,
+                /* selection */ where,
+                /* selection args */ profileIds,
+                /* groupBy */ null,
+                /* having */ null,
+                /* orderBy */ null
+        )) {
+            if (itemsToDelete.moveToFirst()) {
+                String[] columnNames = itemsToDelete.getColumnNames();
+                StringBuilder stringBuilder = new StringBuilder(logHeader + "\n");
+                do {
+                    for (String columnName : columnNames) {
+                        stringBuilder.append(columnName)
+                                .append("=")
+                                .append(itemsToDelete.getString(
+                                        itemsToDelete.getColumnIndex(columnName)))
+                                .append(" ");
+                    }
+                    stringBuilder.append("\n");
+                } while (itemsToDelete.moveToNext());
+                FileLog.d(TAG, stringBuilder.toString());
+            } else {
+                FileLog.d(TAG, "logFavoritesTable: No items found from query for"
+                        + "\"" + logHeader + "\"");
+            }
+        } catch (Exception e) {
+            FileLog.e(TAG, "logFavoritesTable: Error reading from database", e);
+        }
+    }
 }
diff --git a/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt b/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
index ebbff51..7502a43 100644
--- a/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
+++ b/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt
@@ -40,13 +40,28 @@
         return specsGroup
     }
 
+    private fun getSpecIgnoringDimensionType(
+        availableSize: Int,
+        specsGroup: ResponsiveSpecGroup<HotseatSpec>
+    ): HotseatSpec? {
+        val specWidth = specsGroup.widthSpecs.firstOrNull { availableSize <= it.maxAvailableSize }
+        val specHeight = specsGroup.heightSpecs.firstOrNull { availableSize <= it.maxAvailableSize }
+        return specWidth ?: specHeight
+    }
+
     fun getCalculatedSpec(
         aspectRatio: Float,
         dimensionType: DimensionType,
-        availableSpace: Int
+        availableSpace: Int,
     ): CalculatedHotseatSpec {
         val specsGroup = getSpecsByAspectRatio(aspectRatio)
-        val spec = specsGroup.getSpec(dimensionType, availableSpace)
+
+        // TODO(b/315548992): Ignore the dimension type to prevent crash before launcher
+        //  data migration is finished. The restore process allows the initialization of
+        //  an invalid or disabled grid until the data is restored and migrated.
+        val spec = getSpecIgnoringDimensionType(availableSpace, specsGroup)
+        check(spec != null) { "No available spec found within $availableSpace. $specsGroup" }
+        // val spec = specsGroup.getSpec(dimensionType, availableSpace)
         return CalculatedHotseatSpec(availableSpace, spec)
     }
 
diff --git a/src/com/android/launcher3/responsive/ResponsiveSpecGroup.kt b/src/com/android/launcher3/responsive/ResponsiveSpecGroup.kt
index b233d7c..a758be8 100644
--- a/src/com/android/launcher3/responsive/ResponsiveSpecGroup.kt
+++ b/src/com/android/launcher3/responsive/ResponsiveSpecGroup.kt
@@ -18,6 +18,7 @@
 
 import android.content.res.TypedArray
 import com.android.launcher3.R
+import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
 import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
 
 /**
@@ -54,10 +55,29 @@
             } else {
                 heightSpecs.firstOrNull { availableSize <= it.maxAvailableSize }
             }
-        check(spec != null) { "No available $type spec found within $availableSize." }
+        check(spec != null) { "No available $type spec found within $availableSize. $this" }
         return spec
     }
 
+    override fun toString(): String {
+        fun printSpec(spec: IResponsiveSpec) =
+            when (spec.specType) {
+                ResponsiveSpecType.AllApps,
+                ResponsiveSpecType.Folder,
+                ResponsiveSpecType.Workspace -> (spec as ResponsiveSpec).toString()
+                ResponsiveSpecType.Hotseat -> (spec as HotseatSpec).toString()
+                ResponsiveSpecType.Cell -> (spec as CellSpec).toString()
+            }
+
+        val widthSpecsString = widthSpecs.joinToString(", ") { printSpec(it) }
+        val heightSpecsString = heightSpecs.joinToString(", ") { printSpec(it) }
+        return "ResponsiveSpecGroup(" +
+            "aspectRatio=${aspectRatio}, " +
+            "widthSpecs=[${widthSpecsString}], " +
+            "heightSpecs=[${heightSpecsString}]" +
+            ")"
+    }
+
     companion object {
         const val XML_GROUP_NAME = "specs"
 
diff --git a/src/com/android/launcher3/shortcuts/ShortcutRequest.java b/src/com/android/launcher3/shortcuts/ShortcutRequest.java
index 5291ce4..21efceb 100644
--- a/src/com/android/launcher3/shortcuts/ShortcutRequest.java
+++ b/src/com/android/launcher3/shortcuts/ShortcutRequest.java
@@ -24,10 +24,11 @@
 import android.content.pm.LauncherApps.ShortcutQuery;
 import android.content.pm.ShortcutInfo;
 import android.os.UserHandle;
-import android.util.Log;
 
 import androidx.annotation.Nullable;
 
+import com.android.launcher3.logging.FileLog;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
@@ -101,7 +102,7 @@
             return new QueryResult(mContext.getSystemService(LauncherApps.class)
                     .getShortcuts(mQuery, mUserHandle));
         } catch (SecurityException | IllegalStateException e) {
-            Log.e(TAG, "Failed to query for shortcuts", e);
+            FileLog.e(TAG, "Failed to query for shortcuts", e);
             return QueryResult.DEFAULT;
         }
     }
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 1b1d347..2c834bd 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -47,6 +47,7 @@
 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.DisplayController;
 import com.android.launcher3.util.ResourceBasedOverride;
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
 
@@ -179,6 +180,11 @@
                         mDeviceProfile.numShownAllAppsColumns);
                 return response;
 
+            case TestProtocol.REQUEST_IS_TRANSIENT_TASKBAR:
+                response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+                        DisplayController.isTransientTaskbar(mContext));
+                return response;
+
             case TestProtocol.REQUEST_IS_TWO_PANELS:
                 response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
                         FOLDABLE_SINGLE_PAGE.get() ? false : mDeviceProfile.isTwoPanels);
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 3bce377..a9c2a2e 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -145,8 +145,8 @@
      */
     private static void onClickAppPairIcon(View v) {
         Launcher launcher = Launcher.getLauncher(v.getContext());
-        FolderInfo folderInfo = ((AppPairIcon) v).getInfo();
-        launcher.launchAppPair(folderInfo.contents.get(0), folderInfo.contents.get(1));
+        AppPairIcon appPairIcon = (AppPairIcon) v;
+        launcher.launchAppPair(appPairIcon);
     }
 
     /**
diff --git a/src/com/android/launcher3/util/DimensionUtils.kt b/src/com/android/launcher3/util/DimensionUtils.kt
index 0eb0e08..63e919a 100644
--- a/src/com/android/launcher3/util/DimensionUtils.kt
+++ b/src/com/android/launcher3/util/DimensionUtils.kt
@@ -51,12 +51,12 @@
         // Taskbar on phone, portrait
         if (!deviceProfile.isLandscape) {
             p.x = ViewGroup.LayoutParams.MATCH_PARENT
-            p.y = res.getDimensionPixelSize(R.dimen.taskbar_size)
+            p.y = res.getDimensionPixelSize(R.dimen.taskbar_phone_size)
             return p
         }
 
         // Taskbar on phone, landscape
-        p.x = res.getDimensionPixelSize(R.dimen.taskbar_size)
+        p.x = res.getDimensionPixelSize(R.dimen.taskbar_phone_size)
         p.y = ViewGroup.LayoutParams.MATCH_PARENT
         return p
     }
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 4c83668..18f583d 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -22,7 +22,6 @@
 import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
 import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_KEY;
 import static com.android.launcher3.Utilities.dpiFromPx;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TRANSIENT_TASKBAR;
 import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
@@ -71,7 +70,7 @@
 
     private static final String TAG = "DisplayController";
     private static final boolean DEBUG = false;
-    private static boolean sTransientTaskbarStatusForTests;
+    private static boolean sTransientTaskbarStatusForTests = true;
 
     // TODO(b/254119092) remove all logs with this tag
     public static final String TASKBAR_NOT_DESTROYED_TAG = "b/254119092";
@@ -410,18 +409,19 @@
          * Returns whether taskbar is transient.
          */
         public boolean isTransientTaskbar() {
-            // TODO(b/258604917): Once ENABLE_TASKBAR_PINNING is enabled, remove usage of
-            //  sTransientTaskbarStatusForTests and update test to directly
-            //  toggle shred preference to switch transient taskbar on/of
-            if (!Utilities.isRunningInTestHarness()
-                    && enableTaskbarPinning()
-                    && mIsTaskbarPinned) {
+            if (navigationMode != NavigationMode.NO_BUTTON) {
                 return false;
             }
-            return navigationMode == NavigationMode.NO_BUTTON
-                    && (Utilities.isRunningInTestHarness()
-                    ? sTransientTaskbarStatusForTests
-                    : ENABLE_TRANSIENT_TASKBAR.get() && !mIsTaskbarPinned);
+            if (Utilities.isRunningInTestHarness()) {
+                // TODO(b/258604917): Once ENABLE_TASKBAR_PINNING is enabled, remove usage of
+                //  sTransientTaskbarStatusForTests and update test to directly
+                //  toggle shared preference to switch transient taskbar on/off.
+                return sTransientTaskbarStatusForTests;
+            }
+            if (enableTaskbarPinning()) {
+                return !mIsTaskbarPinned;
+            }
+            return true;
         }
 
         /**
@@ -485,6 +485,7 @@
         pw.println("  currentSize=" + info.currentSize);
         info.mPerDisplayBounds.forEach((key, value) -> pw.println(
                 "  perDisplayBounds - " + key + ": " + value));
+        pw.println("  isTransientTaskbar=" + info.isTransientTaskbar());
     }
 
     /**
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index e32fec2..4f20bbc 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -62,7 +62,7 @@
     public static final VibrationEffect EFFECT_CLICK =
             createPredefined(VibrationEffect.EFFECT_CLICK);
 
-    private static final float LOW_TICK_SCALE = 0.7f;
+    private static final float LOW_TICK_SCALE = 0.9f;
     private static final float DRAG_TEXTURE_SCALE = 0.03f;
     private static final float DRAG_COMMIT_SCALE = 0.5f;
     private static final float DRAG_BUMP_SCALE = 0.4f;
@@ -240,7 +240,7 @@
 
     /** Indicates that search has been invoked. */
     public void vibrateForSearch() {
-        if (mSearchEffect != null && FeatureFlags.ENABLE_SEARCH_HAPTIC_COMMIT.get()) {
+        if (mSearchEffect != null) {
             vibrate(mSearchEffect);
         }
     }
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index e4df413..a1cd697 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -41,6 +41,7 @@
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.testing.shared.ResourceUtils;
 import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.TouchController;
@@ -559,7 +560,8 @@
             DeviceProfile dp = mActivity.getDeviceProfile();
             if (dp.isTaskbarPresent) {
                 // Ignore taskbar gesture insets to avoid interfering with TouchControllers.
-                gestureInsetBottom = Math.max(0, gestureInsetBottom - dp.taskbarHeight);
+                gestureInsetBottom = ResourceUtils.getNavbarSize(
+                        ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, getResources());
             }
             mSystemGestureRegion.set(
                     Math.max(gestureInsets.left, imeInset.left),
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index cbc85b6..5cdad03 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -166,12 +166,16 @@
         return show(activityContext, targetRect, items, shouldAddArrow, 0 /* width */);
     }
 
-    public static <T extends Context & ActivityContext> OptionsPopupView<T> show(
-            ActivityContext activityContext,
+    @Nullable
+    private static <T extends Context & ActivityContext> OptionsPopupView<T> show(
+            @Nullable ActivityContext activityContext,
             RectF targetRect,
             List<OptionItem> items,
             boolean shouldAddArrow,
             int width) {
+        if (activityContext == null) {
+            return null;
+        }
         OptionsPopupView<T> popup = (OptionsPopupView<T>) activityContext.getLayoutInflater()
                 .inflate(R.layout.longpress_options_menu, activityContext.getDragLayer(), false);
         popup.mTargetRect = targetRect;
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 5ec1022..5171fa2 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -16,6 +16,7 @@
 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.LauncherPrefs.WIDGETS_EDUCATION_TIP_SEEN;
 
 import android.content.Context;
@@ -67,6 +68,8 @@
     protected int mNavBarScrimHeight;
     private final Paint mNavBarScrimPaint;
 
+    private boolean mDisableNavBarScrim = false;
+
     public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         mContentHorizontalMargin = getResources().getDimensionPixelSize(
@@ -105,6 +108,7 @@
             mNavBarScrimPaint.setColor(navBarScrimColor);
             invalidate();
         }
+        setupNavBarColor();
     }
 
     @Override
@@ -146,8 +150,15 @@
         }
     }
 
+    /** Enables or disables the sheet's nav bar scrim. */
+    public void disableNavBarScrim(boolean disable) {
+        mDisableNavBarScrim = disable;
+    }
+
     private int getNavBarScrimHeight(WindowInsets insets) {
-        if (Utilities.ATLEAST_Q) {
+        if (mDisableNavBarScrim) {
+            return 0;
+        } else if (Utilities.ATLEAST_Q) {
             return insets.getTappableElementInsets().bottom;
         } else {
             return insets.getStableInsetBottom();
@@ -181,12 +192,8 @@
         DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
         int widthUsed;
         if (deviceProfile.isTablet) {
-            int margin = deviceProfile.allAppsLeftRightMargin;
-            if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
-                margin = getResources().getDimensionPixelSize(
-                        R.dimen.widget_picker_landscape_tablet_left_right_margin);
-            }
-            widthUsed = Math.max(2 * margin, 2 * (mInsets.left + mInsets.right));
+            widthUsed = Math.max(2 * getTabletMargin(deviceProfile),
+                    2 * (mInsets.left + mInsets.right));
         } else if (mInsets.bottom > 0) {
             widthUsed = mInsets.left + mInsets.right;
         } else {
@@ -201,6 +208,18 @@
                 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);
+        }
+        return deviceProfile.allAppsLeftRightMargin;
+    }
+
     @Override
     protected Interpolator getIdleInterpolator() {
         return mActivityContext.getDeviceProfile().isTablet
@@ -218,10 +237,18 @@
     }
 
     protected void setupNavBarColor() {
-        boolean isSheetDark = Themes.getAttrBoolean(getContext(), R.attr.isMainColorDark);
-        getSystemUiController().updateUiState(
-                SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET,
-                isSheetDark ? SystemUiController.FLAG_DARK_NAV : SystemUiController.FLAG_LIGHT_NAV);
+        boolean isNavBarDark = Themes.getAttrBoolean(getContext(), R.attr.isMainColorDark);
+
+        // In light mode, landscape reverses navbar background color.
+        boolean isPhoneLandscape =
+                !mActivityContext.getDeviceProfile().isTablet && mInsets.bottom == 0;
+        if (!isNavBarDark && isPhoneLandscape) {
+            isNavBarDark = true;
+        }
+
+        getSystemUiController().updateUiState(SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET,
+                isNavBarDark ? SystemUiController.FLAG_DARK_NAV
+                        : SystemUiController.FLAG_LIGHT_NAV);
     }
 
     protected SystemUiController getSystemUiController() {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index da90f17..e9a590b 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -17,6 +17,7 @@
 
 import static android.view.View.MeasureSpec.makeMeasureSpec;
 
+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.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
@@ -62,7 +63,6 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.model.UserManagerState;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.pm.UserCache;
@@ -163,9 +163,7 @@
     private boolean mIsInSearchMode;
     private boolean mIsNoWidgetsViewNeeded;
     @Px private int mMaxSpanPerRow;
-    private final DeviceProfile mDeviceProfile;
-
-    private int mOrientation;
+    protected DeviceProfile mDeviceProfile;
 
     protected TextView mNoWidgetsView;
     protected StickyHeaderLayout mSearchScrollView;
@@ -179,7 +177,6 @@
     public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
         mDeviceProfile = mActivityContext.getDeviceProfile();
-        mOrientation = context.getResources().getConfiguration().orientation;
         mUserCache = UserCache.INSTANCE.get(context);
         mHasWorkProfile = mUserCache.getUserProfiles()
                 .stream()
@@ -676,30 +673,26 @@
 
     /** Shows the {@link WidgetsFullSheet} on the launcher. */
     public static WidgetsFullSheet show(BaseActivity activity, boolean animate) {
-        boolean isTwoPane = activity.getDeviceProfile().isTablet
-                && activity.getDeviceProfile().isLandscape
-                && (!activity.getDeviceProfile().isTwoPanels
-                    || FeatureFlags.UNFOLDED_WIDGET_PICKER.get());
-
-        WidgetsFullSheet sheet;
-        if (isTwoPane) {
-            sheet = (WidgetsTwoPaneSheet) activity.getLayoutInflater().inflate(
-                    R.layout.widgets_two_pane_sheet,
-                    activity.getDragLayer(),
-                    false);
-        } else {
-            sheet = (WidgetsFullSheet) activity.getLayoutInflater().inflate(
-                    R.layout.widgets_full_sheet,
-                    activity.getDragLayer(),
-                    false);
-        }
-
+        WidgetsFullSheet sheet = (WidgetsFullSheet) activity.getLayoutInflater().inflate(
+                getWidgetSheetId(activity),
+                activity.getDragLayer(),
+                false);
         sheet.attachToContainer();
         sheet.mIsOpen = true;
         sheet.open(animate);
         return sheet;
     }
 
+    private static int getWidgetSheetId(BaseActivity activity) {
+        boolean isTwoPane = (activity.getDeviceProfile().isTablet
+                && activity.getDeviceProfile().isLandscape
+                && !activity.getDeviceProfile().isTwoPanels)
+                // Enables two pane picker for unfolded foldables if the flag is on.
+                || (activity.getDeviceProfile().isTwoPanels && enableUnfoldedTwoPanePicker());
+
+        return isTwoPane ? R.layout.widgets_two_pane_sheet : R.layout.widgets_full_sheet;
+    }
+
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         return isTouchOnScrollbar(ev) || super.onInterceptTouchEvent(ev);
@@ -790,17 +783,25 @@
         if (mIsInSearchMode) {
             mSearchBar.reset();
         }
+    }
 
-        // Checks the orientation of the screen
-        if (mOrientation != newConfig.orientation) {
-            mOrientation = newConfig.orientation;
-            if (mDeviceProfile.isTablet && !mDeviceProfile.isTwoPanels) {
-                handleClose(false);
-                show(BaseActivity.fromContext(getContext()), false);
-            } else {
-                reset();
-            }
+    @Override
+    public void onDeviceProfileChanged(DeviceProfile dp) {
+        if (mDeviceProfile.isLandscape != dp.isLandscape && dp.isTablet && !dp.isTwoPanels) {
+            handleClose(false);
+            show(BaseActivity.fromContext(getContext()), false);
+        } else {
+            reset();
         }
+
+        // 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()) {
+            handleClose(false);
+            show(BaseActivity.fromContext(getContext()), false);
+        }
+
+        mDeviceProfile = dp;
     }
 
     @Override
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index d85737b..c3ab08c 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.widget.picker;
 
+import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
+
 import android.content.Context;
 import android.graphics.Outline;
 import android.os.Process;
@@ -23,12 +25,15 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewOutlineProvider;
+import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.ScrollView;
 
 import androidx.annotation.NonNull;
+import androidx.annotation.Px;
 
 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;
@@ -46,6 +51,8 @@
 
     private static final int PERSONAL_TAB = 0;
     private static final int WORK_TAB = 1;
+    private static final int MINIMUM_WIDTH_LEFT_PANE_FOLDABLE_DP = 268;
+    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;
@@ -117,6 +124,29 @@
     }
 
     @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()) {
+            LinearLayout layout = mContent.findViewById(R.id.linear_layout_container);
+            FrameLayout leftPane = layout.findViewById(R.id.recycler_view_container);
+            LinearLayout.LayoutParams layoutParams = (LayoutParams) leftPane.getLayoutParams();
+            // Width is 1/3 of the sheet unless it's less than min width or max width
+            int leftPaneWidth = layout.getMeasuredWidth() / 3;
+            @Px int minLeftPaneWidthPx = Utilities.dpToPx(MINIMUM_WIDTH_LEFT_PANE_FOLDABLE_DP);
+            @Px int maxLeftPaneWidthPx = Utilities.dpToPx(MAXIMUM_WIDTH_LEFT_PANE_FOLDABLE_DP);
+            if (leftPaneWidth < minLeftPaneWidthPx) {
+                layoutParams.width = minLeftPaneWidthPx;
+            } else if (leftPaneWidth > maxLeftPaneWidthPx) {
+                layoutParams.width = maxLeftPaneWidthPx;
+            } else {
+                layoutParams.width = 0;
+            }
+            layoutParams.weight = layoutParams.width == 0 ? 0.33F : 0;
+            leftPane.setLayoutParams(layoutParams);
+        }
+    }
+
+    @Override
     public void onRecommendedWidgetsBound() {
         super.onRecommendedWidgetsBound();
 
diff --git a/tests/assets/ReorderWidgets/full_reorder_case b/tests/assets/ReorderWidgets/full_reorder_case
index 33ebaae..850e4fd 100644
--- a/tests/assets/ReorderWidgets/full_reorder_case
+++ b/tests/assets/ReorderWidgets/full_reorder_case
@@ -20,7 +20,7 @@
 bbmm
 iimm
 iiaa
-arguments: 0 3
+arguments: 0 2
 board: 4x4
 xxxx
 bbii
diff --git a/tests/assets/ReorderWidgets/simple_reorder_case b/tests/assets/ReorderWidgets/simple_reorder_case
index f5eb7b6..2c50ce4 100644
--- a/tests/assets/ReorderWidgets/simple_reorder_case
+++ b/tests/assets/ReorderWidgets/simple_reorder_case
@@ -34,7 +34,7 @@
 --mm
 --mm
 ----
-arguments: 3 3
+arguments: 2 2
 board: 4x4
 xxxx
 ----
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
index 5f5cf5e..18752e9 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
@@ -38,8 +38,8 @@
 	iconSizePx: 147.0px (56.0dp)
 	iconTextSizePx: 38.0px (14.476191dp)
 	iconDrawablePaddingPx: 12.0px (4.571429dp)
-	inv.numFolderRows: 4
-	inv.numFolderColumns: 4
+	numFolderRows: 4
+	numFolderColumns: 4
 	folderCellWidthPx: 195.0px (74.28571dp)
 	folderCellHeightPx: 230.0px (87.61905dp)
 	folderChildIconSizePx: 147.0px (56.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
index 02bab0e..c0de8d8 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
@@ -38,8 +38,8 @@
 	iconSizePx: 147.0px (56.0dp)
 	iconTextSizePx: 38.0px (14.476191dp)
 	iconDrawablePaddingPx: 12.0px (4.571429dp)
-	inv.numFolderRows: 4
-	inv.numFolderColumns: 4
+	numFolderRows: 4
+	numFolderColumns: 4
 	folderCellWidthPx: 195.0px (74.28571dp)
 	folderCellHeightPx: 230.0px (87.61905dp)
 	folderChildIconSizePx: 147.0px (56.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
index 1ade779..920ba6f 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
@@ -38,8 +38,8 @@
 	iconSizePx: 147.0px (56.0dp)
 	iconTextSizePx: 0.0px (0.0dp)
 	iconDrawablePaddingPx: 0.0px (0.0dp)
-	inv.numFolderRows: 4
-	inv.numFolderColumns: 4
+	numFolderRows: 4
+	numFolderColumns: 4
 	folderCellWidthPx: 163.0px (62.095238dp)
 	folderCellHeightPx: 192.0px (73.14286dp)
 	folderChildIconSizePx: 123.0px (46.857143dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
index b0b745d..65460ec 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
@@ -38,8 +38,8 @@
 	iconSizePx: 147.0px (56.0dp)
 	iconTextSizePx: 0.0px (0.0dp)
 	iconDrawablePaddingPx: 0.0px (0.0dp)
-	inv.numFolderRows: 4
-	inv.numFolderColumns: 4
+	numFolderRows: 4
+	numFolderColumns: 4
 	folderCellWidthPx: 173.0px (65.90476dp)
 	folderCellHeightPx: 205.0px (78.09524dp)
 	folderChildIconSizePx: 131.0px (49.904762dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
index d7f3c1a..1781673 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
@@ -38,8 +38,8 @@
 	iconSizePx: 120.0px (60.0dp)
 	iconTextSizePx: 28.0px (14.0dp)
 	iconDrawablePaddingPx: 9.0px (4.5dp)
-	inv.numFolderRows: 3
-	inv.numFolderColumns: 3
+	numFolderRows: 3
+	numFolderColumns: 3
 	folderCellWidthPx: 240.0px (120.0dp)
 	folderCellHeightPx: 208.0px (104.0dp)
 	folderChildIconSizePx: 120.0px (60.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
index 20a2a99..bd9e267 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
@@ -38,8 +38,8 @@
 	iconSizePx: 120.0px (60.0dp)
 	iconTextSizePx: 28.0px (14.0dp)
 	iconDrawablePaddingPx: 9.0px (4.5dp)
-	inv.numFolderRows: 3
-	inv.numFolderColumns: 3
+	numFolderRows: 3
+	numFolderColumns: 3
 	folderCellWidthPx: 240.0px (120.0dp)
 	folderCellHeightPx: 208.0px (104.0dp)
 	folderChildIconSizePx: 120.0px (60.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
index 94022e4..e983ef7 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
@@ -38,8 +38,8 @@
 	iconSizePx: 120.0px (60.0dp)
 	iconTextSizePx: 28.0px (14.0dp)
 	iconDrawablePaddingPx: 9.0px (4.5dp)
-	inv.numFolderRows: 3
-	inv.numFolderColumns: 3
+	numFolderRows: 3
+	numFolderColumns: 3
 	folderCellWidthPx: 204.0px (102.0dp)
 	folderCellHeightPx: 240.0px (120.0dp)
 	folderChildIconSizePx: 120.0px (60.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
index 7977204..aa92838 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
@@ -38,8 +38,8 @@
 	iconSizePx: 120.0px (60.0dp)
 	iconTextSizePx: 28.0px (14.0dp)
 	iconDrawablePaddingPx: 9.0px (4.5dp)
-	inv.numFolderRows: 3
-	inv.numFolderColumns: 3
+	numFolderRows: 3
+	numFolderColumns: 3
 	folderCellWidthPx: 204.0px (102.0dp)
 	folderCellHeightPx: 240.0px (120.0dp)
 	folderChildIconSizePx: 120.0px (60.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
index 0b17996..43e4a60 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
@@ -38,8 +38,8 @@
 	iconSizePx: 141.0px (53.714287dp)
 	iconTextSizePx: 34.0px (12.952381dp)
 	iconDrawablePaddingPx: 13.0px (4.952381dp)
-	inv.numFolderRows: 3
-	inv.numFolderColumns: 4
+	numFolderRows: 3
+	numFolderColumns: 4
 	folderCellWidthPx: 189.0px (72.0dp)
 	folderCellHeightPx: 219.0px (83.42857dp)
 	folderChildIconSizePx: 141.0px (53.714287dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
index 71fffe8..e7ea839 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
@@ -38,8 +38,8 @@
 	iconSizePx: 141.0px (53.714287dp)
 	iconTextSizePx: 34.0px (12.952381dp)
 	iconDrawablePaddingPx: 13.0px (4.952381dp)
-	inv.numFolderRows: 3
-	inv.numFolderColumns: 4
+	numFolderRows: 3
+	numFolderColumns: 4
 	folderCellWidthPx: 189.0px (72.0dp)
 	folderCellHeightPx: 219.0px (83.42857dp)
 	folderChildIconSizePx: 141.0px (53.714287dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
index 5da4ed0..043380c 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
@@ -38,8 +38,8 @@
 	iconSizePx: 141.0px (53.714287dp)
 	iconTextSizePx: 34.0px (12.952381dp)
 	iconDrawablePaddingPx: 13.0px (4.952381dp)
-	inv.numFolderRows: 3
-	inv.numFolderColumns: 4
+	numFolderRows: 3
+	numFolderColumns: 4
 	folderCellWidthPx: 189.0px (72.0dp)
 	folderCellHeightPx: 219.0px (83.42857dp)
 	folderChildIconSizePx: 141.0px (53.714287dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
index 359e530..a1b3e95 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
@@ -38,8 +38,8 @@
 	iconSizePx: 141.0px (53.714287dp)
 	iconTextSizePx: 34.0px (12.952381dp)
 	iconDrawablePaddingPx: 13.0px (4.952381dp)
-	inv.numFolderRows: 3
-	inv.numFolderColumns: 4
+	numFolderRows: 3
+	numFolderColumns: 4
 	folderCellWidthPx: 189.0px (72.0dp)
 	folderCellHeightPx: 219.0px (83.42857dp)
 	folderChildIconSizePx: 141.0px (53.714287dp)
diff --git a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index d5a645e..fcb5158 100644
--- a/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -30,6 +30,8 @@
     public static final String FOLDER_OPENED_MESSAGE = "TAPL_FOLDER_OPENED";
     public static final String SEARCH_RESULT_COMPLETE = "SEARCH_RESULT_COMPLETE";
     public static final String LAUNCHER_ACTIVITY_STOPPED_MESSAGE = "TAPL_LAUNCHER_ACTIVITY_STOPPED";
+    public static final String WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE =
+            "TAPL_WALLPAPER_OPEN_ANIMATION_FINISHED";
     public static final int NORMAL_STATE_ORDINAL = 0;
     public static final int SPRING_LOADED_STATE_ORDINAL = 1;
     public static final int OVERVIEW_STATE_ORDINAL = 2;
@@ -90,14 +92,13 @@
             "is-launcher-activity-started";
     public static final String REQUEST_FREEZE_APP_LIST = "freeze-app-list";
     public static final String REQUEST_UNFREEZE_APP_LIST = "unfreeze-app-list";
-    public static final String REQUEST_ENABLE_MANUAL_TASKBAR_STASHING = "enable-taskbar-stashing";
-    public static final String REQUEST_DISABLE_MANUAL_TASKBAR_STASHING = "disable-taskbar-stashing";
     public static final String REQUEST_ENABLE_BLOCK_TIMEOUT = "enable-block-timeout";
     public static final String REQUEST_DISABLE_BLOCK_TIMEOUT = "disable-block-timeout";
     public static final String REQUEST_ENABLE_TRANSIENT_TASKBAR = "enable-transient-taskbar";
     public static final String REQUEST_DISABLE_TRANSIENT_TASKBAR = "disable-transient-taskbar";
+    public static final String REQUEST_IS_TRANSIENT_TASKBAR = "is-transient-taskbar";
     public static final String REQUEST_UNSTASH_TASKBAR_IF_STASHED = "unstash-taskbar-if-stashed";
-    public static final String REQUEST_STASHED_TASKBAR_HEIGHT = "stashed-taskbar-height";
+    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_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags";
diff --git a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
index a421006..30b5663 100644
--- a/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/FakeInvariantDeviceProfileTest.kt
@@ -121,8 +121,8 @@
                     listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f))
                         .toTypedArray()
 
-                numFolderRows = 3
-                numFolderColumns = 3
+                numFolderRows = intArrayOf(3, 3, 3, 3)
+                numFolderColumns = intArrayOf(3, 3, 3, 3)
                 folderStyle = R.style.FolderStyleDefault
 
                 inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
@@ -204,8 +204,8 @@
                     listOf(PointF(16f, 64f), PointF(64f, 16f), PointF(16f, 64f), PointF(16f, 64f))
                         .toTypedArray()
 
-                numFolderRows = 3
-                numFolderColumns = 3
+                numFolderRows = intArrayOf(3, 3, 3, 3)
+                numFolderColumns = intArrayOf(3, 3, 3, 3)
                 folderStyle = R.style.FolderStyleDefault
 
                 inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_6_5
@@ -288,8 +288,8 @@
                     listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 20f), PointF(20f, 20f))
                         .toTypedArray()
 
-                numFolderRows = 3
-                numFolderColumns = 3
+                numFolderRows = intArrayOf(3, 3, 3, 3)
+                numFolderColumns = intArrayOf(3, 3, 3, 3)
                 folderStyle = R.style.FolderStyleDefault
 
                 inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
diff --git a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllApps.java b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllApps.java
index 4a42887..b4a5169 100644
--- a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllApps.java
+++ b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllApps.java
@@ -208,9 +208,10 @@
         InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
                 READ_DEVICE_CONFIG_PERMISSION);
         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(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
         mLauncher.pressBack();
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java b/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
index 28471f6..e1af774 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderAlgorithmUnitTest.java
@@ -191,9 +191,21 @@
 
         int[] testCaseXYinPixels = new int[2];
         cl.regionToCenterPoint(x, y, spanX, spanY, testCaseXYinPixels);
-        ItemConfiguration solution = cl.createReorderAlgorithm().calculateReorder(
-                testCaseXYinPixels[0], testCaseXYinPixels[1], minSpanX, minSpanY, spanX, spanY,
-                null);
+        ItemConfiguration configuration = new ItemConfiguration();
+        cl.copyCurrentStateToSolution(configuration);
+        ItemConfiguration solution = cl.createReorderAlgorithm()
+                .calculateReorder(
+                        new ReorderParameters(
+                                testCaseXYinPixels[0],
+                                testCaseXYinPixels[1],
+                                spanX,
+                                spanY,
+                                minSpanX,
+                                minSpanY,
+                                null,
+                                configuration
+                        )
+                );
         if (solution == null) {
             solution = new ItemConfiguration();
             solution.isSolution = false;
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
rename to tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
index 30bde0a..8bdcd03 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
+++ b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
@@ -58,12 +58,12 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class ReorderWidgets extends AbstractLauncherUiTest {
+public class TaplReorderWidgetsTest extends AbstractLauncherUiTest {
 
     @Rule
     public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
 
-    private static final String TAG = ReorderWidgets.class.getSimpleName();
+    private static final String TAG = TaplReorderWidgetsTest.class.getSimpleName();
 
     private static final List<String> FOLDABLE_GRIDS = List.of("normal", "practical", "reasonable");
 
diff --git a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
rename to tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
index c5d5de8..8200c94 100644
--- a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
+++ b/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
@@ -41,7 +41,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class PromiseIconUiTest extends AbstractLauncherUiTest {
+public class TaplPromiseIconUiTest extends AbstractLauncherUiTest {
 
     private int mSessionId = -1;
 
diff --git a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
new file mode 100644
index 0000000..60a4d2d
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
@@ -0,0 +1,184 @@
+/*
+ * 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 androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.util.Executors
+import com.android.launcher3.util.LauncherLayoutBuilder
+import com.android.launcher3.util.LauncherModelHelper
+import com.android.launcher3.util.LauncherModelHelper.*
+import com.android.launcher3.util.TestUtil
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import java.util.concurrent.CountDownLatch
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/** Tests to verify that folder icons are loaded with appropriate resolution */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class FolderIconLoadTest {
+    private lateinit var modelHelper: LauncherModelHelper
+
+    private val uniqueActivities =
+        listOf(
+            TEST_ACTIVITY,
+            TEST_ACTIVITY2,
+            TEST_ACTIVITY3,
+            TEST_ACTIVITY4,
+            TEST_ACTIVITY5,
+            TEST_ACTIVITY6,
+            TEST_ACTIVITY7,
+            TEST_ACTIVITY8,
+            TEST_ACTIVITY9,
+            TEST_ACTIVITY10,
+            TEST_ACTIVITY11,
+            TEST_ACTIVITY12,
+            TEST_ACTIVITY13,
+            TEST_ACTIVITY14
+        )
+
+    @Before
+    fun setUp() {
+        modelHelper = LauncherModelHelper()
+    }
+
+    @After
+    @Throws(Exception::class)
+    fun tearDown() {
+        modelHelper.destroy()
+        TestUtil.uninstallDummyApp()
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun folderLoadedWithHighRes_2x2() {
+        val items = setupAndLoadFolder(4)
+        assertThat(items.size).isEqualTo(4)
+        verifyHighRes(items, 0, 1, 2, 3)
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun folderLoadedWithHighRes_3x2() {
+        val items = setupAndLoadFolder(6)
+        assertThat(items.size).isEqualTo(6)
+        verifyHighRes(items, 0, 1, 3, 4)
+        verifyLowRes(items, 2, 5)
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun folderLoadedWithHighRes_max_3x3() {
+        val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
+        idp.numFolderColumns = intArrayOf(3, 3, 3, 3)
+        idp.numFolderRows = intArrayOf(3, 3, 3, 3)
+        recreateSupportedDeviceProfiles()
+
+        val items = setupAndLoadFolder(14)
+        verifyHighRes(items, 0, 1, 3, 4)
+        verifyLowRes(items, 2, 5, 6, 7, 8, 9, 10, 11, 12, 13)
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun folderLoadedWithHighRes_max_4x4() {
+        val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
+        idp.numFolderColumns = intArrayOf(4, 4, 4, 4)
+        idp.numFolderRows = intArrayOf(4, 4, 4, 4)
+        recreateSupportedDeviceProfiles()
+
+        val items = setupAndLoadFolder(14)
+        verifyHighRes(items, 0, 1, 4, 5)
+        verifyLowRes(items, 2, 3, 6, 7, 8, 9, 10, 11, 12, 13)
+    }
+
+    @Test
+    @Throws(Exception::class)
+    fun folderLoadedWithHighRes_differentFolderConfigurations() {
+        val idp = LauncherAppState.getIDP(modelHelper.sandboxContext)
+        idp.numFolderColumns = intArrayOf(4, 3, 4, 4)
+        idp.numFolderRows = intArrayOf(4, 3, 4, 4)
+        recreateSupportedDeviceProfiles()
+
+        val items = setupAndLoadFolder(14)
+        verifyHighRes(items, 0, 1, 3, 4, 5)
+        verifyLowRes(items, 2, 6, 7, 8, 9, 10, 11, 12, 13)
+    }
+
+    @Throws(Exception::class)
+    private fun setupAndLoadFolder(itemCount: Int): ArrayList<WorkspaceItemInfo> {
+        val builder =
+            LauncherLayoutBuilder()
+                .atWorkspace(0, 0, 1)
+                .putFolder("Sample")
+                .apply {
+                    for (i in 0..itemCount - 1) this.addApp(TEST_PACKAGE, uniqueActivities[i])
+                }
+                .build()
+
+        modelHelper.setupDefaultLayoutProvider(builder)
+        modelHelper.loadModelSync()
+
+        // The first load initializes the DB, load again so that icons are now used from the DB
+        // Wait for the icon cache to be updated and then reload
+        val app = LauncherAppState.getInstance(modelHelper.sandboxContext)
+        val cache = app.iconCache
+        while (cache.isIconUpdateInProgress) {
+            val wait = CountDownLatch(1)
+            Executors.MODEL_EXECUTOR.handler.postDelayed({ wait.countDown() }, 10)
+            wait.await()
+        }
+        TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) { cache.clearMemoryCache() }
+        // Reload again with correct icon state
+        app.model.forceReload()
+        modelHelper.loadModelSync()
+        val folders = modelHelper.getBgDataModel().folders
+
+        assertThat(folders.size()).isEqualTo(1)
+        assertThat(folders.valueAt(0).contents.size).isEqualTo(itemCount)
+        return folders.valueAt(0).contents
+    }
+
+    private fun verifyHighRes(items: ArrayList<WorkspaceItemInfo>, vararg indices: Int) {
+        for (index in indices) {
+            assertWithMessage("Index $index was not highRes")
+                .that(items[index].bitmap.isNullOrLowRes)
+                .isFalse()
+        }
+    }
+
+    private fun verifyLowRes(items: ArrayList<WorkspaceItemInfo>, vararg indices: Int) {
+        for (index in indices) {
+            assertWithMessage("Index $index was not lowRes")
+                .that(items[index].bitmap.isNullOrLowRes)
+                .isTrue()
+        }
+    }
+
+    /** Recreate DeviceProfiles after changing InvariantDeviceProfile */
+    private fun recreateSupportedDeviceProfiles() {
+        LauncherAppState.getIDP(modelHelper.sandboxContext).supportedProfiles =
+            LauncherAppState.getIDP(modelHelper.sandboxContext).supportedProfiles.map {
+                it.copy(modelHelper.sandboxContext)
+            }
+    }
+}
diff --git a/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java b/tests/src/com/android/launcher3/secondarydisplay/TaplSecondaryDisplayLauncherTest.java
similarity index 99%
rename from tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
rename to tests/src/com/android/launcher3/secondarydisplay/TaplSecondaryDisplayLauncherTest.java
index c7431f2..d7b9638 100644
--- a/tests/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncherTest.java
+++ b/tests/src/com/android/launcher3/secondarydisplay/TaplSecondaryDisplayLauncherTest.java
@@ -47,7 +47,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public final class SecondaryDisplayLauncherTest extends AbstractLauncherUiTest {
+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;
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 8ad2249..79d8c60 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -131,6 +131,8 @@
     /** Detects activity leaks and throws an exception if a leak is found. */
     public static void checkDetectedLeaks(LauncherInstrumentation launcher,
             boolean requireOneActiveActivityUnused) {
+        if (TestStabilityRule.isPresubmit()) return; // b/313501215
+
         final boolean requireOneActiveActivity =
                 false; // workaround for leaks when there is an unexpected Recents activity
 
@@ -255,7 +257,7 @@
         final RuleChain inner = RuleChain
                 .outerRule(new PortraitLandscapeRunner(this))
                 .around(new FailureWatcher(mLauncher, viewCaptureRule::getViewCaptureData))
-                .around(viewCaptureRule)
+                // .around(viewCaptureRule) // b/315482167
                 .around(new TestIsolationRule(mLauncher, true));
 
         return TestHelpers.isInLauncherProcess()
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
similarity index 99%
rename from tests/src/com/android/launcher3/ui/WorkProfileTest.java
rename to tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
index 485ef94..f818564 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
@@ -48,7 +48,7 @@
 import java.util.Objects;
 import java.util.function.Predicate;
 
-public class WorkProfileTest extends AbstractLauncherUiTest {
+public class TaplWorkProfileTest extends AbstractLauncherUiTest {
 
     private static final int WORK_PAGE = ActivityAllAppsContainerView.AdapterHolder.WORK;
 
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java
similarity index 91%
rename from tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
rename to tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java
index b2ce400..d96287f 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddConfigWidgetTest.java
@@ -52,7 +52,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class AddConfigWidgetTest extends AbstractLauncherUiTest {
+public class TaplAddConfigWidgetTest extends AbstractLauncherUiTest {
 
     @Rule
     public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
@@ -101,7 +101,7 @@
         // Verify that the widget id is valid and bound
         assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
 
-        setResult(acceptConfig);
+        setResultAndWaitForAnimation(acceptConfig);
         if (acceptConfig) {
             Wait.atMost("", new WidgetSearchCondition(), DEFAULT_ACTIVITY_TIMEOUT, mLauncher);
             assertNotNull(mAppWidgetManager.getAppWidgetInfo(mWidgetId));
@@ -112,12 +112,22 @@
         }
     }
 
-    private void setResult(boolean success) {
+    private static void setResult(boolean success) {
         getInstrumentation().getTargetContext().sendBroadcast(
                 WidgetConfigActivity.getCommandIntent(WidgetConfigActivity.class,
                         success ? "clickOK" : "clickCancel"));
     }
 
+    private void setResultAndWaitForAnimation(boolean success) {
+        if (mLauncher.isLauncher3()) {
+            setResult(success);
+        } else {
+            mLauncher.executeAndWaitForWallpaperAnimation(
+                    () -> setResult(success),
+                    "setting widget coinfig result");
+        }
+    }
+
     /**
      * Condition for searching widget id
      */
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
rename to tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
index fd4b7f1..27fda9b 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplAddWidgetTest.java
@@ -42,7 +42,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class AddWidgetTest extends AbstractLauncherUiTest {
+public class TaplAddWidgetTest extends AbstractLauncherUiTest {
 
     @Rule
     public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java
similarity index 99%
rename from tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
rename to tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java
index 32793cc..6aa746d 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplBindWidgetTest.java
@@ -76,7 +76,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class BindWidgetTest extends AbstractLauncherUiTest {
+public class TaplBindWidgetTest extends AbstractLauncherUiTest {
 
     @Rule
     public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java
similarity index 99%
rename from tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
rename to tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java
index 3c88f1d..f12f961 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplRequestPinItemTest.java
@@ -59,7 +59,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class RequestPinItemTest extends AbstractLauncherUiTest {
+public class TaplRequestPinItemTest extends AbstractLauncherUiTest {
 
     @Rule
     public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
diff --git a/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java b/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
index 465e9b4..bc73683 100644
--- a/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/TaplWidgetPickerTest.java
@@ -15,10 +15,6 @@
  */
 package com.android.launcher3.ui.widget;
 
-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;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
@@ -31,7 +27,6 @@
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
 import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
-import com.android.launcher3.util.rule.TestStabilityRule.Stability;
 import com.android.launcher3.widget.picker.WidgetsFullSheet;
 import com.android.launcher3.widget.picker.WidgetsRecyclerView;
 
@@ -65,11 +60,9 @@
      * Open Widget picker, make sure the widget picker can scroll and then go to home screen.
      */
     @Test
-    @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/303263644
     @ScreenRecord
     @PortraitLandscape
     public void testWidgets() {
-        // Testing if this will fix b/303263644
         mLauncher.goHome();
         // Test opening widgets.
         executeOnLauncher(launcher ->
diff --git a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplThemeIconsTest.java
similarity index 98%
rename from tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
rename to tests/src/com/android/launcher3/ui/workspace/TaplThemeIconsTest.java
index e21918f..a3d3344 100644
--- a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplThemeIconsTest.java
@@ -49,7 +49,7 @@
  * Note running these tests will clear the workspace on the device.
  */
 @LargeTest
-public class ThemeIconsTest extends AbstractLauncherUiTest {
+public class TaplThemeIconsTest extends AbstractLauncherUiTest {
 
     private static final String APP_NAME = "IconThemedActivity";
     private static final String SHORTCUT_NAME = "Shortcut 1";
diff --git a/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
similarity index 99%
rename from tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java
rename to tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
index e7112d1..3693163 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TwoPanelWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
@@ -54,7 +54,7 @@
  */
 @LargeTest
 @RunWith(AndroidJUnit4.class)
-public class TwoPanelWorkspaceTest extends AbstractLauncherUiTest {
+public class TaplTwoPanelWorkspaceTest extends AbstractLauncherUiTest {
 
     private AutoCloseable mLauncherLayout;
 
diff --git a/tests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
index 261436b..244dc26 100644
--- a/tests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -84,6 +84,17 @@
     public static final String TEST_ACTIVITY = "com.android.launcher3.tests.Activity2";
     public static final String TEST_ACTIVITY2 = "com.android.launcher3.tests.Activity3";
     public static final String TEST_ACTIVITY3 = "com.android.launcher3.tests.Activity4";
+    public static final String TEST_ACTIVITY4 = "com.android.launcher3.tests.Activity5";
+    public static final String TEST_ACTIVITY5 = "com.android.launcher3.tests.Activity6";
+    public static final String TEST_ACTIVITY6 = "com.android.launcher3.tests.Activity7";
+    public static final String TEST_ACTIVITY7 = "com.android.launcher3.tests.Activity8";
+    public static final String TEST_ACTIVITY8 = "com.android.launcher3.tests.Activity9";
+    public static final String TEST_ACTIVITY9 = "com.android.launcher3.tests.Activity10";
+    public static final String TEST_ACTIVITY10 = "com.android.launcher3.tests.Activity11";
+    public static final String TEST_ACTIVITY11 = "com.android.launcher3.tests.Activity12";
+    public static final String TEST_ACTIVITY12 = "com.android.launcher3.tests.Activity13";
+    public static final String TEST_ACTIVITY13 = "com.android.launcher3.tests.Activity14";
+    public static final String TEST_ACTIVITY14 = "com.android.launcher3.tests.Activity15";
 
     // Authority for providing a test default-workspace-layout data.
     private static final String TEST_PROVIDER_AUTHORITY =
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
index 51b7b18..dfccffc1 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/AlphaJumpDetector.java
@@ -33,17 +33,17 @@
 
     private static final IgnoreNode IGNORED_NODES_ROOT = buildIgnoreNodesTree(List.of(
             CONTENT
-                    + "AddItemDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
+                    + "SimpleDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
                     + "/add_item_bottom_sheet|LinearLayout:id/add_item_bottom_sheet_content"
                     + "|ScrollView:id/widget_preview_scroll_view|WidgetCell:id/widget_cell"
                     + "|WidgetCellPreview:id/widget_preview_container|ImageView:id/widget_badge",
             CONTENT
-                    + "AddItemDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
+                    + "SimpleDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
                     + "/add_item_bottom_sheet|LinearLayout:id/add_item_bottom_sheet_content"
                     + "|ScrollView:id/widget_preview_scroll_view|WidgetCell:id/widget_cell"
                     + "|WidgetCellPreview:id/widget_preview_container|WidgetCell$1|FrameLayout"
                     + "|ImageView:id/icon",
-            CONTENT + "AddItemDragLayer:id/add_item_drag_layer|View",
+            CONTENT + "SimpleDragLayer:id/add_item_drag_layer|View",
             DRAG_LAYER
                     + "AppWidgetResizeFrame|FrameLayout|ImageButton:id/widget_reconfigure_button",
             DRAG_LAYER
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java
index e333074..fc8f818 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/FlashDetector.java
@@ -44,13 +44,13 @@
                     + "LauncherAllAppsContainerView:id/apps_view|AllAppsRecyclerView:id"
                     + "/apps_list_view|BubbleTextView:id/icon",
             CONTENT
-                    + "AddItemDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
+                    + "SimpleDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
                     + "/add_item_bottom_sheet|LinearLayout:id/add_item_bottom_sheet_content"
                     + "|ScrollView:id/widget_preview_scroll_view|WidgetCell:id/widget_cell"
                     + "|WidgetCellPreview:id/widget_preview_container|WidgetImageView:id"
                     + "/widget_preview",
             CONTENT
-                    + "AddItemDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
+                    + "SimpleDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
                     + "/add_item_bottom_sheet|LinearLayout:id/add_item_bottom_sheet_content"
                     + "|ScrollView:id/widget_preview_scroll_view|WidgetCell:id/widget_cell"
                     + "|WidgetCellPreview:id/widget_preview_container|ImageView:id/widget_badge",
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/PositionJumpDetector.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/PositionJumpDetector.java
index 5f2c68c..88ace68 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/PositionJumpDetector.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/PositionJumpDetector.java
@@ -41,7 +41,7 @@
             DRAG_LAYER + "AppWidgetResizeFrame",
             DRAG_LAYER + "LauncherAllAppsContainerView:id/apps_view",
             CONTENT
-                    + "AddItemDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
+                    + "SimpleDragLayer:id/add_item_drag_layer|AddItemWidgetsBottomSheet:id"
                     + "/add_item_bottom_sheet|LinearLayout:id/add_item_bottom_sheet_content",
             DRAG_LAYER + "WidgetsTwoPaneSheet|SpringRelativeLayout:id/container",
             DRAG_LAYER + "WidgetsFullSheet|SpringRelativeLayout:id/container",
diff --git a/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java b/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java
index ba02473..b27ccbf 100644
--- a/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java
+++ b/tests/src/com/android/launcher3/util/viewcapture_analysis/ViewCaptureAnalyzer.java
@@ -35,7 +35,7 @@
 
     // All detectors. They will be invoked in the order listed here.
     private static final AnomalyDetector[] ANOMALY_DETECTORS = {
-            new AlphaJumpDetector(),
+//            new AlphaJumpDetector(), // b/309014345
 //            new FlashDetector(), // b/309014345
             new PositionJumpDetector()
     };
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index 7d25121..0e78565 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -54,6 +54,7 @@
     private static final int MAX_SCROLL_ATTEMPTS = 40;
 
     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");
@@ -369,9 +370,12 @@
              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                      "want to tap outside AllApps bottom sheet on the "
                              + (tapRight ? "right" : "left"))) {
-            final UiObject2 allAppsBottomSheet =
+
+            final UiObject2 container = (tapRight)
+                    ? mLauncher.waitForLauncherObject(FAST_SCROLLER_RES_ID) :
                     mLauncher.waitForLauncherObject(BOTTOM_SHEET_RES_ID);
-            mLauncher.touchOutsideContainer(allAppsBottomSheet, tapRight);
+
+            mLauncher.touchOutsideContainer(container, tapRight, false);
             try (LauncherInstrumentation.Closable tapped = mLauncher.addContextLayer(
                     "tapped outside AllApps bottom sheet")) {
                 verifyVisibleContainerOnDismiss();
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 44869be..b6b4a47 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -186,7 +186,14 @@
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             Taskbar taskbar = new Taskbar(mLauncher);
             taskbar.touchBottomCorner(tapRight);
-            verifyActiveContainer();
+            if (mLauncher.isTransientTaskbar()) {
+                // Tapping outside Transient Taskbar returns to Workspace, wait for that state.
+                new Workspace(mLauncher);
+            } else {
+                // Should stay in Overview.
+                verifyActiveContainer();
+                verifyActionsViewVisibility();
+            }
         }
     }
 
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
index d9b179c..9ca2dc8 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
@@ -118,4 +118,17 @@
     public boolean isHomeState() {
         return true;
     }
+
+    /** Send the "back" gesture to go to workspace. */
+    public Workspace pressBackToWorkspace() {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                     "want to press back from all apps to workspace")) {
+            mLauncher.runToState(
+                    () -> mLauncher.pressBackImpl(),
+                    NORMAL_STATE_ORDINAL,
+                    "pressing back");
+            return new Workspace(mLauncher);
+        }
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 2512175..fe927b3 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -65,11 +65,9 @@
                         + mLauncher.getVisibleBounds(mObject));
 
                 if (launcherStopsAfterLaunch()) {
-                    mLauncher.executeAndWaitForLauncherEvent(
+                    mLauncher.executeAndWaitForLauncherStop(
                             () -> mLauncher.clickLauncherObject(mObject),
-                            event -> TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE
-                                    .equals(event.getClassName().toString()),
-                            () -> "Launcher activity didn't stop", "clicking the launchable");
+                            "clicking the launchable");
                 } else {
                     mLauncher.clickLauncherObject(mObject);
                 }
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index efeb5f6..184ece7 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -20,12 +20,11 @@
 import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
 import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_BLOCK_TIMEOUT;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_SHELL_DRAG_READY;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_HEIGHT;
 import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_SCALE;
+import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD;
+import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
 
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -84,8 +83,6 @@
     public Taskbar getTaskbar() {
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to get the taskbar")) {
-            mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
-
             return new Taskbar(mLauncher);
         }
     }
@@ -113,37 +110,32 @@
     /**
      * Returns the Taskbar in a visible state.
      *
-     * The taskbar must already be hidden when calling this method.
+     * The taskbar must already be hidden and in transient mode when calling this method.
      */
-    public Taskbar showTaskbar() {
-        mLauncher.getTestInfo(REQUEST_ENABLE_MANUAL_TASKBAR_STASHING);
+    public Taskbar swipeUpToUnstashTaskbar() {
+        mLauncher.assertTrue("Taskbar is not transient, swipe up not supported",
+                mLauncher.isTransientTaskbar());
+
         mLauncher.getTestInfo(REQUEST_ENABLE_BLOCK_TIMEOUT);
 
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
-                     "want to show the taskbar")) {
+                     "want to swipe up to unstash the taskbar")) {
             mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
 
-            final long downTime = SystemClock.uptimeMillis();
-            final int unstashTargetY = mLauncher.getRealDisplaySize().y
-                    - (mLauncher.getTestInfo(REQUEST_STASHED_TASKBAR_HEIGHT)
-                            .getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD) / 2);
-            final Point unstashTarget = new Point(
-                    mLauncher.getRealDisplaySize().x / 2, unstashTargetY);
+            int taskbarFromNavThreshold = mLauncher.getTestInfo(REQUEST_TASKBAR_FROM_NAV_THRESHOLD)
+                    .getInt(TEST_INFO_RESPONSE_FIELD);
+            int startX = mLauncher.getRealDisplaySize().x / 2;
+            int startY = mLauncher.getRealDisplaySize().y - 1;
+            int endX = startX;
+            int endY = startY - taskbarFromNavThreshold;
 
-            mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, unstashTarget,
+            mLauncher.linearGesture(startX, startY, endX, endY, 10, /* slowDown= */ true,
                     LauncherInstrumentation.GestureScope.EXPECT_PILFER);
-            LauncherInstrumentation.log("showTaskbar: sent down");
+            LauncherInstrumentation.log("swipeUpToUnstashTaskbar: sent linear swipe up gesture");
 
-            try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
-                mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
-                mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, unstashTarget,
-                        LauncherInstrumentation.GestureScope.EXPECT_PILFER);
-
-                return new Taskbar(mLauncher);
-            }
+            return new Taskbar(mLauncher);
         } finally {
-            mLauncher.getTestInfo(REQUEST_DISABLE_MANUAL_TASKBAR_STASHING);
             mLauncher.getTestInfo(REQUEST_DISABLE_BLOCK_TIMEOUT);
         }
     }
@@ -348,4 +340,17 @@
             }
         }
     }
+
+    /** Send the "back" gesture to go to workspace. */
+    public Workspace pressBackToWorkspace() {
+        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"
+            );
+            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 dd8ab81..91ef472 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -585,6 +585,8 @@
         if (hasSystemLauncherObject(OVERVIEW_RES_ID)) return "Overview";
         if (hasLauncherObject(WORKSPACE_RES_ID)) return "Workspace";
         if (hasLauncherObject(APPS_RES_ID)) return "AllApps";
+        if (hasLauncherObject(TASKBAR_RES_ID)) return "Taskbar";
+        if (hasLauncherObject("wallpaper_carousel")) return "Launcher Settings Popup";
         if (mDevice.hasObject(By.pkg(getLauncherPackageName()).depth(0))) {
             return "<Launcher in invalid state>";
         }
@@ -823,12 +825,7 @@
                     waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
                     waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
                     waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
-
-                    if (is3PLauncher() && isTablet()) {
-                        waitForSystemLauncherObject(TASKBAR_RES_ID);
-                    } else {
-                        waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
-                    }
+                    waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
 
                     return waitForLauncherObject(WORKSPACE_RES_ID);
                 }
@@ -838,12 +835,7 @@
                     waitUntilSystemLauncherObjectGone(OVERVIEW_RES_ID);
                     waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
                     waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
-
-                    if (is3PLauncher() && isTablet()) {
-                        waitForSystemLauncherObject(TASKBAR_RES_ID);
-                    } else {
-                        waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
-                    }
+                    waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
 
                     return waitForLauncherObject(WIDGETS_RES_ID);
                 }
@@ -864,7 +856,7 @@
                     waitUntilSystemLauncherObjectGone(SPLIT_PLACEHOLDER_RES_ID);
                     waitUntilLauncherObjectGone(KEYBOARD_QUICK_SWITCH_RES_ID);
 
-                    if (is3PLauncher() && isTablet()) {
+                    if (is3PLauncher() && isTablet() && !isTransientTaskbar()) {
                         waitForSystemLauncherObject(TASKBAR_RES_ID);
                     } else {
                         waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
@@ -877,7 +869,7 @@
                     waitUntilLauncherObjectGone(APPS_RES_ID);
                     waitUntilLauncherObjectGone(WORKSPACE_RES_ID);
                     waitUntilLauncherObjectGone(WIDGETS_RES_ID);
-                    if (isTablet()) {
+                    if (isTablet() && !is3PLauncher()) {
                         waitForSystemLauncherObject(TASKBAR_RES_ID);
                     } else {
                         waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
@@ -914,7 +906,11 @@
                     }
 
                     if (isTablet()) {
-                        waitForSystemLauncherObject(TASKBAR_RES_ID);
+                        // Only check that Persistent Taskbar is visible, since Transient Taskbar
+                        // may or may not be visible by design.
+                        if (!isTransientTaskbar()) {
+                            waitForSystemLauncherObject(TASKBAR_RES_ID);
+                        }
                     } else {
                         waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
                     }
@@ -978,6 +974,14 @@
         }
     }
 
+    void executeAndWaitForLauncherStop(Runnable command, String actionName) {
+        executeAndWaitForLauncherEvent(
+                () -> command.run(),
+                event -> TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE
+                        .equals(event.getClassName().toString()),
+                () -> "Launcher activity didn't stop", actionName);
+    }
+
     /**
      * Get the resource ID of visible floating view.
      */
@@ -994,7 +998,7 @@
     /**
      * Using swiping up gesture to dismiss closable floating views, such as Menu or Folder Content.
      */
-    private void swipeUpToCloseFloatingView(boolean gestureStartFromLauncher) {
+    private void swipeUpToCloseFloatingView() {
         final Point displaySize = getRealDisplaySize();
 
         final Optional<String> floatingRes = getFloatingResId();
@@ -1003,16 +1007,11 @@
             return;
         }
 
-        GestureScope gestureScope = gestureStartFromLauncher
-                // Without the navigation bar layer, the gesture scope on tablets remains inside the
-                // launcher process.
-                ? (isTablet() ? GestureScope.DONT_EXPECT_PILFER : GestureScope.EXPECT_PILFER)
-                : GestureScope.EXPECT_PILFER;
         linearGesture(
                 displaySize.x / 2, displaySize.y - 1,
                 displaySize.x / 2, 0,
                 ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
-                false, gestureScope);
+                false, GestureScope.EXPECT_PILFER);
 
         try (LauncherInstrumentation.Closable c1 = addContextLayer(
                 String.format("Swiped up from floating view %s to home", floatingRes.get()))) {
@@ -1080,11 +1079,8 @@
 
                 final Point displaySize = getRealDisplaySize();
 
-                boolean gestureStartFromLauncher =
-                        isTablet() ? !isLauncher3() : isLauncherVisible();
-
                 // CLose floating views before going back to home.
-                swipeUpToCloseFloatingView(gestureStartFromLauncher);
+                swipeUpToCloseFloatingView();
 
                 if (hasLauncherObject(WORKSPACE_RES_ID)) {
                     log(action = "already at home");
@@ -1125,30 +1121,34 @@
      */
     public void pressBack() {
         try (Closable e = eventsCheck(); Closable c = addContextLayer("want to press back")) {
-            waitForLauncherInitialized();
-            final boolean launcherVisible =
-                    isTablet() ? isLauncherContainerVisible() : isLauncherVisible();
-            boolean isThreeFingerTrackpadGesture =
-                    mTrackpadGestureType == TrackpadGestureType.THREE_FINGER;
-            if (getNavigationModel() == NavigationModel.ZERO_BUTTON
-                    || isThreeFingerTrackpadGesture) {
-                final Point displaySize = getRealDisplaySize();
-                // TODO(b/225505986): change startY and endY back to displaySize.y / 2 once the
-                //  issue is solved.
-                int startX = isThreeFingerTrackpadGesture ? displaySize.x / 4 : 0;
-                int endX = isThreeFingerTrackpadGesture ? displaySize.x * 3 / 4 : displaySize.x / 2;
-                linearGesture(startX, displaySize.y / 4, endX, displaySize.y / 4,
-                        10, false, GestureScope.DONT_EXPECT_PILFER);
+            pressBackImpl();
+        }
+    }
+
+    void pressBackImpl() {
+        waitForLauncherInitialized();
+        final boolean launcherVisible =
+                isTablet() ? isLauncherContainerVisible() : isLauncherVisible();
+        boolean isThreeFingerTrackpadGesture =
+                mTrackpadGestureType == TrackpadGestureType.THREE_FINGER;
+        if (getNavigationModel() == NavigationModel.ZERO_BUTTON
+                || isThreeFingerTrackpadGesture) {
+            final Point displaySize = getRealDisplaySize();
+            // TODO(b/225505986): change startY and endY back to displaySize.y / 2 once the
+            //  issue is solved.
+            int startX = isThreeFingerTrackpadGesture ? displaySize.x / 4 : 0;
+            int endX = isThreeFingerTrackpadGesture ? displaySize.x * 3 / 4 : displaySize.x / 2;
+            linearGesture(startX, displaySize.y / 4, endX, displaySize.y / 4,
+                    10, false, GestureScope.DONT_EXPECT_PILFER);
+        } else {
+            waitForNavigationUiObject("back").click();
+        }
+        if (launcherVisible) {
+            if (getContext().getApplicationInfo().isOnBackInvokedCallbackEnabled()) {
+                expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ON_BACK_INVOKED);
             } else {
-                waitForNavigationUiObject("back").click();
-            }
-            if (launcherVisible) {
-                if (getContext().getApplicationInfo().isOnBackInvokedCallbackEnabled()) {
-                    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);
-                }
+                expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_DOWN);
+                expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_UP);
             }
         }
     }
@@ -2038,6 +2038,7 @@
         }
     }
 
+    /** Returns the bounds of the display as a Point where x is width and y is height. */
     Point getRealDisplaySize() {
         final Rect displayBounds = getContext().getSystemService(WindowManager.class)
                 .getMaximumWindowMetrics()
@@ -2100,6 +2101,11 @@
                 : TestProtocol.REQUEST_DISABLE_BLOCK_TIMEOUT);
     }
 
+    public boolean isTransientTaskbar() {
+        return getTestInfo(TestProtocol.REQUEST_IS_TRANSIENT_TASKBAR)
+                .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+    }
+
     /** Enables transient taskbar for testing purposes only. */
     public void enableTransientTaskbar(boolean enable) {
         getTestInfo(enable
@@ -2187,7 +2193,8 @@
         };
     }
 
-    boolean isLauncher3() {
+    /** Returns whether the Launcher is a Launcher3 one */
+    public boolean isLauncher3() {
         if (mIsLauncher3 == null) {
             mIsLauncher3 = "com.android.launcher3".equals(getLauncherPackageName());
         }
@@ -2312,4 +2319,14 @@
         }
         return result;
     }
+
+    /** Executes a runnable and waits for the wallpaper-open animation completion. */
+    public void executeAndWaitForWallpaperAnimation(Runnable r, String actionName) {
+        executeAndWaitForLauncherEvent(
+                () -> r.run(),
+                event -> TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE
+                        .equals(event.getClassName().toString()),
+                () -> "Didn't detect finishing wallpaper-open animation",
+                actionName);
+    }
 }
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 8a34f0d..f383e99 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -16,8 +16,6 @@
 
 package com.android.launcher3.tapl;
 
-import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-
 import android.graphics.Rect;
 
 import androidx.annotation.NonNull;
@@ -192,8 +190,8 @@
     private List<Integer> getCurrentTasksCenterXList() {
         return mLauncher.isTablet()
                 ? mOverview.getCurrentTasksForTablet().stream()
-                    .map(OverviewTask::getTaskCenterX)
-                    .collect(Collectors.toList())
+                .map(OverviewTask::getTaskCenterX)
+                .collect(Collectors.toList())
                 : List.of(mOverview.getCurrentTask().getTaskCenterX());
     }
 
@@ -203,11 +201,8 @@
     public LaunchedAppState open() {
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             verifyActiveContainer();
-            mLauncher.executeAndWaitForEvent(
+            mLauncher.executeAndWaitForLauncherStop(
                     () -> mLauncher.clickLauncherObject(mTask),
-                    event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED,
-                    () -> "Launching task didn't open a new window: "
-                            + mTask.getParent().getContentDescription(),
                     "clicking an overview task");
             if (mOverview.getContainerType()
                     == LauncherInstrumentation.ContainerType.SPLIT_SCREEN_SELECT) {
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index 38cc321..3d2914d 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -59,8 +59,10 @@
         try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
              LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                      "before tapping the app info menu item")) {
-            mLauncher.clickLauncherObject(
-                    mLauncher.findObjectInContainer(mMenu, By.text("App info")));
+            mLauncher.executeAndWaitForLauncherStop(
+                    () -> mLauncher.clickLauncherObject(
+                            mLauncher.findObjectInContainer(mMenu, By.text("App info"))),
+                    "tapped app info menu item");
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "tapped app info menu item")) {
diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
index da26694..a202c53 100644
--- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java
+++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java
@@ -18,8 +18,6 @@
 import static android.view.KeyEvent.KEYCODE_META_RIGHT;
 
 import static com.android.launcher3.tapl.LauncherInstrumentation.TASKBAR_RES_ID;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_DISABLE_MANUAL_TASKBAR_STASHING;
-import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_ENABLE_MANUAL_TASKBAR_STASHING;
 
 import android.graphics.Point;
 import android.graphics.Rect;
@@ -33,6 +31,8 @@
 import androidx.test.uiautomator.BySelector;
 import androidx.test.uiautomator.UiObject2;
 
+import org.junit.Assert;
+
 import java.util.List;
 import java.util.stream.Collectors;
 
@@ -45,6 +45,15 @@
 
     Taskbar(LauncherInstrumentation launcher) {
         mLauncher = launcher;
+        try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+                "expect new taskbar to be visible")) {
+            mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
+        }
+
+        if (!mLauncher.isTransientTaskbar()) {
+            Assert.assertEquals("Persistent taskbar should fill screen width",
+                    getVisibleBounds().width(), mLauncher.getRealDisplaySize().x);
+        }
     }
 
     /**
@@ -61,33 +70,32 @@
     }
 
     /**
-     * Hides this taskbar.
-     *
-     * The taskbar must already be visible when calling this method.
+     * Stashes this taskbar.
+     * <p>
+     * The taskbar must already be unstashed and in transient mode when calling this method.
      */
-    public void hide() {
-        mLauncher.getTestInfo(REQUEST_ENABLE_MANUAL_TASKBAR_STASHING);
+    public void swipeDownToStash() {
+        mLauncher.assertTrue("Taskbar is not transient, swipe down not supported",
+                mLauncher.isTransientTaskbar());
 
         try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
                 "want to hide the taskbar");
              LauncherInstrumentation.Closable e = mLauncher.eventsCheck()) {
             mLauncher.waitForSystemLauncherObject(TASKBAR_RES_ID);
 
-            final long downTime = SystemClock.uptimeMillis();
-            Point stashTarget = new Point(
-                    mLauncher.getRealDisplaySize().x - 1, mLauncher.getRealDisplaySize().y - 1);
+            Rect taskbarBounds = getVisibleBounds();
+            int startX = taskbarBounds.centerX();
+            int startY = taskbarBounds.centerY();
+            int endX = startX;
+            int endY = mLauncher.getRealDisplaySize().y - 1;
 
-            mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, stashTarget,
+            mLauncher.linearGesture(startX, startY, endX, endY, 10, false,
                     LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
-            LauncherInstrumentation.log("hideTaskbar: sent down");
-
-            try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("pressed down")) {
+            LauncherInstrumentation.log("swipeDownToStash: sent linear swipe down gesture");
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+                    "expect transient taskbar to be hidden after swipe down")) {
                 mLauncher.waitUntilSystemLauncherObjectGone(TASKBAR_RES_ID);
-                mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP, stashTarget,
-                        LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
             }
-        } finally {
-            mLauncher.getTestInfo(REQUEST_DISABLE_MANUAL_TASKBAR_STASHING);
         }
     }
 
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 2a2a83f..f8fa00c 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -335,7 +335,8 @@
                     homeAppIcon,
                     () -> new Point(0, 0),
                     () -> mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT),
-                    null);
+                    null,
+                    /* startsActivity = */ false);
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "dragged the app across workspace")) {
@@ -359,7 +360,8 @@
                     homeAppIcon,
                     () -> getDropPointFromDropTargetBar(mLauncher, DELETE_TARGET_TEXT_ID),
                     () -> mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT),
-                    /* expectDropEvents= */ null);
+                    /* expectDropEvents= */ null,
+                    /* startsActivity = */ false);
 
             try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
                     "dragged the app to the drop bar")) {
@@ -368,7 +370,6 @@
         }
     }
 
-
     /**
      * Uninstall the appIcon by dragging it to the 'uninstall' drop point of the drop_target_bar.
      *
@@ -390,7 +391,8 @@
                     homeAppIcon,
                     () -> getDropPointFromDropTargetBar(launcher, UNINSTALL_TARGET_TEXT_ID),
                     expectLongClickEvents,
-                    /* expectDropEvents= */null);
+                    /* expectDropEvents= */null,
+                    /* startsActivity = */ false);
 
             launcher.waitUntilLauncherObjectGone(DROP_BAR_RES_ID);
 
@@ -464,14 +466,25 @@
                 o -> new FolderIcon(mLauncher, o)).collect(Collectors.toList());
     }
 
+    private static void sendUp(LauncherInstrumentation launcher, Point dest,
+            long downTime) {
+        launcher.sendPointer(
+                downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest,
+                LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
+    }
+
     private static void dropDraggedIcon(LauncherInstrumentation launcher, Point dest, long downTime,
-            @Nullable Runnable expectedEvents) {
-        launcher.runToState(
-                () -> launcher.sendPointer(
-                        downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest,
-                        LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER),
-                NORMAL_STATE_ORDINAL,
-                "sending UP event");
+            @Nullable Runnable expectedEvents, boolean startsActivity) {
+        if (startsActivity) {
+            launcher.executeAndWaitForLauncherStop(
+                    () -> sendUp(launcher, dest, downTime),
+                    "sending UP event");
+        } else {
+            launcher.runToState(
+                    () -> sendUp(launcher, dest, downTime),
+                    NORMAL_STATE_ORDINAL,
+                    "sending UP event");
+        }
         if (expectedEvents != null) {
             expectedEvents.run();
         }
@@ -488,7 +501,8 @@
                     LauncherInstrumentation.EVENT_START);
         }
         dragIconToWorkspace(
-                launcher, launchable, dest, expectLongClickEvents, expectDropEvents);
+                launcher, launchable, dest, expectLongClickEvents, expectDropEvents,
+                startsActivity);
     }
 
     static void dragIconToWorkspaceCellPosition(LauncherInstrumentation launcher,
@@ -517,7 +531,8 @@
                 destSupplier,
                 /* isDecelerating= */ false,
                 () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT),
-                /* expectDropEvents= */ null);
+                /* expectDropEvents= */ null,
+                /* startsActivity = */ false);
     }
 
     static void dragIconToWorkspace(
@@ -525,9 +540,10 @@
             Launchable launchable,
             Supplier<Point> dest,
             Runnable expectLongClickEvents,
-            @Nullable Runnable expectDropEvents) {
+            @Nullable Runnable expectDropEvents,
+            boolean startsActivity) {
         dragIconToWorkspace(launcher, launchable, dest, /* isDecelerating */ true,
-                expectLongClickEvents, expectDropEvents);
+                expectLongClickEvents, expectDropEvents, startsActivity);
     }
 
     static void dragIconToWorkspace(
@@ -536,7 +552,8 @@
             Supplier<Point> dest,
             boolean isDecelerating,
             Runnable expectLongClickEvents,
-            @Nullable Runnable expectDropEvents) {
+            @Nullable Runnable expectDropEvents,
+            boolean startsActivity) {
         try (LauncherInstrumentation.Closable ignored = launcher.addContextLayer(
                 "want to drag icon to workspace")) {
             final long downTime = SystemClock.uptimeMillis();
@@ -568,7 +585,7 @@
             launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, isDecelerating,
                     downTime, SystemClock.uptimeMillis(), false,
                     LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
-            dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
+            dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents, startsActivity);
         }
     }
 
@@ -601,7 +618,8 @@
             launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, isDecelerating,
                     downTime, SystemClock.uptimeMillis(), false,
                     LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
-            dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
+            dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents,
+                    /* startsActivity = */ false);
         }
     }
 
@@ -667,7 +685,8 @@
         launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, true,
                 downTime, SystemClock.uptimeMillis(), false,
                 LauncherInstrumentation.GestureScope.DONT_EXPECT_PILFER);
-        dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
+        dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents,
+                /* startsActivity = */ false);
     }
 
     /**
diff --git a/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java b/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
index 5a4d562..e5a2a2e 100644
--- a/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
+++ b/tests/tapl/com/android/launcher3/tapl/WorkspaceDragSource.java
@@ -81,7 +81,8 @@
                     launchable,
                     dest,
                     launchable::addExpectedEventsForLongClick,
-                    /*expectDropEvents= */ null);
+                    /*expectDropEvents= */ null,
+                    /* startsActivity = */ false);
 
             try (LauncherInstrumentation.Closable ignore = launcher.addContextLayer("dragged")) {
                 WorkspaceAppIcon appIcon =