Merge "Fix divider visibility issue on transient taskbar" into tm-qpr-dev
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 9123959..a77791f 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,2 +1,4 @@
 [Hook Scripts]
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --config_xml tools/checkstyle.xml --sha ${PREUPLOAD_COMMIT}
+
+ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check ${PREUPLOAD_FILES}
\ No newline at end of file
diff --git a/go/quickstep/res/values-b+sr+Latn/strings.xml b/go/quickstep/res/values-b+sr+Latn/strings.xml
index 749fc0e..263f011 100644
--- a/go/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/go/quickstep/res/values-b+sr+Latn/strings.xml
@@ -1,20 +1,20 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="app_share_drop_target_label" msgid="5804774105974539508">"Дели апликацију"</string>
-    <string name="action_listen" msgid="2370304050784689486">"Пусти"</string>
-    <string name="action_translate" msgid="8028378961867277746">"Преведи"</string>
-    <string name="action_search" msgid="6269564710943755464">"Објектив"</string>
-    <string name="dialog_acknowledge" msgid="2804025517675853172">"ВАЖИ"</string>
-    <string name="dialog_cancel" msgid="6464336969134856366">"ОТКАЖИ"</string>
-    <string name="dialog_settings" msgid="6564397136021186148">"ПОДЕШАВАЊА"</string>
-    <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"Преводите или слушајте текст на екрану"</string>
-    <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"Информације попут текста на екрану, веб-адреса и снимака екрана могу да се деле са Google-ом.\n\nДа бисте променили информације које делите, идите у "<b>"Подешавања &gt; Апликације &gt; Подразумеване апликације &gt; Апликација дигиталног помоћника"</b>"."</string>
-    <string name="assistant_not_selected_title" msgid="5017072974603345228">"Одаберите помоћника да бисте користили ову функцију"</string>
-    <string name="assistant_not_selected_text" msgid="3244613673884359276">"Да бисте чули текст са екрана или га превели, одаберите апликацију дигиталног помоћника у Подешавањима"</string>
-    <string name="assistant_not_supported_title" msgid="1675788067597484142">"Промените помоћника да бисте користили ову функцију"</string>
-    <string name="assistant_not_supported_text" msgid="1708031078549268884">"Да бисте чули текст са екрана или га превели, промените апликацију дигиталног помоћника у Подешавањима"</string>
-    <string name="tooltip_listen" msgid="7634466447860989102">"Додирните овде да бисте чули текст са овог екрана"</string>
-    <string name="tooltip_translate" msgid="4184845868901542567">"Додирните овде да бисте превели текст са овог екрана"</string>
-    <string name="toast_p2p_app_not_shareable" msgid="7229739094132131536">"Ова апликација не може да се дели"</string>
+    <string name="app_share_drop_target_label" msgid="5804774105974539508">"Deli aplikaciju"</string>
+    <string name="action_listen" msgid="2370304050784689486">"Pusti"</string>
+    <string name="action_translate" msgid="8028378961867277746">"Prevedi"</string>
+    <string name="action_search" msgid="6269564710943755464">"Objektiv"</string>
+    <string name="dialog_acknowledge" msgid="2804025517675853172">"VAŽI"</string>
+    <string name="dialog_cancel" msgid="6464336969134856366">"OTKAŽI"</string>
+    <string name="dialog_settings" msgid="6564397136021186148">"PODEŠAVANJA"</string>
+    <string name="niu_actions_confirmation_title" msgid="3863451714863526143">"Prevodite ili slušajte tekst na ekranu"</string>
+    <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"Informacije poput teksta na ekranu, veb-adresa i snimaka ekrana mogu da se dele sa Google-om.\n\nDa biste promenili informacije koje delite, idite u "<b>"Podešavanja &gt; Aplikacije &gt; Podrazumevane aplikacije &gt; Aplikacija digitalnog pomoćnika"</b>"."</string>
+    <string name="assistant_not_selected_title" msgid="5017072974603345228">"Odaberite pomoćnika da biste koristili ovu funkciju"</string>
+    <string name="assistant_not_selected_text" msgid="3244613673884359276">"Da biste čuli tekst sa ekrana ili ga preveli, odaberite aplikaciju digitalnog pomoćnika u Podešavanjima"</string>
+    <string name="assistant_not_supported_title" msgid="1675788067597484142">"Promenite pomoćnika da biste koristili ovu funkciju"</string>
+    <string name="assistant_not_supported_text" msgid="1708031078549268884">"Da biste čuli tekst sa ekrana ili ga preveli, promenite aplikaciju digitalnog pomoćnika u Podešavanjima"</string>
+    <string name="tooltip_listen" msgid="7634466447860989102">"Dodirnite ovde da biste čuli tekst sa ovog ekrana"</string>
+    <string name="tooltip_translate" msgid="4184845868901542567">"Dodirnite ovde da biste preveli tekst sa ovog ekrana"</string>
+    <string name="toast_p2p_app_not_shareable" msgid="7229739094132131536">"Ova aplikacija ne može da se deli"</string>
 </resources>
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 352cd3e..3647e05 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -37,6 +37,7 @@
     <uses-permission android:name="android.permission.MANAGE_ACCESSIBILITY"/>
     <uses-permission android:name="android.permission.MONITOR_INPUT"/>
     <uses-permission android:name="android.permission.ALLOW_SLIPPERY_TOUCHES"/>
+    <uses-permission android:name="android.permission.ACCESS_SHORTCUTS"/>
 
     <uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
 
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 7e5b85c..bd11c1e 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -28,6 +28,19 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
 
+    <!-- Filtering affects only alpha instead of the visibility since visibility can be altered
+         separately through RecentsView#resetFromSplitSelectionState() -->
+    <ImageView
+        android:id="@+id/show_windows"
+        android:layout_height="@dimen/recents_filter_icon_size"
+        android:layout_width="@dimen/recents_filter_icon_size"
+        android:layout_gravity="end"
+        android:alpha="0"
+        android:tint="@color/recents_filter_icon"
+        android:contentDescription="@string/recents_filter_icon_desc"
+        android:importantForAccessibility="no"
+        android:src="@drawable/ic_select_windows" />
+
     <com.android.quickstep.views.IconView
         android:id="@+id/icon"
         android:layout_width="@dimen/task_thumbnail_icon_size"
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index cd5bcbd..ec03c69 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -38,6 +38,32 @@
         android:layout_width="match_parent"
         android:layout_height="match_parent"/>
 
+    <!-- Filtering affects only alpha instead of the visibility since visibility can be altered
+         separately through RecentsView#resetFromSplitSelectionState() -->
+    <ImageView
+        android:id="@+id/show_windows"
+        android:layout_height="@dimen/recents_filter_icon_size"
+        android:layout_width="@dimen/recents_filter_icon_size"
+        android:layout_gravity="start"
+        android:alpha="0"
+        android:tint="@color/recents_filter_icon"
+        android:contentDescription="@string/recents_filter_icon_desc"
+        android:importantForAccessibility="no"
+        android:src="@drawable/ic_select_windows" />
+
+    <!-- Filtering affects only alpha instead of the visibility since visibility can be altered
+         separately through RecentsView#resetFromSplitSelectionState() -->
+    <ImageView
+        android:id="@+id/show_windows_right"
+        android:layout_height="@dimen/recents_filter_icon_size"
+        android:layout_width="@dimen/recents_filter_icon_size"
+        android:layout_gravity="end"
+        android:alpha="0"
+        android:tint="@color/recents_filter_icon"
+        android:contentDescription="@string/recents_filter_icon_desc"
+        android:importantForAccessibility="no"
+        android:src="@drawable/ic_select_windows" />
+
     <com.android.quickstep.views.IconView
         android:id="@+id/icon"
         android:layout_width="@dimen/task_thumbnail_icon_size"
diff --git a/quickstep/res/layout/taskbar_all_apps_button.xml b/quickstep/res/layout/taskbar_all_apps_button.xml
index 79d087a..6b665e5 100644
--- a/quickstep/res/layout/taskbar_all_apps_button.xml
+++ b/quickstep/res/layout/taskbar_all_apps_button.xml
@@ -13,10 +13,12 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+
+<!-- Note: The actual size will match the taskbar icon sizes in TaskbarView#onLayout(). -->
 <com.android.launcher3.views.IconButtonView
     xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="@dimen/taskbar_icon_touch_size"
-    android:layout_height="@dimen/taskbar_icon_touch_size"
+    android:layout_width="@dimen/taskbar_icon_min_touch_size"
+    android:layout_height="@dimen/taskbar_icon_min_touch_size"
     android:contentDescription="@string/all_apps_button_label"
     android:backgroundTint="@android:color/transparent"
     android:icon="@drawable/ic_all_apps_button"
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 047e05f..df9fe66 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"የተግባር አሞሌ ትምህርት"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"የተግባር አሞሌ ትምህርት ይታያል"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"የተግባር አሞሌ ትምህርት ተዘግቷል"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"በአንድ ጊዜ 2 መተግበሪያዎችን ለመጠቀም ወደ ጎን ይጎትቱ"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"የተግባር አሞሌውን ለማሳየት አጭር ወደ ላይ ያንሸራትቱ"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"የተግባር አሞሌው የዕለት ተዕለት ተግባርዎ ላይ በመመስረት መተግበሪያዎችን ይጠቁማል"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"ቀጣይ"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"ተመለስ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ዝጋ"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 121e535..a6781ef 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"التعريف بشريط التطبيقات"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"ظهرت لوحة تعليم استخدام شريط المهام."</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"تم إغلاق لوحة تعليم استخدام شريط المهام."</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"اسحبه إلى جانب الشاشة لاستخدام تطبيقَين في آنٍ واحد."</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"مرِّر سريعًا للأعلى تمريرة قصيرة لإظهار شريط التطبيقات."</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"يقترح شريط المهام تطبيقات بناءً على روتينك."</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"الشاشة التالية"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"رجوع"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"إغلاق"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 7747148..6e43c19 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"টাস্কবাৰৰ শিক্ষা"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"টাস্কবাৰৰ শিক্ষাৰ পেনেলটো প্ৰদর্শিত হৈছে"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"টাস্কবাৰৰ শিক্ষাৰ পেনেলটো বন্ধ হৈছে"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"এবাৰতে দুটা এপ্‌ ব্যৱহাৰ কৰিবলৈ কাষলৈ টানি আনি এৰক"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"টাস্কবাৰ দেখুৱাবলৈ সামান্য পৰিমাণে ওপৰলৈ ছোৱাইপ কৰক"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"টাস্কবাৰে আপোনাৰ ৰুটিনৰ ভিত্তিত এপৰ পৰামৰ্শ দিয়ে"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"পৰৱৰ্তী"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"উভতি যাওক"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"বন্ধ কৰক"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 6e819ab..2699c3e 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -19,98 +19,98 @@
 
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
-    <string name="recent_task_option_freeform" msgid="48863056265284071">"Слободни облик"</string>
-    <string name="recents_empty_message" msgid="7040467240571714191">"Нема недавних ставки"</string>
-    <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Подешавања коришћења апликације"</string>
-    <string name="recents_clear_all" msgid="5328176793634888831">"Обриши све"</string>
-    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Недавне апликације"</string>
-    <string name="task_view_closed" msgid="9170038230110856166">"Задатак је затворен"</string>
+    <string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
+    <string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
+    <string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
+    <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Podešavanja korišćenja aplikacije"</string>
+    <string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
+    <string name="accessibility_recent_apps" msgid="4058661986695117371">"Nedavne aplikacije"</string>
+    <string name="task_view_closed" msgid="9170038230110856166">"Zadatak je zatvoren"</string>
     <string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
-    <string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"&lt; 1 мин"</string>
-    <string name="time_left_for_app" msgid="3111996412933644358">"Још <xliff:g id="TIME">%1$s</xliff:g> данас"</string>
-    <string name="title_app_suggestions" msgid="4185902664111965088">"Предлози апликација"</string>
-    <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Предвиђене апликације"</string>
-    <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Добијајте предлоге апликација у доњем реду почетног екрана"</string>
-    <string name="hotseat_edu_title_migrate_landscape" msgid="3633942953997845243">"Добијајте предлоге апликација у реду са омиљеним ставкама на почетном екрану"</string>
-    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Лако приступајте апликацијама које најчешће користите директно са почетног екрана. Предлози се мењају на основу употребе. Апликације из доњег реда се премештају нагоре на почетни екран."</string>
-    <string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Лако приступајте апликацијама које најчешће користите директно са почетног екрана. Предлози се мењају на основу ваших рутина. Апликације из реда са омиљеним ставкама се премештају на почетни екран."</string>
-    <string name="hotseat_edu_accept" msgid="1611544083278999837">"Приказуј предлоге апликација"</string>
-    <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Не, хвала"</string>
-    <string name="hotseat_prediction_settings" msgid="6246554993566070818">"Подешавања"</string>
-    <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Овде се приказују најчешће коришћене апликације и мењају се у зависности од употребе"</string>
-    <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Превуците апликације из доњег реда да бисте добили предлоге"</string>
-    <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Предлози апликација се додају на празно место"</string>
-    <string name="hotsaet_tip_prediction_enabled" msgid="2233554377501347650">"Предлози апликација су омогућени"</string>
-    <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"Предлози апликација су онемогућени"</string>
-    <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Предвиђамо апликацију: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
-    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Обавезно превуците од саме десне или леве ивице."</string>
-    <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Обавезно превуците од десне или леве ивице до средине екрана и отпустите."</string>
-    <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Научили сте како да превлачите здесна да бисте се вратили уназад. Сада научите да замените апликације."</string>
-    <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Довршили сте покрет за повратак."</string>
-    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Никако не превлачите превише близу дна екрана."</string>
-    <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Осетљивост пок. за назад можете да промените у Подешавањима"</string>
-    <string name="back_gesture_intro_title" msgid="19551256430224428">"Превуците да бисте се вратили уназад"</string>
-    <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Да бисте се вратили на последњи екран, превуците од леве или десне ивице до средине екрана."</string>
-    <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Да бисте се вратили на последњи екран, превуците помоћу два прста од леве или десне ивице до средине екрана."</string>
-    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Обавезно превуците нагоре од доње ивице екрана."</string>
-    <string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Никако не стајте пре отпуштања."</string>
-    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Обавезно превуците право нагоре."</string>
-    <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Довршили сте покрет за повратак на почетну страницу. Сада сазнајте како да се вратите."</string>
-    <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Довршили сте покрет за повратак на почетну страницу."</string>
-    <string name="home_gesture_intro_title" msgid="836590312858441830">"Превуците да бисте отишли на почетну страницу"</string>
-    <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Превуците нагоре од дна екрана. Овај покрет вас увек води на почетни екран."</string>
-    <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Превуците помоћу два прста нагоре од дна екрана. Овим покретом увек отварате почетни екран."</string>
-    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Обавезно превуците нагоре од доње ивице екрана."</string>
-    <string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Пробајте да држите прозор дуже пре отпуштања."</string>
-    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Обавезно превуците право нагоре, па застаните."</string>
-    <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Научили сте како да користите покрете. Да бисте искључили покрете, идите на подешавања."</string>
-    <string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Довршили сте покрет за промену апликација."</string>
-    <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Превуците да бисте заменили апликације"</string>
-    <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"За прелазак са једне апликације на другу превуците нагоре од дна екрана, задржите, па пустите."</string>
-    <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"За прелазак између апликација превуците помоћу два прста нагоре од дна екрана, задржите, па пустите."</string>
-    <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"То је то"</string>
-    <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Готово"</string>
-    <string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Подешавања"</string>
-    <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Пробајте поново"</string>
-    <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Свака част!"</string>
-    <string name="gesture_tutorial_step" msgid="1279786122817620968">"Водич <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <string name="allset_title" msgid="5021126669778966707">"Готово!"</string>
-    <string name="allset_hint" msgid="2384632994739392447">"Превуците нагоре да бисте отворили почетни екран"</string>
-    <string name="allset_button_hint" msgid="2395219947744706291">"Додирните дугме Почетак да бисти ишли на почетни екран"</string>
-    <string name="allset_description_generic" msgid="5385500062202019855">"Спремни сте да почнете да користите <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
-    <string name="default_device_name" msgid="6660656727127422487">"уређај"</string>
-    <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Подешавања кретања кроз систем"</annotation></string>
-    <string name="action_share" msgid="2648470652637092375">"Дели"</string>
-    <string name="action_screenshot" msgid="8171125848358142917">"Снимак екрана"</string>
-    <string name="action_split" msgid="2098009717623550676">"Подели"</string>
-    <string name="toast_split_select_app" msgid="5453865907322018352">"Додирните другу апликацију за подељени екран"</string>
-    <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Одаберите другу апликацију за подељени екран"</string>
-    <string name="blocked_by_policy" msgid="2071401072261365546">"Апликација или организација не дозвољавају ову радњу"</string>
-    <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Желите да прескочите водич за кретање?"</string>
-    <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Можете да пронађете ово касније у апликацији <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Откажи"</string>
-    <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Прескочи"</string>
-    <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ротирајте екран"</string>
-    <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Упутства на траци задатака"</string>
-    <string name="taskbar_edu_opened" msgid="3950252793551919129">"Едукативно окно из траке задатака се појавило"</string>
-    <string name="taskbar_edu_closed" msgid="126643734478892862">"Едукативно окно из траке задатака је затворено"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Превуците на страну да бисте користили 2 апликације одједном"</string>
-    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Накратко превуците нагоре да бисте приказали траку задатака"</string>
-    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Трака задатака предлаже апликације на основу рутине"</string>
-    <string name="taskbar_edu_next" msgid="4007618274426775841">"Даље"</string>
-    <string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
-    <string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
-    <string name="taskbar_edu_done" msgid="6880178093977704569">"Готово"</string>
-    <string name="taskbar_button_home" msgid="2151398979630664652">"Почетна"</string>
-    <string name="taskbar_button_a11y" msgid="5241161324875094465">"Приступачност"</string>
-    <string name="taskbar_button_back" msgid="8558862226461164514">"Назад"</string>
-    <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME пребацивач"</string>
-    <string name="taskbar_button_recents" msgid="7273376136216613134">"Недавно"</string>
-    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Обавештења"</string>
-    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Брза подешавања"</string>
-    <string name="taskbar_a11y_title" msgid="6432169809852243110">"Трака задатака"</string>
-    <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Трака за навигацију"</string>
-    <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string>
-    <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести доле десно"</string>
+    <string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"&lt; 1 min"</string>
+    <string name="time_left_for_app" msgid="3111996412933644358">"Još <xliff:g id="TIME">%1$s</xliff:g> danas"</string>
+    <string name="title_app_suggestions" msgid="4185902664111965088">"Predlozi aplikacija"</string>
+    <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Predviđene aplikacije"</string>
+    <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Dobijajte predloge aplikacija u donjem redu početnog ekrana"</string>
+    <string name="hotseat_edu_title_migrate_landscape" msgid="3633942953997845243">"Dobijajte predloge aplikacija u redu sa omiljenim stavkama na početnom ekranu"</string>
+    <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Lako pristupajte aplikacijama koje najčešće koristite direktno sa početnog ekrana. Predlozi se menjaju na osnovu upotrebe. Aplikacije iz donjeg reda se premeštaju nagore na početni ekran."</string>
+    <string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Lako pristupajte aplikacijama koje najčešće koristite direktno sa početnog ekrana. Predlozi se menjaju na osnovu vaših rutina. Aplikacije iz reda sa omiljenim stavkama se premeštaju na početni ekran."</string>
+    <string name="hotseat_edu_accept" msgid="1611544083278999837">"Prikazuj predloge aplikacija"</string>
+    <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Ne, hvala"</string>
+    <string name="hotseat_prediction_settings" msgid="6246554993566070818">"Podešavanja"</string>
+    <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Ovde se prikazuju najčešće korišćene aplikacije i menjaju se u zavisnosti od upotrebe"</string>
+    <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Prevucite aplikacije iz donjeg reda da biste dobili predloge"</string>
+    <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Predlozi aplikacija se dodaju na prazno mesto"</string>
+    <string name="hotsaet_tip_prediction_enabled" msgid="2233554377501347650">"Predlozi aplikacija su omogućeni"</string>
+    <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"Predlozi aplikacija su onemogućeni"</string>
+    <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Predviđamo aplikaciju: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+    <string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="1711645592102201538">"Obavezno prevucite od same desne ili leve ivice."</string>
+    <string name="back_gesture_feedback_cancelled" msgid="3274382913290074496">"Obavezno prevucite od desne ili leve ivice do sredine ekrana i otpustite."</string>
+    <string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako da prevlačite zdesna da biste se vratili unazad. Sada naučite da zamenite aplikacije."</string>
+    <string name="back_gesture_feedback_complete_without_follow_up" msgid="6405649621667113830">"Dovršili ste pokret za povratak."</string>
+    <string name="back_gesture_feedback_swipe_in_nav_bar" msgid="1148198467090405643">"Nikako ne prevlačite previše blizu dna ekrana."</string>
+    <string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Osetljivost pok. za nazad možete da promenite u Podešavanjima"</string>
+    <string name="back_gesture_intro_title" msgid="19551256430224428">"Prevucite da biste se vratili unazad"</string>
+    <string name="back_gesture_intro_subtitle" msgid="7912576483031802797">"Da biste se vratili na poslednji ekran, prevucite od leve ili desne ivice do sredine ekrana."</string>
+    <string name="back_gesture_spoken_intro_subtitle" msgid="2162043199263088592">"Da biste se vratili na poslednji ekran, prevucite pomoću dva prsta od leve ili desne ivice do sredine ekrana."</string>
+    <string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="1446774096007065298">"Obavezno prevucite nagore od donje ivice ekrana."</string>
+    <string name="home_gesture_feedback_overview_detected" msgid="1557523944897393013">"Nikako ne stajte pre otpuštanja."</string>
+    <string name="home_gesture_feedback_wrong_swipe_direction" msgid="6993979358080825438">"Obavezno prevucite pravo nagore."</string>
+    <string name="home_gesture_feedback_complete_with_follow_up" msgid="1427872029729605034">"Dovršili ste pokret za povratak na početnu stranicu. Sada saznajte kako da se vratite."</string>
+    <string name="home_gesture_feedback_complete_without_follow_up" msgid="8049099486868933882">"Dovršili ste pokret za povratak na početnu stranicu."</string>
+    <string name="home_gesture_intro_title" msgid="836590312858441830">"Prevucite da biste otišli na početnu stranicu"</string>
+    <string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Prevucite nagore od dna ekrana. Ovaj pokret vas uvek vodi na početni ekran."</string>
+    <string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Prevucite pomoću dva prsta nagore od dna ekrana. Ovim pokretom uvek otvarate početni ekran."</string>
+    <string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="3032757898111577225">"Obavezno prevucite nagore od donje ivice ekrana."</string>
+    <string name="overview_gesture_feedback_home_detected" msgid="1411130969354020489">"Probajte da držite prozor duže pre otpuštanja."</string>
+    <string name="overview_gesture_feedback_wrong_swipe_direction" msgid="6725820500906747925">"Obavezno prevucite pravo nagore, pa zastanite."</string>
+    <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili ste kako da koristite pokrete. Da biste isključili pokrete, idite na podešavanja."</string>
+    <string name="overview_gesture_feedback_complete_without_follow_up" msgid="3199486203448379152">"Dovršili ste pokret za promenu aplikacija."</string>
+    <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Prevucite da biste zamenili aplikacije"</string>
+    <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Za prelazak sa jedne aplikacije na drugu prevucite nagore od dna ekrana, zadržite, pa pustite."</string>
+    <string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Za prelazak između aplikacija prevucite pomoću dva prsta nagore od dna ekrana, zadržite, pa pustite."</string>
+    <string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"To je to"</string>
+    <string name="gesture_tutorial_action_button_label" msgid="6249846312991332122">"Gotovo"</string>
+    <string name="gesture_tutorial_action_button_label_settings" msgid="2923621047916486604">"Podešavanja"</string>
+    <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Probajte ponovo"</string>
+    <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Svaka čast!"</string>
+    <string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
+    <string name="allset_title" msgid="5021126669778966707">"Gotovo!"</string>
+    <string name="allset_hint" msgid="2384632994739392447">"Prevucite nagore da biste otvorili početni ekran"</string>
+    <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme Početak da bisti išli na početni ekran"</string>
+    <string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste da počnete da koristite <xliff:g id="DEVICE">%1$s</xliff:g>"</string>
+    <string name="default_device_name" msgid="6660656727127422487">"uređaj"</string>
+    <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Podešavanja kretanja kroz sistem"</annotation></string>
+    <string name="action_share" msgid="2648470652637092375">"Deli"</string>
+    <string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
+    <string name="action_split" msgid="2098009717623550676">"Podeli"</string>
+    <string name="toast_split_select_app" msgid="5453865907322018352">"Dodirnite drugu aplikaciju za podeljeni ekran"</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>
+    <string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Želite da preskočite vodič za kretanje?"</string>
+    <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Možete da pronađete ovo kasnije u aplikaciji <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Otkaži"</string>
+    <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string>
+    <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotirajte ekran"</string>
+    <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Uputstva na traci zadataka"</string>
+    <string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukativno okno iz trake zadataka se pojavilo"</string>
+    <string name="taskbar_edu_closed" msgid="126643734478892862">"Edukativno okno iz trake zadataka je zatvoreno"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Prevucite na stranu da biste koristili 2 aplikacije odjednom"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Nakratko prevucite nagore da biste prikazali traku zadataka"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Traka zadataka predlaže aplikacije na osnovu rutine"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Dalje"</string>
+    <string name="taskbar_edu_previous" msgid="459202320127201702">"Nazad"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
+    <string name="taskbar_edu_done" msgid="6880178093977704569">"Gotovo"</string>
+    <string name="taskbar_button_home" msgid="2151398979630664652">"Početna"</string>
+    <string name="taskbar_button_a11y" msgid="5241161324875094465">"Pristupačnost"</string>
+    <string name="taskbar_button_back" msgid="8558862226461164514">"Nazad"</string>
+    <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME prebacivač"</string>
+    <string name="taskbar_button_recents" msgid="7273376136216613134">"Nedavno"</string>
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Obaveštenja"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Brza podešavanja"</string>
+    <string name="taskbar_a11y_title" msgid="6432169809852243110">"Traka zadataka"</string>
+    <string name="taskbar_phone_a11y_title" msgid="4933360237131229395">"Traka za navigaciju"</string>
+    <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premesti gore levo"</string>
+    <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premesti dole desno"</string>
 </resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 8f97f0a..0f38c75 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Інфармацыя пра панэль задач"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"З\'явілася панэль навучання на панэлі задач"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Панэль навучання на панэлі задач закрыта"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Перацягніце ўбок, каб адначасова скарыстаць 2 праграмы"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Хутка правядзіце пальцам уверх, каб убачыць панэль задач"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"На панэлі задач праграмы паказваюцца з улікам вашых дзеянняў"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Далей"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Закрыць"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 8b1640d..f0118a7 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -95,9 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Edukacija o traci zadataka"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukacija o programskoj traci je prikazana"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Edukacija o programskoj traci je zatvorena"</string>
-    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Povucite u stranu za istovremeno korištenje 2 aplikacije"</string>
-    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Kratki pokret prema gore za prikaz trake sa zadacima"</string>
-    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Traka sa zadacima predlaže aplikacije na temelju vaše rutine"</string>
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Prevucite u stranu da istovremeno koristite 2 aplikacije"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Nakratko prevucite nagore da prikažete traku zadataka"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Traka zadataka predlaže aplikacije na osnovu vaše rutine"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Naprijed"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Nazad"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 1eeadba..868393d 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informace o panelu aplikací"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Zobrazila se výuka k hlavnímu panelu"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Výuka k hlavnímu panelu byla zavřena"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Po přetažení na stranu lze používat dvě aplikace současně"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Krátkým přejetím nahoru zobrazíte panel aplikací"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Panel aplikací navrhuje aplikace na základě vašeho používání"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Další"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Zpět"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zavřít"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 2e9d76e..c7664be 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -78,7 +78,7 @@
     <string name="allset_title" msgid="5021126669778966707">"Fertig!"</string>
     <string name="allset_hint" msgid="2384632994739392447">"Nach oben wischen, um den Startbildschirm aufzurufen"</string>
     <string name="allset_button_hint" msgid="2395219947744706291">"Startbildschirmtaste drücken, um zum Startbildschirm zu gehen"</string>
-    <string name="allset_description_generic" msgid="5385500062202019855">"Du kannst dein Gerät (<xliff:g id="DEVICE">%1$s</xliff:g>) jetzt verwenden"</string>
+    <string name="allset_description_generic" msgid="5385500062202019855">"Du kannst dein <xliff:g id="DEVICE">%1$s</xliff:g> jetzt verwenden"</string>
     <string name="default_device_name" msgid="6660656727127422487">"Gerät"</string>
     <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Einstellungen der Systemsteuerung"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Teilen"</string>
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informationen zur Taskleiste"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Anleitung für Taskleiste eingeblendet"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Anleitung für Taskleiste geschlossen"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Zur Seite ziehen, um zwei Apps gleichzeitig zu verwenden"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Kurz nach oben wischen, um die Taskleiste anzuzeigen"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Taskleiste empfiehlt Apps basierend auf deinen Gewohnheiten"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Weiter"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Zurück"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Schließen"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 7eda444..b302888 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Zereginen barra erabiltzeko argibideak"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Agertu egin da zereginen barraren tutoriala"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Itxi egin da zereginen barraren tutoriala"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Bi aplikazio batera erabiltzeko, arrastatu hatza albo batera"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Ataza-barra ikusteko, pasatu hatza bizkor gora"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Ataza-barran erabileran oinarritutako aplikazioak iradokitzen dira"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Hurrengoa"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Atzera"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Itxi"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 6e13752..c922f80 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"آموزش نوار وظیفه"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"پانل آموزشی نوار وظیفه نمایان شد"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"پانل آموزشی نوار وظیفه بسته شد"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"برای استفاده هم‌زمان از دو برنامه، آن را به کنار بکشید"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"برای نمایش نوار وظیفه، کمی به بالا بکشید"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"نوار وظیفه برنامه‌ها را براساس روال شما پیشنهاد می‌دهد"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"بعدی"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"برگشت"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"بستن"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 55db0e8..a07fdea 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Tehtäväpalkin ohje"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Tehtäväpalkin ohje näkyvissä"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Tehtäväpalkin ohje suljettu"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Vetämällä sivuun voit käyttää kahta sovellusta samaan aikaan"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Näytä tehtäväpalkki pyyhkäisemällä ylös lyhyesti"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Tehtäväpalkki ehdottaa sovelluksia ohjelmasi perusteella"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Seuraava"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Takaisin"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Sulje"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 972e8e7..a20fbc4 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Fonctionnement de la barre des tâches"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Infos sur la barre des tâches affichées"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Infos sur la barre des tâches fermées"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Faites glisser sur le côté pour utiliser 2 applis à la fois"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Balayez rapidement vers haut pour afficher barre des tâches"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"La barre des tâches suggère des applis selon vos habitudes"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Suivant"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Retour"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Fermer"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 38b09d5..528dd0a 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Información sobre a función Barra de tarefas"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Panel de información de barra de tarefas aberto"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Panel de información de barra de tarefas pechado"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Para usar 2 aplicacións á vez, arrastra cara ao lado"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Pasa o dedo un pouco cara arriba para ver a barra de tarefas"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Na barra de tarefas suxírense apps segundo a túa rutina"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Seguinte"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Atrás"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Pechar"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 1e79961..c9f3930 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"टास्कबार का ट्यूटोरियल"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबार ट्यूटोरियल दिखाया गया"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"टास्कबार ट्यूटोरियल बंद किया गया"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"एक साथ दो ऐप इस्तेमाल करने के लिए, उन्हें किनारे की ओर खींचें और छोड़ें"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"टास्कबार दिखाने के लिए, ऊपर की ओर थोड़ा स्वाइप करें"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"टास्कबार, डिवाइस के इस्तेमाल के आधार पर ऐप के सुझाव देता है"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"आगे बढ़ें"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"वापस जाएं"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"बंद करें"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 54a76ae..9a5cc98 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informazioni sulla barra delle applicazioni"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Riquadro Formazione barra delle applicazioni visualizzato"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Riquadro Formazione barra delle applicazioni chiuso"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Trascina di lato per usare 2 app contemporaneamente"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Scorri verso l\'alto per mostrare la barra delle applicazioni"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Barra delle applicazioni suggerisce app in base alla routine"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Avanti"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Indietro"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Chiudi"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 6e01d06..8722476 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"הסבר על סרגל האפליקציות"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"חלונית ההסברים על שורת המשימות מופיעה"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"חלונית ההסברים על שורת המשימות נסגרה"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"כדי להשתמש בשתי אפליקציות בו-זמנית, צריך לגרור לצד"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"צריך להחליק מעט כדי להציג את סרגל האפליקציות"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"האפליקציות מוצעות בסרגל האפליקציות על סמך השימוש השגרתי שלך"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"הבא"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"חזרה"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"סגירה"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 593c6fc..d0f6a9a 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Тапсырмалар жолағы: үйрену"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Тапсырмалар тақтасы бойынша нұсқаулық ашылды."</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Тапсырмалар тақтасы бойынша нұсқаулық жабылды."</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Екі қолданбаны бір уақытта пайдалану үшін шетке сүйреңіз."</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Тапсырмалар жолағын көру үшін жоғары қарай тез сырғытыңыз."</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Тапсырмалар жолағындағы ұсыныстар әдеттеріңізге негізделеді."</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Келесі"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Артқа"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Жабу"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 04e3439..f9a7209 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ការអប់រំលើរបារកិច្ចការ"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"ការបង្រៀនអំពីរបារកិច្ចការបានបង្ហាញ"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"ការបង្រៀនអំពីរបារកិច្ចការត្រូវបានបិទ"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"អូស​ទៅចំហៀង ដើម្បីប្រើ​កម្មវិធី 2 ក្នុងពេលតែមួយ"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"អូសឡើងលើបន្តិច ដើម្បីបង្ហាញរបារកិច្ចការ"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"របារកិច្ចការនេះណែនាំកម្មវិធីផ្អែកលើទម្លាប់របស់អ្នក"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"បន្ទាប់"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"ថយក្រោយ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"បិទ"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 4ec4ce6..b7c774a 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ಟಾಸ್ಕ್‌ಬಾರ್ ಶಿಕ್ಷಣ"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"ಟಾಸ್ಕ್‌ಬಾರ್ ಶಿಕ್ಷಣ ಕಾಣಿಸಿಕೊಂಡಿದೆ"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"ಟಾಸ್ಕ್‌ಬಾರ್ ಶಿಕ್ಷಣ ಮುಚ್ಚಿದೆ"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ಏಕಕಾಲದಲ್ಲಿ 2 ಆ್ಯಪ್‌ಗಳನ್ನು ಬಳಸಲು ಬದಿಗೆ ಡ್ರ್ಯಾಗ್ ಮಾಡಿ"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"ಟಾಸ್ಕ್‌ಬಾರ್ ಅನ್ನು ತೋರಿಸಲು ಚಿಕ್ಕದಾಗಿ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ಟಾಸ್ಕ್‌ಬಾರ್ ನಿಮ್ಮ ದಿನಚರಿ ಆಧರಿಸಿ ಆ್ಯಪ್‌ಗಳನ್ನು ಸೂಚಿಸುತ್ತದೆ"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"ಮುಂದೆ"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"ಹಿಂದೆ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ಮುಚ್ಚಿರಿ"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 9e99685..55e5a11 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Тапшырмалар панели жөнүндө маалымат"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Тапшырмалар тактасынын окутуу панели көрсөтүлдү"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Тапшырмалар тактасынын окутуу панели жабылды"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"2 колдонмону бир убакта пайдалануу үчүн капталга сүйрөңүз"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Тапшырмалар тактасын көрүү үчүн экранды өйдө серпиңиз"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Тапшырмалар тактасы колдонмолорду аракеттериңизге жараша сунуштайт"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Кийинки"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Артка"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Жабуу"</string>
diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml
index bc5d02a..30983c4 100644
--- a/quickstep/res/values-land/dimens.xml
+++ b/quickstep/res/values-land/dimens.xml
@@ -76,10 +76,8 @@
     <dimen name="gesture_tutorial_taskbar_padding_start_end">218dp</dimen>
 
     <!--  Taskbar 3 button spacing  -->
-    <dimen name="taskbar_button_margin_5_5">94.5dp</dimen>
+    <dimen name="taskbar_button_margin_split">88dp</dimen>
     <dimen name="taskbar_button_margin_6_5">219.6dp</dimen>
-    <dimen name="taskbar_button_margin_4_5">84dp</dimen>
-    <dimen name="taskbar_button_margin_4_4">79dp</dimen>
     <dimen name="taskbar_contextual_button_margin">48dp</dimen>
     <dimen name="taskbar_suw_frame">96dp</dimen>
     <dimen name="taskbar_suw_insets">24dp</dimen>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 5036588..da911c1 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Informācija par uzdevumu joslu"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Tika atvērta uzdevumjoslas apmācība"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Tika aizvērta uzdevumjoslas apmācība"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Velciet uz malu, lai izmantotu divas lietotnes vienlaikus"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Īsi velciet augšup, lai skatītu uzdevumu joslu"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Uzdevumu joslā tiek rādītas lietotnes, ņemot vērā lietojumu"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Tālāk"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Atpakaļ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Aizvērt"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 0b7e0cc..2f0614c 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ଟାସ୍କବାର ଶିକ୍ଷା"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"ଟାସ୍କବାର୍ ଶିକ୍ଷା ଦେଖାଯାଇଛି"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"ଟାସ୍କବାର୍ ଶିକ୍ଷା ବନ୍ଦ ହୋଇଯାଇଛି"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ଥରକେ 2ଟି ଆପ୍ସ ବ୍ୟବହାର କରିବା ପାଇଁ ପାର୍ଶ୍ୱକୁ ଡ୍ରାଗ କରନ୍ତୁ"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"ଟାସ୍କବାର ଦେଖାଇବା ପାଇଁ ଉପରକୁ ଅଳ୍ପ ସମୟ ସ୍ୱାଇପ କରନ୍ତୁ"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ଟାସ୍କବାର ଆପଣଙ୍କ ରୁଟିନ ଆଧାରରେ ଆପ୍ସ ପରାମର୍ଶ ଦିଏ"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"ପରବର୍ତ୍ତୀ"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"ପଛକୁ ଫେରନ୍ତୁ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ବନ୍ଦ କରନ୍ତୁ"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 0d9a565..dc9d78e 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"ਟਾਸਕਬਾਰ ਸਿੱਖਿਆ"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"ਟਾਸਕਵਾਰ ਸਿੱਖਿਆ ਪੈਨਲ ਦਿਖਾਇਆ ਗਿਆ"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"ਟਾਸਕਵਾਰ ਸਿੱਖਿਆ ਪੈਨਲ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ਇੱਕ ਵਾਰ ਵਿੱਚ 2 ਐਪਾਂ ਵਰਤਣ ਲਈ ਉਨ੍ਹਾਂ ਨੂੰ ਸਾਈਡ ਵੱਲ ਘਸੀਟੋ"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"ਟਾਸਕਬਾਰ ਦਿਖਾਉਣ ਲਈ ਥੋੜ੍ਹਾ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"ਟਾਸਕਬਾਰ ਤੁਹਾਡੇ ਨਿਯਮਬੱਧ ਕੰਮ ਮੁਤਾਬਕ ਐਪਾਂ ਦਾ ਸੁਝਾਅ ਦਿੰਦਾ ਹੈ"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"ਅੱਗੇ"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"ਪਿੱਛੇ"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"ਬੰਦ ਕਰੋ"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index c327df9..b663528 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Educação da Barra de tarefas"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Informação da barra de tarefas apresentada"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Informação da barra de tarefas fechada"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Arraste para o lado para usar duas apps em simultâneo"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Deslize rápido curto para cima para ver a barra de tarefas"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"A barra de tarefas sugere apps baseadas na sua rotina"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Seguinte"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Anterior"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Fechar"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index e29c166..573c17b 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Panel vzdelávacích aplikácií"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Zobrazila sa výuka k hlavnému panelu"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Výuka k hlavnému panelu bola zatvorená"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Po presunutí na stranu je možné používať dve aplikácie naraz"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Krátkym potiahnutím nahor zobrazíte panel aplikácií"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Panel aplikácií navrhuje aplikácie na základe vašich zvykov"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Ďalej"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Späť"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Zavrieť"</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index d961410..d73aa48 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Edukimi për shiritin e detyrave"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukimi i shiritit të detyrave u shfaq"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Edukimi nga shiriti i detyrave u mbyll"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Zvarrit në anë për të përdorur 2 aplikacione njëherësh"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Kryej një rrëshqitje të shkurtër lart për të shfaqur shiritin e detyrave"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Shiriti i detyrave sugjeron aplikacione bazuar në rutinën tënde"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Para"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Pas"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Mbyll"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 900b3a1..bab1952 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Aktivitetsfältsutbildning"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Information om aktivitetsfältet visades"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Information om aktivitetsfältet stängdes"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Dra till sidan om du vill använda två appar samtidigt"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Svep en kort bit uppåt för att visa aktivitetsfältet"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"I aktivitetsfältet visas förslag på appar utifrån din rutin"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Nästa"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Tillbaka"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Stäng"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 7961110..f0990b3 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Elimu ya Upauzana"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Paneli ya elimu kwenye upau wa shughuli inaonyeshwa"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Paneli ya elimu kwenye upau wa shughuli imefungwa"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Buruta pembeni ili utumie programu 2 kwa wakati mmoja"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Telezesha kidole juu ili uonyeshe upauzana"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Upauzana hupendekeza programu kulingana na ratiba yako"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Endelea"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Nyuma"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Funga"</string>
diff --git a/quickstep/res/values-sw720dp/dimens.xml b/quickstep/res/values-sw720dp/dimens.xml
index 585f01e..d27561a 100644
--- a/quickstep/res/values-sw720dp/dimens.xml
+++ b/quickstep/res/values-sw720dp/dimens.xml
@@ -37,4 +37,8 @@
     <!-- All Set page-->
     <dimen name="allset_page_allset_text_size">42sp</dimen>
     <dimen name="allset_page_swipe_up_text_size">16sp</dimen>
+
+    <!-- Transient taskbar -->
+    <dimen name="transient_taskbar_size">76dp</dimen>
+    <dimen name="transient_taskbar_icon_size">52dp</dimen>
 </resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 0b916b0..1db0fab 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"செயல் பட்டியைப் பயன்படுத்தும் விதம்"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"பணிப்பட்டியை எவ்வாறு பயன்படுத்துவது என்பது பற்றிய பலகம் காட்டப்படுகிறது"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"பணிப்பட்டியை எவ்வாறு பயன்படுத்துவது என்பது பற்றிய பலகம் மூடப்பட்டது"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"ஒரே நேரத்தில் 2 ஆப்ஸை உபயோகிக்க பக்கவாட்டிற்கு இழுக்கவும்"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"செயல் பட்டியைக் காட்டுவதற்கு மேலே சிறிது ஸ்வைப் செய்யவும்"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"உங்கள் வழக்கத்திற்கேற்ப ஆப்ஸை செயல் பட்டி பரிந்துரைக்கும்"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"அடுத்து"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"பின்செல்"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"மூடுக"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 2e444a9..b426c8b 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Панель завдань Education"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Панель завдань Education відкрито"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Панель завдань Education закрито"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Перетягніть убік, щоб використовувати 2 додатки одночасно"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Швидко проведіть пальцем угору, щоб відкрити панель завдань"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"Панель завдань пропонує додатки на основі вашої програми"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Далі"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Назад"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Закрити"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 8213a8b..5a9e0a1 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -96,8 +96,8 @@
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"顯示咗工作列教學"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"閂咗工作列教學"</string>
     <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"拖曳到一邊即可同時使用 2 個應用程式"</string>
-    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"稍微向上滑動即可讓工作列顯示在畫面上"</string>
-    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"工作列會根據你的日常習慣提供應用程式建議"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"輕輕向上滑動即可顯示工作列"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"工作列會根據您的日常安排提供應用程式建議"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"繼續"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"返回"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 06dc488..0a7e418 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -95,12 +95,9 @@
     <string name="taskbar_edu_a11y_title" msgid="5417986057866415355">"Imfundo ye-taskbar"</string>
     <string name="taskbar_edu_opened" msgid="3950252793551919129">"Imfuno yebha yomsebenzi ivelile"</string>
     <string name="taskbar_edu_closed" msgid="126643734478892862">"Imfundo yebha yomsebenzi ivaliwe"</string>
-    <!-- no translation found for taskbar_edu_splitscreen (5563823414110661454) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_stashing (2805035263048176462) -->
-    <skip />
-    <!-- no translation found for taskbar_edu_suggestions (1416699696825090402) -->
-    <skip />
+    <string name="taskbar_edu_splitscreen" msgid="5563823414110661454">"Hudula ngaseceleni ukuze usebenzise ama-app angu-2 ngesikhathi esisodwa"</string>
+    <string name="taskbar_edu_stashing" msgid="2805035263048176462">"Swayiphela phezulu okufushane ukuze ubonise i-taskbar"</string>
+    <string name="taskbar_edu_suggestions" msgid="1416699696825090402">"I-taskbar iphakamisa ama-app ezisuselwe kumjikelezo wakho"</string>
     <string name="taskbar_edu_next" msgid="4007618274426775841">"Okulandelayo"</string>
     <string name="taskbar_edu_previous" msgid="459202320127201702">"Emuva"</string>
     <string name="taskbar_edu_close" msgid="887022990168191073">"Vala"</string>
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 185c815..f63997b 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -76,4 +76,7 @@
 
     <color name="all_set_page_background">#FFFFFFFF</color>
 
+    <!-- Recents overview -->
+    <color name="recents_filter_icon">#333333</color>
+
 </resources>
\ No newline at end of file
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 198a676..a91507c 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -25,6 +25,7 @@
     <string name="stats_log_manager_class" translatable="false">com.android.quickstep.logging.StatsLogCompatManager</string>
     <string name="test_information_handler_class" translatable="false">com.android.quickstep.QuickstepTestInformationHandler</string>
     <string name="window_manager_proxy_class" translatable="false">com.android.quickstep.util.SystemWindowManagerProxy</string>
+    <string name="widget_holder_factory_class" translatable="false">com.android.launcher3.uioverrides.QuickstepWidgetHolder$QuickstepHolderFactory</string>
 
     <!-- The number of thumbnails and icons to keep in the cache. The thumbnail cache size also
          determines how many thumbnails will be fetched in the background. -->
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index baf097e..2eb4abc 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -255,7 +255,10 @@
     <!-- Taskbar -->
     <dimen name="taskbar_size">@*android:dimen/taskbar_frame_height</dimen>
     <dimen name="taskbar_ime_size">48dp</dimen>
-    <dimen name="taskbar_icon_touch_size">48dp</dimen>
+    <dimen name="taskbar_icon_size">44dp</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. -->
+    <dimen name="taskbar_icon_spacing">12dp</dimen>
     <dimen name="taskbar_icon_drag_icon_size">54dp</dimen>
     <dimen name="taskbar_folder_margin">16dp</dimen>
     <dimen name="taskbar_contextual_button_padding">16dp</dimen>
@@ -281,13 +284,12 @@
     <dimen name="taskbar_icon_size_kids">32dp</dimen>
 
     <!-- Transient taskbar -->
-    <dimen name="transient_taskbar_size">76dp</dimen>
-    <dimen name="transient_taskbar_two_panels_size">72dp</dimen>
+    <dimen name="transient_taskbar_size">72dp</dimen>
+    <dimen name="transient_taskbar_icon_size">48dp</dimen>
     <dimen name="transient_taskbar_margin">24dp</dimen>
     <dimen name="transient_taskbar_shadow_blur">40dp</dimen>
     <dimen name="transient_taskbar_key_shadow_distance">10dp</dimen>
     <dimen name="transient_taskbar_stashed_size">32dp</dimen>
-    <dimen name="transient_taskbar_icon_spacing">10dp</dimen>
     <!-- An additional touch slop to prevent x-axis movement during the swipe up to show taskbar -->
     <dimen name="transient_taskbar_clamped_offset_bound">16dp</dimen>
     <!-- Taskbar swipe up thresholds -->
@@ -303,11 +305,12 @@
     <!--  Taskbar 3 button spacing  -->
     <dimen name="taskbar_button_space_inbetween">24dp</dimen>
     <dimen name="taskbar_button_space_inbetween_phone">40dp</dimen>
-    <dimen name="taskbar_button_margin_5_5">26dp</dimen>
+    <dimen name="taskbar_button_margin_split">48dp</dimen>
     <dimen name="taskbar_button_margin_6_5">75dp</dimen>
-    <dimen name="taskbar_button_margin_4_5">47dp</dimen>
-    <dimen name="taskbar_button_margin_4_4">47dp</dimen>
-    <dimen name="taskbar_button_margin_default">47dp</dimen>
+    <dimen name="taskbar_button_margin_default">48dp</dimen>
+
+    <!-- Recents overview -->
+    <dimen name="recents_filter_icon_size">30dp</dimen>
 
     <!-- Launcher splash screen -->
     <!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 801ba26..e691522 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -36,6 +36,13 @@
     <!-- Recents: Title of a button that clears the task list, i.e. closes all tasks. [CHAR LIMIT=30] -->
     <string name="recents_clear_all">Clear all</string>
 
+    <!-- Recents: Title of a button that goes back from displaying tasks filtered by package name to displaying all tasks [CHAR LIMIT=30] -->
+    <string name="recents_back" translatable="false">Back</string>
+
+    <!-- TODO: b/260610444. Content description of filtering icons needs to be updated -->
+    <!-- Recents: Content description for the icon on top of taskviews to initiate filtering -->
+    <string name="recents_filter_icon_desc" translatable="false">Click to show only this app\'s tasks</string>
+
     <!-- Accessibility title for the list of recent apps [CHAR_LIMIT=none] -->
     <string name="accessibility_recent_apps">Recent apps</string>
 
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 95a94ec..9f9f2c8 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -28,12 +28,15 @@
 import android.content.Context;
 import android.os.Build;
 import android.os.Handler;
+import android.os.RemoteException;
+import android.view.IRemoteAnimationFinishedCallback;
 import android.view.RemoteAnimationTarget;
 
 import androidx.annotation.BinderThread;
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 
+import com.android.systemui.animation.RemoteAnimationDelegate;
 import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
 
 import java.lang.ref.WeakReference;
@@ -89,7 +92,7 @@
         Runnable r = () -> {
             finishExistingAnimation();
             mAnimationResult = new AnimationResult(() -> mAnimationResult = null, runnable);
-            getFactory().onCreateAnimation(transit, appTargets, wallpaperTargets, nonAppTargets,
+            getFactory().onAnimationStart(transit, appTargets, wallpaperTargets, nonAppTargets,
                     mAnimationResult);
         };
         if (mStartAtFrontOfQueue) {
@@ -124,7 +127,11 @@
         });
     }
 
-    public static final class AnimationResult {
+    /**
+     * Used by RemoteAnimationFactory implementations to run the actual animation and its lifecycle
+     * callbacks.
+     */
+    public static final class AnimationResult extends IRemoteAnimationFinishedCallback.Stub {
 
         private final Runnable mSyncFinishRunnable;
         private final Runnable mASyncFinishRunnable;
@@ -199,25 +206,41 @@
                 }
             }
         }
+
+        /**
+         * When used as a simple IRemoteAnimationFinishedCallback, this method is used to run the
+         * animation finished runnable.
+         */
+        @Override
+        public void onAnimationFinished() throws RemoteException {
+            mASyncFinishRunnable.run();
+        }
     }
 
     /**
      * Used with LauncherAnimationRunner as an interface for the runner to call back to the
      * implementation.
      */
-    @FunctionalInterface
-    public interface RemoteAnimationFactory {
+    public interface RemoteAnimationFactory extends RemoteAnimationDelegate<AnimationResult> {
 
         /**
          * Called on the UI thread when the animation targets are received. The implementation must
          * call {@link AnimationResult#setAnimation} with the target animation to be run.
          */
-        void onCreateAnimation(int transit,
+        @Override
+        @UiThread
+        void onAnimationStart(int transit,
                 RemoteAnimationTarget[] appTargets,
                 RemoteAnimationTarget[] wallpaperTargets,
                 RemoteAnimationTarget[] nonAppTargets,
                 LauncherAnimationRunner.AnimationResult result);
 
+        @Override
+        @UiThread
+        default void onAnimationCancelled(boolean isKeyguardOccluded) {
+            onAnimationCancelled();
+        }
+
         /**
          * Called when the animation is cancelled. This can happen with or without
          * the create being called.
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 2aa0af4..668567e 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -1665,7 +1665,7 @@
         }
 
         @Override
-        public void onCreateAnimation(int transit,
+        public void onAnimationStart(int transit,
                 RemoteAnimationTarget[] appTargets,
                 RemoteAnimationTarget[] wallpaperTargets,
                 RemoteAnimationTarget[] nonAppTargets,
@@ -1707,7 +1707,7 @@
         }
 
         @Override
-        public void onCreateAnimation(int transit,
+        public void onAnimationStart(int transit,
                 RemoteAnimationTarget[] appTargets,
                 RemoteAnimationTarget[] wallpaperTargets,
                 RemoteAnimationTarget[] nonAppTargets,
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index a205d19..ae121e2 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -33,6 +33,7 @@
 
     private boolean mFreeformTasksVisible;
     private boolean mInOverviewState;
+    private boolean mGestureInProgress;
 
     public DesktopVisibilityController(Launcher launcher) {
         mLauncher = launcher;
@@ -43,7 +44,7 @@
      */
     private boolean isDesktopModeSupported() {
         return SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false)
-            || SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
+                || SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
     }
 
     /**
@@ -57,9 +58,24 @@
      * Sets whether freeform windows are visible and updates launcher visibility based on that.
      */
     public void setFreeformTasksVisible(boolean freeformTasksVisible) {
+        if (!isDesktopModeSupported()) {
+            return;
+        }
         if (freeformTasksVisible != mFreeformTasksVisible) {
             mFreeformTasksVisible = freeformTasksVisible;
-            updateLauncherVisibility();
+            if (mFreeformTasksVisible) {
+                setLauncherViewsVisibility(View.INVISIBLE);
+                if (!mInOverviewState) {
+                    // When freeform is visible & we're not in overview, we want launcher to appear
+                    // paused, this ensures that taskbar displays.
+                    markLauncherPaused();
+                }
+            } else {
+                setLauncherViewsVisibility(View.VISIBLE);
+                // If freeform isn't visible ensure that launcher appears resumed to behave
+                // normally.
+                markLauncherResumed();
+            }
         }
     }
 
@@ -67,32 +83,66 @@
      * Sets whether the overview is visible and updates launcher visibility based on that.
      */
     public void setOverviewStateEnabled(boolean overviewStateEnabled) {
+        if (!isDesktopModeSupported()) {
+            return;
+        }
         if (overviewStateEnabled != mInOverviewState) {
             mInOverviewState = overviewStateEnabled;
-            updateLauncherVisibility();
+            if (mInOverviewState) {
+                setLauncherViewsVisibility(View.VISIBLE);
+                markLauncherResumed();
+            } else if (mFreeformTasksVisible) {
+                setLauncherViewsVisibility(View.INVISIBLE);
+                markLauncherPaused();
+            }
         }
     }
 
     /**
-     * Updates launcher visibility and state to look like it is paused or resumed depending on
-     * whether freeform windows are showing in desktop mode.
+     * Whether recents gesture is currently in progress.
      */
-    private void updateLauncherVisibility() {
+    public boolean isGestureInProgress() {
+        return mGestureInProgress;
+    }
+
+    /**
+     * Sets whether recents gesture is in progress.
+     */
+    public void setGestureInProgress(boolean gestureInProgress) {
+        if (!isDesktopModeSupported()) {
+            return;
+        }
+        if (gestureInProgress != mGestureInProgress) {
+            mGestureInProgress = gestureInProgress;
+        }
+    }
+
+    private void setLauncherViewsVisibility(int visibility) {
+        View workspaceView = mLauncher.getWorkspace();
+        if (workspaceView != null) {
+            workspaceView.setVisibility(visibility);
+        }
+        View dragLayer = mLauncher.getDragLayer();
+        if (dragLayer != null) {
+            dragLayer.setVisibility(visibility);
+        }
+    }
+
+    private void markLauncherPaused() {
         StatefulActivity<LauncherState> activity =
                 QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
-        View workspaceView = mLauncher.getWorkspace();
-        if (activity == null || workspaceView == null || !isDesktopModeSupported()) return;
+        if (activity != null) {
+            activity.setPaused();
+        }
+    }
 
-        if (mFreeformTasksVisible) {
-            workspaceView.setVisibility(View.INVISIBLE);
-            if (!mInOverviewState) {
-                // When freeform is visible & we're not in overview, we want launcher to appear
-                // paused, this ensures that taskbar displays.
-                activity.setPaused();
-            }
-        } else {
-            workspaceView.setVisibility(View.VISIBLE);
-            // If freeform isn't visible ensure that launcher appears resumed to behave normally.
+    private void markLauncherResumed() {
+        StatefulActivity<LauncherState> activity =
+                QuickstepLauncher.ACTIVITY_TRACKER.getCreatedActivity();
+        // Check activity state before calling setResumed(). Launcher may have been actually
+        // paused (eg fullscreen task moved to front).
+        // In this case we should not mark the activity as resumed.
+        if (activity != null && activity.isResumed()) {
             activity.setResumed();
         }
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 22f7f13..a18aabe 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -310,7 +310,7 @@
             return;
         }
         mTaskbarInAppDisplayProgress.put(progressIndex, progress);
-        if (!mControllers.taskbarStashController.isInApp()
+        if (mControllers.uiController.isIconAlignedWithHotseat()
                 && !mTaskbarLauncherStateController.isAnimatingToLauncher()) {
             // Only animate the nav buttons while home and not animating home, otherwise let
             // the TaskbarViewController handle it.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 902cf29..731eea7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -152,10 +152,10 @@
             TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
             unfoldTransitionProgressProvider) {
         super(windowContext);
-        mDeviceProfile = launcherDp.copy(this);
-
         final Resources resources = getResources();
 
+        matchDeviceProfile(launcherDp, getResources());
+
         mNavMode = DisplayController.getNavigationMode(windowContext);
         mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
         mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
@@ -170,8 +170,6 @@
         mIsNavBarKidsMode = settingsCache.getValue(
                 Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
 
-        updateIconSize(resources);
-
         // Get display and corners first, as views might use them in constructor.
         Display display = windowContext.getDisplay();
         Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY
@@ -259,8 +257,7 @@
     public void updateDeviceProfile(DeviceProfile launcherDp, NavigationMode navMode) {
         mNavMode = navMode;
         mControllers.taskbarOverlayController.updateLauncherDeviceProfile(launcherDp);
-        mDeviceProfile = launcherDp.copy(this);
-        updateIconSize(getResources());
+        matchDeviceProfile(launcherDp, getResources());
 
         AbstractFloatingView.closeAllOpenViewsExcept(this, false, TYPE_REBIND_SAFE);
         // Reapply fullscreen to take potential new screen size into account.
@@ -269,12 +266,25 @@
         dispatchDeviceProfileChanged();
     }
 
+    /**
+     * Copy the original DeviceProfile, match the number of hotseat icons and qsb width and update
+     * the icon size
+     */
+    private void matchDeviceProfile(DeviceProfile originDeviceProfile, Resources resources) {
+        mDeviceProfile = originDeviceProfile.copy(this);
+        // Taskbar should match the number of icons of hotseat
+        mDeviceProfile.numShownHotseatIcons = originDeviceProfile.numShownHotseatIcons;
+        // Same QSB width to have a smooth animation
+        mDeviceProfile.hotseatQsbWidth = originDeviceProfile.hotseatQsbWidth;
+        // Update the size of the icons
+        updateIconSize(resources);
+    }
+
+
     private void updateIconSize(Resources resources) {
         mDeviceProfile.iconSizePx = resources.getDimensionPixelSize(
                 DisplayController.isTransientTaskbar(this)
-                    ? mDeviceProfile.isTwoPanels
-                            ? R.dimen.transient_taskbar_two_panels_icon_size
-                            : R.dimen.transient_taskbar_icon_size
+                    ? R.dimen.transient_taskbar_icon_size
                     : R.dimen.taskbar_icon_size);
         mDeviceProfile.updateIconSize(1f, resources);
     }
@@ -682,9 +692,7 @@
         }
 
         if (DisplayController.isTransientTaskbar(this)) {
-            int taskbarSize = resources.getDimensionPixelSize(mDeviceProfile.isTwoPanels
-                    ? R.dimen.transient_taskbar_two_panels_size
-                    : R.dimen.transient_taskbar_size);
+            int taskbarSize = resources.getDimensionPixelSize(R.dimen.transient_taskbar_size);
             return taskbarSize
                     + (2 * resources.getDimensionPixelSize(R.dimen.transient_taskbar_margin))
                     + resources.getDimensionPixelSize(R.dimen.transient_taskbar_shadow_blur);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index ff7e8e9..cf3af08 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -16,20 +16,17 @@
 
 package com.android.launcher3.taskbar
 
-import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
-import com.android.launcher3.Utilities.mapToRange
-
 import android.graphics.Canvas
 import android.graphics.Color
 import android.graphics.Paint
 import android.graphics.Path
 import com.android.launcher3.R
+import com.android.launcher3.Utilities.mapToRange
 import com.android.launcher3.anim.Interpolators
+import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
 import com.android.launcher3.util.DisplayController
 
-/**
- * Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners.
- */
+/** Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners. */
 class TaskbarBackgroundRenderer(context: TaskbarActivityContext) {
 
     val paint: Paint = Paint()
@@ -39,7 +36,7 @@
     private var maxBackgroundHeight = context.deviceProfile.taskbarSize.toFloat()
     private val transientBackgroundBounds = context.transientTaskbarBounds
 
-    private val isTransientTaskbar = DisplayController.isTransientTaskbar(context);
+    private val isTransientTaskbar = DisplayController.isTransientTaskbar(context)
 
     private var shadowBlur = 0f
     private var keyShadowDistance = 0f
@@ -98,9 +95,7 @@
         invertedRightCornerPath.op(square, circle, Path.Op.DIFFERENCE)
     }
 
-    /**
-     * Draws the background with the given paint and height, on the provided canvas.
-     */
+    /** Draws the background with the given paint and height, on the provided canvas. */
     fun draw(canvas: Canvas) {
         canvas.save()
         canvas.translate(0f, canvas.height - backgroundHeight - bottomMargin)
@@ -124,21 +119,26 @@
             canvas.translate(0f, bottomMargin * ((1f - scaleFactor) / 2f))
 
             // Draw shadow.
-            val shadowAlpha = mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, 25f,
-                Interpolators.LINEAR)
-            paint.setShadowLayer(shadowBlur, 0f, keyShadowDistance,
+            val shadowAlpha =
+                mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, 25f, Interpolators.LINEAR)
+            paint.setShadowLayer(
+                shadowBlur,
+                0f,
+                keyShadowDistance,
                 setColorAlphaBound(Color.BLACK, Math.round(shadowAlpha))
             )
 
             // Draw background.
-            val radius = backgroundHeight / 2f;
+            val radius = backgroundHeight / 2f
 
             canvas.drawRoundRect(
                 transientBackgroundBounds.left + (delta / 2f),
                 translationYForSwipe,
                 transientBackgroundBounds.right - (delta / 2f),
                 backgroundHeight + translationYForSwipe,
-                radius, radius, paint
+                radius,
+                radius,
+                paint
             )
         }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index b388512..9f24565 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -18,8 +18,8 @@
 import android.graphics.Insets
 import android.graphics.Region
 import android.view.InsetsFrameProvider
-import android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES
 import android.view.InsetsState
+import android.view.InsetsState.ITYPE_BOTTOM_MANDATORY_GESTURES
 import android.view.InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT
 import android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR
 import android.view.ViewTreeObserver
@@ -36,10 +36,8 @@
 import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
 import java.io.PrintWriter
 
-/**
- * Handles the insets that Taskbar provides to underlying apps and the IME.
- */
-class TaskbarInsetsController(val context: TaskbarActivityContext): LoggableTaskbarController {
+/** Handles the insets that Taskbar provides to underlying apps and the IME. */
+class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTaskbarController {
 
     /** The bottom insets taskbar provides to the IME when IME is visible. */
     val taskbarHeightForIme: Int = context.resources.getDimensionPixelSize(R.dimen.taskbar_ime_size)
@@ -77,42 +75,56 @@
 
     fun onTaskbarWindowHeightOrInsetsChanged() {
         val touchableHeight = controllers.taskbarStashController.touchableHeight
-        touchableRegion.set(0, windowLayoutParams.height - touchableHeight,
-            context.deviceProfile.widthPx, windowLayoutParams.height)
+        touchableRegion.set(
+            0,
+            windowLayoutParams.height - touchableHeight,
+            context.deviceProfile.widthPx,
+            windowLayoutParams.height
+        )
         val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
         val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
         for (provider in windowLayoutParams.providedInsets) {
-            if (provider.type == ITYPE_EXTRA_NAVIGATION_BAR) {
+            if (
+                provider.type == ITYPE_EXTRA_NAVIGATION_BAR ||
+                    provider.type == ITYPE_BOTTOM_MANDATORY_GESTURES
+            ) {
                 provider.insetsSize = getInsetsByNavMode(contentHeight)
-            } else if (provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT
-                      || provider.type == ITYPE_BOTTOM_MANDATORY_GESTURES) {
+            } else if (provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) {
                 provider.insetsSize = getInsetsByNavMode(tappableHeight)
             }
         }
 
         val imeInsetsSize = getInsetsByNavMode(taskbarHeightForIme)
-        // Use 0 insets for the VoiceInteractionWindow (assistant) when gesture nav is enabled.
-        val visInsetsSize = getInsetsByNavMode(if (context.isGestureNav) 0 else tappableHeight)
-        val insetsSizeOverride = arrayOf(
-            InsetsFrameProvider.InsetsSizeOverride(
-                TYPE_INPUT_METHOD,
-                imeInsetsSize
-            ),
-            InsetsFrameProvider.InsetsSizeOverride(
-                TYPE_VOICE_INTERACTION,
-                visInsetsSize
+        val insetsSizeOverride =
+            arrayOf(
+                InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
             )
-        )
+        // Use 0 tappableElement insets for the VoiceInteractionWindow when gesture nav is enabled.
+        val visInsetsSizeForGestureNavTappableElement = getInsetsByNavMode(0)
+        val insetsSizeOverrideForGestureNavTappableElement =
+            arrayOf(
+                InsetsFrameProvider.InsetsSizeOverride(TYPE_INPUT_METHOD, imeInsetsSize),
+                InsetsFrameProvider.InsetsSizeOverride(
+                    TYPE_VOICE_INTERACTION,
+                    visInsetsSizeForGestureNavTappableElement
+                ),
+            )
         for (provider in windowLayoutParams.providedInsets) {
-            provider.insetsSizeOverrides = insetsSizeOverride
+            if (context.isGestureNav && provider.type == ITYPE_BOTTOM_TAPPABLE_ELEMENT) {
+                provider.insetsSizeOverrides = insetsSizeOverrideForGestureNavTappableElement
+            } else {
+                provider.insetsSizeOverrides = insetsSizeOverride
+            }
         }
     }
 
     /**
      * @return [Insets] where the [bottomInset] is either used as a bottom inset or
+     * ```
      *         right/left inset if using 3 button nav
+     * ```
      */
-    private fun getInsetsByNavMode(bottomInset: Int) : Insets {
+    private fun getInsetsByNavMode(bottomInset: Int): Insets {
         val devicePortrait = !context.deviceProfile.isLandscape
         if (!TaskbarManager.isPhoneButtonNavMode(context) || devicePortrait) {
             // Taskbar or portrait phone mode
@@ -129,9 +141,9 @@
      * @param providesInsetsTypes The inset types we would like this layout params to provide.
      */
     fun setProvidesInsetsTypes(params: WindowManager.LayoutParams, providesInsetsTypes: IntArray) {
-        params.providedInsets = arrayOfNulls<InsetsFrameProvider>(providesInsetsTypes.size);
+        params.providedInsets = arrayOfNulls<InsetsFrameProvider>(providesInsetsTypes.size)
         for (i in providesInsetsTypes.indices) {
-            params.providedInsets[i] = InsetsFrameProvider(providesInsetsTypes[i]);
+            params.providedInsets[i] = InsetsFrameProvider(providesInsetsTypes[i])
         }
     }
 
@@ -143,14 +155,17 @@
         insetsInfo.touchableRegion.setEmpty()
         // Always have nav buttons be touchable
         controllers.navbarButtonsViewController.addVisibleButtonsRegion(
-            context.dragLayer, insetsInfo.touchableRegion
+            context.dragLayer,
+            insetsInfo.touchableRegion
         )
         var insetsIsTouchableRegion = true
         if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
             // Let touches pass through us.
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
-        } else if (controllers.navbarButtonsViewController.isImeVisible
-                && controllers.taskbarStashController.isStashed()) {
+        } else if (
+            controllers.navbarButtonsViewController.isImeVisible &&
+                controllers.taskbarStashController.isStashed()
+        ) {
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
         } else if (!controllers.uiController.isTaskbarTouchable) {
             // Let touches pass through us.
@@ -164,9 +179,10 @@
                 insetsInfo.touchableRegion.set(touchableRegion)
             }
             insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION)
-        } else if (controllers.taskbarViewController.areIconsVisible()
-            || AbstractFloatingView.hasOpenView(context, AbstractFloatingView.TYPE_ALL)
-            || context.isNavBarKidsModeActive
+        } else if (
+            controllers.taskbarViewController.areIconsVisible() ||
+                AbstractFloatingView.hasOpenView(context, AbstractFloatingView.TYPE_ALL) ||
+                context.isNavBarKidsModeActive
         ) {
             // Taskbar has some touchable elements, take over the full taskbar area
             insetsInfo.setTouchableInsets(
@@ -188,8 +204,12 @@
         pw.println(prefix + "TaskbarInsetsController:")
         pw.println("$prefix\twindowHeight=${windowLayoutParams.height}")
         for (provider in windowLayoutParams.providedInsets) {
-            pw.print("$prefix\tprovidedInsets: (type=" + InsetsState.typeToString(provider.type)
-                    + " insetsSize=" + provider.insetsSize)
+            pw.print(
+                "$prefix\tprovidedInsets: (type=" +
+                    InsetsState.typeToString(provider.type) +
+                    " insetsSize=" +
+                    provider.insetsSize
+            )
             if (provider.insetsSizeOverrides != null) {
                 pw.print(" insetsSizeOverrides={")
                 for ((i, overrideSize) in provider.insetsSizeOverrides.withIndex()) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 4ad3858..7a75661 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -160,6 +160,7 @@
 
         mIconAlignment.finishAnimation();
 
+        Log.d("b/260135164", "onDestroy - updateIconAlphaForHome(1)");
         mLauncher.getHotseat().setIconsAlpha(1f);
         mLauncher.getStateManager().removeStateListener(mStateListener);
 
@@ -404,6 +405,8 @@
                 public void onAnimationEnd(Animator animation) {
                     if (isInStashedState && committed) {
                         // Reset hotseat alpha to default
+                        Log.d("b/260135164",
+                                "playStateTransitionAnim#onAnimationEnd - setIconsAlpha(1)");
                         mLauncher.getHotseat().setIconsAlpha(1);
                     }
                 }
@@ -452,6 +455,9 @@
          * Hide Launcher Hotseat icons when Taskbar icons have opacity. Both icon sets
          * should not be visible at the same time.
          */
+        Log.d("b/260135164",
+                "updateIconAlphaForHome - setIconsAlpha(" + (hotseatVisible ? 1 : 0)
+                        + "), isTaskbarPresent: " + mLauncher.getDeviceProfile().isTaskbarPresent);
         mLauncher.getHotseat().setIconsAlpha(hotseatVisible ? 1 : 0);
         mLauncher.getHotseat().setQsbAlpha(
                 mLauncher.getDeviceProfile().isQsbInline && !hotseatVisible ? 0 : 1);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 049c672..86e1911 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -320,6 +320,12 @@
         }
     }
 
+    public void onLongPressHomeEnabled(boolean assistantLongPressEnabled) {
+        if (mNavButtonController != null) {
+            mNavButtonController.setAssistantLongPressEnabled(assistantLongPressEnabled);
+        }
+    }
+
     /**
      * Sets the flag indicating setup UI is visible
      */
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index a395548..5bb958a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -67,6 +67,7 @@
 
     private long mLastScreenPinLongPress;
     private boolean mScreenPinned;
+    private boolean mAssistantLongPressEnabled;
 
     @Override
     public void dumpLogs(String prefix, PrintWriter pw) {
@@ -251,6 +252,10 @@
         mStatsLogManager = null;
     }
 
+    public void setAssistantLongPressEnabled(boolean assistantLongPressEnabled) {
+        mAssistantLongPressEnabled = assistantLongPressEnabled;
+    }
+
     private void logEvent(StatsLogManager.LauncherEvent event) {
         if (mStatsLogManager == null) {
             Log.w(TAG, "No stats log manager to log taskbar button event");
@@ -289,7 +294,7 @@
     }
 
     private void startAssistant() {
-        if (mScreenPinned) {
+        if (mScreenPinned || !mAssistantLongPressEnabled) {
             return;
         }
         Bundle args = new Bundle();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 95337ce..c269648 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -202,9 +202,7 @@
             Resources resources = mActivity.getResources();
             boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
             mUnstashedHeight = resources.getDimensionPixelSize(isTransientTaskbar
-                    ? (mActivity.getDeviceProfile().isTwoPanels
-                            ? R.dimen.transient_taskbar_two_panels_size
-                            : R.dimen.transient_taskbar_size)
+                    ? R.dimen.transient_taskbar_size
                     : R.dimen.taskbar_size);
             mStashedHeight = resources.getDimensionPixelSize(isTransientTaskbar
                     ? R.dimen.transient_taskbar_stashed_size
@@ -492,7 +490,8 @@
                 /* isStashed= */ false,
                 placeholderDuration,
                 /* startDelay= */ 0,
-                /* animateBg= */ false);
+                /* animateBg= */ false,
+                /* changedFlags=*/ 0);
         animation.play(mAnimator);
     }
 
@@ -503,8 +502,8 @@
      * @param startDelay how many milliseconds to delay the animation after starting it.
      * @param animateBg whether the taskbar's background should be animated
      */
-    private void createAnimToIsStashed(
-            boolean isStashed, long duration, long startDelay, boolean animateBg) {
+    private void createAnimToIsStashed(boolean isStashed, long duration, long startDelay,
+            boolean animateBg, int changedFlags) {
         if (mAnimator != null) {
             mAnimator.cancel();
         }
@@ -542,8 +541,10 @@
         final float firstHalfDurationScale;
         final float secondHalfDurationScale;
 
-        boolean isHotseatIconOnTopWhenAligned =
-                mControllers.uiController.isHotseatIconOnTopWhenAligned();
+        // If Hotseat is not the top element during animation to/from Launcher, fade in/out a
+        // already stashed Taskbar.
+        boolean skipStashAnimation = !mControllers.uiController.isHotseatIconOnTopWhenAligned()
+                && hasAnyFlag(changedFlags, FLAG_IN_APP);
         if (isStashed) {
             firstHalfDurationScale = 0.75f;
             secondHalfDurationScale = 0.5f;
@@ -565,8 +566,7 @@
                     mTaskbarStashedHandleAlpha.animateToValue(1)
             );
 
-            // If Hotseat is not the top element, an already stashed Taskbar should fade in.
-            if (!isHotseatIconOnTopWhenAligned) {
+            if (skipStashAnimation) {
                 fullLengthAnimatorSet.setInterpolator(INSTANT);
                 firstHalfAnimatorSet.setInterpolator(INSTANT);
             }
@@ -591,9 +591,7 @@
                     mIconAlphaForStash.animateToValue(1)
             );
 
-            // If Hotseat is not the top element, the stashed Taskbar should fade out without
-            // unstashing.
-            if (!isHotseatIconOnTopWhenAligned) {
+            if (skipStashAnimation) {
                 fullLengthAnimatorSet.setInterpolator(FINAL_FRAME);
                 secondHalfAnimatorSet.setInterpolator(FINAL_FRAME);
             }
@@ -986,7 +984,8 @@
                 mIsHotseatIconOnTopWhenAligned = isHotseatIconOnTopWhenAligned;
 
                 // This sets mAnimator.
-                createAnimToIsStashed(mIsStashed, duration, startDelay, /* animateBg= */ true);
+                createAnimToIsStashed(
+                        mIsStashed, duration, startDelay, /* animateBg= */ true, changedFlags);
                 if (start) {
                     mAnimator.start();
                 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 2433a34..2fcd64b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -101,16 +101,15 @@
         super(context, attrs, defStyleAttr, defStyleRes);
         mActivityContext = ActivityContext.lookupContext(context);
         mIconLayoutBounds = mActivityContext.getTransientTaskbarBounds();
-        mIsRtl = Utilities.isRtl(getResources());
-
         Resources resources = getResources();
-        mIconTouchSize = resources.getDimensionPixelSize(R.dimen.taskbar_icon_touch_size);
+        mIsRtl = Utilities.isRtl(resources);
 
-        int actualMargin = DisplayController.isTransientTaskbar(mActivityContext)
-                ? resources.getDimensionPixelSize(R.dimen.transient_taskbar_icon_spacing)
-                : resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
+        int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
         int actualIconSize = mActivityContext.getDeviceProfile().iconSizePx;
 
+        mIconTouchSize = Math.max(actualIconSize,
+                resources.getDimensionPixelSize(R.dimen.taskbar_icon_min_touch_size));
+
         // We layout the icons to be of mIconTouchSize in width and height
         mItemMarginLeftRight = actualMargin - (mIconTouchSize - actualIconSize) / 2;
         mItemPadding = (mIconTouchSize - actualIconSize) / 2;
diff --git a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
index a033507..be34fb1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/VoiceInteractionWindowController.kt
@@ -10,12 +10,9 @@
 private const val TASKBAR_ICONS_FADE_DURATION = 300L
 private const val STASHED_HANDLE_FADE_DURATION = 180L
 
-/**
- * Controls Taskbar behavior while Voice Interaction Window (assistant) is showing.
- */
-class VoiceInteractionWindowController(val context: TaskbarActivityContext)
-    : TaskbarControllers.LoggableTaskbarController,
-        TaskbarControllers.BackgroundRendererController {
+/** Controls Taskbar behavior while Voice Interaction Window (assistant) is showing. */
+class VoiceInteractionWindowController(val context: TaskbarActivityContext) :
+    TaskbarControllers.LoggableTaskbarController, TaskbarControllers.BackgroundRendererController {
 
     private val taskbarBackgroundRenderer = TaskbarBackgroundRenderer(context)
 
@@ -37,8 +34,10 @@
 
                 override fun draw(canvas: Canvas) {
                     super.draw(canvas)
-                    if (this@VoiceInteractionWindowController.context.isGestureNav
-                        && controllers.taskbarStashController.isInAppAndNotStashed) {
+                    if (
+                        this@VoiceInteractionWindowController.context.isGestureNav &&
+                            controllers.taskbarStashController.isInAppAndNotStashed
+                    ) {
                         taskbarBackgroundRenderer.draw(canvas)
                     }
                 }
@@ -46,8 +45,8 @@
         separateWindowForTaskbarBackground.recreateControllers()
         separateWindowForTaskbarBackground.setWillNotDraw(false)
 
-        separateWindowLayoutParams = context.createDefaultWindowLayoutParams(
-            TYPE_APPLICATION_OVERLAY)
+        separateWindowLayoutParams =
+            context.createDefaultWindowLayoutParams(TYPE_APPLICATION_OVERLAY)
         separateWindowLayoutParams.isSystemApplicationOverlay = true
     }
 
@@ -63,14 +62,16 @@
 
         // Fade out taskbar icons and stashed handle.
         val taskbarIconAlpha = if (isVoiceInteractionWindowVisible) 0f else 1f
-        val fadeTaskbarIcons = controllers.taskbarViewController.taskbarIconAlpha
-            .get(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
-            .animateToValue(taskbarIconAlpha)
-            .setDuration(TASKBAR_ICONS_FADE_DURATION)
-        val fadeStashedHandle = controllers.stashedHandleViewController.stashedHandleAlpha
-            .get(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
-            .animateToValue(taskbarIconAlpha)
-            .setDuration(STASHED_HANDLE_FADE_DURATION)
+        val fadeTaskbarIcons =
+            controllers.taskbarViewController.taskbarIconAlpha
+                .get(TaskbarViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
+                .animateToValue(taskbarIconAlpha)
+                .setDuration(TASKBAR_ICONS_FADE_DURATION)
+        val fadeStashedHandle =
+            controllers.stashedHandleViewController.stashedHandleAlpha
+                .get(StashedHandleViewController.ALPHA_INDEX_ASSISTANT_INVOKED)
+                .animateToValue(taskbarIconAlpha)
+                .setDuration(STASHED_HANDLE_FADE_DURATION)
         fadeTaskbarIcons.start()
         fadeStashedHandle.start()
         if (skipAnim) {
@@ -83,23 +84,30 @@
 
     /**
      * Either:
+     *
      * Hides the TaskbarDragLayer background and creates a new window to draw just that background.
+     *
      * OR
+     *
      * Removes the temporary window and show the TaskbarDragLayer background again.
      */
     private fun moveTaskbarBackgroundToAppropriateLayer(skipAnim: Boolean) {
-        val taskbarBackgroundOverride = controllers.taskbarDragLayerController
-            .overrideBackgroundAlpha
+        val taskbarBackgroundOverride =
+            controllers.taskbarDragLayerController.overrideBackgroundAlpha
         val moveToLowerLayer = isVoiceInteractionWindowVisible
-        val onWindowsSynchronized = if (moveToLowerLayer) {
-            // First add the temporary window, then hide the overlapping taskbar background.
-            context.addWindowView(separateWindowForTaskbarBackground, separateWindowLayoutParams);
-            { taskbarBackgroundOverride.updateValue(0f) }
-        } else {
-            // First reapply the original taskbar background, then remove the temporary window.
-            taskbarBackgroundOverride.updateValue(1f);
-            { context.removeWindowView(separateWindowForTaskbarBackground) }
-        }
+        val onWindowsSynchronized =
+            if (moveToLowerLayer) {
+                // First add the temporary window, then hide the overlapping taskbar background.
+                context.addWindowView(
+                    separateWindowForTaskbarBackground,
+                    separateWindowLayoutParams
+                );
+                { taskbarBackgroundOverride.updateValue(0f) }
+            } else {
+                // First reapply the original taskbar background, then remove the temporary window.
+                taskbarBackgroundOverride.updateValue(1f);
+                { context.removeWindowView(separateWindowForTaskbarBackground) }
+            }
 
         if (skipAnim) {
             onWindowsSynchronized()
@@ -121,4 +129,4 @@
         pw.println(prefix + "VoiceInteractionWindowController:")
         pw.println("$prefix\tisVoiceInteractionWindowVisible=$isVoiceInteractionWindowVisible")
     }
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
index 68ea27a..a82902f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/AbstractNavButtonLayoutter.kt
@@ -30,20 +30,17 @@
  * [navButtonContainer]
  *
  * @property navButtonContainer ViewGroup that holds the 3 navigation buttons.
- * @property endContextualContainer ViewGroup that holds the end contextual button (ex, IME dismiss).
+ * @property endContextualContainer ViewGroup that holds the end contextual button (ex, IME
+ * dismiss).
  * @property startContextualContainer ViewGroup that holds the start contextual button (ex, A11y).
  */
 abstract class AbstractNavButtonLayoutter(
-        val resources: Resources,
-        val navButtonContainer: LinearLayout,
-        protected val endContextualContainer: ViewGroup,
-        protected val startContextualContainer: ViewGroup
+    val resources: Resources,
+    val navButtonContainer: LinearLayout,
+    protected val endContextualContainer: ViewGroup,
+    protected val startContextualContainer: ViewGroup
 ) : NavButtonLayoutter {
-    protected val homeButton: ImageView = navButtonContainer
-            .findViewById(R.id.home)
-    protected val recentsButton: ImageView = navButtonContainer
-            .findViewById(R.id.recent_apps)
-    protected val backButton: ImageView = navButtonContainer
-            .findViewById(R.id.back)
+    protected val homeButton: ImageView = navButtonContainer.findViewById(R.id.home)
+    protected val recentsButton: ImageView = navButtonContainer.findViewById(R.id.recent_apps)
+    protected val backButton: ImageView = navButtonContainer.findViewById(R.id.back)
 }
-
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
index c67ab79..c093c92 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/KidsNavLayoutter.kt
@@ -35,56 +35,47 @@
 import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.DRAWABLE_SYSBAR_HOME_KIDS
 
 class KidsNavLayoutter(
-        resources: Resources,
-        navBarContainer: LinearLayout,
-        endContextualContainer: ViewGroup,
-        startContextualContainer: ViewGroup
-) : AbstractNavButtonLayoutter(
+    resources: Resources,
+    navBarContainer: LinearLayout,
+    endContextualContainer: ViewGroup,
+    startContextualContainer: ViewGroup
+) :
+    AbstractNavButtonLayoutter(
         resources,
         navBarContainer,
         endContextualContainer,
         startContextualContainer
-) {
+    ) {
 
     override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
-        val iconSize: Int = resources.getDimensionPixelSize(
-                DIMEN_TASKBAR_ICON_SIZE_KIDS)
-        val buttonWidth: Int = resources.getDimensionPixelSize(
-                DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS)
-        val buttonHeight: Int = resources.getDimensionPixelSize(
-                DIMEN_TASKBAR_NAV_BUTTONS_HEIGHT_KIDS)
-        val buttonRadius: Int = resources.getDimensionPixelSize(
-                DIMEN_TASKBAR_NAV_BUTTONS_CORNER_RADIUS_KIDS)
+        val iconSize: Int = resources.getDimensionPixelSize(DIMEN_TASKBAR_ICON_SIZE_KIDS)
+        val buttonWidth: Int = resources.getDimensionPixelSize(DIMEN_TASKBAR_NAV_BUTTONS_WIDTH_KIDS)
+        val buttonHeight: Int =
+            resources.getDimensionPixelSize(DIMEN_TASKBAR_NAV_BUTTONS_HEIGHT_KIDS)
+        val buttonRadius: Int =
+            resources.getDimensionPixelSize(DIMEN_TASKBAR_NAV_BUTTONS_CORNER_RADIUS_KIDS)
         val paddingLeft = (buttonWidth - iconSize) / 2
         val paddingTop = (buttonHeight - iconSize) / 2
 
         // Update icons
-        backButton.setImageDrawable(
-                backButton.context.getDrawable(DRAWABLE_SYSBAR_BACK_KIDS))
+        backButton.setImageDrawable(backButton.context.getDrawable(DRAWABLE_SYSBAR_BACK_KIDS))
         backButton.scaleType = ImageView.ScaleType.FIT_CENTER
         backButton.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop)
-        homeButton.setImageDrawable(
-                homeButton.getContext().getDrawable(DRAWABLE_SYSBAR_HOME_KIDS))
+        homeButton.setImageDrawable(homeButton.getContext().getDrawable(DRAWABLE_SYSBAR_HOME_KIDS))
         homeButton.scaleType = ImageView.ScaleType.FIT_CENTER
         homeButton.setPadding(paddingLeft, paddingTop, paddingLeft, paddingTop)
 
         // Home button layout
-        val homeLayoutparams = LinearLayout.LayoutParams(
-                buttonWidth,
-                buttonHeight
-        )
-        val homeButtonLeftMargin: Int = resources.getDimensionPixelSize(
-                DIMEN_TASKBAR_HOME_BUTTON_LEFT_MARGIN_KIDS)
+        val homeLayoutparams = LinearLayout.LayoutParams(buttonWidth, buttonHeight)
+        val homeButtonLeftMargin: Int =
+            resources.getDimensionPixelSize(DIMEN_TASKBAR_HOME_BUTTON_LEFT_MARGIN_KIDS)
         homeLayoutparams.setMargins(homeButtonLeftMargin, 0, 0, 0)
         homeButton.layoutParams = homeLayoutparams
 
         // Back button layout
-        val backLayoutParams = LinearLayout.LayoutParams(
-                buttonWidth,
-                buttonHeight
-        )
-        val backButtonLeftMargin: Int = resources.getDimensionPixelSize(
-                DIMEN_TASKBAR_BACK_BUTTON_LEFT_MARGIN_KIDS)
+        val backLayoutParams = LinearLayout.LayoutParams(buttonWidth, buttonHeight)
+        val backButtonLeftMargin: Int =
+            resources.getDimensionPixelSize(DIMEN_TASKBAR_BACK_BUTTON_LEFT_MARGIN_KIDS)
         backLayoutParams.setMargins(backButtonLeftMargin, 0, 0, 0)
         backButton.layoutParams = backLayoutParams
 
@@ -106,4 +97,4 @@
 
         homeButton.onLongClickListener = null
     }
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
index db0a2d8..2092721 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactory.kt
@@ -30,10 +30,9 @@
 /**
  * Select the correct layout for nav buttons
  *
- * Since layouts are done dynamically for the nav buttons on Taskbar, this
- * class returns a corresponding [NavButtonLayoutter] via
- * [Companion.getUiLayoutter]
- * that can help position the buttons based on the current [DeviceProfile]
+ * Since layouts are done dynamically for the nav buttons on Taskbar, this class returns a
+ * corresponding [NavButtonLayoutter] via [Companion.getUiLayoutter] that can help position the
+ * buttons based on the current [DeviceProfile]
  */
 class NavButtonLayoutFactory {
     companion object {
@@ -41,11 +40,10 @@
          * Get the correct instance of [NavButtonLayoutter]
          *
          * No layouts supported for configurations where:
-         *  * taskbar isn't showing AND
-         *  * the device is not in [phoneMode]
-         * OR
-         *  * phone is showing
-         *  * device is using gesture navigation
+         * * taskbar isn't showing AND
+         * * the device is not in [phoneMode] OR
+         * * phone is showing
+         * * device is using gesture navigation
          *
          * @param navButtonsView ViewGroup that contains start, end, nav button ViewGroups
          * @param isKidsMode no-op when taskbar is hidden/not showing
@@ -53,44 +51,64 @@
          * @param phoneMode refers to the device using the taskbar window on phones
          * @param isThreeButtonNav are no-ops when taskbar is present/showing
          */
-        fun getUiLayoutter(deviceProfile: DeviceProfile,
-                           navButtonsView: FrameLayout,
-                           resources: Resources,
-                           isKidsMode: Boolean,
-                           isInSetup: Boolean,
-                           isThreeButtonNav: Boolean,
-                           phoneMode: Boolean):
-                NavButtonLayoutter {
-            val navButtonContainer =
-                    navButtonsView.findViewById<LinearLayout>(ID_END_NAV_BUTTONS)
+        fun getUiLayoutter(
+            deviceProfile: DeviceProfile,
+            navButtonsView: FrameLayout,
+            resources: Resources,
+            isKidsMode: Boolean,
+            isInSetup: Boolean,
+            isThreeButtonNav: Boolean,
+            phoneMode: Boolean
+        ): NavButtonLayoutter {
+            val navButtonContainer = navButtonsView.findViewById<LinearLayout>(ID_END_NAV_BUTTONS)
             val endContextualContainer =
-                    navButtonsView.findViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS)
+                navButtonsView.findViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS)
             val startContextualContainer =
-                    navButtonsView.findViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS)
+                navButtonsView.findViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS)
             val isPhoneNavMode = phoneMode && isThreeButtonNav
             return when {
                 isPhoneNavMode -> {
                     if (!deviceProfile.isLandscape) {
-                        PhonePortraitNavLayoutter(resources, navButtonContainer,
-                                endContextualContainer, startContextualContainer)
+                        PhonePortraitNavLayoutter(
+                            resources,
+                            navButtonContainer,
+                            endContextualContainer,
+                            startContextualContainer
+                        )
                     } else {
-                        PhoneLandscapeNavLayoutter(resources, navButtonContainer,
-                                endContextualContainer, startContextualContainer)
+                        PhoneLandscapeNavLayoutter(
+                            resources,
+                            navButtonContainer,
+                            endContextualContainer,
+                            startContextualContainer
+                        )
                     }
                 }
                 deviceProfile.isTaskbarPresent -> {
                     return when {
                         isInSetup -> {
-                            SetupNavLayoutter(resources, navButtonContainer, endContextualContainer,
-                                    startContextualContainer)
+                            SetupNavLayoutter(
+                                resources,
+                                navButtonContainer,
+                                endContextualContainer,
+                                startContextualContainer
+                            )
                         }
                         isKidsMode -> {
-                            KidsNavLayoutter(resources, navButtonContainer, endContextualContainer,
-                                    startContextualContainer)
+                            KidsNavLayoutter(
+                                resources,
+                                navButtonContainer,
+                                endContextualContainer,
+                                startContextualContainer
+                            )
                         }
                         else ->
-                            TaskbarNavLayoutter(resources, navButtonContainer, endContextualContainer,
-                                    startContextualContainer)
+                            TaskbarNavLayoutter(
+                                resources,
+                                navButtonContainer,
+                                endContextualContainer,
+                                startContextualContainer
+                            )
                     }
                 }
                 else -> error("No layoutter found")
@@ -98,8 +116,8 @@
         }
     }
 
-    /** Lays out and provides access to the home, recents, and back buttons for various mischief  */
+    /** Lays out and provides access to the home, recents, and back buttons for various mischief */
     interface NavButtonLayoutter {
         fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean)
     }
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
index a89476e..201895f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhoneLandscapeNavLayoutter.kt
@@ -28,24 +28,24 @@
 import com.android.launcher3.util.DimensionUtils
 
 class PhoneLandscapeNavLayoutter(
-        resources: Resources,
-        navBarContainer: LinearLayout,
-        endContextualContainer: ViewGroup,
-        startContextualContainer: ViewGroup
-) : AbstractNavButtonLayoutter(
+    resources: Resources,
+    navBarContainer: LinearLayout,
+    endContextualContainer: ViewGroup,
+    startContextualContainer: ViewGroup
+) :
+    AbstractNavButtonLayoutter(
         resources,
         navBarContainer,
         endContextualContainer,
         startContextualContainer
-) {
+    ) {
 
     override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
         // TODO(b/230395757): Polish pending, this is just to make it usable
         val navContainerParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
-        val endStartMargins =
-                resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
-        val taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(dp, resources,
-                TaskbarManager.isPhoneMode(dp))
+        val endStartMargins = resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
+        val taskbarDimensions =
+            DimensionUtils.getTaskbarPhoneDimensions(dp, resources, TaskbarManager.isPhoneMode(dp))
         navButtonContainer.removeAllViews()
         navButtonContainer.orientation = LinearLayout.VERTICAL
 
@@ -68,7 +68,7 @@
 
         // Add the spaces in between the nav buttons
         val spaceInBetween: Int =
-                resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
+            resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
         navButtonContainer.children.forEachIndexed { i, navButton ->
             val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
             buttonLayoutParams.weight = 1f
@@ -86,4 +86,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
index 275f59f..f7ac974 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/PhonePortraitNavLayoutter.kt
@@ -26,17 +26,24 @@
 import com.android.launcher3.taskbar.TaskbarManager
 import com.android.launcher3.util.DimensionUtils
 
-class PhonePortraitNavLayoutter(resources: Resources, navBarContainer: LinearLayout,
-                                endContextualContainer: ViewGroup,
-                                startContextualContainer: ViewGroup) :
-        AbstractNavButtonLayoutter(resources, navBarContainer, endContextualContainer,
-                startContextualContainer) {
+class PhonePortraitNavLayoutter(
+    resources: Resources,
+    navBarContainer: LinearLayout,
+    endContextualContainer: ViewGroup,
+    startContextualContainer: ViewGroup
+) :
+    AbstractNavButtonLayoutter(
+        resources,
+        navBarContainer,
+        endContextualContainer,
+        startContextualContainer
+    ) {
 
     override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
         // TODO(b/230395757): Polish pending, this is just to make it usable
         val navContainerParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
-        val taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(dp, resources,
-                TaskbarManager.isPhoneMode(dp))
+        val taskbarDimensions =
+            DimensionUtils.getTaskbarPhoneDimensions(dp, resources, TaskbarManager.isPhoneMode(dp))
         val endStartMargins = resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
         navContainerParams.width = taskbarDimensions.x
         navContainerParams.height = ViewGroup.LayoutParams.MATCH_PARENT
@@ -58,7 +65,7 @@
 
         // Add the spaces in between the nav buttons
         val spaceInBetween =
-                resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
+            resources.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween_phone)
         for (i in 0 until navButtonContainer.childCount) {
             val navButton = navButtonContainer.getChildAt(i)
             val buttonLayoutParams = navButton.layoutParams as LinearLayout.LayoutParams
@@ -80,4 +87,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
index afe70d6..a24002c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/SetupNavLayoutter.kt
@@ -24,16 +24,17 @@
 import com.android.launcher3.DeviceProfile
 
 class SetupNavLayoutter(
-        resources: Resources,
-        navButtonContainer: LinearLayout,
-        endContextualContainer: ViewGroup,
-        startContextualContainer: ViewGroup
-) : AbstractNavButtonLayoutter(
+    resources: Resources,
+    navButtonContainer: LinearLayout,
+    endContextualContainer: ViewGroup,
+    startContextualContainer: ViewGroup
+) :
+    AbstractNavButtonLayoutter(
         resources,
         navButtonContainer,
         endContextualContainer,
         startContextualContainer
-) {
+    ) {
 
     override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
         // Since setup wizard only has back button enabled, it looks strange to be
@@ -46,4 +47,4 @@
         }
         navButtonContainer.requestLayout()
     }
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
index b2ca2af..5ec7ca0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/navbutton/TaskbarNavLayoutter.kt
@@ -24,20 +24,19 @@
 import com.android.launcher3.DeviceProfile
 import com.android.launcher3.R
 
-/**
- * Layoutter for showing 3 button navigation on large screen
- */
+/** Layoutter for showing 3 button navigation on large screen */
 class TaskbarNavLayoutter(
-        resources: Resources,
-        navBarContainer: LinearLayout,
-        endContextualContainer: ViewGroup,
-        startContextualContainer: ViewGroup
-) : AbstractNavButtonLayoutter(
+    resources: Resources,
+    navBarContainer: LinearLayout,
+    endContextualContainer: ViewGroup,
+    startContextualContainer: ViewGroup
+) :
+    AbstractNavButtonLayoutter(
         resources,
         navBarContainer,
         endContextualContainer,
         startContextualContainer
-) {
+    ) {
 
     override fun layoutButtons(dp: DeviceProfile, isContextualButtonShowing: Boolean) {
         // Add spacing after the end of the last nav button
@@ -80,4 +79,4 @@
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index 379a6cd..ca7ce74 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -17,14 +17,9 @@
 package com.android.launcher3.uioverrides;
 
 import android.app.Person;
-import android.appwidget.AppWidgetHost;
 import android.content.pm.ShortcutInfo;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 import com.android.launcher3.Utilities;
-import com.android.launcher3.widget.LauncherWidgetHolder;
 
 /**
  * A wrapper for the hidden API calls
@@ -37,14 +32,4 @@
         Person[] persons = si.getPersons();
         return persons == null ? Utilities.EMPTY_PERSON_ARRAY : persons;
     }
-
-    /**
-     * Set the interaction handler for the host
-     * @param host AppWidgetHost that needs the interaction handler
-     * @param handler InteractionHandler for the views in the host
-     */
-    public static void setHostInteractionHandler(@NonNull AppWidgetHost host,
-            @Nullable LauncherWidgetHolder.LauncherWidgetInteractionHandler handler) {
-        host.setInteractionHandler(handler::onInteraction);
-    }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java
new file mode 100644
index 0000000..6659fa0
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepAppWidgetHost.java
@@ -0,0 +1,70 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.uioverrides;
+
+import static com.android.launcher3.widget.LauncherWidgetHolder.APPWIDGET_HOST_ID;
+
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.os.Looper;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.LauncherWidgetHolder;
+
+import java.util.function.IntConsumer;
+
+/**
+ * {@link AppWidgetHost} that is used to receive the changes to the widgets without
+ * storing any {@code Activity} info like that of the launcher.
+ */
+final class QuickstepAppWidgetHost extends AppWidgetHost {
+    private final @NonNull Context mContext;
+    private final @NonNull IntConsumer mAppWidgetRemovedCallback;
+    private final @NonNull LauncherWidgetHolder.ProviderChangedListener mProvidersChangedListener;
+
+    QuickstepAppWidgetHost(@NonNull Context context, @NonNull IntConsumer appWidgetRemovedCallback,
+            @NonNull LauncherWidgetHolder.ProviderChangedListener listener,
+            @NonNull Looper looper) {
+        super(context, APPWIDGET_HOST_ID, null, looper);
+        mContext = context;
+        mAppWidgetRemovedCallback = appWidgetRemovedCallback;
+        mProvidersChangedListener = listener;
+    }
+
+    @Override
+    protected void onProvidersChanged() {
+        mProvidersChangedListener.notifyWidgetProvidersChanged();
+    }
+
+    @Override
+    public void onAppWidgetRemoved(int appWidgetId) {
+        mAppWidgetRemovedCallback.accept(appWidgetId);
+    }
+
+    @Override
+    protected void onProviderChanged(int appWidgetId, @NonNull AppWidgetProviderInfo appWidget) {
+        LauncherAppWidgetProviderInfo info = LauncherAppWidgetProviderInfo.fromProviderInfo(
+                mContext, appWidget);
+        super.onProviderChanged(appWidgetId, info);
+        // The super method updates the dimensions of the providerInfo. Update the
+        // launcher spans accordingly.
+        info.initSpans(mContext, LauncherAppState.getIDP(mContext));
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
index 353d817..08d147f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
@@ -34,11 +34,9 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.ActivityOptionsWrapper;
 import com.android.launcher3.widget.LauncherAppWidgetHostView;
-import com.android.launcher3.widget.LauncherWidgetHolder;
 
 /** Provides a Quickstep specific animation when launching an activity from an app widget. */
-class QuickstepInteractionHandler
-        implements LauncherWidgetHolder.LauncherWidgetInteractionHandler {
+class QuickstepInteractionHandler implements RemoteViews.InteractionHandler {
 
     private static final String TAG = "QuickstepInteractionHandler";
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 13d0be5..28c8980 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -96,7 +96,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.proxy.StartActivityParams;
@@ -106,6 +105,7 @@
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.taskbar.LauncherTaskbarUIController;
 import com.android.launcher3.taskbar.TaskbarManager;
+import com.android.launcher3.uioverrides.QuickstepWidgetHolder.QuickstepHolderFactory;
 import com.android.launcher3.uioverrides.states.QuickstepAtomicAnimationFactory;
 import com.android.launcher3.uioverrides.touchcontrollers.NavBarToHomeTouchController;
 import com.android.launcher3.uioverrides.touchcontrollers.NoButtonNavbarToOverviewTouchController;
@@ -141,6 +141,7 @@
 import com.android.quickstep.util.SplitToWorkspaceController;
 import com.android.quickstep.util.SplitWithKeyboardShortcutController;
 import com.android.quickstep.util.TISBindHelper;
+import com.android.quickstep.views.DesktopTaskView;
 import com.android.quickstep.views.OverviewActionsView;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
@@ -517,9 +518,11 @@
 
     @Override
     protected LauncherWidgetHolder createAppWidgetHolder() {
-        LauncherWidgetHolder appWidgetHolder = super.createAppWidgetHolder();
-        appWidgetHolder.setInteractionHandler(new QuickstepInteractionHandler(this));
-        return appWidgetHolder;
+        final QuickstepHolderFactory factory =
+                (QuickstepHolderFactory) LauncherWidgetHolder.HolderFactory.newFactory(this);
+        return factory.newInstance(this,
+                appWidgetId -> getWorkspace().removeWidget(appWidgetId),
+                new QuickstepInteractionHandler(this));
     }
 
     @Override
@@ -662,6 +665,21 @@
     }
 
     @Override
+    public void setResumed() {
+        if (DesktopTaskView.DESKTOP_IS_PROTO2_ENABLED) {
+            DesktopVisibilityController controller = mDesktopVisibilityController;
+            if (controller != null && controller.areFreeformTasksVisible()
+                    && !controller.isGestureInProgress()) {
+                // Return early to skip setting activity to appear as resumed
+                // TODO(b/255649902): shouldn't be needed when we have a separate launcher state
+                //  for desktop that we can use to control other parts of launcher
+                return;
+            }
+        }
+        super.setResumed();
+    }
+
+    @Override
     protected void onDeferredResumed() {
         super.onDeferredResumed();
         handlePendingActivityRequest();
@@ -920,7 +938,11 @@
         // When changing screens, force moving to rest state similar to StatefulActivity.onStop, as
         // StatefulActivity isn't called consistently.
         if ((flags & CHANGE_ACTIVE_SCREEN) != 0) {
-            getStateManager().moveToRestState();
+            // Do not animate moving to rest state, as it can clash with Launcher#onIdpChanged
+            // where reapplyUi calls StateManager's reapplyState during the state change animation,
+            // and cancel the state change unexpectedly. The screen will be off during screen
+            // transition, hiding the unanimated transition.
+            getStateManager().moveToRestState(/* isAnimated = */false);
         }
 
         if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
new file mode 100644
index 0000000..a8edd51
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
@@ -0,0 +1,270 @@
+/**
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.uioverrides;
+
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetHostView;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.Context;
+import android.util.SparseArray;
+import android.widget.RemoteViews;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
+import androidx.annotation.WorkerThread;
+
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.util.Thunk;
+import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.LauncherWidgetHolder;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.WeakHashMap;
+import java.util.function.Consumer;
+import java.util.function.IntConsumer;
+
+/**
+ * {@link LauncherWidgetHolder} that puts the app widget host in the background
+ */
+public final class QuickstepWidgetHolder extends LauncherWidgetHolder {
+    private static final List<QuickstepWidgetHolder> sHolders = new ArrayList<>();
+    private static final SparseArray<QuickstepWidgetHolderListener> sListeners =
+            new SparseArray<>();
+
+    private static AppWidgetHost sWidgetHost = null;
+
+    private final @Nullable RemoteViews.InteractionHandler mInteractionHandler;
+
+    private final @NonNull IntConsumer mAppWidgetRemovedCallback;
+
+    private final ArrayList<ProviderChangedListener> mProviderChangedListeners = new ArrayList<>();
+
+    @Thunk
+    QuickstepWidgetHolder(@NonNull Context context,
+            @Nullable IntConsumer appWidgetRemovedCallback,
+            @Nullable RemoteViews.InteractionHandler interactionHandler) {
+        super(context, appWidgetRemovedCallback);
+        mAppWidgetRemovedCallback = appWidgetRemovedCallback != null ? appWidgetRemovedCallback
+                : i -> {};
+        mInteractionHandler = interactionHandler;
+        sHolders.add(this);
+    }
+
+    @Override
+    @NonNull
+    protected AppWidgetHost createHost(@NonNull Context context,
+            @Nullable IntConsumer appWidgetRemovedCallback) {
+        if (sWidgetHost == null) {
+            sWidgetHost = new QuickstepAppWidgetHost(context.getApplicationContext(),
+                    i -> MAIN_EXECUTOR.execute(() ->
+                            sHolders.forEach(h -> h.mAppWidgetRemovedCallback.accept(i))),
+                    () -> MAIN_EXECUTOR.execute(() ->
+                            sHolders.forEach(h -> h.mProviderChangedListeners.forEach(
+                            ProviderChangedListener::notifyWidgetProvidersChanged))),
+                    UI_HELPER_EXECUTOR.getLooper());
+            if (!WidgetsModel.GO_DISABLE_WIDGETS) {
+                sWidgetHost.startListening();
+            }
+        }
+        return sWidgetHost;
+    }
+
+    /**
+     * Delete the specified app widget from the host
+     * @param appWidgetId The ID of the app widget to be deleted
+     */
+    @Override
+    public void deleteAppWidgetId(int appWidgetId) {
+        super.deleteAppWidgetId(appWidgetId);
+        sListeners.remove(appWidgetId);
+    }
+
+    /**
+     * Called when the launcher is destroyed
+     */
+    @Override
+    public void destroy() {
+        sHolders.remove(this);
+    }
+
+    /**
+     * Add a listener that is triggered when the providers of the widgets are changed
+     * @param listener The listener that notifies when the providers changed
+     */
+    @Override
+    public void addProviderChangeListener(
+            @NonNull LauncherWidgetHolder.ProviderChangedListener listener) {
+        mProviderChangedListeners.add(listener);
+    }
+
+    /**
+     * Remove the specified listener from the host
+     * @param listener The listener that is to be removed from the host
+     */
+    @Override
+    public void removeProviderChangeListener(
+            LauncherWidgetHolder.ProviderChangedListener listener) {
+        mProviderChangedListeners.remove(listener);
+    }
+
+    /**
+     * Stop the host from updating the widget views
+     */
+    @Override
+    public void stopListening() {
+        if (WidgetsModel.GO_DISABLE_WIDGETS) {
+            return;
+        }
+
+        sWidgetHost.setAppWidgetHidden();
+        setListeningFlag(false);
+    }
+
+    /**
+     * Create a view for the specified app widget
+     * @param context The activity context for which the view is created
+     * @param appWidgetId The ID of the widget
+     * @param appWidget The {@link LauncherAppWidgetProviderInfo} of the widget
+     * @return A view for the widget
+     */
+    @NonNull
+    @Override
+    public LauncherAppWidgetHostView createView(@NonNull Context context, int appWidgetId,
+            @NonNull LauncherAppWidgetProviderInfo appWidget) {
+        LauncherAppWidgetHostView widgetView = getPendingView(appWidgetId);
+        if (widgetView != null) {
+            removePendingView(appWidgetId);
+        } else {
+            widgetView = new LauncherAppWidgetHostView(context);
+        }
+        widgetView.setInteractionHandler(mInteractionHandler);
+        widgetView.setAppWidget(appWidgetId, appWidget);
+
+        QuickstepWidgetHolderListener listener = sListeners.get(appWidgetId);
+        if (listener == null) {
+            listener = new QuickstepWidgetHolderListener(this, widgetView);
+            sWidgetHost.setListener(appWidgetId, listener);
+            sListeners.put(appWidgetId, listener);
+        } else {
+            listener.resetView(this, widgetView);
+        }
+
+        return widgetView;
+    }
+
+    /**
+     * Clears all the views from the host
+     */
+    @Override
+    public void clearViews() {
+        for (int i = sListeners.size() - 1; i >= 0; i--) {
+            sListeners.valueAt(i).mView.remove(this);
+        }
+    }
+
+    private static class QuickstepWidgetHolderListener
+            implements AppWidgetHost.AppWidgetHostListener {
+        @NonNull
+        private final Map<QuickstepWidgetHolder, AppWidgetHostView> mView = new WeakHashMap<>();
+
+        @Nullable
+        private RemoteViews mRemoteViews = null;
+
+        QuickstepWidgetHolderListener(@NonNull QuickstepWidgetHolder holder,
+                @NonNull LauncherAppWidgetHostView view) {
+            mView.put(holder, view);
+        }
+
+        @UiThread
+        public void resetView(@NonNull QuickstepWidgetHolder holder,
+                @NonNull AppWidgetHostView view) {
+            mView.put(holder, view);
+            view.updateAppWidget(mRemoteViews);
+        }
+
+        @Override
+        @WorkerThread
+        public void onUpdateProviderInfo(@Nullable AppWidgetProviderInfo info) {
+            mRemoteViews = null;
+            executeOnMainExecutor(v -> v.onUpdateProviderInfo(info));
+        }
+
+        @Override
+        @WorkerThread
+        public void updateAppWidget(@Nullable RemoteViews views) {
+            mRemoteViews = views;
+            executeOnMainExecutor(v -> v.updateAppWidget(mRemoteViews));
+        }
+
+        @Override
+        @WorkerThread
+        public void onViewDataChanged(int viewId) {
+            executeOnMainExecutor(v -> v.onViewDataChanged(viewId));
+        }
+
+        private void executeOnMainExecutor(Consumer<AppWidgetHostView> consumer) {
+            MAIN_EXECUTOR.execute(() -> mView.values().forEach(consumer));
+        }
+    }
+
+    /**
+     * {@code HolderFactory} subclass that takes an interaction handler as one of the parameters
+     * when creating a new instance.
+     */
+    public static class QuickstepHolderFactory extends HolderFactory {
+
+        @SuppressWarnings("unused")
+        public QuickstepHolderFactory(Context context) { }
+
+        @Override
+        public LauncherWidgetHolder newInstance(@NonNull Context context,
+                @Nullable IntConsumer appWidgetRemovedCallback) {
+            return newInstance(context, appWidgetRemovedCallback, null);
+        }
+
+        /**
+         * @param context The context of the caller
+         * @param appWidgetRemovedCallback The callback that is called when widgets are removed
+         * @param interactionHandler The interaction handler when the widgets are clicked
+         * @return A new {@link LauncherWidgetHolder} instance
+         */
+        public LauncherWidgetHolder newInstance(@NonNull Context context,
+                @Nullable IntConsumer appWidgetRemovedCallback,
+                @Nullable RemoteViews.InteractionHandler interactionHandler) {
+
+            if (!FeatureFlags.ENABLE_WIDGET_HOST_IN_BACKGROUND.get()) {
+                return new LauncherWidgetHolder(context, appWidgetRemovedCallback) {
+                    @Override
+                    protected AppWidgetHost createHost(Context context,
+                            @Nullable IntConsumer appWidgetRemovedCallback) {
+                        AppWidgetHost host = super.createHost(context, appWidgetRemovedCallback);
+                        host.setInteractionHandler(interactionHandler);
+                        return host;
+                    }
+                };
+            }
+            return new QuickstepWidgetHolder(context, appWidgetRemovedCallback, interactionHandler);
+        }
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index f343f52..b5afda3 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -25,7 +25,7 @@
 import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
 import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
 import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
-import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
+import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ONE_HANDED_ACTIVE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
 
@@ -42,11 +42,11 @@
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.taskbar.LauncherTaskbarUIController;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.VibratorWrapper;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.util.OverviewToHomeAnim;
-import com.android.quickstep.util.VibratorWrapper;
 import com.android.quickstep.views.RecentsView;
 
 /**
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 2c7e46c..e0cb0b4 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -41,8 +41,8 @@
 import static com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM;
 import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT;
 import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_UP;
+import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
 import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
-import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
 import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
 import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
@@ -70,11 +70,11 @@
 import com.android.launcher3.touch.BothAxesSwipeDetector;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.TouchController;
+import com.android.launcher3.util.VibratorWrapper;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.util.MotionPauseDetector;
-import com.android.quickstep.util.VibratorWrapper;
 import com.android.quickstep.util.WorkspaceRevealAnim;
 import com.android.quickstep.views.LauncherRecentsView;
 import com.android.quickstep.views.RecentsView;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
index 9efbc34..8368f9c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java
@@ -186,12 +186,17 @@
             case MotionEvent.ACTION_DOWN:
                 InteractionJankMonitorWrapper.begin(
                         mLauncher.getRootView(), InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
+                InteractionJankMonitorWrapper.begin(
+                        mLauncher.getRootView(),
+                        InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE);
                 break;
 
             case MotionEvent.ACTION_CANCEL:
             case MotionEvent.ACTION_UP:
                 InteractionJankMonitorWrapper.cancel(
                         InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
+                InteractionJankMonitorWrapper.cancel(
+                        InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE);
                 break;
         }
         return super.onControllerInterceptTouchEvent(ev);
@@ -204,6 +209,10 @@
         if (newToState != ALL_APPS) {
             InteractionJankMonitorWrapper.cancel(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
         }
+        if (newToState != NORMAL) {
+            InteractionJankMonitorWrapper.cancel(
+                    InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE);
+        }
     }
 
     @Override
@@ -211,6 +220,9 @@
         super.onReachedFinalState(toState);
         if (toState == ALL_APPS) {
             InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
+        } else if (toState == NORMAL) {
+            InteractionJankMonitorWrapper.end(
+                    InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE);
         }
     }
 
@@ -218,5 +230,7 @@
     protected void clearState() {
         super.clearState();
         InteractionJankMonitorWrapper.cancel(InteractionJankMonitorWrapper.CUJ_OPEN_ALL_APPS);
+        InteractionJankMonitorWrapper.cancel(
+                InteractionJankMonitorWrapper.CUJ_CLOSE_ALL_APPS_SWIPE);
     }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index c49848a..eddc50c 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -41,8 +41,9 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.FlingBlockCheck;
 import com.android.launcher3.util.TouchController;
+import com.android.launcher3.util.VibratorWrapper;
 import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.util.VibratorWrapper;
+import com.android.quickstep.util.VibrationConstants;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 
@@ -61,7 +62,7 @@
             Utilities.ATLEAST_R ? VibrationEffect.Composition.PRIMITIVE_TICK : -1;
     public static final float TASK_DISMISS_VIBRATION_PRIMITIVE_SCALE = 1f;
     public static final VibrationEffect TASK_DISMISS_VIBRATION_FALLBACK =
-            VibratorWrapper.EFFECT_TEXTURE_TICK;
+            VibrationConstants.EFFECT_TEXTURE_TICK;
 
     protected final T mActivity;
     private final SingleAxisSwipeDetector mDetector;
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index eadf323..a2adbd7 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -38,6 +38,7 @@
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
+import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
 import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
 import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
@@ -51,7 +52,6 @@
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED;
 import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET;
-import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
 import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
 
@@ -107,6 +107,7 @@
 import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.TraceHelper;
+import com.android.launcher3.util.VibratorWrapper;
 import com.android.launcher3.util.WindowBounds;
 import com.android.quickstep.BaseActivityInterface.AnimationFactory;
 import com.android.quickstep.GestureState.GestureEndTarget;
@@ -126,7 +127,6 @@
 import com.android.quickstep.util.SurfaceTransactionApplier;
 import com.android.quickstep.util.SwipePipToHomeAnimator;
 import com.android.quickstep.util.TaskViewSimulator;
-import com.android.quickstep.util.VibratorWrapper;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
 import com.android.systemui.shared.recents.model.Task;
@@ -325,6 +325,9 @@
     private boolean mCanSlowSwipeGoHome = true;
     private boolean mHasReachedOverviewThreshold = false;
 
+    @Nullable
+    private RemoteAnimationTargets.ReleaseCheck mSwipePipToHomeReleaseCheck = null;
+
     public AbsSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
             TaskAnimationManager taskAnimationManager, GestureState gestureState,
             long touchTimeMs, boolean continuingLastGesture,
@@ -874,6 +877,9 @@
         mRemoteTargetHandles = mTargetGluer.assignTargetsForSplitScreen(mContext, targets);
         mRecentsAnimationController = controller;
         mRecentsAnimationTargets = targets;
+        mSwipePipToHomeReleaseCheck = new RemoteAnimationTargets.ReleaseCheck();
+        mSwipePipToHomeReleaseCheck.setCanRelease(true);
+        mRecentsAnimationTargets.addReleaseCheck(mSwipePipToHomeReleaseCheck);
 
         // Only initialize the device profile, if it has not been initialized before, as in some
         // configurations targets.homeContentInsets may not be correct.
@@ -1435,9 +1441,16 @@
                 mSwipePipToHomeAnimator = createWindowAnimationToPip(
                         homeAnimFactory, runningTaskTarget, start);
                 mSwipePipToHomeAnimators[0] = mSwipePipToHomeAnimator;
+                if (mSwipePipToHomeReleaseCheck != null) {
+                    mSwipePipToHomeReleaseCheck.setCanRelease(false);
+                }
                 windowAnim = mSwipePipToHomeAnimators;
             } else {
                 mSwipePipToHomeAnimator = null;
+                if (mSwipePipToHomeReleaseCheck != null) {
+                    mSwipePipToHomeReleaseCheck.setCanRelease(true);
+                    mSwipePipToHomeReleaseCheck = null;
+                }
                 windowAnim = createWindowAnimationToHome(start, homeAnimFactory);
 
                 windowAnim[0].addAnimatorListener(new AnimationSuccessListener() {
@@ -1961,6 +1974,10 @@
             finishRecentsControllerToHome(
                     () -> mStateCallback.setStateOnUiThread(STATE_CURRENT_TASK_FINISHED));
         }
+        if (mSwipePipToHomeReleaseCheck != null) {
+            mSwipePipToHomeReleaseCheck.setCanRelease(true);
+            mSwipePipToHomeReleaseCheck = null;
+        }
         doLogGesture(HOME, mRecentsView == null ? null : mRecentsView.getCurrentPageTaskView());
     }
 
diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
index 2741751..3edbbdf 100644
--- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
+++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java
@@ -36,6 +36,7 @@
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.window.BackEvent;
+import android.window.BackMotionEvent;
 import android.window.BackProgressAnimator;
 import android.window.IOnBackInvokedCallback;
 
@@ -134,14 +135,14 @@
             }
 
             @Override
-            public void onBackProgressed(BackEvent backEvent) {
+            public void onBackProgressed(BackMotionEvent backEvent) {
                 handler.post(() -> {
                     mProgressAnimator.onBackProgressed(backEvent);
                 });
             }
 
             @Override
-            public void onBackStarted(BackEvent backEvent) {
+            public void onBackStarted(BackMotionEvent backEvent) {
                 handler.post(() -> {
                     startBack(backEvent);
                     mProgressAnimator.onBackStarted(backEvent, event -> {
@@ -185,7 +186,7 @@
         mBackCallback = null;
     }
 
-    private void startBack(BackEvent backEvent) {
+    private void startBack(BackMotionEvent backEvent) {
         mBackInProgress = true;
         RemoteAnimationTarget appTarget = backEvent.getDepartingAnimationTarget();
 
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index d46565b..b33ceca 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -45,6 +45,8 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
 
 /**
  * Manages the recent task list from the system, caching it as necessary.
@@ -129,14 +131,18 @@
      * @return The change id of the current task list
      */
     public synchronized int getTasks(boolean loadKeysOnly,
-            Consumer<ArrayList<GroupTask>> callback) {
+            Consumer<ArrayList<GroupTask>> callback, Predicate<GroupTask> filter) {
         final int requestLoadId = mChangeId;
         if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) {
             // The list is up to date, send the callback on the next frame,
             // so that requestID can be returned first.
             if (callback != null) {
                 // Copy synchronously as the changeId might change by next frame
-                ArrayList<GroupTask> result = copyOf(mResultsUi);
+                // and filter GroupTasks
+                ArrayList<GroupTask> result = mResultsUi.stream().filter(filter)
+                        .map(GroupTask::copy)
+                        .collect(Collectors.toCollection(ArrayList<GroupTask>::new));
+
                 mMainThreadExecutor.post(() -> {
                     callback.accept(result);
                 });
@@ -156,7 +162,11 @@
                 mLoadingTasksInBackground = false;
                 mResultsUi = loadResult;
                 if (callback != null) {
-                    ArrayList<GroupTask> result = copyOf(mResultsUi);
+                    // filter the tasks if needed before passing them into the callback
+                    ArrayList<GroupTask> result = mResultsUi.stream().filter(filter)
+                            .map(GroupTask::copy)
+                            .collect(Collectors.toCollection(ArrayList<GroupTask>::new));
+
                     callback.accept(result);
                 }
             });
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index dc405ff..6f86bf5 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -240,7 +240,7 @@
 
         mActivityLaunchAnimationRunner = new RemoteAnimationFactory() {
             @Override
-            public void onCreateAnimation(int transit, RemoteAnimationTarget[] appTargets,
+            public void onAnimationStart(int transit, RemoteAnimationTarget[] appTargets,
                     RemoteAnimationTarget[] wallpaperTargets,
                     RemoteAnimationTarget[] nonAppTargets, AnimationResult result) {
                 mHandler.removeCallbacks(mAnimationStartTimeoutRunnable);
@@ -407,28 +407,24 @@
     }
 
     private final RemoteAnimationFactory mAnimationToHomeFactory =
-            new RemoteAnimationFactory() {
-        @Override
-        public void onCreateAnimation(int transit, RemoteAnimationTarget[] appTargets,
-                RemoteAnimationTarget[] wallpaperTargets,
-                RemoteAnimationTarget[] nonAppTargets, AnimationResult result) {
-            AnimatorPlaybackController controller = getStateManager()
-                    .createAnimationToNewWorkspace(RecentsState.BG_LAUNCHER, HOME_APPEAR_DURATION);
-            controller.dispatchOnStart();
+            (transit, appTargets, wallpaperTargets, nonAppTargets, result) -> {
+                AnimatorPlaybackController controller =
+                        getStateManager().createAnimationToNewWorkspace(
+                                RecentsState.BG_LAUNCHER, HOME_APPEAR_DURATION);
+                controller.dispatchOnStart();
 
-            RemoteAnimationTargets targets = new RemoteAnimationTargets(
-                    appTargets, wallpaperTargets, nonAppTargets, MODE_OPENING);
-            for (RemoteAnimationTarget app : targets.apps) {
-                new Transaction().setAlpha(app.leash, 1).apply();
-            }
-            AnimatorSet anim = new AnimatorSet();
-            anim.play(controller.getAnimationPlayer());
-            anim.setDuration(HOME_APPEAR_DURATION);
-            result.setAnimation(anim, RecentsActivity.this,
-                    () -> getStateManager().goToState(RecentsState.HOME, false),
-                    true /* skipFirstFrame */);
-        }
-    };
+                RemoteAnimationTargets targets = new RemoteAnimationTargets(
+                        appTargets, wallpaperTargets, nonAppTargets, MODE_OPENING);
+                for (RemoteAnimationTarget app : targets.apps) {
+                    new Transaction().setAlpha(app.leash, 1).apply();
+                }
+                AnimatorSet anim = new AnimatorSet();
+                anim.play(controller.getAnimationPlayer());
+                anim.setDuration(HOME_APPEAR_DURATION);
+                result.setAnimation(anim, RecentsActivity.this,
+                        () -> getStateManager().goToState(RecentsState.HOME, false),
+                        true /* skipFirstFrame */);
+            };
 
     @Override
     protected void collectStateHandlers(List<StateHandler> out) {
diff --git a/quickstep/src/com/android/quickstep/RecentsFilterState.java b/quickstep/src/com/android/quickstep/RecentsFilterState.java
new file mode 100644
index 0000000..ff6951d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/RecentsFilterState.java
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import androidx.annotation.Nullable;
+
+import com.android.quickstep.util.GroupTask;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.function.Predicate;
+
+/**
+ * Keeps track of the state of {@code RecentsView}.
+ *
+ * <p> More specifically, used for keeping track of the state of filters applied on tasks
+ * in {@code RecentsView} for multi-instance management.
+ */
+public class RecentsFilterState {
+    // the minimum number of tasks per package present to allow filtering
+    public static final int MIN_FILTERING_TASK_COUNT = 2;
+
+    // default filter that returns true for any input
+    public static final Predicate<GroupTask> DEFAULT_FILTER = (groupTask -> true);
+
+    // the package name to filter recent tasks by
+    @Nullable
+    private String mPackageNameToFilter = null;
+
+    // the callback that gets executed upon filter change
+    @Nullable
+    private Runnable mOnFilterUpdatedListener = null;
+
+    // map maintaining the count for each unique base activity package name currently in the recents
+    @Nullable
+    private Map<String, Integer> mInstanceCountMap;
+
+    /**
+     * Returns {@code true} if {@code RecentsView} filters tasks by some package name.
+     */
+    public boolean isFiltered() {
+        return mPackageNameToFilter != null;
+    }
+
+    /**
+     * Returns the package name that tasks are filtered by.
+     */
+    @Nullable
+    public String getPackageNameToFilter() {
+        return mPackageNameToFilter;
+    }
+
+
+    /**
+     * Sets a listener on any changes to the filter.
+     *
+     * @param callback listener to be executed upon filter updates
+     */
+    public void setOnFilterUpdatedListener(@Nullable Runnable callback) {
+        mOnFilterUpdatedListener = callback;
+    }
+
+    /**
+     * Updates the filter such that tasks are filtered by a certain package name.
+     *
+     * @param packageName package name of the base activity to filter tasks by;
+     *                    if null, filter is turned off
+     */
+    public void setFilterBy(@Nullable String packageName) {
+        if (Objects.equals(packageName, mPackageNameToFilter)) {
+            return;
+        }
+
+        mPackageNameToFilter = packageName;
+
+        if (mOnFilterUpdatedListener != null) {
+            mOnFilterUpdatedListener.run();
+        }
+    }
+
+    /**
+     * Updates the map of package names to their count in the most recent list of tasks.
+     *
+     * @param groupTaskList the list of tasks that map update is be based on
+     */
+    public void updateInstanceCountMap(List<GroupTask> groupTaskList) {
+        mInstanceCountMap = getInstanceCountMap(groupTaskList);
+    }
+
+    /**
+     * Returns the map of package names to their count in the most recent list of tasks.
+     */
+    @Nullable
+    public Map<String, Integer> getInstanceCountMap() {
+        return mInstanceCountMap;
+    }
+
+    /**
+     * Returns a predicate for filtering out GroupTasks by package name.
+     *
+     * @param packageName package name to filter GroupTasks by
+     *                    if null, Predicate always returns true.
+     */
+    public static Predicate<GroupTask> getFilter(@Nullable String packageName) {
+        if (packageName == null) {
+            return DEFAULT_FILTER;
+        }
+
+        return (groupTask) -> (groupTask.task2 != null
+                && groupTask.task2.key.getPackageName().equals(packageName))
+                || groupTask.task1.key.getPackageName().equals(packageName);
+    }
+
+    /**
+     * Returns a map of package names to their frequencies in a list of GroupTasks.
+     *
+     * @param groupTasks the list to go through to create the map
+     */
+    public static Map<String, Integer> getInstanceCountMap(List<GroupTask> groupTasks) {
+        Map<String, Integer> instanceCountMap = new HashMap<>();
+
+        for (GroupTask groupTask : groupTasks) {
+            final String firstTaskPkgName = groupTask.task1.key.getPackageName();
+            final String secondTaskPkgName =
+                    groupTask.task2 == null ? null : groupTask.task2.key.getPackageName();
+
+            // increment the instance count for the first task's base activity package name
+            incrementOrAddIfNotExists(instanceCountMap, firstTaskPkgName);
+
+            // check if second task is non existent
+            if (secondTaskPkgName != null) {
+                // increment the instance count for the second task's base activity package name
+                incrementOrAddIfNotExists(instanceCountMap, secondTaskPkgName);
+            }
+        }
+
+        return instanceCountMap;
+    }
+
+    /**
+     * Returns true if tasks of provided package name should show filter UI.
+     *
+     * @param taskPackageName package name of the task in question
+     */
+    public boolean shouldShowFilterUI(String taskPackageName) {
+        // number of occurrences in recents overview with the package name of this task
+        int instanceCount = getInstanceCountMap().get(taskPackageName);
+
+        // if the number of occurrences isn't enough make sure tasks can't be filtered by
+        // the package name of this task
+        return !(isFiltered() || instanceCount < MIN_FILTERING_TASK_COUNT);
+    }
+
+    private static void incrementOrAddIfNotExists(Map<String, Integer> map, String pkgName) {
+        if (!map.containsKey(pkgName)) {
+            map.put(pkgName, 0);
+        }
+        map.put(pkgName, map.get(pkgName) + 1);
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 3d6da8e..913f08f 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -50,6 +50,7 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.Executors;
 import java.util.function.Consumer;
+import java.util.function.Predicate;
 
 /**
  * Singleton class to load and manage recents model.
@@ -104,7 +105,22 @@
      * @return the request id associated with this call.
      */
     public int getTasks(Consumer<ArrayList<GroupTask>> callback) {
-        return mTaskList.getTasks(false /* loadKeysOnly */, callback);
+        return mTaskList.getTasks(false /* loadKeysOnly */, callback,
+                RecentsFilterState.DEFAULT_FILTER);
+    }
+
+
+    /**
+     * Fetches the list of recent tasks, based on a filter
+     *
+     * @param callback The callback to receive the task plan once its complete or null. This is
+     *                always called on the UI thread.
+     * @param filter  Returns true if a GroupTask should be included into the list passed into
+     *                callback.
+     * @return the request id associated with this call.
+     */
+    public int getTasks(Consumer<ArrayList<GroupTask>> callback, Predicate<GroupTask> filter) {
+        return mTaskList.getTasks(false /* loadKeysOnly */, callback, filter);
     }
 
     /**
@@ -126,8 +142,9 @@
      * Checks if a task has been removed or not.
      *
      * @param callback Receives true if task is removed, false otherwise
+     * @param filter Returns true if GroupTask should be in the list of considerations
      */
-    public void isTaskRemoved(int taskId, Consumer<Boolean> callback) {
+    public void isTaskRemoved(int taskId, Consumer<Boolean> callback, Predicate<GroupTask> filter) {
         mTaskList.getTasks(true /* loadKeysOnly */, (taskGroups) -> {
             for (GroupTask group : taskGroups) {
                 if (group.containsTask(taskId)) {
@@ -136,7 +153,7 @@
                 }
             }
             callback.accept(true);
-        });
+        }, filter);
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index b7252bc..67de4b1 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -22,6 +22,8 @@
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 
 import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
+import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
 import static com.android.launcher3.LauncherState.BACKGROUND_APP;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.QuickstepTransitionManager.ANIMATION_DELAY_NAV_FADE_IN;
@@ -330,6 +332,17 @@
                 Matrix localMti = new Matrix();
                 localMt.invert(localMti);
                 mti[i] = localMti;
+
+                // Translations for child thumbnails also get scaled as the parent taskView scales
+                // Add inverse scaling to keep translations the same
+                float translationY = ttv.getTranslationY();
+                float translationX = ttv.getTranslationX();
+                float fullScreenScale =
+                        topMostSimulators[i].getTaskViewSimulator().getFullScreenScale();
+                out.addFloat(ttv, VIEW_TRANSLATE_Y, translationY,
+                        translationY / fullScreenScale, TOUCH_RESPONSE_INTERPOLATOR);
+                out.addFloat(ttv, VIEW_TRANSLATE_X, translationX,
+                         translationX / fullScreenScale, TOUCH_RESPONSE_INTERPOLATOR);
             }
 
             Matrix[] k0i = new Matrix[matrixSize];
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 2565697..08a0ab3 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -216,10 +216,12 @@
 
         @BinderThread
         @Override
-        public void onAssistantAvailable(boolean available) {
+        public void onAssistantAvailable(boolean available, boolean longPressHomeEnabled) {
             MAIN_EXECUTOR.execute(() -> {
                 mDeviceState.setAssistantAvailable(available);
                 TouchInteractionService.this.onAssistantVisibilityChanged();
+                executeForTaskbarManager(() -> mTaskbarManager
+                        .onLongPressHomeEnabled(longPressHomeEnabled));
             });
         }
 
@@ -798,7 +800,7 @@
 
             // If Taskbar is present, we listen for long press to unstash it.
             TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
-            if (tac != null) {
+            if (tac != null && canStartSystemGesture) {
                 reasonString.append(NEWLINE_PREFIX)
                         .append(reasonPrefix)
                         .append(SUBSTRING_PREFIX)
diff --git a/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java b/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java
index 437572b..8eb4059 100644
--- a/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java
+++ b/quickstep/src/com/android/quickstep/interaction/EdgeBackGesturePanel.java
@@ -41,9 +41,9 @@
 import androidx.dynamicanimation.animation.SpringForce;
 
 import com.android.launcher3.R;
-import com.android.launcher3.testing.shared.ResourceUtils;
 import com.android.launcher3.anim.Interpolators;
-import com.android.quickstep.util.VibratorWrapper;
+import com.android.launcher3.testing.shared.ResourceUtils;
+import com.android.launcher3.util.VibratorWrapper;
 
 /** Forked from platform/frameworks/base/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarEdgePanel.java. */
 public class EdgeBackGesturePanel extends View {
diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
index e7bf7e2..57874d9 100644
--- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
@@ -16,6 +16,7 @@
 package com.android.quickstep.interaction;
 
 import static com.android.launcher3.Utilities.squaredHypot;
+import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
 import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_COMPLETED;
 import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_NOT_STARTED_BAD_ANGLE;
 import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.ASSISTANT_NOT_STARTED_SWIPE_TOO_SHORT;
@@ -25,7 +26,6 @@
 import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION;
 import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_GESTURE_COMPLETED;
 import static com.android.quickstep.interaction.NavBarGestureHandler.NavBarGestureResult.OVERVIEW_NOT_STARTED_TOO_FAR_FROM_EDGE;
-import static com.android.quickstep.util.VibratorWrapper.OVERVIEW_HAPTIC;
 
 import android.animation.ValueAnimator;
 import android.content.Context;
@@ -48,10 +48,10 @@
 import com.android.launcher3.testing.shared.ResourceUtils;
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.NavigationMode;
+import com.android.launcher3.util.VibratorWrapper;
 import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.util.NavBarPosition;
 import com.android.quickstep.util.TriggerSwipeUpTouchTracker;
-import com.android.quickstep.util.VibratorWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
 
 /** Utility class to handle Home and Assistant gestures. */
diff --git a/quickstep/src/com/android/quickstep/util/LogUtils.kt b/quickstep/src/com/android/quickstep/util/LogUtils.kt
index bad8506..300c4a1 100644
--- a/quickstep/src/com/android/quickstep/util/LogUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/LogUtils.kt
@@ -20,15 +20,14 @@
 import com.android.launcher3.logging.InstanceId
 
 object LogUtils {
-  /**
-   * @return a [Pair] of two InstanceIds but with different types, one that can be used by framework
-   * (if needing to pass through an intent or such) and one used in Launcher
-   */
-  @JvmStatic
-  fun getShellShareableInstanceId():
-    Pair<com.android.internal.logging.InstanceId, InstanceId> {
-    val internalInstanceId = InstanceIdSequence(InstanceId.INSTANCE_ID_MAX).newInstanceId()
-    val launcherInstanceId = InstanceId(internalInstanceId.id)
-    return Pair(internalInstanceId, launcherInstanceId)
-  }
+    /**
+     * @return a [Pair] of two InstanceIds but with different types, one that can be used by
+     * framework (if needing to pass through an intent or such) and one used in Launcher
+     */
+    @JvmStatic
+    fun getShellShareableInstanceId(): Pair<com.android.internal.logging.InstanceId, InstanceId> {
+        val internalInstanceId = InstanceIdSequence(InstanceId.INSTANCE_ID_MAX).newInstanceId()
+        val launcherInstanceId = InstanceId(internalInstanceId.id)
+        return Pair(internalInstanceId, launcherInstanceId)
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/util/VibrationConstants.java b/quickstep/src/com/android/quickstep/util/VibrationConstants.java
new file mode 100644
index 0000000..0f0306e
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/VibrationConstants.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.os.VibrationEffect;
+
+public class VibrationConstants {
+    public static final VibrationEffect EFFECT_TEXTURE_TICK =
+            VibrationEffect.createPredefined(VibrationEffect.EFFECT_TEXTURE_TICK);
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
index 308249c..c878278 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java
@@ -59,10 +59,14 @@
 // TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks.
 public class DesktopTaskView extends TaskView {
 
+    /** Flag to indicate whether desktop windowing proto 2 is enabled */
+    public static final boolean DESKTOP_IS_PROTO2_ENABLED = SystemProperties.getBoolean(
+            "persist.wm.debug.desktop_mode_2", false);
+
     /** Flags to indicate whether desktop mode is available on the device */
     public static final boolean DESKTOP_MODE_SUPPORTED =
             SystemProperties.getBoolean("persist.wm.debug.desktop_mode", false)
-                    || SystemProperties.getBoolean("persist.wm.debug.desktop_mode_2", false);
+                    || DESKTOP_IS_PROTO2_ENABLED;
 
     private static final String TAG = DesktopTaskView.class.getSimpleName();
 
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 2cada0a..3f7d677 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -2,7 +2,6 @@
 
 import static com.android.launcher3.util.SplitConfigurationOptions.DEFAULT_SPLIT_RATIO;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 
 import android.content.Context;
 import android.graphics.PointF;
@@ -102,6 +101,22 @@
                 PreviewPositionHelper.STAGE_POSITION_BOTTOM_OR_RIGHT);
     }
 
+    /**
+     * Sets up an on-click listener and the visibility for show_windows icon on top of each task.
+     */
+    @Override
+    public void setUpShowAllInstancesListener() {
+        // sets up the listener for the left/top task
+        super.setUpShowAllInstancesListener();
+
+        // right/bottom task's base package name
+        String taskPackageName = mTaskIdAttributeContainer[1].getTask().key.getPackageName();
+
+        // icon of the right/bottom task
+        View showWindowsView = findViewById(R.id.show_windows_right);
+        updateFilterCallback(showWindowsView, getFilterUpdateCallback(taskPackageName));
+    }
+
     @Override
     public void onTaskListVisibilityChanged(boolean visible, int changes) {
         super.onTaskListVisibilityChanged(visible, changes);
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 6c27587..cf033a6 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -36,12 +36,15 @@
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.popup.QuickstepSystemShortcut;
 import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
 import com.android.launcher3.statemanager.StateManager.StateListener;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
 import com.android.launcher3.util.PendingSplitSelectInfo;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.quickstep.LauncherActivityInterface;
+import com.android.quickstep.RotationTouchHelper;
 import com.android.quickstep.util.SplitSelectStateController;
+import com.android.systemui.shared.recents.model.Task;
 
 /**
  * {@link RecentsView} used in Launcher activity
@@ -205,4 +208,25 @@
     protected boolean canLaunchFullscreenTask() {
         return !mActivity.isInState(OVERVIEW_SPLIT_SELECT);
     }
+
+    @Override
+    public void onGestureAnimationStart(Task[] runningTasks,
+            RotationTouchHelper rotationTouchHelper) {
+        super.onGestureAnimationStart(runningTasks, rotationTouchHelper);
+        DesktopVisibilityController desktopVisibilityController =
+                mActivity.getDesktopVisibilityController();
+        if (desktopVisibilityController != null) {
+            desktopVisibilityController.setGestureInProgress(true);
+        }
+    }
+
+    @Override
+    public void onGestureAnimationEnd() {
+        super.onGestureAnimationEnd();
+        DesktopVisibilityController desktopVisibilityController =
+                mActivity.getDesktopVisibilityController();
+        if (desktopVisibilityController != null) {
+            desktopVisibilityController.setGestureInProgress(false);
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 3a2841e..9cf0601 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -159,11 +159,13 @@
 import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
 import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TranslateEdgeEffect;
+import com.android.launcher3.util.VibratorWrapper;
 import com.android.launcher3.util.ViewPool;
 import com.android.quickstep.BaseActivityInterface;
 import com.android.quickstep.GestureState;
 import com.android.quickstep.RecentsAnimationController;
 import com.android.quickstep.RecentsAnimationTargets;
+import com.android.quickstep.RecentsFilterState;
 import com.android.quickstep.RecentsModel;
 import com.android.quickstep.RemoteAnimationTargets;
 import com.android.quickstep.RemoteTargetGluer;
@@ -189,7 +191,7 @@
 import com.android.quickstep.util.TaskViewSimulator;
 import com.android.quickstep.util.TaskVisualsChangeListener;
 import com.android.quickstep.util.TransformParams;
-import com.android.quickstep.util.VibratorWrapper;
+import com.android.quickstep.util.VibrationConstants;
 import com.android.systemui.plugins.ResourceProvider;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -282,7 +284,7 @@
             Utilities.ATLEAST_S ? VibrationEffect.Composition.PRIMITIVE_LOW_TICK : -1;
     public static final float SCROLL_VIBRATION_PRIMITIVE_SCALE = 0.6f;
     public static final VibrationEffect SCROLL_VIBRATION_FALLBACK =
-            VibratorWrapper.EFFECT_TEXTURE_TICK;
+            VibrationConstants.EFFECT_TEXTURE_TICK;
 
     /**
      * Can be used to tint the color of the RecentsView to simulate a scrim that can views
@@ -580,7 +582,7 @@
                                 if (taskRemoved) {
                                     dismissTask(taskId);
                                 }
-                            });
+                            }, RecentsFilterState.getFilter(mFilterState.getPackageNameToFilter()));
                         }
                     }));
         }
@@ -721,6 +723,9 @@
     @Nullable
     private TaskLaunchListener mTaskLaunchListener;
 
+    // keeps track of the state of the filter for tasks in recents view
+    private final RecentsFilterState mFilterState = new RecentsFilterState();
+
     public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
             BaseActivityInterface sizeStrategy) {
         super(context, attrs, defStyleAttr);
@@ -784,6 +789,55 @@
         mActivity.getViewCache().setCacheSize(R.layout.digital_wellbeing_toast, 5);
 
         mTintingColor = getForegroundScrimDimColor(context);
+
+        // if multi-instance feature is enabled
+        if (FeatureFlags.ENABLE_MULTI_INSTANCE.get()) {
+            // invalidate the current list of tasks if filter changes
+            mFilterState.setOnFilterUpdatedListener(this::invalidateTaskList);
+        }
+        // make sure filter is turned off by default
+        mFilterState.setFilterBy(null);
+    }
+
+    /** Get the state of the filter */
+    public RecentsFilterState getFilterState() {
+        return mFilterState;
+    }
+
+    /**
+     * Toggles the filter and reloads the recents view if needed.
+     *
+     * @param packageName package name to filter by if the filter is being turned on;
+     *                    should be null if filter is being turned off
+     */
+    public void setAndApplyFilter(@Nullable String packageName) {
+        mFilterState.setFilterBy(packageName);
+        updateClearAllFunction();
+        reloadIfNeeded();
+    }
+
+    /**
+     * Updates the "Clear All" button and its function depending on the recents view state.
+     *
+     * TODO: add a different button for going back to overview. Present solution is for demo only.
+     */
+    public void updateClearAllFunction() {
+        if (mFilterState.isFiltered()) {
+            mClearAllButton.setText(R.string.recents_back);
+            mClearAllButton.setOnClickListener((view) -> {
+                this.setAndApplyFilter(null);
+            });
+        } else {
+            mClearAllButton.setText(R.string.recents_clear_all);
+            mClearAllButton.setOnClickListener(this::dismissAllTasks);
+        }
+    }
+
+    /**
+     * Invalidates the list of tasks so that an update occurs to the list of tasks if requested.
+     */
+    private void invalidateTaskList() {
+        mTaskListChangeId = -1;
     }
 
     public OverScroller getScroller() {
@@ -1503,6 +1557,11 @@
                 ActiveGestureErrorDetector.GestureEvent.SCROLLER_ANIMATION_ABORTED);
     }
 
+    @Override
+    protected boolean isPageScrollsInitialized() {
+        return super.isPageScrollsInitialized() && mLoadPlanEverApplied;
+    }
+
     protected void applyLoadPlan(ArrayList<GroupTask> taskGroups) {
         if (mPendingAnimation != null) {
             mPendingAnimation.addEndListener(success -> applyLoadPlan(taskGroups));
@@ -1516,6 +1575,9 @@
             // With all tasks removed, touch handling in PagedView is disabled and we need to reset
             // touch state or otherwise values will be obsolete.
             resetTouchState();
+            if (isPageScrollsInitialized()) {
+                onPageScrollsInitialized();
+            }
             return;
         }
 
@@ -1546,6 +1608,9 @@
         Task stagedTaskToBeRemovedFromGrid =
                 mSplitSelectSource != null ? mSplitSelectSource.alreadyRunningTask : null;
 
+        // update the map of instance counts
+        mFilterState.updateInstanceCountMap(taskGroups);
+
         // Add views as children based on whether it's grouped or single task. Looping through
         // taskGroups backwards populates the thumbnail grid from least recent to most recent.
         for (int i = taskGroups.size() - 1; i >= 0; i--) {
@@ -1580,6 +1645,7 @@
                         groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id;
                 Task leftTopTask = firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2;
                 Task rightBottomTask = firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1;
+
                 ((GroupedTaskView) taskView).bind(leftTopTask, rightBottomTask, mOrientationState,
                         groupTask.mSplitBounds);
             } else if (taskView instanceof DesktopTaskView) {
@@ -1588,6 +1654,11 @@
             } else {
                 taskView.bind(groupTask.task1, mOrientationState);
             }
+
+            // enables instance filtering if the feature flag for it is on
+            if (FeatureFlags.ENABLE_MULTI_INSTANCE.get()) {
+                taskView.setUpShowAllInstancesListener();
+            }
         }
 
         if (!taskGroups.isEmpty()) {
@@ -1660,6 +1731,9 @@
         resetTaskVisuals();
         onTaskStackUpdated();
         updateEnabledOverlays();
+        if (isPageScrollsInitialized()) {
+            onPageScrollsInitialized();
+        }
     }
 
     private boolean isModal() {
@@ -2003,7 +2077,7 @@
         if (!mActivity.getDeviceProfile().isTablet) {
             return super.getDestinationPage(scaledScroll);
         }
-        if (!pageScrollsInitialized()) {
+        if (!isPageScrollsInitialized()) {
             Log.e(TAG,
                     "Cannot get destination page: RecentsView not properly initialized",
                     new IllegalStateException());
@@ -2257,7 +2331,8 @@
      */
     public void reloadIfNeeded() {
         if (!mModel.isTaskListValid(mTaskListChangeId)) {
-            mTaskListChangeId = mModel.getTasks(this::applyLoadPlan);
+            mTaskListChangeId = mModel.getTasks(this::applyLoadPlan, RecentsFilterState
+                    .getFilter(mFilterState.getPackageNameToFilter()));
         }
     }
 
@@ -3114,8 +3189,6 @@
             }
         }
 
-        announceForAccessibility(getResources().getString(R.string.task_view_closed));
-
         float dismissTranslationInterpolationEnd = 1;
         boolean closeGapBetweenClearAll = false;
         boolean isClearAllHidden = isClearAllHidden();
@@ -3442,6 +3515,8 @@
                             } else {
                                 removeTaskInternal(dismissedTaskViewId);
                             }
+                            announceForAccessibility(
+                                    getResources().getString(R.string.task_view_closed));
                             mActivity.getStatsLogManager().logger()
                                     .withItemInfo(dismissedTaskView.getItemInfo())
                                     .log(LAUNCHER_TASK_DISMISS_SWIPE_UP);
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index bdc0585..54b58b9 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -48,13 +48,15 @@
             taskContainer: TaskIdAttributeContainer,
             alignSecondRow: Boolean = false
         ): Boolean {
-            val activity = BaseDraggingActivity
-                .fromContext<BaseDraggingActivity>(taskContainer.taskView.context)
-            val taskMenuViewWithArrow = activity.layoutInflater
-                .inflate(
-                        R.layout.task_menu_with_arrow,
-                        activity.dragLayer,
-                        false
+            val activity =
+                BaseDraggingActivity.fromContext<BaseDraggingActivity>(
+                    taskContainer.taskView.context
+                )
+            val taskMenuViewWithArrow =
+                activity.layoutInflater.inflate(
+                    R.layout.task_menu_with_arrow,
+                    activity.dragLayer,
+                    false
                 ) as TaskMenuViewWithArrow<*>
 
             return taskMenuViewWithArrow.populateAndShowForTask(taskContainer, alignSecondRow)
@@ -63,11 +65,11 @@
 
     constructor(context: Context) : super(context)
     constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
-    constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(
-        context,
-        attrs,
-        defStyleAttr
-    )
+    constructor(
+        context: Context,
+        attrs: AttributeSet,
+        defStyleAttr: Int
+    ) : super(context, attrs, defStyleAttr)
 
     init {
         clipToOutline = true
@@ -91,10 +93,10 @@
 
     private var optionMeasuredHeight = 0
     private val arrowHorizontalPadding: Int
-        get() = if (taskView.isFocusedTask)
-            resources.getDimensionPixelSize(R.dimen.task_menu_horizontal_padding)
-        else
-            0
+        get() =
+            if (taskView.isFocusedTask)
+                resources.getDimensionPixelSize(R.dimen.task_menu_horizontal_padding)
+            else 0
 
     private var iconView: IconView? = null
     private var scrim: View? = null
@@ -139,19 +141,20 @@
     }
 
     private fun addScrim() {
-        scrim = View(context).apply {
-            layoutParams = FrameLayout.LayoutParams(
-                FrameLayout.LayoutParams.MATCH_PARENT,
-                FrameLayout.LayoutParams.MATCH_PARENT
-            )
-            setBackgroundColor(Themes.getAttrColor(context, R.attr.overviewScrimColor))
-            alpha = 0f
-        }
+        scrim =
+            View(context).apply {
+                layoutParams =
+                    FrameLayout.LayoutParams(
+                        FrameLayout.LayoutParams.MATCH_PARENT,
+                        FrameLayout.LayoutParams.MATCH_PARENT
+                    )
+                setBackgroundColor(Themes.getAttrColor(context, R.attr.overviewScrimColor))
+                alpha = 0f
+            }
         popupContainer.addView(scrim)
     }
 
-    /** @return true if successfully able to populate task view menu, false otherwise
-     */
+    /** @return true if successfully able to populate task view menu, false otherwise */
     private fun populateMenu(): Boolean {
         // Icon may not be loaded
         if (taskContainer.task.icon == null) return false
@@ -162,9 +165,9 @@
 
     private fun addMenuOptions() {
         // Add the options
-        TaskOverlayFactory
-            .getEnabledShortcuts(taskView, taskContainer)
-            .forEach { this.addMenuOption(it) }
+        TaskOverlayFactory.getEnabledShortcuts(taskView, taskContainer).forEach {
+            this.addMenuOption(it)
+        }
 
         // Add the spaces between items
         val divider = ShapeDrawable(RectShape())
@@ -185,9 +188,9 @@
     }
 
     private fun addMenuOption(menuOption: SystemShortcut<*>) {
-        val menuOptionView = mActivityContext.layoutInflater.inflate(
-                R.layout.task_view_menu_option, this, false
-        ) as LinearLayout
+        val menuOptionView =
+            mActivityContext.layoutInflater.inflate(R.layout.task_view_menu_option, this, false)
+                as LinearLayout
         menuOption.setIconAndLabelFor(
             menuOptionView.findViewById(R.id.icon),
             menuOptionView.findViewById(R.id.text)
@@ -230,24 +233,25 @@
     }
 
     /**
-     * Copy the iconView from taskView to dragLayer so it can stay on top of the scrim.
-     * It needs to be called after [getTargetObjectLocation] because [mTempRect] needs to be
-     * populated.
+     * Copy the iconView from taskView to dragLayer so it can stay on top of the scrim. It needs to
+     * be called after [getTargetObjectLocation] because [mTempRect] needs to be populated.
      */
     private fun copyIconToDragLayer(insets: Rect) {
-        iconView = IconView(context).apply {
-            layoutParams = FrameLayout.LayoutParams(
-                taskContainer.iconView.width,
-                taskContainer.iconView.height
-            )
-            x = mTempRect.left.toFloat() - insets.left
-            y = mTempRect.top.toFloat() - insets.top
-            drawable = taskContainer.iconView.drawable
-            setDrawableSize(
-                taskContainer.iconView.drawableWidth,
-                taskContainer.iconView.drawableHeight
-            )
-        }
+        iconView =
+            IconView(context).apply {
+                layoutParams =
+                    FrameLayout.LayoutParams(
+                        taskContainer.iconView.width,
+                        taskContainer.iconView.height
+                    )
+                x = mTempRect.left.toFloat() - insets.left
+                y = mTempRect.top.toFloat() - insets.top
+                drawable = taskContainer.iconView.drawable
+                setDrawableSize(
+                    taskContainer.iconView.drawableWidth,
+                    taskContainer.iconView.drawableHeight
+                )
+            }
 
         popupContainer.addView(iconView)
     }
@@ -281,12 +285,13 @@
         // which means the arrow is left aligned with the menu
         val rightAlignedMenuStartX = mTempRect.left - widthWithArrow
         val leftAlignedMenuStartX = mTempRect.right + extraHorizontalSpace
-        mIsLeftAligned = if (mIsRtl) {
-            rightAlignedMenuStartX + insets.left < 0
-        } else {
-            leftAlignedMenuStartX + (widthWithArrow - extraHorizontalSpace) + insets.left <
+        mIsLeftAligned =
+            if (mIsRtl) {
+                rightAlignedMenuStartX + insets.left < 0
+            } else {
+                leftAlignedMenuStartX + (widthWithArrow - extraHorizontalSpace) + insets.left <
                     dragLayer.width - insets.right
-        }
+            }
 
         var menuStartX = if (mIsLeftAligned) leftAlignedMenuStartX else rightAlignedMenuStartX
 
@@ -311,8 +316,8 @@
     override fun addArrow() {
         popupContainer.addView(mArrow)
         mArrow.x = getArrowX()
-        mArrow.y = y + (optionMeasuredHeight / 2) - (mArrowHeight / 2) +
-                extraSpaceForSecondRowAlignment
+        mArrow.y =
+            y + (optionMeasuredHeight / 2) - (mArrowHeight / 2) + extraSpaceForSecondRowAlignment
 
         updateArrowColor()
 
@@ -322,22 +327,19 @@
     }
 
     private fun getArrowX(): Float {
-        return if (mIsLeftAligned)
-            x - mArrowHeight
-        else
-            x + measuredWidth + mArrowOffsetVertical
+        return if (mIsLeftAligned) x - mArrowHeight else x + measuredWidth + mArrowOffsetVertical
     }
 
     override fun updateArrowColor() {
-        mArrow.background = RoundedArrowDrawable(
-            mArrowWidth.toFloat(),
-            mArrowHeight.toFloat(),
-            mArrowPointRadius.toFloat(),
-            mIsLeftAligned,
-            mArrowColor
-        )
+        mArrow.background =
+            RoundedArrowDrawable(
+                mArrowWidth.toFloat(),
+                mArrowHeight.toFloat(),
+                mArrowPointRadius.toFloat(),
+                mIsLeftAligned,
+                mArrowColor
+            )
         elevation = mElevation
         mArrow.elevation = mElevation
     }
-
-}
\ No newline at end of file
+}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index bda30a5..aa37fdd 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -526,6 +526,52 @@
         setOrientationState(orientedState);
     }
 
+    /**
+     * Sets up an on-click listener and the visibility for show_windows icon on top of the task.
+     */
+    public void setUpShowAllInstancesListener() {
+        String taskPackageName = mTaskIdAttributeContainer[0].mTask.key.getPackageName();
+
+        // icon of the top/left task
+        View showWindowsView = findViewById(R.id.show_windows);
+        updateFilterCallback(showWindowsView, getFilterUpdateCallback(taskPackageName));
+    }
+
+    /**
+     * Returns a callback that updates the state of the filter and the recents overview
+     *
+     * @param taskPackageName package name of the task to filter by
+     */
+    @Nullable
+    protected View.OnClickListener getFilterUpdateCallback(String taskPackageName) {
+        View.OnClickListener cb = (view) -> {
+            // update and apply a new filter
+            getRecentsView().setAndApplyFilter(taskPackageName);
+        };
+
+        if (!getRecentsView().getFilterState().shouldShowFilterUI(taskPackageName)) {
+            cb = null;
+        }
+        return cb;
+    }
+
+    /**
+     * Sets the correct visibility and callback on the provided filterView based on whether
+     * the callback is null or not
+     */
+    protected void updateFilterCallback(@NonNull View filterView,
+            @Nullable View.OnClickListener callback) {
+        // Filtering changes alpha instead of the visibility since visibility
+        // can be altered separately through RecentsView#resetFromSplitSelectionState()
+        if (callback == null) {
+            filterView.setAlpha(0);
+        } else {
+            filterView.setAlpha(1);
+        }
+
+        filterView.setOnClickListener(callback);
+    }
+
     public TaskIdAttributeContainer[] getTaskIdAttributeContainers() {
         return mTaskIdAttributeContainer;
     }
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
index 4eec319..9622619 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
@@ -18,6 +18,7 @@
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
@@ -103,12 +104,20 @@
     }
 
     @Test
-    public void testLongPressHome() {
+    public void testLongPressHome_enabled() {
+        mNavButtonController.setAssistantLongPressEnabled(true /*assistantLongPressEnabled*/);
         mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
         verify(mockSystemUiProxy, times(1)).startAssistant(any());
     }
 
     @Test
+    public void testLongPressHome_disabled() {
+        mNavButtonController.setAssistantLongPressEnabled(false /*assistantLongPressEnabled*/);
+        mNavButtonController.onButtonLongClick(BUTTON_HOME, mockView);
+        verify(mockSystemUiProxy, never()).startAssistant(any());
+    }
+
+    @Test
     public void testPressHome() {
         mNavButtonController.onButtonClick(BUTTON_HOME, mockView);
         verify(mockCommandHelper, times(1)).addCommand(TYPE_HOME);
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
index 58f0949..236b5db 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
@@ -8,38 +8,29 @@
 import android.widget.LinearLayout
 import androidx.test.runner.AndroidJUnit4
 import com.android.launcher3.DeviceProfile
+import com.android.launcher3.R
 import com.android.launcher3.taskbar.TaskbarManager
+import java.lang.IllegalStateException
+import org.junit.Assume.assumeTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mock
-import com.android.launcher3.R
-import org.junit.Assume.assumeTrue
 import org.mockito.Mockito.`when` as whenever
 import org.mockito.MockitoAnnotations
-import java.lang.IllegalStateException
 
 @RunWith(AndroidJUnit4::class)
 class NavButtonLayoutFactoryTest {
 
-    @Mock
-    lateinit var mockDeviceProfile: DeviceProfile
-    @Mock
-    lateinit var mockParentButtonContainer: FrameLayout
-    @Mock
-    lateinit var mockNavLayout: LinearLayout
-    @Mock
-    lateinit var mockStartContextualLayout: ViewGroup
-    @Mock
-    lateinit var mockEndContextualLayout: ViewGroup
-    @Mock
-    lateinit var mockResources: Resources
-    @Mock
-    lateinit var mockBackButton: ImageView
-    @Mock
-    lateinit var mockRecentsButton: ImageView
-    @Mock
-    lateinit var mockHomeButton: ImageView
+    @Mock lateinit var mockDeviceProfile: DeviceProfile
+    @Mock lateinit var mockParentButtonContainer: FrameLayout
+    @Mock lateinit var mockNavLayout: LinearLayout
+    @Mock lateinit var mockStartContextualLayout: ViewGroup
+    @Mock lateinit var mockEndContextualLayout: ViewGroup
+    @Mock lateinit var mockResources: Resources
+    @Mock lateinit var mockBackButton: ImageView
+    @Mock lateinit var mockRecentsButton: ImageView
+    @Mock lateinit var mockHomeButton: ImageView
 
     @Before
     fun setup() {
@@ -53,11 +44,11 @@
 
         // Init top level layout
         whenever(mockParentButtonContainer.findViewById<LinearLayout>(R.id.end_nav_buttons))
-                .thenReturn(mockNavLayout)
+            .thenReturn(mockNavLayout)
         whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.end_contextual_buttons))
-                .thenReturn(mockEndContextualLayout)
+            .thenReturn(mockEndContextualLayout)
         whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.start_contextual_buttons))
-                .thenReturn(mockStartContextualLayout)
+            .thenReturn(mockStartContextualLayout)
     }
 
     @Test
@@ -65,8 +56,12 @@
         assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
         mockDeviceProfile.isTaskbarPresent = true
         val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
-                getLayoutter(isKidsMode = true, isInSetup = false, isThreeButtonNav = false,
-                        phoneMode = false)
+            getLayoutter(
+                isKidsMode = true,
+                isInSetup = false,
+                isThreeButtonNav = false,
+                phoneMode = false
+            )
         assert(layoutter is KidsNavLayoutter)
     }
 
@@ -75,8 +70,12 @@
         assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
         mockDeviceProfile.isTaskbarPresent = true
         val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
-                getLayoutter(isKidsMode = false, isInSetup = true, isThreeButtonNav = false,
-                        phoneMode = false)
+            getLayoutter(
+                isKidsMode = false,
+                isInSetup = true,
+                isThreeButtonNav = false,
+                phoneMode = false
+            )
         assert(layoutter is SetupNavLayoutter)
     }
 
@@ -85,8 +84,12 @@
         assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
         mockDeviceProfile.isTaskbarPresent = true
         val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
-                getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false,
-                        phoneMode = false)
+            getLayoutter(
+                isKidsMode = false,
+                isInSetup = false,
+                isThreeButtonNav = false,
+                phoneMode = false
+            )
         assert(layoutter is TaskbarNavLayoutter)
     }
 
@@ -94,8 +97,12 @@
     fun noValidLayoutForLargeScreenTaskbarNotPresent() {
         assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
         mockDeviceProfile.isTaskbarPresent = false
-        getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false,
-                        phoneMode = false)
+        getLayoutter(
+            isKidsMode = false,
+            isInSetup = false,
+            isThreeButtonNav = false,
+            phoneMode = false
+        )
     }
 
     @Test
@@ -103,8 +110,12 @@
         assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
         mockDeviceProfile.isTaskbarPresent = false
         val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
-                getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = true,
-                        phoneMode = true)
+            getLayoutter(
+                isKidsMode = false,
+                isInSetup = false,
+                isThreeButtonNav = true,
+                phoneMode = true
+            )
         assert(layoutter is PhonePortraitNavLayoutter)
     }
 
@@ -114,8 +125,12 @@
         mockDeviceProfile.isTaskbarPresent = false
         setDeviceProfileLandscape()
         val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
-                getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = true,
-                        phoneMode = true)
+            getLayoutter(
+                isKidsMode = false,
+                isInSetup = false,
+                isThreeButtonNav = true,
+                phoneMode = true
+            )
         assert(layoutter is PhoneLandscapeNavLayoutter)
     }
 
@@ -123,8 +138,12 @@
     fun noValidLayoutForPhoneGestureNav() {
         assumeTrue(TaskbarManager.FLAG_HIDE_NAVBAR_WINDOW)
         mockDeviceProfile.isTaskbarPresent = false
-        getLayoutter(isKidsMode = false, isInSetup = false, isThreeButtonNav = false,
-                phoneMode = true)
+        getLayoutter(
+            isKidsMode = false,
+            isInSetup = false,
+            isThreeButtonNav = false,
+            phoneMode = true
+        )
     }
 
     private fun setDeviceProfileLandscape() {
@@ -134,15 +153,20 @@
         landscapeField.set(mockDeviceProfile, true)
     }
 
-    private fun getLayoutter(isKidsMode: Boolean, isInSetup: Boolean,
-                             isThreeButtonNav: Boolean, phoneMode: Boolean):
-            NavButtonLayoutFactory.NavButtonLayoutter {
+    private fun getLayoutter(
+        isKidsMode: Boolean,
+        isInSetup: Boolean,
+        isThreeButtonNav: Boolean,
+        phoneMode: Boolean
+    ): NavButtonLayoutFactory.NavButtonLayoutter {
         return NavButtonLayoutFactory.getUiLayoutter(
-                deviceProfile = mockDeviceProfile,
-                navButtonsView = mockParentButtonContainer,
-                resources = mockResources,
-                isKidsMode = isKidsMode, isInSetup = isInSetup,
-                isThreeButtonNav = isThreeButtonNav, phoneMode = phoneMode
+            deviceProfile = mockDeviceProfile,
+            navButtonsView = mockParentButtonContainer,
+            resources = mockResources,
+            isKidsMode = isKidsMode,
+            isInSetup = isInSetup,
+            isThreeButtonNav = isThreeButtonNav,
+            phoneMode = phoneMode
         )
     }
-}
\ No newline at end of file
+}
diff --git a/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt b/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
index 5ec935f..9afd893 100644
--- a/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/FullscreenDrawParamsTest.kt
@@ -27,15 +27,13 @@
 import com.android.systemui.shared.recents.utilities.PreviewPositionHelper
 import com.android.wm.shell.util.SplitBounds
 import com.google.common.truth.Truth.assertThat
+import kotlin.math.roundToInt
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.Mockito.mock
-import kotlin.math.roundToInt
 
-/**
- * Test for FullscreenDrawParams class.
- */
+/** Test for FullscreenDrawParams class. */
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class FullscreenDrawParamsTest : DeviceProfileBaseTest() {
@@ -61,15 +59,29 @@
         val currentRotation = 0
         val isRtl = false
 
-        mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
-                canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
-                isRtl)
-        params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
-                /* taskViewScale= */ 1.0f,  /* previewWidth= */ 0, dp, mPreviewPositionHelper)
+        mPreviewPositionHelper.updateThumbnailMatrix(
+            previewRect,
+            mThumbnailData,
+            canvasWidth,
+            canvasHeight,
+            dp.widthPx,
+            dp.heightPx,
+            dp.taskbarSize,
+            dp.isTablet,
+            currentRotation,
+            isRtl
+        )
+        params.setProgress(
+            /* fullscreenProgress= */ 1.0f,
+            /* parentScale= */ 1.0f,
+            /* taskViewScale= */ 1.0f,
+            /* previewWidth= */ 0,
+            dp,
+            mPreviewPositionHelper
+        )
 
         val expectedClippedInsets = RectF(0f, 0f, 0f, dp.taskbarSize * TASK_SCALE)
-        assertThat(params.mCurrentDrawnInsets)
-                .isEqualTo(expectedClippedInsets)
+        assertThat(params.mCurrentDrawnInsets).isEqualTo(expectedClippedInsets)
     }
 
     @Test
@@ -83,25 +95,42 @@
         val isRtl = false
         // portrait/vertical split apps
         val dividerSize = 10
-        val splitBounds = SplitBounds(
+        val splitBounds =
+            SplitBounds(
                 Rect(0, 0, dp.widthPx, (dp.heightPx - dividerSize) / 2),
                 Rect(0, (dp.heightPx + dividerSize) / 2, dp.widthPx, dp.heightPx),
-                0 /*lefTopTaskId*/, 0 /*rightBottomTaskId*/)
+                0 /*lefTopTaskId*/,
+                0 /*rightBottomTaskId*/
+            )
         mPreviewPositionHelper.setSplitBounds(splitBounds, STAGE_POSITION_BOTTOM_OR_RIGHT)
 
-        mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
-                canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
-                isRtl)
-        params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
-                /* taskViewScale= */ 1.0f,  /* previewWidth= */ 0, dp, mPreviewPositionHelper)
+        mPreviewPositionHelper.updateThumbnailMatrix(
+            previewRect,
+            mThumbnailData,
+            canvasWidth,
+            canvasHeight,
+            dp.widthPx,
+            dp.heightPx,
+            dp.taskbarSize,
+            dp.isTablet,
+            currentRotation,
+            isRtl
+        )
+        params.setProgress(
+            /* fullscreenProgress= */ 1.0f,
+            /* parentScale= */ 1.0f,
+            /* taskViewScale= */ 1.0f,
+            /* previewWidth= */ 0,
+            dp,
+            mPreviewPositionHelper
+        )
 
         // Probably unhelpful, but also unclear how to test otherwise ¯\_(ツ)_/¯
-        val fullscreenTaskHeight = dp.heightPx *
-                (1 - (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent))
+        val fullscreenTaskHeight =
+            dp.heightPx * (1 - (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent))
         val canvasScreenRatio = canvasHeight / fullscreenTaskHeight
         val expectedBottomHint = dp.taskbarSize * canvasScreenRatio
-        assertThat(params.mCurrentDrawnInsets.bottom)
-                .isWithin(1f).of(expectedBottomHint)
+        assertThat(params.mCurrentDrawnInsets.bottom).isWithin(1f).of(expectedBottomHint)
     }
 
     @Test
@@ -115,20 +144,37 @@
         val isRtl = false
         // portrait/vertical split apps
         val dividerSize = 10
-        val splitBounds = SplitBounds(
+        val splitBounds =
+            SplitBounds(
                 Rect(0, 0, dp.widthPx, (dp.heightPx - dividerSize) / 2),
                 Rect(0, (dp.heightPx + dividerSize) / 2, dp.widthPx, dp.heightPx),
-                0 /*lefTopTaskId*/, 0 /*rightBottomTaskId*/)
+                0 /*lefTopTaskId*/,
+                0 /*rightBottomTaskId*/
+            )
         mPreviewPositionHelper.setSplitBounds(splitBounds, STAGE_POSITION_TOP_OR_LEFT)
 
-        mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
-                canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
-                isRtl)
-        params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
-                /* taskViewScale= */ 1.0f,  /* previewWidth= */ 0, dp, mPreviewPositionHelper)
+        mPreviewPositionHelper.updateThumbnailMatrix(
+            previewRect,
+            mThumbnailData,
+            canvasWidth,
+            canvasHeight,
+            dp.widthPx,
+            dp.heightPx,
+            dp.taskbarSize,
+            dp.isTablet,
+            currentRotation,
+            isRtl
+        )
+        params.setProgress(
+            /* fullscreenProgress= */ 1.0f,
+            /* parentScale= */ 1.0f,
+            /* taskViewScale= */ 1.0f,
+            /* previewWidth= */ 0,
+            dp,
+            mPreviewPositionHelper
+        )
 
-        assertThat(params.mCurrentDrawnInsets.bottom)
-                .isWithin(1f).of((0f))
+        assertThat(params.mCurrentDrawnInsets.bottom).isWithin(1f).of((0f))
     }
 
     @Test
@@ -142,20 +188,37 @@
         val isRtl = false
         // portrait/vertical split apps
         val dividerSize = 10
-        val splitBounds = SplitBounds(
+        val splitBounds =
+            SplitBounds(
                 Rect(0, 0, (dp.widthPx - dividerSize) / 2, dp.heightPx),
                 Rect((dp.widthPx + dividerSize) / 2, 0, dp.widthPx, dp.heightPx),
-                0 /*lefTopTaskId*/, 0 /*rightBottomTaskId*/)
+                0 /*lefTopTaskId*/,
+                0 /*rightBottomTaskId*/
+            )
         mPreviewPositionHelper.setSplitBounds(splitBounds, STAGE_POSITION_BOTTOM_OR_RIGHT)
 
-        mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
-                canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
-                isRtl)
-        params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
-                /* taskViewScale= */ 1.0f,  /* previewWidth= */ 0, dp, mPreviewPositionHelper)
+        mPreviewPositionHelper.updateThumbnailMatrix(
+            previewRect,
+            mThumbnailData,
+            canvasWidth,
+            canvasHeight,
+            dp.widthPx,
+            dp.heightPx,
+            dp.taskbarSize,
+            dp.isTablet,
+            currentRotation,
+            isRtl
+        )
+        params.setProgress(
+            /* fullscreenProgress= */ 1.0f,
+            /* parentScale= */ 1.0f,
+            /* taskViewScale= */ 1.0f,
+            /* previewWidth= */ 0,
+            dp,
+            mPreviewPositionHelper
+        )
 
-        assertThat(params.mCurrentDrawnInsets.bottom)
-                .isWithin(1f).of((dp.taskbarSize * TASK_SCALE))
+        assertThat(params.mCurrentDrawnInsets.bottom).isWithin(1f).of((dp.taskbarSize * TASK_SCALE))
     }
 
     @Test
@@ -168,14 +231,28 @@
         val currentRotation = 0
         val isRtl = false
 
-        mPreviewPositionHelper.updateThumbnailMatrix(previewRect, mThumbnailData, canvasWidth,
-                canvasHeight, dp.widthPx, dp.heightPx, dp.taskbarSize, dp.isTablet, currentRotation,
-                isRtl)
-        params.setProgress(/* fullscreenProgress= */ 1.0f, /* parentScale= */ 1.0f,
-                /* taskViewScale= */ 1.0f,  /* previewWidth= */ 0, dp, mPreviewPositionHelper)
+        mPreviewPositionHelper.updateThumbnailMatrix(
+            previewRect,
+            mThumbnailData,
+            canvasWidth,
+            canvasHeight,
+            dp.widthPx,
+            dp.heightPx,
+            dp.taskbarSize,
+            dp.isTablet,
+            currentRotation,
+            isRtl
+        )
+        params.setProgress(
+            /* fullscreenProgress= */ 1.0f,
+            /* parentScale= */ 1.0f,
+            /* taskViewScale= */ 1.0f,
+            /* previewWidth= */ 0,
+            dp,
+            mPreviewPositionHelper
+        )
 
         val expectedClippedInsets = RectF(0f, 0f, 0f, 0f)
-        assertThat(params.mCurrentDrawnInsets)
-                .isEqualTo(expectedClippedInsets)
+        assertThat(params.mCurrentDrawnInsets).isEqualTo(expectedClippedInsets)
     }
-}
\ No newline at end of file
+}
diff --git a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
index 0303bc1..adbca32 100644
--- a/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/HotseatWidthCalculationTest.kt
@@ -29,8 +29,8 @@
 class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
 
     /**
-     * This is a case when after setting the hotseat, the space needs to be recalculated
-     * but it doesn't need to change QSB width or remove icons
+     * This is a case when after setting the hotseat, the space needs to be recalculated but it
+     * doesn't need to change QSB width or remove icons
      */
     @Test
     fun distribute_border_space_when_space_is_enough_portrait() {
@@ -39,20 +39,20 @@
         val dp = newDP()
         dp.isTaskbarPresentInApps = true
 
-        assertThat(dp.hotseatBarEndOffset).isEqualTo(558)
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(510)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(69)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(70)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(176)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(558)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(150)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(580)
 
         assertThat(dp.isQsbInline).isFalse()
         assertThat(dp.hotseatQsbWidth).isEqualTo(1445)
     }
 
     /**
-     * This is a case when after setting the hotseat, and recalculating spaces
-     * it still needs to remove icons for everything to fit
+     * This is a case when after setting the hotseat, and recalculating spaces it still needs to
+     * remove icons for everything to fit
      */
     @Test
     fun decrease_num_of_icons_when_not_enough_space_portrait() {
@@ -61,20 +61,20 @@
         val dp = newDP()
         dp.isTaskbarPresentInApps = true
 
-        assertThat(dp.hotseatBarEndOffset).isEqualTo(558)
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(510)
         assertThat(dp.numShownHotseatIcons).isEqualTo(4)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(50)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(40)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(112)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(558)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(150)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(550)
 
         assertThat(dp.isQsbInline).isFalse()
         assertThat(dp.hotseatQsbWidth).isEqualTo(1080)
     }
 
     /**
-     * This is a case when after setting the hotseat, the space needs to be recalculated
-     * but it doesn't need to change QSB width or remove icons
+     * This is a case when after setting the hotseat, the space needs to be recalculated but it
+     * doesn't need to change QSB width or remove icons
      */
     @Test
     fun distribute_border_space_when_space_is_enough_landscape() {
@@ -82,20 +82,20 @@
         val dp = newDP()
         dp.isTaskbarPresentInApps = true
 
-        assertThat(dp.hotseatBarEndOffset).isEqualTo(744)
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(705)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(82)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(54)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(106)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(744)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(231)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(759)
 
         assertThat(dp.isQsbInline).isFalse()
         assertThat(dp.hotseatQsbWidth).isEqualTo(1468)
     }
 
     /**
-     * This is a case when the hotseat spans a certain amount of columns
-     * and the nav buttons push the hotseat to the side, but not enough to change the border space.
+     * This is a case when the hotseat spans a certain amount of columns and the nav buttons push
+     * the hotseat to the side, but not enough to change the border space.
      */
     @Test
     fun nav_buttons_dont_interfere_with_required_hotseat_width() {
@@ -107,20 +107,18 @@
         val dp = newDP()
         dp.isTaskbarPresentInApps = true
 
-        assertThat(dp.hotseatBarEndOffset).isEqualTo(705)
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(660)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(102)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(100)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(625)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(705)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(300)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(1040)
 
         assertThat(dp.isQsbInline).isFalse()
         assertThat(dp.hotseatQsbWidth).isEqualTo(1233)
     }
 
-    /**
-     * This is a case when after setting the hotseat, the QSB width needs to be changed to fit
-     */
+    /** This is a case when after setting the hotseat, the QSB width needs to be changed to fit */
     @Test
     fun decrease_qsb_when_not_enough_space_landscape() {
         initializeVarsForTablet(isGestureMode = false, isLandscape = true)
@@ -128,15 +126,15 @@
         val dp = newDP()
         dp.isTaskbarPresentInApps = true
 
-        assertThat(dp.hotseatBarEndOffset).isEqualTo(705)
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(660)
         assertThat(dp.numShownHotseatIcons).isEqualTo(6)
         assertThat(dp.hotseatBorderSpace).isEqualTo(36)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(854)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(705)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(864)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(696)
 
         assertThat(dp.isQsbInline).isTrue()
-        assertThat(dp.hotseatQsbWidth).isEqualTo(531)
+        assertThat(dp.hotseatQsbWidth).isEqualTo(528)
     }
 
     /**
@@ -150,12 +148,12 @@
         val dp = newDP()
         dp.isTaskbarPresentInApps = true
 
-        assertThat(dp.hotseatBarEndOffset).isEqualTo(705)
+        assertThat(dp.hotseatBarEndOffset).isEqualTo(660)
         assertThat(dp.numShownHotseatIcons).isEqualTo(5)
-        assertThat(dp.hotseatBorderSpace).isEqualTo(43)
+        assertThat(dp.hotseatBorderSpace).isEqualTo(36)
 
-        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(782)
-        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(705)
+        assertThat(dp.getHotseatLayoutPadding(context).left).isEqualTo(816)
+        assertThat(dp.getHotseatLayoutPadding(context).right).isEqualTo(700)
 
         assertThat(dp.isQsbInline).isTrue()
         assertThat(dp.hotseatQsbWidth).isEqualTo(480)
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 9a2fcc0..9f34775 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -262,6 +262,19 @@
         return launchedAppState;
     }
 
+    private void quickSwitchToPreviousAppAndAssert(boolean toRight) {
+        final LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
+        if (toRight) {
+            launchedAppState.quickSwitchToPreviousApp();
+        } else {
+            launchedAppState.quickSwitchToPreviousAppSwipeLeft();
+        }
+
+        // While enable shell transition, Launcher can be resumed due to transient launch.
+        waitForLauncherCondition("Launcher shouldn't stay in resume forever",
+                this::isInLaunchedApp, 3000 /* timeout */);
+    }
+
     @Test
     @PortraitLandscape
     public void testAllAppsFromHome() throws Exception {
@@ -288,13 +301,11 @@
         startTestActivity(3);
         startTestActivity(4);
 
-        LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
-        launchedAppState.quickSwitchToPreviousApp();
+        quickSwitchToPreviousAppAndAssert(true /* toRight */);
         assertTrue("The first app we should have quick switched to is not running",
                 isTestActivityRunning(3));
 
-        launchedAppState = getAndAssertLaunchedApp();
-        launchedAppState.quickSwitchToPreviousApp();
+        quickSwitchToPreviousAppAndAssert(true /* toRight */);
         if (mLauncher.getNavigationModel() == NavigationModel.THREE_BUTTON) {
             // 3-button mode toggles between 2 apps, rather than going back further.
             assertTrue("Second quick switch should have returned to the first app.",
@@ -303,12 +314,12 @@
             assertTrue("The second app we should have quick switched to is not running",
                     isTestActivityRunning(2));
         }
-        launchedAppState = getAndAssertLaunchedApp();
-        launchedAppState.quickSwitchToPreviousAppSwipeLeft();
+
+        quickSwitchToPreviousAppAndAssert(false /* toRight */);
         assertTrue("The 2nd app we should have quick switched to is not running",
                 isTestActivityRunning(3));
 
-        launchedAppState = getAndAssertLaunchedApp();
+        final LaunchedAppState launchedAppState = getAndAssertLaunchedApp();
         launchedAppState.switchToOverview();
     }
 
@@ -327,8 +338,10 @@
         launchedAppState.assertTaskbarHidden();
 
         // Quick-switch to the test app with swiping to right.
-        launchedAppState.quickSwitchToPreviousApp();
+        quickSwitchToPreviousAppAndAssert(true /* toRight */);
 
+        assertTrue("The first app we should have quick switched to is not running",
+                isTestActivityRunning(2));
         // Expect task bar visible when the launched app was the test activity.
         launchedAppState = getAndAssertLaunchedApp();
         launchedAppState.assertTaskbarVisible();
diff --git a/res/drawable/ic_select_windows.xml b/res/drawable/ic_select_windows.xml
new file mode 100644
index 0000000..cba0fde
--- /dev/null
+++ b/res/drawable/ic_select_windows.xml
@@ -0,0 +1,26 @@
+<!--
+  ~ Copyright (C) 2022 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="48dp"
+    android:height="48dp"
+    android:viewportWidth="48"
+    android:viewportHeight="48"
+    android:tint="?attr/colorControlNormal">
+  <path
+      android:fillColor="@android:color/white"
+      android:pathData="M7,44Q5.8,44 4.9,43.1Q4,42.2 4,41V21.65Q4,20.45 4.9,19.55Q5.8,18.65 7,18.65H12.75V7Q12.75,5.8 13.65,4.9Q14.55,4 15.75,4H41Q42.2,4 43.1,4.9Q44,5.8 44,7V26.35Q44,27.55 43.1,28.45Q42.2,29.35 41,29.35H35.3V41Q35.3,42.2 34.4,43.1Q33.5,44 32.3,44ZM7,41H32.3Q32.3,41 32.3,41Q32.3,41 32.3,41V24.65H7V41Q7,41 7,41Q7,41 7,41ZM35.3,26.35H41Q41,26.35 41,26.35Q41,26.35 41,26.35V10H15.75V18.65H31.6Q33.2,18.65 34.25,19.7Q35.3,20.75 35.3,22.35Z"/>
+</vector>
\ No newline at end of file
diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml
index 81b28ba..c116c12 100644
--- a/res/layout/work_mode_fab.xml
+++ b/res/layout/work_mode_fab.xml
@@ -12,24 +12,35 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<com.android.launcher3.allapps.WorkModeSwitch xmlns:android="http://schemas.android.com/apk/res/android"
-    style="@style/TextHeadline"
+<com.android.launcher3.allapps.WorkModeSwitch
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/work_mode_toggle"
     android:layout_alignParentBottom="true"
     android:layout_alignParentEnd="true"
     android:layout_height="@dimen/work_fab_height"
     android:layout_width="wrap_content"
-    android:gravity="center"
-    android:includeFontPadding="false"
-    android:textDirection="locale"
-    android:drawableTint="@color/all_apps_tab_text"
-    android:textColor="@color/all_apps_tab_text"
-    android:textSize="14sp"
+    android:minHeight="@dimen/work_fab_height"
+    android:gravity="center_vertical"
     android:background="@drawable/work_apps_toggle_background"
     android:forceHasOverlappingRendering="false"
-    android:drawablePadding="8dp"
-    android:drawableStart="@drawable/ic_corp_off"
-    android:layout_marginBottom="@dimen/work_fab_margin_bottom"
-    android:paddingLeft="@dimen/work_mode_fab_padding"
-    android:paddingRight="@dimen/work_mode_fab_padding"
-    android:text="@string/work_apps_pause_btn_text" />
\ No newline at end of file
+    android:contentDescription="@string/work_apps_pause_btn_text"
+    android:animateLayoutChanges="true">
+    <ImageView
+        android:id="@+id/work_icon"
+        android:layout_width="@dimen/work_fab_icon_size"
+        android:layout_height="@dimen/work_fab_icon_size"
+        android:importantForAccessibility="no"
+        android:src="@drawable/ic_corp_off"
+        android:scaleType="center"/>
+    <TextView
+        android:id="@+id/pause_text"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textColor="@color/all_apps_tab_text"
+        android:textSize="14sp"
+        android:includeFontPadding="false"
+        android:textDirection="locale"
+        android:text="@string/work_apps_pause_btn_text"
+        android:layout_marginStart="@dimen/work_fab_text_start_margin"
+        style="@style/TextHeadline"/>
+</com.android.launcher3.allapps.WorkModeSwitch>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 460a73e..cc6e908 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -21,156 +21,156 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="app_name" msgid="649227358658669779">"Launcher3"</string>
     <string name="work_folder_name" msgid="3753320833950115786">"Work"</string>
-    <string name="activity_not_found" msgid="8071924732094499514">"Апликација није инсталирана."</string>
-    <string name="activity_not_available" msgid="7456344436509528827">"Апликација није доступна"</string>
-    <string name="safemode_shortcut_error" msgid="9160126848219158407">"Преузета апликација је онемогућена у Безбедном режиму"</string>
-    <string name="safemode_widget_error" msgid="4863470563535682004">"Виџети су онемогућени у Безбедном режиму"</string>
-    <string name="shortcut_not_available" msgid="2536503539825726397">"Пречица није доступна"</string>
-    <string name="home_screen" msgid="5629429142036709174">"Почетни екран"</string>
-    <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Подељени екран"</string>
-    <string name="split_screen_position_top" msgid="1504965011158689649">"Подели у врху"</string>
-    <string name="split_screen_position_left" msgid="7537793098851830883">"Подели лево"</string>
-    <string name="split_screen_position_right" msgid="1569377524925193369">"Подели десно"</string>
-    <string name="split_app_info_accessibility" msgid="5475288491241414932">"Информације о апликацији за: %1$s"</string>
-    <string name="long_press_widget_to_add" msgid="3587712543577675817">"Додирните и задржите ради померања виџета."</string>
-    <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Двапут додирните и задржите да бисте померали виџет или користите прилагођене радње."</string>
+    <string name="activity_not_found" msgid="8071924732094499514">"Aplikacija nije instalirana."</string>
+    <string name="activity_not_available" msgid="7456344436509528827">"Aplikacija nije dostupna"</string>
+    <string name="safemode_shortcut_error" msgid="9160126848219158407">"Preuzeta aplikacija je onemogućena u Bezbednom režimu"</string>
+    <string name="safemode_widget_error" msgid="4863470563535682004">"Vidžeti su onemogućeni u Bezbednom režimu"</string>
+    <string name="shortcut_not_available" msgid="2536503539825726397">"Prečica nije dostupna"</string>
+    <string name="home_screen" msgid="5629429142036709174">"Početni ekran"</string>
+    <string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podeljeni ekran"</string>
+    <string name="split_screen_position_top" msgid="1504965011158689649">"Podeli u vrhu"</string>
+    <string name="split_screen_position_left" msgid="7537793098851830883">"Podeli levo"</string>
+    <string name="split_screen_position_right" msgid="1569377524925193369">"Podeli desno"</string>
+    <string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji za: %1$s"</string>
+    <string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite radi pomeranja vidžeta."</string>
+    <string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite da biste pomerali vidžet ili koristite prilagođene radnje."</string>
     <string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
-    <string name="widget_accessible_dims_format" msgid="3640149169885301790">"ширина од %1$d и висина од %2$d"</string>
-    <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виџет"</string>
-    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Додирните и задржите виџет да бисте га померали по почетном екрану"</string>
-    <string name="add_to_home_screen" msgid="9168649446635919791">"Додај на почетни екран"</string>
-    <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Додали сте виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g> на почетни екран"</string>
-    <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виџет}one{# виџет}few{# виџета}other{# виџета}}"</string>
-    <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# пречица}one{# пречица}few{# пречице}other{# пречица}}"</string>
+    <string name="widget_accessible_dims_format" msgid="3640149169885301790">"širina od %1$d i visina od %2$d"</string>
+    <string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidžet"</string>
+    <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i zadržite vidžet da biste ga pomerali po početnom ekranu"</string>
+    <string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
+    <string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Dodali ste vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> na početni ekran"</string>
+    <string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidžet}one{# vidžet}few{# vidžeta}other{# vidžeta}}"</string>
+    <string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečica}one{# prečica}few{# prečice}other{# prečica}}"</string>
     <string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
-    <string name="widget_button_text" msgid="2880537293434387943">"Виџети"</string>
-    <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"Претражите"</string>
-    <string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Обришите текст из оквира за претрагу"</string>
-    <string name="no_widgets_available" msgid="4337693382501046170">"Виџети и пречице нису доступни"</string>
-    <string name="no_search_results" msgid="3787956167293097509">"Није пронађен ниједан виџет ни пречица"</string>
-    <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Лично"</string>
-    <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Посао"</string>
-    <string name="widget_category_conversations" msgid="8894438636213590446">"Конверзације"</string>
-    <string name="widget_education_header" msgid="4874760613775913787">"Корисне информације надохват руке"</string>
-    <string name="widget_education_content" msgid="1731667670753497052">"Да бисте пронашли информације без отварања апликација, можете да додате виџете на почетни екран"</string>
-    <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Додирните да бисте променили подешавања виџета"</string>
-    <string name="widget_education_close_button" msgid="8676165703104836580">"Важи"</string>
-    <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Промените подешавања виџета"</string>
-    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Претражите апликације"</string>
-    <string name="all_apps_loading_message" msgid="5813968043155271636">"Апликације се учитавају…"</string>
-    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Није пронађена ниједна апликација за „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
-    <string name="label_application" msgid="8531721983832654978">"Апликација"</string>
-    <string name="all_apps_label" msgid="5015784846527570951">"Све апликације"</string>
-    <string name="notifications_header" msgid="1404149926117359025">"Обавештења"</string>
-    <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Додирните и задржите ради померања пречице."</string>
-    <string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Двапут додирните и задржите да бисте померали пречицу или користите прилагођене радње."</string>
-    <string name="out_of_space" msgid="6455557115204099579">"Нема места на овом почетном екрану"</string>
-    <string name="hotseat_out_of_space" msgid="7448809638125333693">"Нема више простора на траци Омиљено"</string>
-    <string name="all_apps_button_label" msgid="8130441508702294465">"Листа апликација"</string>
-    <string name="all_apps_search_results" msgid="5889367432531296759">"Резултати претраге"</string>
-    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Листа личних апликација"</string>
-    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Листа пословних апликација"</string>
-    <string name="remove_drop_target_label" msgid="7812859488053230776">"Уклони"</string>
-    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталирај"</string>
-    <string name="app_info_drop_target_label" msgid="692894985365717661">"Инфор. о апликацији"</string>
-    <string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
-    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлажи апликацију"</string>
-    <string name="pin_prediction" msgid="4196423321649756498">"Закачи предвиђање"</string>
-    <string name="permlab_install_shortcut" msgid="5632423390354674437">"инсталирање пречица"</string>
-    <string name="permdesc_install_shortcut" msgid="923466509822011139">"Дозвољава апликацији да додаје пречице без интервенције корисника."</string>
-    <string name="permlab_read_settings" msgid="5136500343007704955">"читање подешавања и пречица на почетном екрану"</string>
-    <string name="permdesc_read_settings" msgid="4208061150510996676">"Дозвољава апликацији да чита подешавања и пречице на почетном екрану."</string>
-    <string name="permlab_write_settings" msgid="4820028712156303762">"уписивање подешавања и пречица на почетном екрану"</string>
-    <string name="permdesc_write_settings" msgid="726859348127868466">"Дозвољава апликацији да мења подешавања и пречице на почетном екрану."</string>
-    <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> нема дозволу за упућивање телефонских позива"</string>
-    <string name="gadget_error_text" msgid="740356548025791839">"Учитавање виџета није успело"</string>
-    <string name="gadget_setup_text" msgid="8348374825537681407">"Подешавања виџета"</string>
-    <string name="gadget_complete_setup_text" msgid="309040266978007925">"Додирните да бисте довршили подешавање"</string>
-    <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ово је системска апликација и не може да се деинсталира."</string>
-    <string name="folder_hint_text" msgid="5174843001373488816">"Измените назив"</string>
-    <string name="disabled_app_label" msgid="6673129024321402780">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је онемогућена"</string>
-    <string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{{app_name}, има # обавештење}one{{app_name}, има # обавештење}few{{app_name}, има # обавештења}other{{app_name}, има # обавештења}}"</string>
-    <string name="default_scroll_format" msgid="7475544710230993317">"%1$d. страница од %2$d"</string>
-    <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d. почетни екран од %2$d"</string>
-    <string name="workspace_new_page" msgid="257366611030256142">"Нова страница почетног екрана"</string>
-    <string name="folder_opened" msgid="94695026776264709">"Фолдер је отворен, <xliff:g id="WIDTH">%1$d</xliff:g> пута <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
-    <string name="folder_tap_to_close" msgid="4625795376335528256">"Додирните да бисте затворили фолдер"</string>
-    <string name="folder_tap_to_rename" msgid="4017685068016979677">"Додирните да бисте сачували преименовање"</string>
-    <string name="folder_closed" msgid="4100806530910930934">"Фолдер је затворен"</string>
-    <string name="folder_renamed" msgid="1794088362165669656">"Фолдер је преименован у <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="folder_name_format_exact" msgid="8626242716117004803">"Фолдер: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> ставке"</string>
-    <string name="folder_name_format_overflow" msgid="4270108890534995199">"Фолдер: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> или више ставки"</string>
-    <string name="wallpaper_button_text" msgid="8404103075899945851">"Позадине"</string>
-    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Позадина и стил"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Подешавања почетног екрана"</string>
-    <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Администратор је онемогућио"</string>
-    <string name="allow_rotation_title" msgid="7222049633713050106">"Дозволи ротацију почетног екрана"</string>
-    <string name="allow_rotation_desc" msgid="8662546029078692509">"Када се телефон ротира"</string>
-    <string name="notification_dots_title" msgid="9062440428204120317">"Тачке за обавештења"</string>
-    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Укључено"</string>
-    <string name="notification_dots_desc_off" msgid="1760796511504341095">"Искључено"</string>
-    <string name="title_missing_notification_access" msgid="7503287056163941064">"Потребан је приступ за обавештења"</string>
-    <string name="msg_missing_notification_access" msgid="281113995110910548">"Да бисте приказали тачке за обавештења, укључите обавештења за апликацију <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="title_change_settings" msgid="1376365968844349552">"Промените подешавања"</string>
-    <string name="notification_dots_service_title" msgid="4284221181793592871">"Приказуј тачке за обавештења"</string>
-    <string name="developer_options_title" msgid="700788437593726194">"Опције за програмера"</string>
-    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Додај иконе апликација на почетни екран"</string>
-    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"За нове апликације"</string>
-    <string name="package_state_unknown" msgid="7592128424511031410">"Непознато"</string>
-    <string name="abandoned_clean_this" msgid="7610119707847920412">"Уклони"</string>
-    <string name="abandoned_search" msgid="891119232568284442">"Претражи"</string>
-    <string name="abandoned_promises_title" msgid="7096178467971716750">"Ова апликација није инсталирана"</string>
-    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Апликација за ову икону није инсталирана. Можете да је уклоните или да потражите апликацију и инсталирате је ручно."</string>
-    <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> се инсталира, <xliff:g id="PROGRESS">%2$s</xliff:g> готово"</string>
-    <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> се преузима, завршено је <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
-    <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> чека на инсталирање"</string>
-    <string name="dialog_update_title" msgid="114234265740994042">"Треба да ажурирате апликацију"</string>
-    <string name="dialog_update_message" msgid="4176784553982226114">"Апликација за ову икону није ажурирана. Можете да је ручно ажурирате да бисте поново омогућили ову пречицу или уклоните икону."</string>
-    <string name="dialog_update" msgid="2178028071796141234">"Ажурирај"</string>
-    <string name="dialog_remove" msgid="6510806469849709407">"Уклони"</string>
-    <string name="widgets_list" msgid="796804551140113767">"Листа виџета"</string>
-    <string name="widgets_list_closed" msgid="6141506579418771922">"Листа виџета је затворена"</string>
-    <string name="action_add_to_workspace" msgid="215894119683164916">"Додајте на почетни екран"</string>
-    <string name="action_move_here" msgid="2170188780612570250">"Премести ставку овде"</string>
-    <string name="item_added_to_workspace" msgid="4211073925752213539">"Ставка је додата на почетни екран"</string>
-    <string name="item_removed" msgid="851119963877842327">"Ставка је уклоњена"</string>
-    <string name="undo" msgid="4151576204245173321">"Опозови"</string>
-    <string name="action_move" msgid="4339390619886385032">"Премести ставку"</string>
-    <string name="move_to_empty_cell_description" msgid="5254852678218206889">"Преместите у ред <xliff:g id="NUMBER_0">%1$s</xliff:g> колону <xliff:g id="NUMBER_1">%2$s</xliff:g> на <xliff:g id="STRING">%3$s</xliff:g>"</string>
-    <string name="move_to_position" msgid="6750008980455459790">"Премести на <xliff:g id="NUMBER">%1$s</xliff:g>. позицију"</string>
-    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Премести на <xliff:g id="NUMBER">%1$s</xliff:g>. позицију у омиљеним"</string>
-    <string name="item_moved" msgid="4606538322571412879">"Ставка је премештена"</string>
-    <string name="add_to_folder" msgid="9040534766770853243">"Додај у фолдер: <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Додај у фолдер у коме је <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="added_to_folder" msgid="4793259502305558003">"Ставка је додата у фолдер"</string>
-    <string name="create_folder_with" msgid="4050141361160214248">"Направите фолдер са: <xliff:g id="NAME">%1$s</xliff:g>"</string>
-    <string name="folder_created" msgid="6409794597405184510">"Фолдер је направљен"</string>
-    <string name="action_move_to_workspace" msgid="39528912300293768">"Преместите на почетни екран"</string>
-    <string name="action_resize" msgid="1802976324781771067">"Промени величину"</string>
-    <string name="action_increase_width" msgid="8773715375078513326">"Повећај ширину"</string>
-    <string name="action_increase_height" msgid="459390020612501122">"Повећај висину"</string>
-    <string name="action_decrease_width" msgid="1374549771083094654">"Смањи ширину"</string>
-    <string name="action_decrease_height" msgid="282377193880900022">"Смањи висину"</string>
-    <string name="widget_resized" msgid="9130327887929620">"Величина виџета је промењена на ширину <xliff:g id="NUMBER_0">%1$s</xliff:g> и висину <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
-    <string name="action_deep_shortcut" msgid="2864038805849372848">"Пречице"</string>
-    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Пречице и обавештења"</string>
-    <string name="action_dismiss_notification" msgid="5909461085055959187">"Одбаци"</string>
-    <string name="accessibility_close" msgid="2277148124685870734">"Затвори"</string>
-    <string name="notification_dismissed" msgid="6002233469409822874">"Обавештење је одбачено"</string>
-    <string name="all_apps_personal_tab" msgid="4190252696685155002">"Личне"</string>
-    <string name="all_apps_work_tab" msgid="4884822796154055118">"Пословне"</string>
-    <string name="work_profile_toggle_label" msgid="3081029915775481146">"Пословни профил"</string>
-    <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Пословне апликације су означене значком и ИТ администратор може да их види"</string>
-    <string name="work_profile_edu_accept" msgid="6069788082535149071">"Важи"</string>
-    <string name="work_apps_paused_title" msgid="3040901117349444598">"Пословне апликације су паузиране"</string>
-    <string name="work_apps_paused_body" msgid="261634750995824906">"Пословне апликације не могу да вам шаљу обавештења, користе батерију нити приступају локацији"</string>
-    <string name="work_apps_paused_content_description" msgid="5149623040804051095">"Пословне апликације су искључене. Пословне апликације не могу да вам шаљу обавештења, користе батерију нити приступају локацији"</string>
-    <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"Пословне апликације су означене значком и ИТ администратор може да их види"</string>
-    <string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Важи"</string>
-    <string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Паузирај пословне апликације"</string>
-    <string name="work_apps_enable_btn_text" msgid="1156432622148413741">"Укључи пословне апликације"</string>
-    <string name="developer_options_filter_hint" msgid="5896817443635989056">"Филтер"</string>
-    <string name="search_pref_screen_title" msgid="3258959643336315962">"Претражите телефон"</string>
-    <string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Претражите таблет"</string>
-    <string name="remote_action_failed" msgid="1383965239183576790">"Није успело: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
+    <string name="widget_button_text" msgid="2880537293434387943">"Vidžeti"</string>
+    <string name="widgets_full_sheet_search_bar_hint" msgid="8484659090860596457">"Pretražite"</string>
+    <string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Obrišite tekst iz okvira za pretragu"</string>
+    <string name="no_widgets_available" msgid="4337693382501046170">"Vidžeti i prečice nisu dostupni"</string>
+    <string name="no_search_results" msgid="3787956167293097509">"Nije pronađen nijedan vidžet ni prečica"</string>
+    <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Lično"</string>
+    <string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Posao"</string>
+    <string name="widget_category_conversations" msgid="8894438636213590446">"Konverzacije"</string>
+    <string name="widget_education_header" msgid="4874760613775913787">"Korisne informacije nadohvat ruke"</string>
+    <string name="widget_education_content" msgid="1731667670753497052">"Da biste pronašli informacije bez otvaranja aplikacija, možete da dodate vidžete na početni ekran"</string>
+    <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Dodirnite da biste promenili podešavanja vidžeta"</string>
+    <string name="widget_education_close_button" msgid="8676165703104836580">"Važi"</string>
+    <string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Promenite podešavanja vidžeta"</string>
+    <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Pretražite aplikacije"</string>
+    <string name="all_apps_loading_message" msgid="5813968043155271636">"Aplikacije se učitavaju…"</string>
+    <string name="all_apps_no_search_results" msgid="3200346862396363786">"Nije pronađena nijedna aplikacija za „<xliff:g id="QUERY">%1$s</xliff:g>“"</string>
+    <string name="label_application" msgid="8531721983832654978">"Aplikacija"</string>
+    <string name="all_apps_label" msgid="5015784846527570951">"Sve aplikacije"</string>
+    <string name="notifications_header" msgid="1404149926117359025">"Obaveštenja"</string>
+    <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Dodirnite i zadržite radi pomeranja prečice."</string>
+    <string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Dvaput dodirnite i zadržite da biste pomerali prečicu ili koristite prilagođene radnje."</string>
+    <string name="out_of_space" msgid="6455557115204099579">"Nema mesta na ovom početnom ekranu"</string>
+    <string name="hotseat_out_of_space" msgid="7448809638125333693">"Nema više prostora na traci Omiljeno"</string>
+    <string name="all_apps_button_label" msgid="8130441508702294465">"Lista aplikacija"</string>
+    <string name="all_apps_search_results" msgid="5889367432531296759">"Rezultati pretrage"</string>
+    <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Lista ličnih aplikacija"</string>
+    <string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista poslovnih aplikacija"</string>
+    <string name="remove_drop_target_label" msgid="7812859488053230776">"Ukloni"</string>
+    <string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
+    <string name="app_info_drop_target_label" msgid="692894985365717661">"Infor. o aplikaciji"</string>
+    <string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
+    <string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
+    <string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
+    <string name="permlab_install_shortcut" msgid="5632423390354674437">"instaliranje prečica"</string>
+    <string name="permdesc_install_shortcut" msgid="923466509822011139">"Dozvoljava aplikaciji da dodaje prečice bez intervencije korisnika."</string>
+    <string name="permlab_read_settings" msgid="5136500343007704955">"čitanje podešavanja i prečica na početnom ekranu"</string>
+    <string name="permdesc_read_settings" msgid="4208061150510996676">"Dozvoljava aplikaciji da čita podešavanja i prečice na početnom ekranu."</string>
+    <string name="permlab_write_settings" msgid="4820028712156303762">"upisivanje podešavanja i prečica na početnom ekranu"</string>
+    <string name="permdesc_write_settings" msgid="726859348127868466">"Dozvoljava aplikaciji da menja podešavanja i prečice na početnom ekranu."</string>
+    <string name="msg_no_phone_permission" msgid="9208659281529857371">"<xliff:g id="APP_NAME">%1$s</xliff:g> nema dozvolu za upućivanje telefonskih poziva"</string>
+    <string name="gadget_error_text" msgid="740356548025791839">"Učitavanje vidžeta nije uspelo"</string>
+    <string name="gadget_setup_text" msgid="8348374825537681407">"Podešavanja vidžeta"</string>
+    <string name="gadget_complete_setup_text" msgid="309040266978007925">"Dodirnite da biste dovršili podešavanje"</string>
+    <string name="uninstall_system_app_text" msgid="4172046090762920660">"Ovo je sistemska aplikacija i ne može da se deinstalira."</string>
+    <string name="folder_hint_text" msgid="5174843001373488816">"Izmenite naziv"</string>
+    <string name="disabled_app_label" msgid="6673129024321402780">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je onemogućena"</string>
+    <string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{{app_name}, ima # obaveštenje}one{{app_name}, ima # obaveštenje}few{{app_name}, ima # obaveštenja}other{{app_name}, ima # obaveštenja}}"</string>
+    <string name="default_scroll_format" msgid="7475544710230993317">"%1$d. stranica od %2$d"</string>
+    <string name="workspace_scroll_format" msgid="8458889198184077399">"%1$d. početni ekran od %2$d"</string>
+    <string name="workspace_new_page" msgid="257366611030256142">"Nova stranica početnog ekrana"</string>
+    <string name="folder_opened" msgid="94695026776264709">"Folder je otvoren, <xliff:g id="WIDTH">%1$d</xliff:g> puta <xliff:g id="HEIGHT">%2$d</xliff:g>"</string>
+    <string name="folder_tap_to_close" msgid="4625795376335528256">"Dodirnite da biste zatvorili folder"</string>
+    <string name="folder_tap_to_rename" msgid="4017685068016979677">"Dodirnite da biste sačuvali preimenovanje"</string>
+    <string name="folder_closed" msgid="4100806530910930934">"Folder je zatvoren"</string>
+    <string name="folder_renamed" msgid="1794088362165669656">"Folder je preimenovan u <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_name_format_exact" msgid="8626242716117004803">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> stavke"</string>
+    <string name="folder_name_format_overflow" msgid="4270108890534995199">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> ili više stavki"</string>
+    <string name="wallpaper_button_text" msgid="8404103075899945851">"Pozadine"</string>
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Pozadina i stil"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Podešavanja početnog ekrana"</string>
+    <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Administrator je onemogućio"</string>
+    <string name="allow_rotation_title" msgid="7222049633713050106">"Dozvoli rotaciju početnog ekrana"</string>
+    <string name="allow_rotation_desc" msgid="8662546029078692509">"Kada se telefon rotira"</string>
+    <string name="notification_dots_title" msgid="9062440428204120317">"Tačke za obaveštenja"</string>
+    <string name="notification_dots_desc_on" msgid="1679848116452218908">"Uključeno"</string>
+    <string name="notification_dots_desc_off" msgid="1760796511504341095">"Isključeno"</string>
+    <string name="title_missing_notification_access" msgid="7503287056163941064">"Potreban je pristup za obaveštenja"</string>
+    <string name="msg_missing_notification_access" msgid="281113995110910548">"Da biste prikazali tačke za obaveštenja, uključite obaveštenja za aplikaciju <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="title_change_settings" msgid="1376365968844349552">"Promenite podešavanja"</string>
+    <string name="notification_dots_service_title" msgid="4284221181793592871">"Prikazuj tačke za obaveštenja"</string>
+    <string name="developer_options_title" msgid="700788437593726194">"Opcije za programera"</string>
+    <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Dodaj ikone aplikacija na početni ekran"</string>
+    <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Za nove aplikacije"</string>
+    <string name="package_state_unknown" msgid="7592128424511031410">"Nepoznato"</string>
+    <string name="abandoned_clean_this" msgid="7610119707847920412">"Ukloni"</string>
+    <string name="abandoned_search" msgid="891119232568284442">"Pretraži"</string>
+    <string name="abandoned_promises_title" msgid="7096178467971716750">"Ova aplikacija nije instalirana"</string>
+    <string name="abandoned_promise_explanation" msgid="3990027586878167529">"Aplikacija za ovu ikonu nije instalirana. Možete da je uklonite ili da potražite aplikaciju i instalirate je ručno."</string>
+    <string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> se instalira, <xliff:g id="PROGRESS">%2$s</xliff:g> gotovo"</string>
+    <string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> se preuzima, završeno je <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
+    <string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> čeka na instaliranje"</string>
+    <string name="dialog_update_title" msgid="114234265740994042">"Treba da ažurirate aplikaciju"</string>
+    <string name="dialog_update_message" msgid="4176784553982226114">"Aplikacija za ovu ikonu nije ažurirana. Možete da je ručno ažurirate da biste ponovo omogućili ovu prečicu ili uklonite ikonu."</string>
+    <string name="dialog_update" msgid="2178028071796141234">"Ažuriraj"</string>
+    <string name="dialog_remove" msgid="6510806469849709407">"Ukloni"</string>
+    <string name="widgets_list" msgid="796804551140113767">"Lista vidžeta"</string>
+    <string name="widgets_list_closed" msgid="6141506579418771922">"Lista vidžeta je zatvorena"</string>
+    <string name="action_add_to_workspace" msgid="215894119683164916">"Dodajte na početni ekran"</string>
+    <string name="action_move_here" msgid="2170188780612570250">"Premesti stavku ovde"</string>
+    <string name="item_added_to_workspace" msgid="4211073925752213539">"Stavka je dodata na početni ekran"</string>
+    <string name="item_removed" msgid="851119963877842327">"Stavka je uklonjena"</string>
+    <string name="undo" msgid="4151576204245173321">"Opozovi"</string>
+    <string name="action_move" msgid="4339390619886385032">"Premesti stavku"</string>
+    <string name="move_to_empty_cell_description" msgid="5254852678218206889">"Premestite u red <xliff:g id="NUMBER_0">%1$s</xliff:g> kolonu <xliff:g id="NUMBER_1">%2$s</xliff:g> na <xliff:g id="STRING">%3$s</xliff:g>"</string>
+    <string name="move_to_position" msgid="6750008980455459790">"Premesti na <xliff:g id="NUMBER">%1$s</xliff:g>. poziciju"</string>
+    <string name="move_to_hotseat_position" msgid="6295412897075147808">"Premesti na <xliff:g id="NUMBER">%1$s</xliff:g>. poziciju u omiljenim"</string>
+    <string name="item_moved" msgid="4606538322571412879">"Stavka je premeštena"</string>
+    <string name="add_to_folder" msgid="9040534766770853243">"Dodaj u folder: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="add_to_folder_with_app" msgid="4534929978967147231">"Dodaj u folder u kome je <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="added_to_folder" msgid="4793259502305558003">"Stavka je dodata u folder"</string>
+    <string name="create_folder_with" msgid="4050141361160214248">"Napravite folder sa: <xliff:g id="NAME">%1$s</xliff:g>"</string>
+    <string name="folder_created" msgid="6409794597405184510">"Folder je napravljen"</string>
+    <string name="action_move_to_workspace" msgid="39528912300293768">"Premestite na početni ekran"</string>
+    <string name="action_resize" msgid="1802976324781771067">"Promeni veličinu"</string>
+    <string name="action_increase_width" msgid="8773715375078513326">"Povećaj širinu"</string>
+    <string name="action_increase_height" msgid="459390020612501122">"Povećaj visinu"</string>
+    <string name="action_decrease_width" msgid="1374549771083094654">"Smanji širinu"</string>
+    <string name="action_decrease_height" msgid="282377193880900022">"Smanji visinu"</string>
+    <string name="widget_resized" msgid="9130327887929620">"Veličina vidžeta je promenjena na širinu <xliff:g id="NUMBER_0">%1$s</xliff:g> i visinu <xliff:g id="NUMBER_1">%2$s</xliff:g>"</string>
+    <string name="action_deep_shortcut" msgid="2864038805849372848">"Prečice"</string>
+    <string name="shortcuts_menu_with_notifications_description" msgid="2676582286544232849">"Prečice i obaveštenja"</string>
+    <string name="action_dismiss_notification" msgid="5909461085055959187">"Odbaci"</string>
+    <string name="accessibility_close" msgid="2277148124685870734">"Zatvori"</string>
+    <string name="notification_dismissed" msgid="6002233469409822874">"Obaveštenje je odbačeno"</string>
+    <string name="all_apps_personal_tab" msgid="4190252696685155002">"Lične"</string>
+    <string name="all_apps_work_tab" msgid="4884822796154055118">"Poslovne"</string>
+    <string name="work_profile_toggle_label" msgid="3081029915775481146">"Poslovni profil"</string>
+    <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Poslovne aplikacije su označene značkom i IT administrator može da ih vidi"</string>
+    <string name="work_profile_edu_accept" msgid="6069788082535149071">"Važi"</string>
+    <string name="work_apps_paused_title" msgid="3040901117349444598">"Poslovne aplikacije su pauzirane"</string>
+    <string name="work_apps_paused_body" msgid="261634750995824906">"Poslovne aplikacije ne mogu da vam šalju obaveštenja, koriste bateriju niti pristupaju lokaciji"</string>
+    <string name="work_apps_paused_content_description" msgid="5149623040804051095">"Poslovne aplikacije su isključene. Poslovne aplikacije ne mogu da vam šalju obaveštenja, koriste bateriju niti pristupaju lokaciji"</string>
+    <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"Poslovne aplikacije su označene značkom i IT administrator može da ih vidi"</string>
+    <string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"Važi"</string>
+    <string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Pauziraj poslovne aplikacije"</string>
+    <string name="work_apps_enable_btn_text" msgid="1156432622148413741">"Uključi poslovne aplikacije"</string>
+    <string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
+    <string name="search_pref_screen_title" msgid="3258959643336315962">"Pretražite telefon"</string>
+    <string name="search_pref_screen_title_tablet" msgid="5220319680451343959">"Pretražite tablet"</string>
+    <string name="remote_action_failed" msgid="1383965239183576790">"Nije uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
 </resources>
diff --git a/res/values/config.xml b/res/values/config.xml
index 4cab2de..016420b 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -83,6 +83,7 @@
     <string name="model_delegate_class" translatable="false"></string>
     <string name="window_manager_proxy_class" translatable="false"></string>
     <string name="secondary_display_predictions_class" translatable="false"></string>
+    <string name="widget_holder_factory_class" translatable="false"></string>
 
     <!-- View ID to use for QSB widget -->
     <item type="id" name="qsb_widget" />
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index dc53552..4d2e1b7 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -114,6 +114,8 @@
     <dimen name="all_apps_tabs_indicator_height">2dp</dimen>
     <dimen name="all_apps_header_top_margin">33dp</dimen>
     <dimen name="all_apps_header_top_padding">36dp</dimen>
+    <!-- Additional top padding to add when Floating Searchbar is enabled. -->
+    <dimen name="all_apps_additional_top_padding_floating_search">16dp</dimen>
     <dimen name="all_apps_header_bottom_padding">14dp</dimen>
     <dimen name="all_apps_header_top_adjustment">6dp</dimen>
     <dimen name="all_apps_header_bottom_adjustment">4dp</dimen>
@@ -147,6 +149,8 @@
     <!-- Floating action button inside work tab to toggle work profile -->
     <dimen name="work_fab_height">56dp</dimen>
     <dimen name="work_fab_radius">16dp</dimen>
+    <dimen name="work_fab_icon_size">24dp</dimen>
+    <dimen name="work_fab_text_start_margin">8dp</dimen>
     <dimen name="work_card_padding_horizontal">10dp</dimen>
     <dimen name="work_card_button_height">52dp</dimen>
     <dimen name="work_fab_margin">16dp</dimen>
@@ -359,32 +363,26 @@
     <dimen name="qsb_widget_height">0dp</dimen>
     <dimen name="qsb_shadow_height">0dp</dimen>
     <dimen name="min_hotseat_icon_space">18dp</dimen>
+    <dimen name="max_hotseat_icon_space">50dp</dimen>
     <dimen name="min_hotseat_qsb_width">0dp</dimen>
-    <dimen name="taskbar_icon_size">44dp</dimen>
-    <dimen name="transient_taskbar_icon_size">57dp</dimen>
-    <dimen name="transient_taskbar_two_panels_icon_size">50dp</dimen>
+    <dimen name="taskbar_icon_size">0dp</dimen>
+    <dimen name="transient_taskbar_icon_size">0dp</dimen>
     <!-- Transient taskbar (placeholders to compile in Launcher3 without Quickstep) -->
     <dimen name="transient_taskbar_size">0dp</dimen>
-    <dimen name="transient_taskbar_two_panels_size">0dp</dimen>
     <dimen name="transient_taskbar_margin">0dp</dimen>
     <dimen name="transient_taskbar_shadow_blur">0dp</dimen>
     <dimen name="transient_taskbar_key_shadow_distance">0dp</dimen>
     <dimen name="transient_taskbar_stashed_size">0dp</dimen>
     <dimen name="transient_taskbar_clamped_offset_bound">0dp</dimen>
-    <!-- Note that this applies to both sides of all icons, so visible space is double this. -->
-    <dimen name="transient_taskbar_icon_spacing">0dp</dimen>
-    <!-- Note that this applies to both sides of all icons, so visible space is double this. -->
-    <dimen name="taskbar_icon_spacing">8dp</dimen>
+    <dimen name="taskbar_icon_spacing">0dp</dimen>
     <dimen name="taskbar_nav_buttons_size">0dp</dimen>
     <dimen name="taskbar_contextual_button_margin">0dp</dimen>
     <dimen name="taskbar_hotseat_nav_spacing">0dp</dimen>
     <dimen name="taskbar_button_margin_default">0dp</dimen>
     <dimen name="taskbar_button_space_inbetween">0dp</dimen>
     <dimen name="taskbar_button_space_inbetween_phone">0dp</dimen>
-    <dimen name="taskbar_button_margin_5_5">0dp</dimen>
+    <dimen name="taskbar_button_margin_split">0dp</dimen>
     <dimen name="taskbar_button_margin_6_5">0dp</dimen>
-    <dimen name="taskbar_button_margin_4_5">0dp</dimen>
-    <dimen name="taskbar_button_margin_4_4">0dp</dimen>
     <!-- Taskbar swipe up thresholds threshold -->
     <dimen name="taskbar_nav_threshold">0dp</dimen>
     <dimen name="taskbar_app_window_threshold">0dp</dimen>
diff --git a/res/xml/device_profiles.xml b/res/xml/device_profiles.xml
index 407f217..c9a44a1 100644
--- a/res/xml/device_profiles.xml
+++ b/res/xml/device_profiles.xml
@@ -57,8 +57,9 @@
         launcher:numFolderRows="3"
         launcher:numFolderColumns="4"
         launcher:numHotseatIcons="4"
+        launcher:numExtendedHotseatIcons="6"
         launcher:dbFile="launcher_4_by_4.db"
-        launcher:inlineNavButtonsEndSpacing="@dimen/taskbar_button_margin_4_4"
+        launcher:inlineNavButtonsEndSpacing="@dimen/taskbar_button_margin_split"
         launcher:defaultLayoutId="@xml/default_workspace_4x4"
         launcher:deviceCategory="phone|multi_display" >
 
@@ -121,8 +122,9 @@
         launcher:numFolderRows="4"
         launcher:numFolderColumns="4"
         launcher:numHotseatIcons="5"
+        launcher:numExtendedHotseatIcons="6"
         launcher:dbFile="launcher.db"
-        launcher:inlineNavButtonsEndSpacing="@dimen/taskbar_button_margin_5_5"
+        launcher:inlineNavButtonsEndSpacing="@dimen/taskbar_button_margin_split"
         launcher:defaultLayoutId="@xml/default_workspace_5x5"
         launcher:deviceCategory="phone|multi_display" >
 
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 7ccd195..25520e1 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -188,6 +188,10 @@
     public final int hotseatQsbVisualHeight;
     private final int hotseatQsbShadowHeight;
     public int hotseatBorderSpace;
+    private int minHotseatIconSpacePx;
+    private int minHotseatQsbWidthPx;
+    private final int maxHotseatIconSpacePx;
+    private int inlineNavButtonsEndSpacing;
 
     // Bottom sheets
     public int bottomSheetTopPadding;
@@ -321,9 +325,7 @@
 
         if (isTaskbarPresent) {
             if (DisplayController.isTransientTaskbar(context)) {
-                taskbarSize = res.getDimensionPixelSize(isTwoPanels
-                        ? R.dimen.transient_taskbar_two_panels_size
-                        : R.dimen.transient_taskbar_size);
+                taskbarSize = res.getDimensionPixelSize(R.dimen.transient_taskbar_size);
                 stashedTaskbarSize =
                         res.getDimensionPixelSize(R.dimen.transient_taskbar_stashed_size);
                 transientTaskbarMargin =
@@ -434,7 +436,7 @@
                 || inv.inlineQsb[INDEX_TWO_PANEL_LANDSCAPE]
                 : inv.inlineQsb[INDEX_DEFAULT] || inv.inlineQsb[INDEX_LANDSCAPE])
                 && hotseatQsbHeight > 0;
-        isQsbInline = inv.inlineQsb[mTypeIndex] && canQsbInline;
+        isQsbInline = isScalableGrid && inv.inlineQsb[mTypeIndex] && canQsbInline;
 
         areNavButtonsInline = isTaskbarPresent && !isGestureMode;
         numShownHotseatIcons =
@@ -474,17 +476,17 @@
         hotseatBarSidePaddingStartPx = isVerticalBarLayout() ? workspacePageIndicatorHeight : 0;
         updateHotseatSizes(pxFromDp(inv.iconSize[INDEX_DEFAULT], mMetrics));
         if (areNavButtonsInline && !isPhone) {
+            inlineNavButtonsEndSpacing = res.getDimensionPixelSize(inv.inlineNavButtonsEndSpacing);
             /*
              * 3 nav buttons +
              * Spacing between nav buttons +
-             * Little space at the end for contextual buttons +
-             * Little space between icons and nav buttons
+             * Space at the end for contextual buttons
              */
             hotseatBarEndOffset = 3 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size)
                     + 2 * res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween)
-                    + res.getDimensionPixelSize(inv.inlineNavButtonsEndSpacing)
-                    + res.getDimensionPixelSize(R.dimen.taskbar_hotseat_nav_spacing);
+                    + inlineNavButtonsEndSpacing;
         } else {
+            inlineNavButtonsEndSpacing = 0;
             hotseatBarEndOffset = 0;
         }
 
@@ -531,8 +533,12 @@
                 cellLayoutPadding);
         updateWorkspacePadding();
 
+        minHotseatIconSpacePx = res.getDimensionPixelSize(R.dimen.min_hotseat_icon_space);
+        minHotseatQsbWidthPx = res.getDimensionPixelSize(R.dimen.min_hotseat_qsb_width);
+        maxHotseatIconSpacePx = areNavButtonsInline
+                ? res.getDimensionPixelSize(R.dimen.max_hotseat_icon_space) : Integer.MAX_VALUE;
         // Hotseat and QSB width depends on updated cellSize and workspace padding
-        recalculateHotseatWidthAndBorderSpace(res);
+        recalculateHotseatWidthAndBorderSpace();
 
         // AllApps height calculation depends on updated cellSize
         if (isTablet) {
@@ -621,68 +627,57 @@
         }
     }
 
-    private void recalculateHotseatWidthAndBorderSpace(Resources res) {
-        hotseatBorderSpace = calculateHotseatBorderSpace();
+    /**
+     * Calculates the width of the hotseat, changing spaces between the icons and removing icons if
+     * necessary.
+     */
+    public void recalculateHotseatWidthAndBorderSpace() {
+        if (!isScalableGrid) return;
+
+        int columns = inv.hotseatColumnSpan[mTypeIndex];
+        float hotseatWidthPx = getIconToIconWidthForColumns(columns);
+        hotseatBorderSpace = calculateHotseatBorderSpace(hotseatWidthPx, /* numExtraBorder= */ 0);
         hotseatQsbWidth = calculateQsbWidth(hotseatBorderSpace);
-        // Spaces should be correct when there nav buttons are not inline
+        // Spaces should be correct when the nav buttons are not inline
         if (!areNavButtonsInline) {
             return;
         }
 
-        // Get the maximum width that the hotseat can be
-        int columns = getPanelCount() * inv.numColumns;
-        int maxHotseatWidth = getIconToIconWidthForColumns(columns);
-        int sideSpace = (availableWidthPx - maxHotseatWidth) / 2;
-        int inlineButtonsOverlap = Math.max(0, hotseatBarEndOffset - sideSpace);
-        // decrease how much the nav buttons go "inside" the hotseat
-        maxHotseatWidth -= inlineButtonsOverlap;
+        // The side space with inline buttons should be what is defined in InvariantDeviceProfile
+        int sideSpace = inlineNavButtonsEndSpacing;
+        int maxHotseatWidth = availableWidthPx - sideSpace - hotseatBarEndOffset;
+        int maxHotseatIconsWidth = maxHotseatWidth - (isQsbInline ? hotseatQsbWidth : 0);
+        hotseatBorderSpace = calculateHotseatBorderSpace(maxHotseatIconsWidth,
+                (isQsbInline ? 1 : 0) + /* border between nav buttons and first icon */ 1);
 
-        // Get how much space is required to show the hotseat with QSB
-        int requiredWidth = getHotseatRequiredWidth();
-
-        // If spaces are fine, use them
-        if (requiredWidth <= maxHotseatWidth) {
-            return;
-        }
-
-        // Calculate the difference of widths and remove a little from each space between icons
-        // and QSB if it's inline
-        int spaceDiff = requiredWidth - maxHotseatWidth;
-        int numOfSpaces = numShownHotseatIcons - (isQsbInline ? 0 : 1);
-        hotseatBorderSpace -= (spaceDiff / numOfSpaces);
-
-        int minHotseatIconSpaceDp = res.getDimensionPixelSize(R.dimen.min_hotseat_icon_space);
-        int minHotseatQsbWidthDp = res.getDimensionPixelSize(R.dimen.min_hotseat_qsb_width);
-
-        if (hotseatBorderSpace >= minHotseatIconSpaceDp) {
+        if (hotseatBorderSpace >= minHotseatIconSpacePx) {
             return;
         }
 
         // Border space can't be less than the minimum
-        hotseatBorderSpace = minHotseatIconSpaceDp;
-        requiredWidth = getHotseatRequiredWidth();
+        hotseatBorderSpace = minHotseatIconSpacePx;
+        int requiredWidth = getHotseatRequiredWidth();
 
         // If there is an inline qsb, change its size
         if (isQsbInline) {
             hotseatQsbWidth -= requiredWidth - maxHotseatWidth;
-            if (hotseatQsbWidth >= minHotseatQsbWidthDp) {
+            if (hotseatQsbWidth >= minHotseatQsbWidthPx) {
                 return;
             }
 
             // QSB can't be less than the minimum
-            hotseatQsbWidth = minHotseatQsbWidthDp;
+            hotseatQsbWidth = minHotseatQsbWidthPx;
         }
 
+        maxHotseatIconsWidth = maxHotseatWidth - (isQsbInline ? hotseatQsbWidth : 0);
+
         // If it still doesn't fit, start removing icons
         do {
             numShownHotseatIcons--;
-            requiredWidth = getHotseatRequiredWidth();
-        } while (requiredWidth > maxHotseatWidth && numShownHotseatIcons > 1);
+            hotseatBorderSpace = calculateHotseatBorderSpace(maxHotseatIconsWidth,
+                    (isQsbInline ? 1 : 0) + /* border between nav buttons and first icon */ 1);
+        } while (hotseatBorderSpace < minHotseatIconSpacePx && numShownHotseatIcons > 1);
 
-        // Add back some space between the icons
-        spaceDiff = maxHotseatWidth - requiredWidth;
-        numOfSpaces = numShownHotseatIcons - (isQsbInline ? 0 : 1);
-        hotseatBorderSpace += (spaceDiff / numOfSpaces);
     }
 
     private Point getCellLayoutBorderSpace(InvariantDeviceProfile idp) {
@@ -954,15 +949,14 @@
     }
 
     /**
-     * Hotseat width spans a certain number of columns on scalable grids.
-     * This method calculates the space between the icons to achieve that width.
+     * This method calculates the space between the icons to achieve a certain width.
      */
-    private int calculateHotseatBorderSpace() {
-        if (!isScalableGrid) return 0;
-        int columns = inv.hotseatColumnSpan[mTypeIndex];
-        float hotseatWidthPx = getIconToIconWidthForColumns(columns);
+    private int calculateHotseatBorderSpace(float hotseatWidthPx, int numExtraBorder) {
         float hotseatIconsTotalPx = iconSizePx * numShownHotseatIcons;
-        return (int) (hotseatWidthPx - hotseatIconsTotalPx) / (numShownHotseatIcons - 1);
+        int hotseatBorderSpace =
+                (int) (hotseatWidthPx - hotseatIconsTotalPx)
+                        / (numShownHotseatIcons - 1 + numExtraBorder);
+        return Math.min(hotseatBorderSpace, maxHotseatIconSpacePx);
     }
 
 
@@ -1054,12 +1048,9 @@
     }
 
     private void updateFolderCellSize(float scale, Resources res) {
-        float invIconSizeDp = isVerticalBarLayout()
-                ? inv.iconSize[INDEX_LANDSCAPE]
-                : inv.iconSize[INDEX_DEFAULT];
+        float invIconSizeDp = inv.iconSize[mTypeIndex];
         folderChildIconSizePx = Math.max(1, pxFromDp(invIconSizeDp, mMetrics, scale));
-        folderChildTextSizePx =
-                pxFromSp(inv.iconTextSize[INDEX_DEFAULT], mMetrics, scale);
+        folderChildTextSizePx = pxFromSp(inv.iconTextSize[mTypeIndex], mMetrics, scale);
         folderLabelTextSizePx = Math.max(pxFromSp(MIN_FOLDER_TEXT_SIZE_SP, mMetrics),
                 (int) (folderChildTextSizePx * folderLabelTextScale));
 
@@ -1283,12 +1274,16 @@
             int hotseatBarTopPadding =
                     hotseatBarSizePx - hotseatBarBottomPadding - hotseatCellHeightPx;
 
-            // Push icons to the side
-            int requiredWidth = getHotseatRequiredWidth();
-            int hotseatWidth = Math.min(requiredWidth, availableWidthPx - hotseatBarEndOffset);
-            int sideSpacing = (availableWidthPx - hotseatWidth) / 2;
+            int hotseatWidth = getHotseatRequiredWidth();
+            int leftSpacing = (availableWidthPx - hotseatWidth) / 2;
+            int rightSpacing = leftSpacing;
+            // Hotseat aligns to the left with nav buttons
+            if (hotseatBarEndOffset > 0) {
+                leftSpacing = inlineNavButtonsEndSpacing;
+                rightSpacing = availableWidthPx - hotseatWidth - leftSpacing + hotseatBorderSpace;
+            }
 
-            hotseatBarPadding.set(sideSpacing, hotseatBarTopPadding, sideSpacing,
+            hotseatBarPadding.set(leftSpacing, hotseatBarTopPadding, rightSpacing,
                     hotseatBarBottomPadding);
 
             boolean isRtl = Utilities.isRtl(context.getResources());
@@ -1297,14 +1292,6 @@
             } else {
                 hotseatBarPadding.left += getAdditionalQsbSpace();
             }
-
-            if (hotseatBarEndOffset > sideSpacing) {
-                int diff = isRtl
-                        ? sideSpacing - hotseatBarEndOffset
-                        : hotseatBarEndOffset - sideSpacing;
-                hotseatBarPadding.left -= diff;
-                hotseatBarPadding.right += diff;
-            }
         } else if (isScalableGrid) {
             int sideSpacing = (availableWidthPx - hotseatQsbWidth) / 2;
             hotseatBarPadding.set(sideSpacing,
@@ -1340,7 +1327,7 @@
     private int getHotseatRequiredWidth() {
         int additionalQsbSpace = getAdditionalQsbSpace();
         return iconSizePx * numShownHotseatIcons
-                + hotseatBorderSpace * (numShownHotseatIcons - 1)
+                + hotseatBorderSpace * (numShownHotseatIcons - (areNavButtonsInline ? 0 : 1))
                 + additionalQsbSpace;
     }
 
@@ -1384,7 +1371,7 @@
     public int getOverviewActionsClaimedSpaceBelow() {
         if (isTaskbarPresent) {
             if (FeatureFlags.ENABLE_TASKBAR_IN_OVERVIEW.get()) {
-                return taskbarSize + transientTaskbarMargin;
+                return taskbarSize + transientTaskbarMargin * 2;
             }
 
             return isGestureMode
@@ -1655,6 +1642,8 @@
                 overviewActionsTopMarginPx));
         writer.println(prefix + pxToDpStr("overviewActionsHeight",
                 overviewActionsHeight));
+        writer.println(prefix + pxToDpStr("overviewActionsClaimedSpaceBelow",
+                getOverviewActionsClaimedSpaceBelow()));
         writer.println(prefix + pxToDpStr("overviewActionsButtonSpacing",
                 overviewActionsButtonSpacing));
         writer.println(prefix + pxToDpStr("overviewPageSpacing", overviewPageSpacing));
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 6f44375..a4020f9 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -206,6 +206,8 @@
         if (!newGridName.equals(gridName)) {
             LauncherPrefs.getPrefs(context).edit().putString(KEY_IDP_GRID_NAME, newGridName)
                     .apply();
+            Log.d("b/258560494", "InvariantDeviceProfile - setting newGridName: " + newGridName
+                    + ", gridName: " + gridName);
         }
         new DeviceGridState(this).writeToPrefs(context);
 
@@ -422,6 +424,21 @@
         }
         supportedProfiles = Collections.unmodifiableList(localSupportedProfiles);
 
+        int numMinShownHotseatIconsForTablet = supportedProfiles
+                .stream()
+                .filter(deviceProfile -> deviceProfile.isTablet)
+                .mapToInt(deviceProfile -> deviceProfile.numShownHotseatIcons)
+                .min()
+                .orElse(0);
+
+        supportedProfiles
+                .stream()
+                .filter(deviceProfile -> deviceProfile.isTablet)
+                .forEach(deviceProfile -> {
+                    deviceProfile.numShownHotseatIcons = numMinShownHotseatIconsForTablet;
+                    deviceProfile.recalculateHotseatWidthAndBorderSpace();
+                });
+
         ComponentName cn = new ComponentName(context.getPackageName(), getClass().getName());
         defaultWidgetPadding = AppWidgetHostView.getDefaultPaddingForWidget(context, cn, null);
     }
@@ -438,6 +455,7 @@
     public void setCurrentGrid(Context context, String gridName) {
         Context appContext = context.getApplicationContext();
         LauncherPrefs.getPrefs(appContext).edit().putString(KEY_IDP_GRID_NAME, gridName).apply();
+        Log.d("b/258560494", "setCurrentGrid: " + gridName);
         MAIN_EXECUTOR.execute(() -> onConfigChanged(appContext));
     }
 
@@ -502,6 +520,10 @@
             }
         }
         if (filteredProfiles.isEmpty()) {
+            if (gridName != null) {
+                Log.d("b/258560494", "No matching grid from for gridName: " + gridName
+                        + ", deviceType: " + deviceType);
+            }
             // No grid found, use the default options
             for (DisplayOption option : profiles) {
                 if (option.canBeDefault) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 18ed0fc..43772e4 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1548,8 +1548,8 @@
     }
 
     protected LauncherWidgetHolder createAppWidgetHolder() {
-        return new LauncherWidgetHolder(this,
-                appWidgetId -> getWorkspace().removeWidget(appWidgetId));
+        return LauncherWidgetHolder.HolderFactory.newFactory(this).newInstance(
+                this, appWidgetId -> getWorkspace().removeWidget(appWidgetId));
     }
 
     public LauncherModel getModel() {
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 23ff10a..0d6ed04 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -9,12 +9,17 @@
     fun getPrefs(context: Context): SharedPreferences {
         // Use application context for shared preferences, so that we use a single cached instance
         return context.applicationContext.getSharedPreferences(
-                LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
+            LauncherFiles.SHARED_PREFERENCES_KEY,
+            Context.MODE_PRIVATE
+        )
     }
 
     @JvmStatic
     fun getDevicePrefs(context: Context): SharedPreferences {
         // Use application context for shared preferences, so that we use a single cached instance
         return context.applicationContext.getSharedPreferences(
-                LauncherFiles.DEVICE_PREFERENCES_KEY, Context.MODE_PRIVATE)
-    }}
\ No newline at end of file
+            LauncherFiles.DEVICE_PREFERENCES_KEY,
+            Context.MODE_PRIVATE
+        )
+    }
+}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index f4c0501..767c3d9 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -1093,7 +1093,7 @@
          */
         @NonNull
         public LauncherWidgetHolder newLauncherWidgetHolder() {
-            return new LauncherWidgetHolder(mContext);
+            return LauncherWidgetHolder.newInstance(mContext);
         }
 
         @Override
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 932f98a..6ea331d 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -207,12 +207,9 @@
         public static final int CONTAINER_BOTTOM_WIDGETS_TRAY = -112;
         public static final int CONTAINER_PIN_WIDGETS = -113;
         public static final int CONTAINER_WALLPAPERS = -114;
-        // Represents search results view.
-        public static final int CONTAINER_SEARCH_RESULTS = -106;
         public static final int CONTAINER_SHORTCUTS = -107;
         public static final int CONTAINER_SETTINGS = -108;
         public static final int CONTAINER_TASKSWITCHER = -109;
-        public static final int CONTAINER_QSB = -110;
 
         // Represents any of the extended containers implemented in non-AOSP variants.
         public static final int EXTENDED_CONTAINERS = -200;
@@ -226,7 +223,6 @@
                 case CONTAINER_PREDICTION: return "prediction";
                 case CONTAINER_ALL_APPS: return "all_apps";
                 case CONTAINER_WIDGETS_TRAY: return "widgets_tray";
-                case CONTAINER_SEARCH_RESULTS: return "search_result";
                 case CONTAINER_SHORTCUTS: return "shortcuts";
                 default: return String.valueOf(container);
             }
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index eb68adb..4f5cc4a 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -699,7 +699,7 @@
     }
 
     /** Returns true iff this PagedView's scroll amounts are initialized to each page index. */
-    protected boolean pageScrollsInitialized() {
+    protected boolean isPageScrollsInitialized() {
         return mPageScrolls != null && mPageScrolls.length == getChildCount();
     }
 
@@ -708,12 +708,12 @@
      */
     public void runOnPageScrollsInitialized(Runnable callback) {
         mOnPageScrollsInitializedCallbacks.add(callback);
-        if (pageScrollsInitialized()) {
+        if (isPageScrollsInitialized()) {
             onPageScrollsInitialized();
         }
     }
 
-    private void onPageScrollsInitialized() {
+    protected void onPageScrollsInitialized() {
         for (Runnable callback : mOnPageScrollsInitializedCallbacks) {
             callback.run();
         }
@@ -727,7 +727,7 @@
         final int childCount = getChildCount();
         int[] pageScrolls = mPageScrolls;
         boolean pageScrollChanged = false;
-        if (!pageScrollsInitialized()) {
+        if (!isPageScrollsInitialized()) {
             pageScrolls = new int[childCount];
             pageScrollChanged = true;
         }
@@ -1199,7 +1199,7 @@
     }
 
     public int getScrollForPage(int index) {
-        if (!pageScrollsInitialized() || index >= mPageScrolls.length || index < 0) {
+        if (!isPageScrollsInitialized() || index >= mPageScrolls.length || index < 0) {
             return 0;
         } else {
             return mPageScrolls[index];
@@ -1209,7 +1209,7 @@
     // While layout transitions are occurring, a child's position may stray from its baseline
     // position. This method returns the magnitude of this stray at any given time.
     public int getLayoutTransitionOffsetForPage(int index) {
-        if (!pageScrollsInitialized() || index >= mPageScrolls.length || index < 0) {
+        if (!isPageScrollsInitialized() || index >= mPageScrolls.length || index < 0) {
             return 0;
         } else {
             View child = getChildAt(index);
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index b10256e..d7e84f0 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -723,4 +723,14 @@
         }
         return options;
     }
+
+    /** Logs the Scale and Translate properties of a matrix. Ignores skew and perspective. */
+    public static void logMatrix(String label, Matrix matrix) {
+        float[] matrixValues = new float[9];
+        matrix.getValues(matrixValues);
+        Log.d(label, String.format("%s: %s\nscale (x,y) = (%f, %f)\ntranslate (x,y) = (%f, %f)",
+                label, matrix, matrixValues[Matrix.MSCALE_X], matrixValues[Matrix.MSCALE_Y],
+                matrixValues[Matrix.MTRANS_X], matrixValues[Matrix.MTRANS_Y]
+        ));
+    }
 }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 483309d..2b9c135 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -62,6 +62,7 @@
 import android.widget.Toast;
 
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
 import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper;
@@ -161,7 +162,9 @@
 
     protected ShortcutAndWidgetContainer mDragSourceInternal;
 
-    @Thunk final IntSparseArrayMap<CellLayout> mWorkspaceScreens = new IntSparseArrayMap<>();
+    @VisibleForTesting(otherwise = VisibleForTesting.PRIVATE)
+    @Thunk public final IntSparseArrayMap<CellLayout> mWorkspaceScreens = new IntSparseArrayMap<>();
+
     @Thunk final IntArray mScreenOrder = new IntArray();
 
     @Thunk boolean mDeferRemoveExtraEmptyScreen = false;
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 9933ffb..63e6d13 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -203,8 +203,12 @@
 
         @Override
         public int getSpanSize(int position) {
-            int viewType = mApps.getAdapterItems().get(position).viewType;
             int totalSpans = mGridLayoutMgr.getSpanCount();
+            List<AdapterItem> items = mApps.getAdapterItems();
+            if (position >= items.size()) {
+                return totalSpans;
+            }
+            int viewType = items.get(position).viewType;
             if (isIconViewType(viewType)) {
                 return totalSpans / mAppsPerRow;
             } else {
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index fc1b830..29767bf 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -239,23 +239,24 @@
             mAdapterItems.addAll(mSearchResults);
         } else {
             int position = 0;
+            boolean addApps = true;
             if (mWorkProviderManager != null) {
                 position += mWorkProviderManager.addWorkItems(mAdapterItems);
-                if (!mWorkProviderManager.shouldShowWorkApps()) {
-                    return;
-                }
+                addApps = mWorkProviderManager.shouldShowWorkApps();
             }
-            String lastSectionName = null;
-            for (AppInfo info : mApps) {
-                mAdapterItems.add(AdapterItem.asApp(info));
+            if (addApps) {
+                String lastSectionName = null;
+                for (AppInfo info : mApps) {
+                    mAdapterItems.add(AdapterItem.asApp(info));
 
-                String sectionName = info.sectionName;
-                // Create a new section if the section names do not match
-                if (!sectionName.equals(lastSectionName)) {
-                    lastSectionName = sectionName;
-                    mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, position));
+                    String sectionName = info.sectionName;
+                    // Create a new section if the section names do not match
+                    if (!sectionName.equals(lastSectionName)) {
+                        lastSectionName = sectionName;
+                        mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, position));
+                    }
+                    position++;
                 }
-                position++;
             }
         }
         mAccessibilityResultsCount = (int) mAdapterItems.stream()
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
index d1ada7a..00e89ba 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsContainerView.java
@@ -163,7 +163,8 @@
 
         mWorkManager = new WorkProfileManager(
                 mActivityContext.getSystemService(UserManager.class),
-                this, LauncherPrefs.getPrefs(mActivityContext));
+                this, LauncherPrefs.getPrefs(mActivityContext),
+                mActivityContext.getStatsLogManager());
         mAH = Arrays.asList(null, null, null);
         mNavBarScrimPaint = new Paint();
         mNavBarScrimPaint.setColor(Themes.getAttrColor(context, R.attr.allAppsNavBarScrimColor));
@@ -508,8 +509,12 @@
         if (grid.isVerticalBarLayout()) {
             setPadding(grid.workspacePadding.left, 0, grid.workspacePadding.right, 0);
         } else {
-            setPadding(grid.allAppsLeftRightMargin, grid.allAppsTopPadding,
-                    grid.allAppsLeftRightMargin, 0);
+            int topPadding = grid.allAppsTopPadding;
+            if (FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() && !grid.isTablet) {
+                topPadding += getResources().getDimensionPixelSize(
+                        R.dimen.all_apps_additional_top_padding_floating_search);
+            }
+            setPadding(grid.allAppsLeftRightMargin, topPadding, grid.allAppsLeftRightMargin, 0);
         }
 
         InsettableFrameLayout.dispatchInsets(this, insets);
@@ -571,6 +576,10 @@
             mAH.get(AdapterHolder.MAIN).setup(mViewPager.getChildAt(0), mPersonalMatcher);
             mAH.get(AdapterHolder.WORK).setup(mViewPager.getChildAt(1), mWorkManager.getMatcher());
             mAH.get(AdapterHolder.WORK).mRecyclerView.setId(R.id.apps_list_view_work);
+            if (FeatureFlags.ENABLE_EXPANDING_PAUSE_WORK_BUTTON.get()) {
+                mAH.get(AdapterHolder.WORK).mRecyclerView.addOnScrollListener(
+                        mWorkManager.newScrollListener());
+            }
             mViewPager.getPageIndicator().setActiveMarker(AdapterHolder.MAIN);
             findViewById(R.id.tab_personal)
                     .setOnClickListener((View view) -> {
@@ -662,10 +671,10 @@
             mViewPager = (AllAppsPagedView) newView;
             mViewPager.initParentViews(this);
             mViewPager.getPageIndicator().setOnActivePageChangedListener(this);
-            if (mWorkManager.attachWorkModeSwitch()) {
-                mWorkManager.getWorkModeSwitch().post(
-                        () -> mAH.get(AdapterHolder.WORK).applyPadding());
-            }
+
+            mWorkManager.reset();
+            post(() -> mAH.get(AdapterHolder.WORK).applyPadding());
+
         } else {
             mWorkManager.detachWorkModeSwitch();
             mViewPager = null;
@@ -824,7 +833,7 @@
         if (mHeaderPaint.getColor() == mScrimColor || mHeaderPaint.getColor() == 0) {
             return;
         }
-        int bottom = getHeaderBottom();
+        int bottom = getHeaderBottom() + getVisibleContainerView().getPaddingTop();
         FloatingHeaderView headerView = getFloatingHeaderView();
         if (isTablet) {
             // Start adding header protection if search bar or tabs will attach to the top.
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index aadd0b5..11ce738 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -15,17 +15,21 @@
  */
 package com.android.launcher3.allapps;
 
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TURN_OFF_WORK_APPS_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORK_FAB_BUTTON_COLLAPSE;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WORK_FAB_BUTTON_EXTEND;
 import static com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.getTabWidth;
 
+import android.animation.LayoutTransition;
 import android.content.Context;
 import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.view.View;
-import android.view.ViewGroup.MarginLayoutParams;
 import android.view.WindowInsets;
-import android.widget.Button;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
 
+import androidx.annotation.NonNull;
 import androidx.core.graphics.Insets;
 import androidx.core.view.WindowInsetsCompat;
 
@@ -35,57 +39,68 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
 import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.StringCache;
 import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
-
 /**
  * Work profile toggle switch shown at the bottom of AllApps work tab
  */
-public class WorkModeSwitch extends Button implements Insettable, View.OnClickListener,
-        KeyboardInsetAnimationCallback.KeyboardInsetListener,
-        PersonalWorkSlidingTabStrip.OnActivePageChangedListener {
+public class WorkModeSwitch extends LinearLayout implements Insettable,
+        KeyboardInsetAnimationCallback.KeyboardInsetListener {
 
     private static final int FLAG_FADE_ONGOING = 1 << 1;
     private static final int FLAG_TRANSLATION_ONGOING = 1 << 2;
     private static final int FLAG_PROFILE_TOGGLE_ONGOING = 1 << 3;
+    private static final int SCROLL_THRESHOLD_DP = 10;
 
     private final Rect mInsets = new Rect();
     private final Rect mImeInsets = new Rect();
     private int mFlags;
-    private boolean mWorkEnabled;
-    private boolean mOnWorkTab;
+    private final ActivityContext mActivityContext;
 
-    public WorkModeSwitch(Context context) {
+    // Threshold when user scrolls up/down to determine when should button extend/collapse
+    private final int mScrollThreshold;
+    private ImageView mIcon;
+    private TextView mTextView;
+    private final StatsLogManager mStatsLogManager;
+
+
+    public WorkModeSwitch(@NonNull Context context) {
         this(context, null, 0);
     }
 
-    public WorkModeSwitch(Context context, AttributeSet attrs) {
+    public WorkModeSwitch(@NonNull Context context, @NonNull AttributeSet attrs) {
         this(context, attrs, 0);
     }
 
-    public WorkModeSwitch(Context context, AttributeSet attrs, int defStyleAttr) {
+    public WorkModeSwitch(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
+        mScrollThreshold = Utilities.dpToPx(SCROLL_THRESHOLD_DP);
+        mActivityContext = ActivityContext.lookupContext(getContext());
+        mStatsLogManager = mActivityContext.getStatsLogManager();
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
+
+        mIcon = findViewById(R.id.work_icon);
+        mTextView = findViewById(R.id.pause_text);
         setSelected(true);
-        setOnClickListener(this);
         if (Utilities.ATLEAST_R) {
             KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
                     new KeyboardInsetAnimationCallback(this);
             setWindowInsetsAnimationCallback(keyboardInsetAnimationCallback);
         }
-        ActivityContext activityContext = ActivityContext.lookupContext(getContext());
-        DeviceProfile grid = activityContext.getDeviceProfile();
-        setInsets(grid.getInsets());
 
-        StringCache cache = activityContext.getStringCache();
+        setInsets(mActivityContext.getDeviceProfile().getInsets());
+        StringCache cache = mActivityContext.getStringCache();
         if (cache != null) {
-            setText(cache.workProfilePauseButton);
+            mTextView.setText(cache.workProfilePauseButton);
         }
+
+        mIcon.setColorFilter(mTextView.getCurrentTextColor());
+        getLayoutTransition().enableTransitionType(LayoutTransition.CHANGING);
     }
 
     @Override
@@ -102,8 +117,6 @@
 
             if (!dp.isGestureMode && dp.isTaskbarPresent) {
                 bottomMargin += dp.taskbarSize;
-            } else {
-                bottomMargin += insets.bottom;
             }
 
             lp.bottomMargin = bottomMargin;
@@ -113,58 +126,32 @@
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        DeviceProfile dp = ActivityContext.lookupContext(getContext()).getDeviceProfile();
         View parent = (View) getParent();
+        int allAppsLeftRightPadding = mActivityContext.getDeviceProfile().allAppsLeftRightPadding;
         int size = parent.getWidth() - parent.getPaddingLeft() - parent.getPaddingRight()
-                - 2 * dp.allAppsLeftRightPadding;
+                - 2 * allAppsLeftRightPadding;
         int tabWidth = getTabWidth(getContext(), size);
-        int shift = (size - tabWidth) / 2 + dp.allAppsLeftRightPadding;
+        int shift = (size - tabWidth) / 2 + allAppsLeftRightPadding;
         setTranslationX(Utilities.isRtl(getResources()) ? shift : -shift);
     }
 
     @Override
-    public void onActivePageChanged(int page) {
-        mOnWorkTab = page == ActivityAllAppsContainerView.AdapterHolder.WORK;
-        updateVisibility();
-    }
-
-    @Override
-    public void onClick(View view) {
-        if (Utilities.ATLEAST_P && isEnabled()) {
-            setFlag(FLAG_PROFILE_TOGGLE_ONGOING);
-            ActivityContext activityContext = ActivityContext.lookupContext(getContext());
-            activityContext.getStatsLogManager().logger().log(LAUNCHER_TURN_OFF_WORK_APPS_TAP);
-            activityContext.getAppsView().getWorkManager().setWorkProfileEnabled(false);
-        }
-    }
-
-    @Override
     public boolean isEnabled() {
         return super.isEnabled() && getVisibility() == VISIBLE && mFlags == 0;
     }
 
-    /**
-     * Sets the enabled or disabled state of the button
-     */
-    public void updateCurrentState(boolean isEnabled) {
-        removeFlag(FLAG_PROFILE_TOGGLE_ONGOING);
-        if (mWorkEnabled != isEnabled) {
-            mWorkEnabled = isEnabled;
-            updateVisibility();
-        }
-    }
-
-    private void updateVisibility() {
+    public void animateVisibility(boolean visible) {
         clearAnimation();
-        if (mWorkEnabled && mOnWorkTab) {
+        if (visible) {
             setFlag(FLAG_FADE_ONGOING);
             setVisibility(VISIBLE);
+            extend();
             animate().alpha(1).withEndAction(() -> removeFlag(FLAG_FADE_ONGOING)).start();
         } else if (getVisibility() != GONE) {
             setFlag(FLAG_FADE_ONGOING);
             animate().alpha(0).withEndAction(() -> {
                 removeFlag(FLAG_FADE_ONGOING);
-                this.setVisibility(GONE);
+                setVisibility(GONE);
             }).start();
         }
     }
@@ -213,4 +200,18 @@
     private void removeFlag(int flag) {
         mFlags &= ~flag;
     }
+
+    public void extend() {
+        mTextView.setVisibility(VISIBLE);
+        mStatsLogManager.logger().log(LAUNCHER_WORK_FAB_BUTTON_EXTEND);
+    }
+
+    public void shrink(){
+        mTextView.setVisibility(GONE);
+        mStatsLogManager.logger().log(LAUNCHER_WORK_FAB_BUTTON_COLLAPSE);
+    }
+
+    public int getScrollThreshold() {
+        return mScrollThreshold;
+    }
 }
diff --git a/src/com/android/launcher3/allapps/WorkProfileManager.java b/src/com/android/launcher3/allapps/WorkProfileManager.java
index cfac985..279f0d3 100644
--- a/src/com/android/launcher3/allapps/WorkProfileManager.java
+++ b/src/com/android/launcher3/allapps/WorkProfileManager.java
@@ -17,6 +17,10 @@
 
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD;
 import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD;
+import static com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder.MAIN;
+import static com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder.SEARCH;
+import static com.android.launcher3.allapps.BaseAllAppsContainerView.AdapterHolder.WORK;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TURN_OFF_WORK_APPS_TAP;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_HAS_SHORTCUT_PERMISSION;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_CHANGE_PERMISSION;
 import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_QUIET_MODE_ENABLED;
@@ -28,13 +32,18 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
+import android.view.View;
 
 import androidx.annotation.IntDef;
+import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.RequiresApi;
+import androidx.recyclerview.widget.RecyclerView;
 
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
+import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip;
 
@@ -71,6 +80,7 @@
     private final UserManager mUserManager;
     private final BaseAllAppsContainerView<?> mAllApps;
     private final Predicate<ItemInfo> mMatcher;
+    private final StatsLogManager mStatsLogManager;
 
     private WorkModeSwitch mWorkModeSwitch;
 
@@ -79,11 +89,13 @@
     private SharedPreferences mPreferences;
 
     public WorkProfileManager(
-            UserManager userManager, BaseAllAppsContainerView<?> allApps, SharedPreferences prefs) {
+            UserManager userManager, BaseAllAppsContainerView<?> allApps, SharedPreferences prefs,
+            StatsLogManager statsLogManager) {
         mUserManager = userManager;
         mAllApps = allApps;
         mPreferences = prefs;
         mMatcher = mAllApps.mPersonalMatcher.negate();
+        mStatsLogManager = statsLogManager;
     }
 
     /**
@@ -104,8 +116,16 @@
 
     @Override
     public void onActivePageChanged(int page) {
+        updateWorkFAB(page);
+    }
+
+    private void updateWorkFAB(int page) {
         if (mWorkModeSwitch != null) {
-            mWorkModeSwitch.onActivePageChanged(page);
+            if (page == MAIN || page == SEARCH) {
+                mWorkModeSwitch.animateVisibility(false);
+            } else if (page == WORK && mCurrentState == STATE_ENABLED) {
+                mWorkModeSwitch.animateVisibility(true);
+            }
         }
     }
 
@@ -123,7 +143,12 @@
             getAH().mAppsList.updateAdapterItems();
         }
         if (mWorkModeSwitch != null) {
-            mWorkModeSwitch.updateCurrentState(currentState == STATE_ENABLED);
+            updateWorkFAB(mAllApps.getCurrentPage());
+        }
+        if (mCurrentState == STATE_ENABLED) {
+            attachWorkModeSwitch();
+        } else if (mCurrentState == STATE_DISABLED) {
+            detachWorkModeSwitch();
         }
     }
 
@@ -140,13 +165,16 @@
             mWorkModeSwitch = (WorkModeSwitch) mAllApps.getLayoutInflater().inflate(
                     R.layout.work_mode_fab, mAllApps, false);
         }
-        if (mWorkModeSwitch.getParent() != mAllApps) {
+        if (mWorkModeSwitch.getParent() == null) {
             mAllApps.addView(mWorkModeSwitch);
         }
+        if (mAllApps.getCurrentPage() != WORK) {
+            mWorkModeSwitch.animateVisibility(false);
+        }
         if (getAH() != null) {
             getAH().applyPadding();
         }
-        mWorkModeSwitch.updateCurrentState(mCurrentState == STATE_ENABLED);
+        mWorkModeSwitch.setOnClickListener(this::onWorkFabClicked);
         return true;
     }
     /**
@@ -169,7 +197,7 @@
     }
 
     private BaseAllAppsContainerView<?>.AdapterHolder getAH() {
-        return mAllApps.mAH.get(BaseAllAppsContainerView.AdapterHolder.WORK);
+        return mAllApps.mAH.get(WORK);
     }
 
     public int getCurrentState() {
@@ -199,4 +227,38 @@
     private boolean isEduSeen() {
         return mPreferences.getInt(KEY_WORK_EDU_STEP, 0) != 0;
     }
+
+    private void onWorkFabClicked(View view) {
+        if (Utilities.ATLEAST_P && mCurrentState == STATE_ENABLED && mWorkModeSwitch.isEnabled()) {
+            mStatsLogManager.logger().log(LAUNCHER_TURN_OFF_WORK_APPS_TAP);
+            setWorkProfileEnabled(false);
+        }
+    }
+
+    public RecyclerView.OnScrollListener newScrollListener() {
+        return new RecyclerView.OnScrollListener() {
+            int totalDelta = 0;
+            @Override
+            public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState){
+                if (newState == RecyclerView.SCROLL_STATE_IDLE) {
+                    totalDelta = 0;
+                }
+            }
+            @Override
+            public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {
+                WorkModeSwitch fab = getWorkModeSwitch();
+                if (fab == null){
+                    return;
+                }
+                totalDelta = Utilities.boundToRange(totalDelta,
+                        -fab.getScrollThreshold(), fab.getScrollThreshold()) + dy;
+                boolean isScrollAtTop = recyclerView.computeVerticalScrollOffset() == 0;
+                if ((isScrollAtTop || totalDelta < -fab.getScrollThreshold())) {
+                    fab.extend();
+                } else if (totalDelta > fab.getScrollThreshold()) {
+                    fab.shrink();
+                }
+            }
+        };
+    }
 }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 0e546ed..082f6a1 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -92,6 +92,10 @@
     public static final BooleanFlag ENABLE_HIDE_HEADER = new DeviceFlag("ENABLE_HIDE_HEADER",
             true, "Hide header on keyboard before typing in all apps");
 
+    public static final BooleanFlag ENABLE_EXPANDING_PAUSE_WORK_BUTTON = new DeviceFlag(
+            "ENABLE_EXPANDING_PAUSE_WORK_BUTTON", false,
+            "Expand and collapse pause work button while scrolling");
+
     public static final BooleanFlag ENABLE_HIDE_HEADER_STATIC = new DeviceFlag(
             "ENABLE_HIDE_HEADER_STATIC", false, "Hide keyboard suggestion strip");
 
@@ -356,9 +360,6 @@
             "ENABLE_NEW_GESTURE_NAV_TUTORIAL", false,
             "Enable the redesigned gesture navigation tutorial");
 
-    public static final BooleanFlag ENABLE_TOAST_IMPRESSION_LOGGING = getDebugFlag(
-            "ENABLE_TOAST_IMPRESSION_LOGGING", false, "Enable toast impression logging");
-
     public static final BooleanFlag ENABLE_DEVICE_PROFILE_LOGGING = new DeviceFlag(
             "ENABLE_DEVICE_PROFILE_LOGGING", false, "Allows DeviceProfile logging");
 
@@ -372,6 +373,14 @@
             "Enable the ability to generate monochromatic icons, if it is not provided by the app"
     );
 
+    public static final BooleanFlag ENABLE_TASKBAR_EDU_TOOLTIP = getDebugFlag(
+            "ENABLE_TASKBAR_EDU_TOOLTIP", false,
+            "Enable the tooltip version of the Taskbar education flow.");
+
+    public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(
+            "ENABLE_MULTI_INSTANCE", false,
+            "Enables creation and filtering of multiple task instances in overview");
+
     public static void initialize(Context context) {
         synchronized (sDebugFlags) {
             for (DebugFlag flag : sDebugFlags) {
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index a610548..4906c1d 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -295,7 +295,7 @@
         mWidgetCell.setRemoteViewsPreview(PinItemDragListener.getPreview(mRequest));
 
         mAppWidgetManager = new WidgetManagerHelper(this);
-        mAppWidgetHolder = new LauncherWidgetHolder(this);
+        mAppWidgetHolder = LauncherWidgetHolder.newInstance(this);
 
         PendingAddWidgetInfo pendingInfo =
                 new PendingAddWidgetInfo(widgetInfo, CONTAINER_PIN_WIDGETS);
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 09fe740..f54d05d 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -568,7 +568,8 @@
                     .setSpring(new SpringForce(0)
                             .setDampingRatio(DAMPENING_RATIO)
                             .setStiffness(STIFFNESS));
-            mDelta = view.getResources().getDisplayMetrics().density * PARALLAX_MAX_IN_DP;
+            mDelta = Math.min(
+                    range, view.getResources().getDisplayMetrics().density * PARALLAX_MAX_IN_DP);
         }
 
         public void animateToPos(float value) {
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index 0eb86b1..de47cb5 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -17,31 +17,43 @@
 
 package com.android.launcher3.graphics;
 
+import static com.android.launcher3.anim.Interpolators.EMPHASIZED;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_DOWNLOAD_APP_UX_V2;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ObjectAnimator;
 import android.content.Context;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Path;
 import android.graphics.PathMeasure;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
+import android.os.SystemClock;
 import android.util.Property;
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.anim.AnimatedFloat;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.launcher3.icons.GraphicsUtils;
 import com.android.launcher3.model.data.ItemInfoWithIcon;
 import com.android.launcher3.util.Themes;
+import com.android.launcher3.util.window.RefreshRateTracker;
+
+import java.util.WeakHashMap;
+import java.util.function.Function;
 
 /**
  * Extension of {@link FastBitmapDrawable} which shows a progress bar around the icon.
  */
-public class PreloadIconDrawable extends FastBitmapDrawable {
+public class PreloadIconDrawable extends FastBitmapDrawable implements Runnable {
 
     private static final Property<PreloadIconDrawable, Float> INTERNAL_STATE =
             new Property<PreloadIconDrawable, Float>(Float.TYPE, "internalStateProgress") {
@@ -62,17 +74,26 @@
     private static final int DISABLED_ICON_ALPHA = (int) (0.6f * MAX_PAINT_ALPHA);
 
     private static final long DURATION_SCALE = 500;
+    private static final long SCALE_AND_ALPHA_ANIM_DURATION = 500;
 
     // The smaller the number, the faster the animation would be.
     // Duration = COMPLETE_ANIM_FRACTION * DURATION_SCALE
     private static final float COMPLETE_ANIM_FRACTION = 0.3f;
 
-    private static final float SMALL_SCALE = 0.7f;
+    private static final float SMALL_SCALE = ENABLE_DOWNLOAD_APP_UX_V2.get() ? 0.867f : 0.7f;
     private static final float PROGRESS_STROKE_SCALE = 0.075f;
 
     private static final int PRELOAD_ACCENT_COLOR_INDEX = 0;
     private static final int PRELOAD_BACKGROUND_COLOR_INDEX = 1;
 
+    private static final int ALPHA_DURATION_MILLIS = 3000;
+    private static final float OVERLAY_ALPHA_RANGE = 127.5f;
+    private static final long WAVE_MOTION_DELAY_FACTOR_MILLIS = 100;
+    private static final WeakHashMap<Integer, PorterDuffColorFilter> COLOR_FILTER_MAP =
+            new WeakHashMap<>();
+    public static final Function<Integer, PorterDuffColorFilter> FILTER_FACTORY =
+            currArgb -> new PorterDuffColorFilter(currArgb, PorterDuff.Mode.SRC_ATOP);
+
     private final Matrix mTmpMatrix = new Matrix();
     private final PathMeasure mPathMeasure = new PathMeasure();
 
@@ -92,10 +113,14 @@
 
     private int mTrackAlpha;
     private float mTrackLength;
-    private float mIconScale;
 
     private boolean mRanFinishAnimation;
 
+    private final int mRefreshRateMillis;
+    private final AnimatedFloat mIconScale = new AnimatedFloat(this::invalidateSelf);
+    private final AnimatedFloat mOverlayAlpha = new AnimatedFloat(this::updateOverlayAlpha);
+    private boolean mShouldAnimateScaleAndAlpha;
+
     // Progress of the internal state. [0, 1] indicates the fraction of completed progress,
     // [1, (1 + COMPLETE_ANIM_FRACTION)] indicates the progress of zoom animation.
     private float mInternalStateProgress;
@@ -109,14 +134,16 @@
                 info,
                 IconPalette.getPreloadProgressColor(context, info.bitmap.color),
                 getPreloadColors(context),
-                Utilities.isDarkTheme(context));
+                Utilities.isDarkTheme(context),
+                getRefreshRateMillis(context));
     }
 
     public PreloadIconDrawable(
             ItemInfoWithIcon info,
             int indicatorColor,
             int[] preloadColors,
-            boolean isDarkMode) {
+            boolean isDarkMode,
+            int refreshRateMillis) {
         super(info.bitmap);
         mItem = info;
         mShapePath = GraphicsUtils.getShapePath(DEFAULT_PATH_SIZE);
@@ -130,6 +157,13 @@
         mSystemAccentColor = preloadColors[PRELOAD_ACCENT_COLOR_INDEX];
         mSystemBackgroundColor = preloadColors[PRELOAD_BACKGROUND_COLOR_INDEX];
         mIsDarkMode = isDarkMode;
+        mRefreshRateMillis = refreshRateMillis;
+
+        // If it's a pending app we will animate scale and alpha when it's no longer pending.
+        if (ENABLE_DOWNLOAD_APP_UX_V2.get() && info.getProgressLevel() == 0) {
+            mShouldAnimateScaleAndAlpha = true;
+            mOverlayAlpha.updateValue(127);
+        }
 
         setLevel(info.getProgressLevel());
         setIsStartable(info.isAppStartable());
@@ -175,14 +209,21 @@
         canvas.drawPath(mScaledProgressPath, mProgressPaint);
 
         int saveCount = canvas.save();
-        canvas.scale(mIconScale, mIconScale, bounds.exactCenterX(), bounds.exactCenterY());
+        canvas.scale(
+                mIconScale.value, mIconScale.value, bounds.exactCenterX(), bounds.exactCenterY());
         super.drawInternal(canvas, bounds);
         canvas.restoreToCount(saveCount);
+
+        if (ENABLE_DOWNLOAD_APP_UX_V2.get() && mInternalStateProgress == 0) {
+            reschedule();
+        }
     }
 
     @Override
     protected void updateFilter() {
-        setAlpha(mIsDisabled ? DISABLED_ICON_ALPHA : MAX_PAINT_ALPHA);
+        if (!ENABLE_DOWNLOAD_APP_UX_V2.get()) {
+            setAlpha(mIsDisabled ? DISABLED_ICON_ALPHA : MAX_PAINT_ALPHA);
+        }
     }
 
     /**
@@ -237,7 +278,7 @@
             mCurrentAnim = ObjectAnimator.ofFloat(this, INTERNAL_STATE, finalProgress);
             mCurrentAnim.setDuration(
                     (long) ((finalProgress - mInternalStateProgress) * DURATION_SCALE));
-            mCurrentAnim.setInterpolator(Interpolators.LINEAR);
+            mCurrentAnim.setInterpolator(LINEAR);
             if (isFinish) {
                 mCurrentAnim.addListener(new AnimatorListenerAdapter() {
                     @Override
@@ -253,13 +294,13 @@
     /**
      * Sets the internal progress and updates the UI accordingly
      *   for progress <= 0:
-     *     - icon in the small scale and disabled state
-     *     - progress track is visible
+     *     - icon with pending motion
+     *     - progress track is not visible
      *     - progress bar is not visible
-     *   for 0 < progress < 1
-     *     - icon in the small scale and disabled state
+     *   for progress < 1
+     *     - icon without pending motion
      *     - progress track is visible
-     *     - progress bar is visible with dominant color. Progress bar is drawn as a fraction of
+     *     - progress bar is visible. Progress bar is drawn as a fraction of
      *       {@link #mScaledTrackPath}.
      *       @see PathMeasure#getSegment(float, float, Path, boolean)
      *   for 1 <= progress < (1 + COMPLETE_ANIM_FRACTION)
@@ -271,29 +312,47 @@
      *     - only icon is drawn in normal state
      */
     private void setInternalProgress(float progress) {
-        mInternalStateProgress = progress;
-        if (progress <= 0) {
-            mIconScale = SMALL_SCALE;
-            mScaledTrackPath.reset();
-            mTrackAlpha = MAX_PAINT_ALPHA;
+        // Animate scale and alpha from pending to downloading state.
+        if (ENABLE_DOWNLOAD_APP_UX_V2.get()
+                && mShouldAnimateScaleAndAlpha && mInternalStateProgress == 0 && progress > 0) {
+            Animator iconScaleAnimator = mIconScale.animateToValue(SMALL_SCALE);
+            iconScaleAnimator.setDuration(SCALE_AND_ALPHA_ANIM_DURATION);
+            iconScaleAnimator.setInterpolator(EMPHASIZED);
+            iconScaleAnimator.start();
+
+            Animator overlayAlphaAnimator = mOverlayAlpha.animateToValue(0);
+            overlayAlphaAnimator.setDuration(SCALE_AND_ALPHA_ANIM_DURATION);
+            overlayAlphaAnimator.setInterpolator(EMPHASIZED);
+            overlayAlphaAnimator.start();
         }
 
-        if (progress < 1 && progress > 0) {
-            mPathMeasure.getSegment(0, progress * mTrackLength, mScaledProgressPath, true);
-            mIconScale = SMALL_SCALE;
+        mInternalStateProgress = progress;
+        if (progress <= 0) {
+            mIconScale.updateValue(ENABLE_DOWNLOAD_APP_UX_V2.get() ? 1 : SMALL_SCALE);
+            mScaledTrackPath.reset();
             mTrackAlpha = MAX_PAINT_ALPHA;
-        } else if (progress >= 1) {
+        } else if (progress < 1) {
+            mPathMeasure.getSegment(0, progress * mTrackLength, mScaledProgressPath, true);
+            if (ENABLE_DOWNLOAD_APP_UX_V2.get()) {
+                mPathMeasure.getSegment(0, mTrackLength, mScaledTrackPath, true);
+            }
+
+            if (!ENABLE_DOWNLOAD_APP_UX_V2.get() || !mShouldAnimateScaleAndAlpha) {
+                mIconScale.updateValue(SMALL_SCALE);
+            }
+            mTrackAlpha = MAX_PAINT_ALPHA;
+        } else {
             setIsDisabled(mItem.isDisabled());
             mScaledTrackPath.set(mScaledProgressPath);
             float fraction = (progress - 1) / COMPLETE_ANIM_FRACTION;
 
             if (fraction >= 1) {
                 // Animation has completed
-                mIconScale = 1;
+                mIconScale.updateValue(1);
                 mTrackAlpha = 0;
             } else {
                 mTrackAlpha = Math.round((1 - fraction) * MAX_PAINT_ALPHA);
-                mIconScale = SMALL_SCALE + (1 - SMALL_SCALE) * fraction;
+                mIconScale.updateValue(SMALL_SCALE + (1 - SMALL_SCALE) * fraction);
             }
         }
         invalidateSelf();
@@ -310,6 +369,10 @@
         return preloadColors;
     }
 
+    private static int getRefreshRateMillis(Context context) {
+        return RefreshRateTracker.getSingleFrameMs(context);
+    }
+
     /**
      * Returns a FastBitmapDrawable with the icon.
      */
@@ -325,7 +388,76 @@
                 mItem,
                 mIndicatorColor,
                 new int[] {mSystemAccentColor, mSystemBackgroundColor},
-                mIsDarkMode);
+                mIsDarkMode,
+                mRefreshRateMillis);
+    }
+
+    @Override
+    public void run() {
+        if (!ENABLE_DOWNLOAD_APP_UX_V2.get() || mInternalStateProgress > 0) {
+            return;
+        }
+        if (!applyPendingIconOverlay()) {
+            reschedule();
+        }
+    }
+
+    @Override
+    public boolean setVisible(boolean visible, boolean restart) {
+        boolean result = super.setVisible(visible, restart);
+        if (visible) {
+            reschedule();
+        } else {
+            unscheduleSelf(this);
+        }
+        return result;
+    }
+
+    private void reschedule() {
+        unscheduleSelf(this);
+
+        if (!isVisible()) {
+            return;
+        }
+
+        final long upTime = SystemClock.uptimeMillis();
+        scheduleSelf(this, upTime - ((upTime % mRefreshRateMillis)) + mRefreshRateMillis);
+    }
+
+
+    /**
+     * Apply an overlay on the pending icon with cascading motion based on its position.
+     * Returns {@code true} if the icon alpha is updated, so that we re-draw.
+     */
+    private boolean applyPendingIconOverlay() {
+        long waveMotionDelay = (mItem.cellX * WAVE_MOTION_DELAY_FACTOR_MILLIS)
+                + (mItem.cellY * WAVE_MOTION_DELAY_FACTOR_MILLIS);
+        long time = SystemClock.uptimeMillis();
+        float newAlpha = Utilities.mapBoundToRange(
+                (float) (time + waveMotionDelay) % ALPHA_DURATION_MILLIS,
+                0,
+                ALPHA_DURATION_MILLIS,
+                0,
+                MAX_PAINT_ALPHA,
+                LINEAR);
+        if (newAlpha > OVERLAY_ALPHA_RANGE) {
+            newAlpha = (OVERLAY_ALPHA_RANGE - (newAlpha % OVERLAY_ALPHA_RANGE));
+        }
+
+        boolean invalidate = false;
+        if ((int) mOverlayAlpha.value != newAlpha) {
+            mOverlayAlpha.updateValue(newAlpha);
+            invalidate = true;
+        }
+        return invalidate;
+    }
+
+    private void updateOverlayAlpha() {
+        int overlayColor = mIsDarkMode ? 0 : 255;
+        int currArgb =
+                Color.argb((int) mOverlayAlpha.value, overlayColor, overlayColor, overlayColor);
+        mPaint.setColorFilter(COLOR_FILTER_MAP.computeIfAbsent(currArgb, FILTER_FACTORY));
+        invalidateSelf();
     }
 
     protected static class PreloadIconConstantState extends FastBitmapConstantState {
@@ -335,6 +467,7 @@
         protected final int[] mPreloadColors;
         protected final boolean mIsDarkMode;
         protected final int mLevel;
+        protected final int mRefreshRateMillis;
 
         public PreloadIconConstantState(
                 Bitmap bitmap,
@@ -342,13 +475,15 @@
                 ItemInfoWithIcon info,
                 int indicatorColor,
                 int[] preloadColors,
-                boolean isDarkMode) {
+                boolean isDarkMode,
+                int refreshRateMillis) {
             super(bitmap, iconColor);
             mInfo = info;
             mIndicatorColor = indicatorColor;
             mPreloadColors = preloadColors;
             mIsDarkMode = isDarkMode;
             mLevel = info.getProgressLevel();
+            mRefreshRateMillis = refreshRateMillis;
         }
 
         @Override
@@ -357,7 +492,8 @@
                     mInfo,
                     mIndicatorColor,
                     mPreloadColors,
-                    mIsDarkMode);
+                    mIsDarkMode,
+                    mRefreshRateMillis);
         }
     }
 }
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 24d8c9d..2159c6b 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -624,7 +624,13 @@
         LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_RIGHT_BOTTOM(1232),
 
         @UiEvent(doc = "User has invoked split to left half with a keyboard shortcut.")
-        LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP(1233)
+        LAUNCHER_KEYBOARD_SHORTCUT_SPLIT_LEFT_TOP(1233),
+
+        @UiEvent(doc = "User has collapsed the work FAB button by swiping down")
+        LAUNCHER_WORK_FAB_BUTTON_COLLAPSE(1276),
+
+        @UiEvent(doc = "User has collapsed the work FAB button by swiping up")
+        LAUNCHER_WORK_FAB_BUTTON_EXTEND(1277),
         ;
 
         // ADD MORE
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 6da948c..8f85bfb 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -18,7 +18,6 @@
 
 import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
 import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY;
-import static com.android.launcher3.testing.shared.TestProtocol.INCORRECT_INFO_UPDATED;
 
 import android.content.ComponentName;
 import android.content.Context;
@@ -39,7 +38,6 @@
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.pm.PackageInstallInfo;
-import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.FlagOp;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.SafeCloseable;
@@ -275,14 +273,8 @@
     }
 
     public void updateIconsAndLabels(HashSet<String> packages, UserHandle user) {
-        if (TestProtocol.sDebugTracing) {
-            Log.i(INCORRECT_INFO_UPDATED, "updateIconsAndLabels: packages=" + packages);
-        }
         for (AppInfo info : data) {
             if (info.user.equals(user) && packages.contains(info.componentName.getPackageName())) {
-                if (TestProtocol.sDebugTracing) {
-                    Log.i(INCORRECT_INFO_UPDATED, "updateIconsAndLabels: updating info=" + info);
-                }
                 mIconCache.updateTitleAndIcon(info);
                 info.sectionName = mIndex.computeSectionName(info.title);
                 mDataChanged = true;
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 159af60..2dd44a4 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -21,7 +21,6 @@
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
-import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SEARCH_RESULTS;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SETTINGS;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_TASKSWITCHER;
@@ -54,7 +53,6 @@
 import com.android.launcher3.logger.LauncherAtom.AllAppsContainer;
 import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
 import com.android.launcher3.logger.LauncherAtom.PredictionContainer;
-import com.android.launcher3.logger.LauncherAtom.SearchResultContainer;
 import com.android.launcher3.logger.LauncherAtom.SettingsContainer;
 import com.android.launcher3.logger.LauncherAtom.Shortcut;
 import com.android.launcher3.logger.LauncherAtom.ShortcutsContainer;
@@ -439,10 +437,6 @@
                 return ContainerInfo.newBuilder()
                         .setPredictionContainer(PredictionContainer.getDefaultInstance())
                         .build();
-            case CONTAINER_SEARCH_RESULTS:
-                return ContainerInfo.newBuilder()
-                        .setSearchResultContainer(SearchResultContainer.getDefaultInstance())
-                        .build();
             case CONTAINER_SHORTCUTS:
                 return ContainerInfo.newBuilder()
                         .setShortcutsContainer(ShortcutsContainer.getDefaultInstance())
@@ -459,10 +453,12 @@
                 return ContainerInfo.newBuilder()
                         .setWallpapersContainer(WallpapersContainer.getDefaultInstance())
                         .build();
-            case EXTENDED_CONTAINERS:
-                return ContainerInfo.newBuilder()
-                        .setExtendedContainers(getExtendedContainer())
-                        .build();
+            default:
+                if (container <= EXTENDED_CONTAINERS) {
+                    return ContainerInfo.newBuilder()
+                            .setExtendedContainers(getExtendedContainer())
+                            .build();
+                }
         }
         return ContainerInfo.getDefaultInstance();
     }
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index a45e835..5e97b2d 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -355,7 +355,7 @@
     private void restoreAppWidgetIdsIfExists(Context context) {
         SharedPreferences prefs = LauncherPrefs.getPrefs(context);
         if (prefs.contains(APPWIDGET_OLD_IDS) && prefs.contains(APPWIDGET_IDS)) {
-            LauncherWidgetHolder holder = new LauncherWidgetHolder(context);
+            LauncherWidgetHolder holder = LauncherWidgetHolder.newInstance(context);
             AppWidgetsRestoredReceiver.restoreAppWidgetIds(context,
                     IntArray.fromConcatString(prefs.getString(APPWIDGET_OLD_IDS, "")).toArray(),
                     IntArray.fromConcatString(prefs.getString(APPWIDGET_IDS, "")).toArray(),
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 3e2d051..7ab3013 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -268,8 +268,8 @@
                     return !WidgetsModel.GO_DISABLE_NOTIFICATION_DOTS;
 
                 case ALLOW_ROTATION_PREFERENCE_KEY:
-                    DisplayController.Info info = InvariantDeviceProfile.INSTANCE.get(
-                            getContext()).getDeviceProfile(getContext()).getDisplayInfo();
+                    DisplayController.Info info =
+                            DisplayController.INSTANCE.get(getContext()).getInfo();
                     if (info.isTablet(info.realBounds)) {
                         // Launcher supports rotation by default. No need to show this setting.
                         return false;
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index 86277a7..ad1e7f0 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -342,7 +342,6 @@
             public void onAnimationSuccess(Animator animator) {
                 onStateTransitionEnd(state);
             }
-
         };
     }
 
@@ -377,12 +376,16 @@
     }
 
     public void moveToRestState() {
+        moveToRestState(shouldAnimateStateChange());
+    }
+
+    public void moveToRestState(boolean isAnimated) {
         if (mConfig.currentAnimation != null && mConfig.userControlled) {
             // The user is doing something. Lets not mess it up
             return;
         }
         if (mState.shouldDisableRestore()) {
-            goToState(getRestState());
+            goToState(getRestState(), isAnimated);
             // Reset history
             mLastStableState = mBaseState;
         }
diff --git a/src/com/android/launcher3/testing/shared/TestProtocol.java b/src/com/android/launcher3/testing/shared/TestProtocol.java
index 1deb23d..f5ee91b 100644
--- a/src/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/src/com/android/launcher3/testing/shared/TestProtocol.java
@@ -148,7 +148,6 @@
     public static final String NULL_INT_SET = "b/200572078";
     public static final String MISSING_PROMISE_ICON = "b/202985412";
     public static final String TASKBAR_IN_APP_STATE = "b/227657604";
-    public static final String INCORRECT_INFO_UPDATED = "b/239465630";
     public static final String NPE_TRANSIENT_TASKBAR = "b/257549303";
 
     public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
diff --git a/src/com/android/launcher3/util/DimensionUtils.kt b/src/com/android/launcher3/util/DimensionUtils.kt
index 758b3a9..1922310 100644
--- a/src/com/android/launcher3/util/DimensionUtils.kt
+++ b/src/com/android/launcher3/util/DimensionUtils.kt
@@ -24,12 +24,15 @@
 
 object DimensionUtils {
     /**
-     * Point where x is width, and y is height of taskbar based on provided [deviceProfile]
-     * x or y could also be -1 to indicate there is no dimension specified
+     * Point where x is width, and y is height of taskbar based on provided [deviceProfile] x or y
+     * could also be -1 to indicate there is no dimension specified
      */
     @JvmStatic
-    fun getTaskbarPhoneDimensions(deviceProfile: DeviceProfile, res: Resources,
-                                  isPhoneMode: Boolean): Point {
+    fun getTaskbarPhoneDimensions(
+        deviceProfile: DeviceProfile,
+        res: Resources,
+        isPhoneMode: Boolean
+    ): Point {
         val p = Point()
         // Taskbar for large screen
         if (!isPhoneMode) {
@@ -57,4 +60,4 @@
         p.y = ViewGroup.LayoutParams.MATCH_PARENT
         return p
     }
-}
\ No newline at end of file
+}
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 8e3daf3..c52890f 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -131,13 +131,20 @@
      * Returns whether taskbar is transient.
      */
     public static boolean isTransientTaskbar(Context context) {
+        return INSTANCE.get(context).isTransientTaskbar();
+    }
+
+    /**
+     * Returns whether taskbar is transient.
+     */
+    public boolean isTransientTaskbar() {
         // TODO(b/258604917): When running in test harness, use !sTransientTaskbarStatusForTests
         //  once tests are updated to expect new persistent behavior such as not allowing long press
         //  to stash.
         if (!Utilities.IS_RUNNING_IN_TEST_HARNESS && FORCE_PERSISTENT_TASKBAR.get()) {
             return false;
         }
-        return getNavigationMode(context) == NavigationMode.NO_BUTTON
+        return getInfo().navigationMode == NavigationMode.NO_BUTTON
                 && (Utilities.IS_RUNNING_IN_TEST_HARNESS
                     ? sTransientTaskbarStatusForTests
                     : ENABLE_TRANSIENT_TASKBAR.get());
diff --git a/quickstep/src/com/android/quickstep/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
similarity index 95%
rename from quickstep/src/com/android/quickstep/util/VibratorWrapper.java
rename to src/com/android/launcher3/util/VibratorWrapper.java
index 211bd08..932bcfc 100644
--- a/quickstep/src/com/android/quickstep/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -13,7 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.quickstep.util;
+package com.android.launcher3.util;
 
 import static android.os.VibrationEffect.createPredefined;
 import static android.provider.Settings.System.HAPTIC_FEEDBACK_ENABLED;
@@ -51,8 +51,6 @@
 
     public static final VibrationEffect EFFECT_CLICK =
             createPredefined(VibrationEffect.EFFECT_CLICK);
-    public static final VibrationEffect EFFECT_TEXTURE_TICK =
-            VibrationEffect.createPredefined(VibrationEffect.EFFECT_TEXTURE_TICK);
 
     /**
      * Haptic when entering overview.
diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
index 5497729..d7235ad 100644
--- a/src/com/android/launcher3/widget/LauncherWidgetHolder.java
+++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
@@ -19,7 +19,6 @@
 
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
-import android.app.PendingIntent;
 import android.appwidget.AppWidgetHost;
 import android.appwidget.AppWidgetHostView;
 import android.appwidget.AppWidgetManager;
@@ -29,7 +28,6 @@
 import android.content.Intent;
 import android.os.Bundle;
 import android.util.SparseArray;
-import android.view.View;
 import android.widget.RemoteViews;
 import android.widget.Toast;
 
@@ -45,7 +43,7 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.testing.TestLogging;
 import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.ResourceBasedOverride;
 import com.android.launcher3.widget.custom.CustomWidgetManager;
 
 import java.util.function.IntConsumer;
@@ -86,11 +84,7 @@
     // TODO(b/191735836): Replace with SplashScreen.SPLASH_SCREEN_STYLE_EMPTY when un-hidden
     private static final int SPLASH_SCREEN_STYLE_EMPTY = 0;
 
-    public LauncherWidgetHolder(@NonNull Context context) {
-        this(context, null);
-    }
-
-    public LauncherWidgetHolder(@NonNull Context context,
+    protected LauncherWidgetHolder(@NonNull Context context,
             @Nullable IntConsumer appWidgetRemovedCallback) {
         mContext = context;
         mWidgetHost = createHost(context, appWidgetRemovedCallback);
@@ -321,15 +315,6 @@
     }
 
     /**
-     * Set the interaction handler for the widget host
-     * @param handler The interaction handler
-     */
-    public void setInteractionHandler(
-            @Nullable LauncherWidgetInteractionHandler handler) {
-        ApiWrapper.setHostInteractionHandler(mWidgetHost, handler);
-    }
-
-    /**
      * Delete the host
      */
     public void deleteHost() {
@@ -489,20 +474,35 @@
     }
 
     /**
-     * Set as a substitution for the hidden interaction handler in RemoteViews
+     * Returns the new LauncherWidgetHolder instance
      */
-    public interface LauncherWidgetInteractionHandler {
+    public static LauncherWidgetHolder newInstance(Context context) {
+        return HolderFactory.newFactory(context).newInstance(context, null);
+    }
+
+    /**
+     * A factory class that generates new instances of {@code LauncherWidgetHolder}
+     */
+    public static class HolderFactory implements ResourceBasedOverride {
+
         /**
-         * Invoked when the user performs an interaction on the View.
-         *
-         * @param view the View with which the user interacted
-         * @param pendingIntent the base PendingIntent associated with the view
-         * @param response the response to the interaction, which knows how to fill in the
-         *                 attached PendingIntent
+         * @param context The context of the caller
+         * @param appWidgetRemovedCallback The callback that is called when widgets are removed
+         * @return A new instance of {@code LauncherWidgetHolder}
          */
-        boolean onInteraction(
-                View view,
-                PendingIntent pendingIntent,
-                RemoteViews.RemoteResponse response);
+        public LauncherWidgetHolder newInstance(@NonNull Context context,
+                @Nullable IntConsumer appWidgetRemovedCallback) {
+            return new LauncherWidgetHolder(context, appWidgetRemovedCallback);
+        }
+
+        /**
+         * @param context The context of the caller
+         * @return A new instance of factory class for widget holders. If not specified, returning
+         * {@code HolderFactory} by default.
+         */
+        public static HolderFactory newFactory(Context context) {
+            return Overrides.getObject(
+                    HolderFactory.class, context, R.string.widget_holder_factory_class);
+        }
     }
 }
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 220d1c1..38cdb4b 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -169,6 +169,7 @@
     private View mSearchBarContainer;
     private WidgetsSearchBar mSearchBar;
     private TextView mHeaderTitle;
+    private @Nullable WidgetsRecyclerView mCurrentTouchEventRecyclerView;
 
     public WidgetsFullSheet(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
@@ -642,6 +643,51 @@
         return sheet;
     }
 
+    @Override
+    public boolean onInterceptTouchEvent(MotionEvent ev) {
+        return isTouchOnScrollbar(ev) || super.onInterceptTouchEvent(ev);
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent ev) {
+        return maybeHandleTouchEvent(ev) || super.onTouchEvent(ev);
+    }
+
+    private boolean maybeHandleTouchEvent(MotionEvent ev) {
+        boolean isEventHandled = false;
+
+        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
+            mCurrentTouchEventRecyclerView = isTouchOnScrollbar(ev) ? getRecyclerView() : null;
+        }
+
+        if (mCurrentTouchEventRecyclerView != null) {
+            final float offsetX = mContent.getX();
+            final float offsetY = mContent.getY();
+            ev.offsetLocation(-offsetX, -offsetY);
+            isEventHandled = mCurrentTouchEventRecyclerView.dispatchTouchEvent(ev);
+            ev.offsetLocation(offsetX, offsetY);
+        }
+
+        if (ev.getAction() == MotionEvent.ACTION_UP
+                || ev.getAction() == MotionEvent.ACTION_CANCEL) {
+            mCurrentTouchEventRecyclerView = null;
+        }
+
+        return isEventHandled;
+    }
+
+    private boolean isTouchOnScrollbar(MotionEvent ev) {
+        final float offsetX = mContent.getX();
+        final float offsetY = mContent.getY();
+        WidgetsRecyclerView rv = getRecyclerView();
+
+        ev.offsetLocation(-offsetX, -offsetY);
+        boolean isOnScrollBar = rv != null && rv.getScrollbar() != null && rv.isHitOnScrollBar(ev);
+        ev.offsetLocation(offsetX, offsetY);
+
+        return isOnScrollBar;
+    }
+
     /** Gets the {@link WidgetsRecyclerView} which shows all widgets in {@link WidgetsFullSheet}. */
     @VisibleForTesting
     public static WidgetsRecyclerView getWidgetsView(Launcher launcher) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index 5969e3e..698e764 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -127,8 +127,7 @@
     @Override
     public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
         if (e.getAction() == MotionEvent.ACTION_DOWN) {
-            mTouchDownOnScroller =
-                    mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset);
+            mTouchDownOnScroller = isHitOnScrollBar(e);
         }
         if (mTouchDownOnScroller) {
             final boolean result = mScrollbar.handleTouchEvent(e, mFastScrollerOffset);
@@ -144,6 +143,15 @@
         }
     }
 
+    /**
+     * Detects whether a {@code MotionEvent} is on the scroll bar
+     * @param e The {@code MotionEvent} on the screen
+     * @return {@code true} if the motion is on the scroll bar
+     */
+    boolean isHitOnScrollBar(MotionEvent e) {
+        return mScrollbar.isHitInParent(e.getX(), e.getY(), mFastScrollerOffset);
+    }
+
     @Override
     public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
     }
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
index 02f4ece..47bf135 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -17,14 +17,9 @@
 package com.android.launcher3.uioverrides;
 
 import android.app.Person;
-import android.appwidget.AppWidgetHost;
 import android.content.pm.ShortcutInfo;
 
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
 import com.android.launcher3.Utilities;
-import com.android.launcher3.widget.LauncherWidgetHolder;
 
 /**
  * A wrapper for the hidden API calls
@@ -36,14 +31,4 @@
     public static Person[] getPersons(ShortcutInfo si) {
         return Utilities.EMPTY_PERSON_ARRAY;
     }
-
-    /**
-     * Set the interaction handler for the host
-     * @param host AppWidgetHost that needs the interaction handler
-     * @param handler InteractionHandler for the views in the host
-     */
-    public static void setHostInteractionHandler(@NonNull AppWidgetHost host,
-            @Nullable LauncherWidgetHolder.LauncherWidgetInteractionHandler handler) {
-        // No-op
-    }
 }
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index bedf277..b170061 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -280,7 +280,7 @@
             </intent-filter>
         </activity-alias>
         <activity-alias android:name="Activity15" android:exported="true"
-            android:label="ThemeIconTestActivity"
+            android:label="IconThemedActivity"
             android:icon="@drawable/test_theme_icon"
             android:targetActivity="com.android.launcher3.testcomponent.OtherBaseTestingActivity">
             <intent-filter>
diff --git a/tests/res/xml/shortcuts.xml b/tests/res/xml/shortcuts.xml
index fde0dbb..94e8edd 100644
--- a/tests/res/xml/shortcuts.xml
+++ b/tests/res/xml/shortcuts.xml
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="utf-8"?>
 <shortcuts xmlns:android="http://schemas.android.com/apk/res/android" >
     <shortcut
-        android:shortcutId="shortcut1"
+        android:shortcutId="shortcut1_themed"
         android:icon="@drawable/test_theme_icon"
         android:shortcutShortLabel="@string/shortcut1">
         <intent android:action="com.android.launcher3.intent.action.test_shortcut"/>
diff --git a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
index 4e166ce..2da5eee 100644
--- a/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
+++ b/tests/src/com/android/launcher3/DeviceProfileBaseTest.kt
@@ -23,11 +23,11 @@
 import com.android.launcher3.DeviceProfile.DEFAULT_PROVIDER
 import com.android.launcher3.util.DisplayController.Info
 import com.android.launcher3.util.WindowBounds
+import java.io.PrintWriter
+import java.io.StringWriter
 import org.junit.Before
 import org.mockito.ArgumentMatchers.any
 import org.mockito.Mockito.mock
-import java.io.PrintWriter
-import java.io.StringWriter
 import org.mockito.Mockito.`when` as whenever
 
 abstract class DeviceProfileBaseTest {
@@ -49,31 +49,36 @@
         isGestureMode = true
     }
 
-    protected fun newDP(): DeviceProfile = DeviceProfile(
-        context,
-        inv,
-        info,
-        windowBounds,
-        SparseArray(),
-        isMultiWindowMode,
-        transposeLayoutWithOrientation,
-        useTwoPanels,
-        isGestureMode,
-        DEFAULT_PROVIDER
-    )
+    protected fun newDP(): DeviceProfile =
+        DeviceProfile(
+            context,
+            inv,
+            info,
+            windowBounds,
+            SparseArray(),
+            isMultiWindowMode,
+            transposeLayoutWithOrientation,
+            useTwoPanels,
+            isGestureMode,
+            DEFAULT_PROVIDER
+        )
 
-    protected fun initializeVarsForPhone(isGestureMode: Boolean = true,
-                                         isVerticalBar: Boolean = false) {
-        val (x, y) = if (isVerticalBar)
-            Pair(2400, 1080)
-        else
-            Pair(1080, 2400)
+    protected fun initializeVarsForPhone(
+        isGestureMode: Boolean = true,
+        isVerticalBar: Boolean = false
+    ) {
+        val (x, y) = if (isVerticalBar) Pair(2400, 1080) else Pair(1080, 2400)
 
-        windowBounds = WindowBounds(Rect(0, 0, x, y), Rect(
-                if (isVerticalBar) 118 else 0,
-                if (isVerticalBar) 74 else 118,
-                if (!isGestureMode && isVerticalBar) 126 else 0,
-                if (isGestureMode) 63 else if (isVerticalBar) 0 else 126))
+        windowBounds =
+            WindowBounds(
+                Rect(0, 0, x, y),
+                Rect(
+                    if (isVerticalBar) 118 else 0,
+                    if (isVerticalBar) 74 else 118,
+                    if (!isGestureMode && isVerticalBar) 126 else 0,
+                    if (isGestureMode) 63 else if (isVerticalBar) 0 else 126
+                )
+            )
 
         whenever(info.isTablet(any())).thenReturn(false)
         whenever(info.getDensityDpi()).thenReturn(420)
@@ -82,79 +87,76 @@
         this.isGestureMode = isGestureMode
         transposeLayoutWithOrientation = true
 
-        inv = InvariantDeviceProfile().apply {
-            numRows = 5
-            numColumns = 4
-            numSearchContainerColumns = 4
+        inv =
+            InvariantDeviceProfile().apply {
+                numRows = 5
+                numColumns = 4
+                numSearchContainerColumns = 4
 
-            iconSize = floatArrayOf(60f, 54f, 60f, 60f)
-            iconTextSize = FloatArray(4) { 14f }
-            deviceType = InvariantDeviceProfile.TYPE_PHONE
+                iconSize = floatArrayOf(60f, 54f, 60f, 60f)
+                iconTextSize = FloatArray(4) { 14f }
+                deviceType = InvariantDeviceProfile.TYPE_PHONE
 
-            minCellSize = listOf(
-                    PointF(80f, 104f),
-                    PointF(80f, 104f),
-                    PointF(80f, 104f),
-                    PointF(80f, 104f)
-            ).toTypedArray()
+                minCellSize =
+                    listOf(
+                            PointF(80f, 104f),
+                            PointF(80f, 104f),
+                            PointF(80f, 104f),
+                            PointF(80f, 104f)
+                        )
+                        .toTypedArray()
 
-            borderSpaces = listOf(
-                    PointF(16f, 16f),
-                    PointF(16f, 16f),
-                    PointF(16f, 16f),
-                    PointF(16f, 16f)
-            ).toTypedArray()
+                borderSpaces =
+                    listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f))
+                        .toTypedArray()
 
-            numFolderRows = 3
-            numFolderColumns = 3
-            folderStyle = R.style.FolderDefaultStyle
+                numFolderRows = 3
+                numFolderColumns = 3
+                folderStyle = R.style.FolderDefaultStyle
 
-            inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_4_5
+                inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
 
-            horizontalMargin = FloatArray(4) { 22f }
+                horizontalMargin = FloatArray(4) { 22f }
 
-            allAppsCellSize = listOf(
-                    PointF(80f, 104f),
-                    PointF(80f, 104f),
-                    PointF(80f, 104f),
-                    PointF(80f, 104f)
-            ).toTypedArray()
-            allAppsIconSize = floatArrayOf(60f, 60f, 60f, 60f)
-            allAppsIconTextSize = FloatArray(4) { 14f }
-            allAppsBorderSpaces = listOf(
-                    PointF(16f, 16f),
-                    PointF(16f, 16f),
-                    PointF(16f, 16f),
-                    PointF(16f, 16f)
-            ).toTypedArray()
+                allAppsCellSize =
+                    listOf(
+                            PointF(80f, 104f),
+                            PointF(80f, 104f),
+                            PointF(80f, 104f),
+                            PointF(80f, 104f)
+                        )
+                        .toTypedArray()
+                allAppsIconSize = floatArrayOf(60f, 60f, 60f, 60f)
+                allAppsIconTextSize = FloatArray(4) { 14f }
+                allAppsBorderSpaces =
+                    listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 16f))
+                        .toTypedArray()
 
-            numShownHotseatIcons = 4
+                numShownHotseatIcons = 4
 
-            numDatabaseHotseatIcons = 4
+                numDatabaseHotseatIcons = 4
 
-            hotseatColumnSpan = IntArray(4) { 4 }
-            hotseatBarBottomSpace = FloatArray(4) { 48f }
-            hotseatQsbSpace = FloatArray(4) { 36f }
+                hotseatColumnSpan = IntArray(4) { 4 }
+                hotseatBarBottomSpace = FloatArray(4) { 48f }
+                hotseatQsbSpace = FloatArray(4) { 36f }
 
-            numAllAppsColumns = 4
+                numAllAppsColumns = 4
 
-            isScalable = true
+                isScalable = true
 
-            inlineQsb = BooleanArray(4) { false }
+                inlineQsb = BooleanArray(4) { false }
 
-            devicePaddingId = R.xml.paddings_handhelds
-        }
+                devicePaddingId = R.xml.paddings_handhelds
+            }
     }
 
-    protected fun initializeVarsForTablet(isLandscape: Boolean = false,
-                                          isGestureMode: Boolean = true) {
-        val (x, y) = if (isLandscape)
-            Pair(2560, 1600)
-        else
-            Pair(1600, 2560)
+    protected fun initializeVarsForTablet(
+        isLandscape: Boolean = false,
+        isGestureMode: Boolean = true
+    ) {
+        val (x, y) = if (isLandscape) Pair(2560, 1600) else Pair(1600, 2560)
 
-        windowBounds =
-                WindowBounds(Rect(0, 0, x, y), Rect(0, 104, 0, 0))
+        windowBounds = WindowBounds(Rect(0, 0, x, y), Rect(0, 104, 0, 0))
 
         whenever(info.isTablet(any())).thenReturn(true)
         whenever(info.getDensityDpi()).thenReturn(320)
@@ -163,85 +165,77 @@
         this.isGestureMode = isGestureMode
         useTwoPanels = false
 
-        inv = InvariantDeviceProfile().apply {
-            numRows = 5
-            numColumns = 6
-            numSearchContainerColumns = 3
+        inv =
+            InvariantDeviceProfile().apply {
+                numRows = 5
+                numColumns = 6
+                numSearchContainerColumns = 3
 
-            iconSize = FloatArray(4) { 60f }
-            iconTextSize = FloatArray(4) { 14f }
-            deviceType = InvariantDeviceProfile.TYPE_TABLET
+                iconSize = FloatArray(4) { 60f }
+                iconTextSize = FloatArray(4) { 14f }
+                deviceType = InvariantDeviceProfile.TYPE_TABLET
 
-            minCellSize = listOf(
-                    PointF(102f, 120f),
-                    PointF(120f, 104f),
-                    PointF(102f, 120f),
-                    PointF(102f, 120f)
-            ).toTypedArray()
+                minCellSize =
+                    listOf(
+                            PointF(102f, 120f),
+                            PointF(120f, 104f),
+                            PointF(102f, 120f),
+                            PointF(102f, 120f)
+                        )
+                        .toTypedArray()
 
-            borderSpaces = listOf(
-                    PointF(16f, 64f),
-                    PointF(64f, 16f),
-                    PointF(16f, 64f),
-                    PointF(16f, 64f)
-            ).toTypedArray()
+                borderSpaces =
+                    listOf(PointF(16f, 64f), PointF(64f, 16f), PointF(16f, 64f), PointF(16f, 64f))
+                        .toTypedArray()
 
-            numFolderRows = 3
-            numFolderColumns = 3
-            folderStyle = R.style.FolderDefaultStyle
+                numFolderRows = 3
+                numFolderColumns = 3
+                folderStyle = R.style.FolderDefaultStyle
 
-            inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_6_5
+                inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_6_5
 
-            horizontalMargin = floatArrayOf(54f, 120f, 54f, 54f)
+                horizontalMargin = floatArrayOf(54f, 120f, 54f, 54f)
 
-            allAppsCellSize = listOf(
-                    PointF(96f, 142f),
-                    PointF(126f, 126f),
-                    PointF(96f, 142f),
-                    PointF(96f, 142f)
-            ).toTypedArray()
-            allAppsIconSize = FloatArray(4) { 60f }
-            allAppsIconTextSize = FloatArray(4) { 14f }
-            allAppsBorderSpaces = listOf(
-                    PointF(8f, 16f),
-                    PointF(16f, 16f),
-                    PointF(8f, 16f),
-                    PointF(8f, 16f)
-            ).toTypedArray()
+                allAppsCellSize =
+                    listOf(
+                            PointF(96f, 142f),
+                            PointF(126f, 126f),
+                            PointF(96f, 142f),
+                            PointF(96f, 142f)
+                        )
+                        .toTypedArray()
+                allAppsIconSize = FloatArray(4) { 60f }
+                allAppsIconTextSize = FloatArray(4) { 14f }
+                allAppsBorderSpaces =
+                    listOf(PointF(8f, 16f), PointF(16f, 16f), PointF(8f, 16f), PointF(8f, 16f))
+                        .toTypedArray()
 
-            numShownHotseatIcons = 6
+                numShownHotseatIcons = 6
 
-            numDatabaseHotseatIcons = 6
+                numDatabaseHotseatIcons = 6
 
-            hotseatColumnSpan = intArrayOf(6, 4, 6, 6)
-            hotseatBarBottomSpace = floatArrayOf(36f, 40f, 36f, 36f)
-            hotseatQsbSpace = FloatArray(4) { 32f }
+                hotseatColumnSpan = intArrayOf(6, 4, 6, 6)
+                hotseatBarBottomSpace = floatArrayOf(36f, 40f, 36f, 36f)
+                hotseatQsbSpace = FloatArray(4) { 32f }
 
-            numAllAppsColumns = 6
+                numAllAppsColumns = 6
 
-            isScalable = true
-            devicePaddingId = R.xml.paddings_6x5
+                isScalable = true
+                devicePaddingId = R.xml.paddings_6x5
 
-            inlineQsb = booleanArrayOf(
-                    false,
-                    true,
-                    false,
-                    false
-            )
+                inlineQsb = booleanArrayOf(false, true, false, false)
 
-            devicePaddingId = R.xml.paddings_handhelds
-        }
+                devicePaddingId = R.xml.paddings_handhelds
+            }
     }
 
-    protected fun initializeVarsForTwoPanel(isLandscape: Boolean = false,
-            isGestureMode: Boolean = true) {
-        val (x, y) = if (isLandscape)
-            Pair(2208, 1840)
-        else
-            Pair(1840, 2208)
+    protected fun initializeVarsForTwoPanel(
+        isLandscape: Boolean = false,
+        isGestureMode: Boolean = true
+    ) {
+        val (x, y) = if (isLandscape) Pair(2208, 1840) else Pair(1840, 2208)
 
-        windowBounds = WindowBounds(Rect(0, 0, x, y),
-                Rect(0, 110, 0, 0))
+        windowBounds = WindowBounds(Rect(0, 0, x, y), Rect(0, 110, 0, 0))
 
         whenever(info.isTablet(any())).thenReturn(true)
         whenever(info.getDensityDpi()).thenReturn(420)
@@ -250,74 +244,63 @@
         this.isGestureMode = isGestureMode
         useTwoPanels = true
 
-        inv = InvariantDeviceProfile().apply {
-            numRows = 4
-            numColumns = 4
-            numSearchContainerColumns = 4
+        inv =
+            InvariantDeviceProfile().apply {
+                numRows = 4
+                numColumns = 4
+                numSearchContainerColumns = 4
 
-            iconSize = floatArrayOf(60f, 52f, 52f, 60f)
-            iconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
-            deviceType = InvariantDeviceProfile.TYPE_MULTI_DISPLAY
+                iconSize = floatArrayOf(60f, 52f, 52f, 60f)
+                iconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
+                deviceType = InvariantDeviceProfile.TYPE_MULTI_DISPLAY
 
-            minCellSize = listOf(
-                    PointF(80f, 104f),
-                    PointF(80f, 104f),
-                    PointF(68f, 116f),
-                    PointF(80f, 102f)
-            ).toTypedArray()
+                minCellSize =
+                    listOf(
+                            PointF(80f, 104f),
+                            PointF(80f, 104f),
+                            PointF(68f, 116f),
+                            PointF(80f, 102f)
+                        )
+                        .toTypedArray()
 
-            borderSpaces = listOf(
-                    PointF(16f, 16f),
-                    PointF(16f, 16f),
-                    PointF(16f, 20f),
-                    PointF(20f, 20f)
-            ).toTypedArray()
+                borderSpaces =
+                    listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 20f), PointF(20f, 20f))
+                        .toTypedArray()
 
-            numFolderRows = 3
-            numFolderColumns = 3
-            folderStyle = R.style.FolderDefaultStyle
+                numFolderRows = 3
+                numFolderColumns = 3
+                folderStyle = R.style.FolderDefaultStyle
 
-            inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_4_4
+                inlineNavButtonsEndSpacing = R.dimen.taskbar_button_margin_split
 
-            horizontalMargin = floatArrayOf(21.5f, 21.5f, 22.5f, 30.5f)
+                horizontalMargin = floatArrayOf(21.5f, 21.5f, 22.5f, 30.5f)
 
-            allAppsCellSize = listOf(
-                    PointF(0f, 0f),
-                    PointF(0f, 0f),
-                    PointF(68f, 104f),
-                    PointF(80f, 104f)
-            ).toTypedArray()
-            allAppsIconSize = floatArrayOf(60f, 60f, 52f, 60f)
-            allAppsIconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
-            allAppsBorderSpaces = listOf(
-                    PointF(16f, 16f),
-                    PointF(16f, 16f),
-                    PointF(16f, 28f),
-                    PointF(20f, 16f)
-            ).toTypedArray()
+                allAppsCellSize =
+                    listOf(PointF(0f, 0f), PointF(0f, 0f), PointF(68f, 104f), PointF(80f, 104f))
+                        .toTypedArray()
+                allAppsIconSize = floatArrayOf(60f, 60f, 52f, 60f)
+                allAppsIconTextSize = floatArrayOf(14f, 14f, 12f, 14f)
+                allAppsBorderSpaces =
+                    listOf(PointF(16f, 16f), PointF(16f, 16f), PointF(16f, 28f), PointF(20f, 16f))
+                        .toTypedArray()
 
-            numShownHotseatIcons = 6
+                numShownHotseatIcons = 6
 
-            numDatabaseHotseatIcons = 6
+                numDatabaseHotseatIcons = 6
 
-            hotseatColumnSpan = IntArray(4) { 6 }
-            hotseatBarBottomSpace = floatArrayOf(48f, 48f, 36f, 20f)
-            hotseatQsbSpace = floatArrayOf(36f, 36f, 36f, 28f)
+                hotseatColumnSpan = IntArray(4) { 6 }
+                hotseatBarBottomSpace = floatArrayOf(48f, 48f, 36f, 20f)
+                hotseatQsbSpace = floatArrayOf(36f, 36f, 36f, 28f)
 
-            numAllAppsColumns = 6
-            numDatabaseAllAppsColumns = 6
+                numAllAppsColumns = 6
+                numDatabaseAllAppsColumns = 6
 
-            isScalable = true
+                isScalable = true
 
-            inlineQsb = booleanArrayOf(
-                    false,
-                    false,
-                    false,
-                    false
-            )
+                inlineQsb = booleanArrayOf(false, false, false, false)
 
-            devicePaddingId = R.xml.paddings_handhelds
-        }
+                devicePaddingId = R.xml.paddings_handhelds
+            }
     }
 
     fun dump(dp: DeviceProfile): String {
@@ -327,4 +310,4 @@
         printWriter.flush()
         return stringWriter.toString()
     }
-}
\ No newline at end of file
+}
diff --git a/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java b/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
index a32ce3c..469d79f 100644
--- a/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
+++ b/tests/src/com/android/launcher3/celllayout/CellLayoutBoard.java
@@ -26,6 +26,7 @@
 import java.util.Map;
 import java.util.Queue;
 import java.util.Set;
+import java.util.stream.Collectors;
 
 
 public class CellLayoutBoard {
@@ -140,6 +141,73 @@
         return mWidgetsMap.get(c);
     }
 
+    private void removeWidgetFromBoard(WidgetRect widget) {
+        for (int xi = widget.mBounds.left; xi < widget.mBounds.right; xi++) {
+            for (int yi = widget.mBounds.top; yi < widget.mBounds.bottom; yi++) {
+                mWidget[xi][yi] = '-';
+            }
+        }
+    }
+
+    private void removeOverlappingItems(Rect rect) {
+        // Remove overlapping widgets and remove them from the board
+        mWidgetsRects = mWidgetsRects.stream().filter(widget -> {
+            if (rect.intersect(widget.mBounds)) {
+                removeWidgetFromBoard(widget);
+                return false;
+            }
+            return true;
+        }).collect(Collectors.toList());
+        // Remove overlapping icons and remove them from the board
+        mIconPoints = mIconPoints.stream().filter(iconPoint -> {
+            int x = iconPoint.coord.x;
+            int y = iconPoint.coord.y;
+            if (rect.contains(x, y)) {
+                mWidget[x][y] = '-';
+                return false;
+            }
+            return true;
+        }).collect(Collectors.toList());
+    }
+
+    private void removeOverlappingItems(Point p) {
+        // Remove overlapping widgets and remove them from the board
+        mWidgetsRects = mWidgetsRects.stream().filter(widget -> {
+            if (widget.mBounds.contains(p.x, p.y)) {
+                removeWidgetFromBoard(widget);
+                return false;
+            }
+            return true;
+        }).collect(Collectors.toList());
+        // Remove overlapping icons and remove them from the board
+        mIconPoints = mIconPoints.stream().filter(iconPoint -> {
+            int x = iconPoint.coord.x;
+            int y = iconPoint.coord.y;
+            if (p.x == x && p.y == y) {
+                mWidget[x][y] = '-';
+                return false;
+            }
+            return true;
+        }).collect(Collectors.toList());
+    }
+
+    public void addWidget(int x, int y, int spanX, int spanY, char type) {
+        Rect rect = new Rect(x, y + spanY - 1, x + spanX - 1, y);
+        removeOverlappingItems(rect);
+        WidgetRect widgetRect = new WidgetRect(type, rect);
+        mWidgetsRects.add(widgetRect);
+        for (int xi = rect.left; xi < rect.right + 1; xi++) {
+            for (int yi = rect.bottom; yi < rect.top + 1; yi++) {
+                mWidget[xi][yi] = type;
+            }
+        }
+    }
+
+    public void addIcon(int x, int y) {
+        removeOverlappingItems(new Point(x, y));
+        mWidget[x][y] = 'i';
+    }
+
     public static WidgetRect getWidgetRect(int x, int y, Set<Point> used, char[][] board) {
         char type = board[x][y];
         Queue<Point> search = new ArrayDeque<Point>();
@@ -227,4 +295,17 @@
         board.mIconPoints = getIconPoints(board.mWidget);
         return board;
     }
+
+    public String toString(int maxX, int maxY) {
+        StringBuilder s = new StringBuilder();
+        maxX = Math.min(maxX, mWidget.length);
+        maxY = Math.min(maxY, mWidget[0].length);
+        for (int y = 0; y < maxY; y++) {
+            for (int x = 0; x < maxX; x++) {
+                s.append(mWidget[x][y]);
+            }
+            s.append('\n');
+        }
+        return s.toString();
+    }
 }
diff --git a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
index 9da7e0f..843f011 100644
--- a/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
+++ b/tests/src/com/android/launcher3/celllayout/ReorderWidgets.java
@@ -26,6 +26,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.launcher3.CellLayout;
+import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.celllayout.testcases.FullReorderCase;
 import com.android.launcher3.celllayout.testcases.MoveOutReorderCase;
 import com.android.launcher3.celllayout.testcases.PushReorderCase;
@@ -46,6 +47,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.ArrayList;
 import java.util.Map;
 import java.util.concurrent.ExecutionException;
 
@@ -108,6 +110,42 @@
         return match;
     }
 
+    private void printCurrentWorkspace() {
+        InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(mTargetContext);
+        ArrayList<CellLayoutBoard> boards = workspaceToBoards();
+        for (int i = 0; i < boards.size(); i++) {
+            Log.d(TAG, "Screen number " + i);
+            Log.d(TAG, ".\n" + boards.get(i).toString(idp.numColumns, idp.numRows));
+        }
+    }
+
+    private ArrayList<CellLayoutBoard> workspaceToBoards() {
+        return getFromLauncher(l -> {
+            ArrayList<CellLayoutBoard> boards = new ArrayList<>();
+            int widgetCount = 0;
+            for (CellLayout cellLayout : l.getWorkspace().mWorkspaceScreens) {
+                CellLayoutBoard board = new CellLayoutBoard();
+                int count = cellLayout.getShortcutsAndWidgets().getChildCount();
+                for (int i = 0; i < count; i++) {
+                    View callView = cellLayout.getShortcutsAndWidgets().getChildAt(i);
+                    CellLayoutLayoutParams params =
+                            (CellLayoutLayoutParams) callView.getLayoutParams();
+                    // is icon
+                    if (callView instanceof DoubleShadowBubbleTextView) {
+                        board.addIcon(params.cellX, params.cellY);
+                    } else {
+                        // is widget
+                        board.addWidget(params.cellX, params.cellY, params.cellHSpan,
+                                params.cellVSpan, (char) ('A' + widgetCount));
+                        widgetCount++;
+                    }
+                }
+                boards.add(board);
+            }
+            return boards;
+        });
+    }
+
     private void runTestCase(ReorderTestCase testCase)
             throws ExecutionException, InterruptedException {
         Point mainWidgetCellPos = testCase.mStart.getMain();
@@ -127,6 +165,7 @@
         for (CellLayoutBoard board : testCase.mEnd) {
             isValid |= validateBoard(board);
         }
+        printCurrentWorkspace();
         assertTrue("Non of the valid boards match with the current state", isValid);
     }
 
diff --git a/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt b/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt
index d26381d..03352fe 100644
--- a/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt
+++ b/tests/src/com/android/launcher3/model/AbstractWorkspaceModelTest.kt
@@ -30,9 +30,7 @@
 import com.android.launcher3.util.LauncherModelHelper
 import java.util.UUID
 
-/**
- * Base class for workspace related tests.
- */
+/** Base class for workspace related tests. */
 abstract class AbstractWorkspaceModelTest {
     companion object {
         val emptyScreenSpaces = listOf(Rect(0, 0, 5, 5))
@@ -64,10 +62,7 @@
         mModelHelper.destroy()
     }
 
-
-    /**
-     * Sets up workspaces with the given screen IDs with some items and a 2x2 space.
-     */
+    /** Sets up workspaces with the given screen IDs with some items and a 2x2 space. */
     fun setupWorkspaces(screenIdsWithItems: List<Int>) {
         var nextItemId = 1
         screenIdsWithItems.forEach { screenId ->
@@ -83,8 +78,7 @@
         screen1: List<Rect>? = null,
         screen2: List<Rect>? = null,
         screen3: List<Rect>? = null,
-    ) = listOf(screen0, screen1, screen2, screen3)
-        .let(this::setupWithSpaces)
+    ) = listOf(screen0, screen1, screen2, screen3).let(this::setupWithSpaces)
 
     private fun setupWithSpaces(workspaceSpaces: List<List<Rect>?>) {
         var nextItemId = 1
@@ -110,9 +104,7 @@
         var itemId = itemStartId
         val occupancy = GridOccupancy(mIdp.numColumns, mIdp.numRows)
         occupancy.markCells(0, 0, mIdp.numColumns, mIdp.numRows, true)
-        spaces.forEach { spaceRect ->
-            occupancy.markCells(spaceRect, false)
-        }
+        spaces.forEach { spaceRect -> occupancy.markCells(spaceRect, false) }
         mExistingScreens.add(screenId)
         mScreenOccupancy.append(screenId, occupancy)
         for (x in 0 until mIdp.numColumns) {
@@ -139,24 +131,21 @@
         return itemId
     }
 
-    fun getExistingItem() = WorkspaceItemInfo()
-        .apply { intent = Intent().setComponent(ComponentName("a", "b")) }
+    fun getExistingItem() =
+        WorkspaceItemInfo().apply { intent = Intent().setComponent(ComponentName("a", "b")) }
 
     fun getNewItem(): WorkspaceItemInfo {
         val itemPackage = UUID.randomUUID().toString()
-        return WorkspaceItemInfo()
-            .apply { intent = Intent().setComponent(ComponentName(itemPackage, itemPackage)) }
+        return WorkspaceItemInfo().apply {
+            intent = Intent().setComponent(ComponentName(itemPackage, itemPackage))
+        }
     }
 }
 
-data class NewItemSpace(
-    val screenId: Int,
-    val cellX: Int,
-    val cellY: Int
-) {
+data class NewItemSpace(val screenId: Int, val cellX: Int, val cellY: Int) {
     fun toIntArray() = intArrayOf(screenId, cellX, cellY)
 
     companion object {
         fun fromIntArray(array: kotlin.IntArray) = NewItemSpace(array[0], array[1], array[2])
     }
-}
\ No newline at end of file
+}
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
index 65d938b..749ffcf 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
@@ -23,9 +23,9 @@
 import com.android.launcher3.model.data.WorkspaceItemInfo
 import com.android.launcher3.util.Executors
 import com.android.launcher3.util.IntArray
-import com.android.launcher3.util.same
-import com.android.launcher3.util.eq
 import com.android.launcher3.util.any
+import com.android.launcher3.util.eq
+import com.android.launcher3.util.same
 import com.google.common.truth.Truth.assertThat
 import org.junit.After
 import org.junit.Before
@@ -34,31 +34,24 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.Captor
 import org.mockito.Mock
-import org.mockito.MockitoAnnotations
+import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyZeroInteractions
-import org.mockito.Mockito.times
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
-/**
- * Tests for [AddWorkspaceItemsTask]
- */
+/** Tests for [AddWorkspaceItemsTask] */
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class AddWorkspaceItemsTaskTest : AbstractWorkspaceModelTest() {
 
-    @Captor
-    private lateinit var mAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
+    @Captor private lateinit var mAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
 
-    @Captor
-    private lateinit var mNotAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
+    @Captor private lateinit var mNotAnimatedItemArgumentCaptor: ArgumentCaptor<ArrayList<ItemInfo>>
 
-    @Mock
-    private lateinit var mDataModelCallbacks: BgDataModel.Callbacks
+    @Mock private lateinit var mDataModelCallbacks: BgDataModel.Callbacks
 
-    @Mock
-    private lateinit var mWorkspaceItemSpaceFinder: WorkspaceItemSpaceFinder
-
+    @Mock private lateinit var mWorkspaceItemSpaceFinder: WorkspaceItemSpaceFinder
 
     @Before
     override fun setup() {
@@ -89,10 +82,7 @@
 
     @Test
     fun givenNewAndExistingItems_whenExecuteTask_thenOnlyAddNewItem() {
-        val itemsToAdd = arrayOf(
-            getNewItem(),
-            getExistingItem()
-        )
+        val itemsToAdd = arrayOf(getNewItem(), getExistingItem())
         givenNewItemSpaces(NewItemSpace(1, 0, 0))
         val nonEmptyScreenIds = listOf(0)
 
@@ -132,13 +122,14 @@
 
     @Test
     fun givenMultipleItems_whenExecuteTask_thenAddThem() {
-        val itemsToAdd = arrayOf(
-            getNewItem(),
-            getExistingItem(),
-            getNewItem(),
-            getNewItem(),
-            getExistingItem(),
-        )
+        val itemsToAdd =
+            arrayOf(
+                getNewItem(),
+                getExistingItem(),
+                getNewItem(),
+                getNewItem(),
+                getExistingItem(),
+            )
         givenNewItemSpaces(
             NewItemSpace(1, 3, 3),
             NewItemSpace(2, 0, 0),
@@ -159,27 +150,16 @@
         // Items that are added to the second screen should be animated
         val itemsAddedToSecondScreen = addedItems.filter { it.itemInfo.screenId == 2 }
         assertThat(itemsAddedToSecondScreen.size).isEqualTo(2)
-        itemsAddedToSecondScreen.forEach {
-            assertThat(it.isAnimated).isTrue()
-        }
+        itemsAddedToSecondScreen.forEach { assertThat(it.isAnimated).isTrue() }
         verifyItemSpaceFinderCall(nonEmptyScreenIds, numberOfExpectedCall = 3)
     }
 
-    /**
-     * Sets up the item space data that will be returned from WorkspaceItemSpaceFinder.
-     */
+    /** Sets up the item space data that will be returned from WorkspaceItemSpaceFinder. */
     private fun givenNewItemSpaces(vararg newItemSpaces: NewItemSpace) {
         val spaceStack = newItemSpaces.toMutableList()
         whenever(
-            mWorkspaceItemSpaceFinder.findSpaceForItem(
-                any(),
-                any(),
-                any(),
-                any(),
-                any(),
-                any()
+                mWorkspaceItemSpaceFinder.findSpaceForItem(any(), any(), any(), any(), any(), any())
             )
-        )
             .then { spaceStack.removeFirst().toIntArray() }
     }
 
@@ -187,20 +167,21 @@
      * Verifies if WorkspaceItemSpaceFinder was called with proper arguments and how many times was
      * it called.
      */
-    private fun verifyItemSpaceFinderCall(
-        nonEmptyScreenIds: List<Int>,
-        numberOfExpectedCall: Int
-    ) {
+    private fun verifyItemSpaceFinderCall(nonEmptyScreenIds: List<Int>, numberOfExpectedCall: Int) {
         verify(mWorkspaceItemSpaceFinder, times(numberOfExpectedCall))
             .findSpaceForItem(
-                same(mAppState), same(mModelHelper.bgDataModel),
-                eq(IntArray.wrap(*nonEmptyScreenIds.toIntArray())), eq(IntArray()), eq(1), eq(1)
+                same(mAppState),
+                same(mModelHelper.bgDataModel),
+                eq(IntArray.wrap(*nonEmptyScreenIds.toIntArray())),
+                eq(IntArray()),
+                eq(1),
+                eq(1)
             )
     }
 
     /**
-     * Sets up the workspaces with items, executes the task, collects the added items from the
-     * model callback then returns it.
+     * Sets up the workspaces with items, executes the task, collects the added items from the model
+     * callback then returns it.
      */
     private fun testAddItems(
         nonEmptyScreenIds: List<Int>,
@@ -209,21 +190,21 @@
         setupWorkspaces(nonEmptyScreenIds)
         val task = newTask(*itemsToAdd)
         var updateCount = 0
-        mModelHelper.executeTaskForTest(task)
-            .forEach {
-                updateCount++
-                it.run()
-            }
+        mModelHelper.executeTaskForTest(task).forEach {
+            updateCount++
+            it.run()
+        }
 
         val addedItems = mutableListOf<AddedItem>()
         if (updateCount > 0) {
-            verify(mDataModelCallbacks).bindAppsAdded(
-                any(),
-                mNotAnimatedItemArgumentCaptor.capture(), mAnimatedItemArgumentCaptor.capture()
-            )
+            verify(mDataModelCallbacks)
+                .bindAppsAdded(
+                    any(),
+                    mNotAnimatedItemArgumentCaptor.capture(),
+                    mAnimatedItemArgumentCaptor.capture()
+                )
             addedItems.addAll(mAnimatedItemArgumentCaptor.value.map { AddedItem(it, true) })
             addedItems.addAll(mNotAnimatedItemArgumentCaptor.value.map { AddedItem(it, false) })
-
         }
 
         return addedItems
@@ -234,12 +215,10 @@
      * with a mock.
      */
     private fun newTask(vararg items: ItemInfo): AddWorkspaceItemsTask =
-        items.map { Pair.create(it, Any()) }
+        items
+            .map { Pair.create(it, Any()) }
             .toMutableList()
             .let { AddWorkspaceItemsTask(it, mWorkspaceItemSpaceFinder) }
 }
 
-private data class AddedItem(
-    val itemInfo: ItemInfo,
-    val isAnimated: Boolean
-)
+private data class AddedItem(val itemInfo: ItemInfo, val isAnimated: Boolean)
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index 7d36740..f55b244 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -1,7 +1,5 @@
 package com.android.launcher3.model;
 
-import static com.android.launcher3.testing.shared.TestProtocol.INCORRECT_INFO_UPDATED;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotSame;
@@ -16,7 +14,6 @@
 import android.os.Process;
 import android.os.UserHandle;
 import android.os.UserManager;
-import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
@@ -29,7 +26,6 @@
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.testing.shared.TestProtocol;
 import com.android.launcher3.util.LauncherModelHelper;
 
 import org.junit.After;
@@ -47,15 +43,12 @@
 @RunWith(AndroidJUnit4.class)
 public class CacheDataUpdatedTaskTest {
 
-    private static final String TAG = "CacheDataUpdatedTaskTest";
-
     private static final String NEW_LABEL_PREFIX = "new-label-";
 
     private LauncherModelHelper mModelHelper;
 
     @Before
     public void setup() throws Exception {
-        TestProtocol.sDebugTracing = true;
         mModelHelper = new LauncherModelHelper();
         mModelHelper.initializeData("cache_data_updated_task_data");
 
@@ -98,7 +91,6 @@
     @After
     public void tearDown() {
         mModelHelper.destroy();
-        TestProtocol.sDebugTracing = false;
     }
 
     private CacheDataUpdatedTask newTask(int op, String... pkg) {
@@ -122,7 +114,6 @@
         // Verify that only app1 var updated in allAppsList
         assertFalse(mModelHelper.getAllAppsList().data.isEmpty());
         for (AppInfo info : mModelHelper.getAllAppsList().data) {
-            Log.i(INCORRECT_INFO_UPDATED, "testCacheUpdate_update_apps: checking info=" + info);
             if (info.componentName.getPackageName().equals("app1")) {
                 assertFalse(info.bitmap.isNullOrLowRes());
             } else {
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
index 76a186b..dcc8ec7 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
+++ b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
@@ -17,7 +17,7 @@
 
 import android.content.Context
 import android.content.Intent
-import android.database.Cursor;
+import android.database.Cursor
 import android.database.sqlite.SQLiteDatabase
 import android.graphics.Point
 import android.os.Process
@@ -38,7 +38,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
-/** Unit tests for [GridSizeMigrationUtil]  */
+/** Unit tests for [GridSizeMigrationUtil] */
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class GridSizeMigrationUtilTest {
@@ -64,19 +64,20 @@
         context = modelHelper.sandboxContext
         db = modelHelper.provider.db
 
-        validPackages = setOf(
-            TEST_PACKAGE,
-            testPackage1,
-            testPackage2,
-            testPackage3,
-            testPackage4,
-            testPackage5,
-            testPackage6,
-            testPackage7,
-            testPackage8,
-            testPackage9,
-            testPackage10
-        )
+        validPackages =
+            setOf(
+                TEST_PACKAGE,
+                testPackage1,
+                testPackage2,
+                testPackage3,
+                testPackage4,
+                testPackage5,
+                testPackage6,
+                testPackage7,
+                testPackage8,
+                testPackage9,
+                testPackage10
+            )
 
         idp = InvariantDeviceProfile.INSTANCE[context]
         val userSerial = UserCache.INSTANCE[context].getSerialNumberForUser(Process.myUserHandle())
@@ -90,8 +91,8 @@
     }
 
     /**
-     * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is
-     * not needed anymore
+     * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
+     * needed anymore
      */
     @Test
     @Throws(Exception::class)
@@ -124,25 +125,27 @@
         val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
         val destReader = DbReader(db, TABLE_NAME, context, validPackages)
         GridSizeMigrationUtil.migrate(
-                context,
-                db,
-                srcReader,
-                destReader,
-                idp.numDatabaseHotseatIcons,
-                Point(idp.numColumns, idp.numRows),
-                DeviceGridState(context),
-                DeviceGridState(idp)
+            context,
+            db,
+            srcReader,
+            destReader,
+            idp.numDatabaseHotseatIcons,
+            Point(idp.numColumns, idp.numRows),
+            DeviceGridState(context),
+            DeviceGridState(idp)
         )
 
         // Check hotseat items
-        var c = context.contentResolver.query(
-            CONTENT_URI,
-            arrayOf(SCREEN, INTENT),
-            "container=$CONTAINER_HOTSEAT",
-            null,
-            SCREEN,
-            null
-        ) ?: throw IllegalStateException()
+        var c =
+            context.contentResolver.query(
+                CONTENT_URI,
+                arrayOf(SCREEN, INTENT),
+                "container=$CONTAINER_HOTSEAT",
+                null,
+                SCREEN,
+                null
+            )
+                ?: throw IllegalStateException()
 
         assertThat(c.count).isEqualTo(idp.numDatabaseHotseatIcons)
 
@@ -163,14 +166,16 @@
         c.close()
 
         // Check workspace items
-        c = context.contentResolver.query(
-            CONTENT_URI,
-            arrayOf(CELLX, CELLY, INTENT),
-            "container=$CONTAINER_DESKTOP",
-            null,
-            null,
-            null
-        ) ?: throw IllegalStateException()
+        c =
+            context.contentResolver.query(
+                CONTENT_URI,
+                arrayOf(CELLX, CELLY, INTENT),
+                "container=$CONTAINER_DESKTOP",
+                null,
+                null,
+                null
+            )
+                ?: throw IllegalStateException()
 
         intentIndex = c.getColumnIndex(INTENT)
         val cellXIndex = c.getColumnIndex(CELLX)
@@ -195,8 +200,8 @@
     }
 
     /**
-     * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is
-     * not needed anymore
+     * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
+     * needed anymore
      */
     @Test
     @Throws(Exception::class)
@@ -235,39 +240,46 @@
         val readerGridB = DbReader(db, TABLE_NAME, context, validPackages)
         // migrate from A -> B
         GridSizeMigrationUtil.migrate(
-                context,
-                db,
-                readerGridA,
-                readerGridB,
-                idp.numDatabaseHotseatIcons,
-                Point(idp.numColumns, idp.numRows),
-                DeviceGridState(context),
-                DeviceGridState(idp)
+            context,
+            db,
+            readerGridA,
+            readerGridB,
+            idp.numDatabaseHotseatIcons,
+            Point(idp.numColumns, idp.numRows),
+            DeviceGridState(context),
+            DeviceGridState(idp)
         )
 
         // Check hotseat items in grid B
-        var c = context.contentResolver.query(
+        var c =
+            context.contentResolver.query(
                 CONTENT_URI,
                 arrayOf(SCREEN, INTENT),
                 "container=$CONTAINER_HOTSEAT",
                 null,
                 SCREEN,
                 null
-        ) ?: throw IllegalStateException()
+            )
+                ?: throw IllegalStateException()
         // Expected hotseat items in grid B
         // 2 1 3 4
-        verifyHotseat(c, idp,
-                mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList())
+        verifyHotseat(
+            c,
+            idp,
+            mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList()
+        )
 
         // Check workspace items in grid B
-        c = context.contentResolver.query(
+        c =
+            context.contentResolver.query(
                 CONTENT_URI,
                 arrayOf(SCREEN, CELLX, CELLY, INTENT),
                 "container=$CONTAINER_DESKTOP",
                 null,
                 null,
                 null
-        ) ?: throw IllegalStateException()
+            )
+                ?: throw IllegalStateException()
         var locMap = parseLocMap(context, c)
         // Expected items in grid B
         // _ _ _ _
@@ -285,38 +297,45 @@
 
         // migrate from B -> A
         GridSizeMigrationUtil.migrate(
-                context,
-                db,
-                readerGridB,
-                readerGridA,
-                5,
-                Point(5, 5),
-                DeviceGridState(idp),
-                DeviceGridState(context)
+            context,
+            db,
+            readerGridB,
+            readerGridA,
+            5,
+            Point(5, 5),
+            DeviceGridState(idp),
+            DeviceGridState(context)
         )
         // Check hotseat items in grid A
-        c = context.contentResolver.query(
+        c =
+            context.contentResolver.query(
                 TMP_CONTENT_URI,
                 arrayOf(SCREEN, INTENT),
                 "container=$CONTAINER_HOTSEAT",
                 null,
                 SCREEN,
                 null
-        ) ?: throw IllegalStateException()
+            )
+                ?: throw IllegalStateException()
         // Expected hotseat items in grid A
         // 1 2 _ 3 4
-        verifyHotseat(c, idp, mutableListOf(
-                testPackage1, testPackage2, null, testPackage3, testPackage4).toList())
+        verifyHotseat(
+            c,
+            idp,
+            mutableListOf(testPackage1, testPackage2, null, testPackage3, testPackage4).toList()
+        )
 
         // Check workspace items in grid A
-        c = context.contentResolver.query(
+        c =
+            context.contentResolver.query(
                 TMP_CONTENT_URI,
                 arrayOf(SCREEN, CELLX, CELLY, INTENT),
                 "container=$CONTAINER_DESKTOP",
                 null,
                 null,
                 null
-        ) ?: throw IllegalStateException()
+            )
+                ?: throw IllegalStateException()
         locMap = parseLocMap(context, c)
         // Expected workspace items in grid A
         // _ _ _ _ _
@@ -338,39 +357,46 @@
 
         // migrate from A -> B
         GridSizeMigrationUtil.migrate(
-                context,
-                db,
-                readerGridA,
-                readerGridB,
-                idp.numDatabaseHotseatIcons,
-                Point(idp.numColumns, idp.numRows),
-                DeviceGridState(context),
-                DeviceGridState(idp)
+            context,
+            db,
+            readerGridA,
+            readerGridB,
+            idp.numDatabaseHotseatIcons,
+            Point(idp.numColumns, idp.numRows),
+            DeviceGridState(context),
+            DeviceGridState(idp)
         )
 
         // Check hotseat items in grid B
-        c = context.contentResolver.query(
+        c =
+            context.contentResolver.query(
                 CONTENT_URI,
                 arrayOf(SCREEN, INTENT),
                 "container=$CONTAINER_HOTSEAT",
                 null,
                 SCREEN,
                 null
-        ) ?: throw IllegalStateException()
+            )
+                ?: throw IllegalStateException()
         // Expected hotseat items in grid B
         // 2 1 3 4
-        verifyHotseat(c, idp,
-                mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList())
+        verifyHotseat(
+            c,
+            idp,
+            mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList()
+        )
 
         // Check workspace items in grid B
-        c = context.contentResolver.query(
+        c =
+            context.contentResolver.query(
                 CONTENT_URI,
                 arrayOf(SCREEN, CELLX, CELLY, INTENT),
                 "container=$CONTAINER_DESKTOP",
                 null,
                 null,
                 null
-        ) ?: throw IllegalStateException()
+            )
+                ?: throw IllegalStateException()
         locMap = parseLocMap(context, c)
         // Expected workspace items in grid B
         // _ _ _ _
@@ -406,7 +432,7 @@
         val locMap = mutableMapOf<String, Triple<Int, Int, Int>>()
         while (c.moveToNext()) {
             locMap[Intent.parseUri(c.getString(intentIndex), 0).getPackage()] =
-                    Triple(c.getInt(screenIndex), c.getInt(cellXIndex), c.getInt(cellYIndex))
+                Triple(c.getInt(screenIndex), c.getInt(cellXIndex), c.getInt(cellYIndex))
         }
         c.close()
         return locMap.toMap()
@@ -414,12 +440,13 @@
 
     @Test
     fun migrateToLargerHotseat() {
-        val srcHotseatItems = intArrayOf(
-            modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
-            modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
-            modelHelper.addItem(APP_ICON, 2, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI),
-            modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI)
-        )
+        val srcHotseatItems =
+            intArrayOf(
+                modelHelper.addItem(APP_ICON, 0, HOTSEAT, 0, 0, testPackage1, 1, TMP_CONTENT_URI),
+                modelHelper.addItem(SHORTCUT, 1, HOTSEAT, 0, 0, testPackage2, 2, TMP_CONTENT_URI),
+                modelHelper.addItem(APP_ICON, 2, HOTSEAT, 0, 0, testPackage3, 3, TMP_CONTENT_URI),
+                modelHelper.addItem(SHORTCUT, 3, HOTSEAT, 0, 0, testPackage4, 4, TMP_CONTENT_URI)
+            )
         val numSrcDatabaseHotseatIcons = srcHotseatItems.size
         idp.numDatabaseHotseatIcons = 6
         idp.numColumns = 4
@@ -427,25 +454,27 @@
         val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
         val destReader = DbReader(db, TABLE_NAME, context, validPackages)
         GridSizeMigrationUtil.migrate(
-                context,
-                db,
-                srcReader,
-                destReader,
-                idp.numDatabaseHotseatIcons,
-                Point(idp.numColumns, idp.numRows),
-                DeviceGridState(context),
-                DeviceGridState(idp)
+            context,
+            db,
+            srcReader,
+            destReader,
+            idp.numDatabaseHotseatIcons,
+            Point(idp.numColumns, idp.numRows),
+            DeviceGridState(context),
+            DeviceGridState(idp)
         )
 
         // Check hotseat items
-        val c = context.contentResolver.query(
-            CONTENT_URI,
-            arrayOf(SCREEN, INTENT),
-            "container=$CONTAINER_HOTSEAT",
-            null,
-            SCREEN,
-            null
-        ) ?: throw IllegalStateException()
+        val c =
+            context.contentResolver.query(
+                CONTENT_URI,
+                arrayOf(SCREEN, INTENT),
+                "container=$CONTAINER_HOTSEAT",
+                null,
+                SCREEN,
+                null
+            )
+                ?: throw IllegalStateException()
 
         assertThat(c.count.toLong()).isEqualTo(numSrcDatabaseHotseatIcons.toLong())
         val screenIndex = c.getColumnIndex(SCREEN)
@@ -483,25 +512,27 @@
         val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
         val destReader = DbReader(db, TABLE_NAME, context, validPackages)
         GridSizeMigrationUtil.migrate(
-                context,
-                db,
-                srcReader,
-                destReader,
-                idp.numDatabaseHotseatIcons,
-                Point(idp.numColumns, idp.numRows),
-                DeviceGridState(context),
-                DeviceGridState(idp)
+            context,
+            db,
+            srcReader,
+            destReader,
+            idp.numDatabaseHotseatIcons,
+            Point(idp.numColumns, idp.numRows),
+            DeviceGridState(context),
+            DeviceGridState(idp)
         )
 
         // Check hotseat items
-        val c = context.contentResolver.query(
-            CONTENT_URI,
-            arrayOf(SCREEN, INTENT),
-            "container=$CONTAINER_HOTSEAT",
-            null,
-            SCREEN,
-            null
-        ) ?: throw IllegalStateException()
+        val c =
+            context.contentResolver.query(
+                CONTENT_URI,
+                arrayOf(SCREEN, INTENT),
+                "container=$CONTAINER_HOTSEAT",
+                null,
+                SCREEN,
+                null
+            )
+                ?: throw IllegalStateException()
 
         assertThat(c.count.toLong()).isEqualTo(idp.numDatabaseHotseatIcons.toLong())
         val screenIndex = c.getColumnIndex(SCREEN)
@@ -527,8 +558,8 @@
     }
 
     /**
-     * Migrating from a smaller grid to a large one should keep the pages
-     * if the column difference is less than 2
+     * Migrating from a smaller grid to a large one should keep the pages if the column difference
+     * is less than 2
      */
     @Test
     @Throws(Exception::class)
@@ -549,25 +580,27 @@
         val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
         val destReader = DbReader(db, TABLE_NAME, context, validPackages)
         GridSizeMigrationUtil.migrate(
-                context,
-                db,
-                srcReader,
-                destReader,
-                idp.numDatabaseHotseatIcons,
-                Point(idp.numColumns, idp.numRows),
-                DeviceGridState(context),
-                DeviceGridState(idp)
+            context,
+            db,
+            srcReader,
+            destReader,
+            idp.numDatabaseHotseatIcons,
+            Point(idp.numColumns, idp.numRows),
+            DeviceGridState(context),
+            DeviceGridState(idp)
         )
 
         // Get workspace items
-        val c = context.contentResolver.query(
-            CONTENT_URI,
-            arrayOf(INTENT, SCREEN),
-            "container=$CONTAINER_DESKTOP",
-            null,
-            null,
-            null
-        ) ?: throw IllegalStateException()
+        val c =
+            context.contentResolver.query(
+                CONTENT_URI,
+                arrayOf(INTENT, SCREEN),
+                "container=$CONTAINER_DESKTOP",
+                null,
+                null,
+                null
+            )
+                ?: throw IllegalStateException()
         val intentIndex = c.getColumnIndex(INTENT)
         val screenIndex = c.getColumnIndex(SCREEN)
 
@@ -589,8 +622,8 @@
     }
 
     /**
-     * Migrating from a smaller grid to a large one should reflow the pages
-     * if the column difference is more than 2
+     * Migrating from a smaller grid to a large one should reflow the pages if the column difference
+     * is more than 2
      */
     @Test
     @Throws(Exception::class)
@@ -610,25 +643,27 @@
         val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
         val destReader = DbReader(db, TABLE_NAME, context, validPackages)
         GridSizeMigrationUtil.migrate(
-                context,
-                db,
-                srcReader,
-                destReader,
-                idp.numDatabaseHotseatIcons,
-                Point(idp.numColumns, idp.numRows),
-                DeviceGridState(context),
-                DeviceGridState(idp)
+            context,
+            db,
+            srcReader,
+            destReader,
+            idp.numDatabaseHotseatIcons,
+            Point(idp.numColumns, idp.numRows),
+            DeviceGridState(context),
+            DeviceGridState(idp)
         )
 
         // Get workspace items
-        val c = context.contentResolver.query(
-            CONTENT_URI,
-            arrayOf(INTENT, SCREEN),
-            "container=$CONTAINER_DESKTOP",
-            null,
-            null,
-            null
-        ) ?: throw IllegalStateException()
+        val c =
+            context.contentResolver.query(
+                CONTENT_URI,
+                arrayOf(INTENT, SCREEN),
+                "container=$CONTAINER_DESKTOP",
+                null,
+                null,
+                null
+            )
+                ?: throw IllegalStateException()
 
         val intentIndex = c.getColumnIndex(INTENT)
         val screenIndex = c.getColumnIndex(SCREEN)
@@ -651,9 +686,7 @@
         disableNewMigrationLogic()
     }
 
-    /**
-     * Migrating from a larger grid to a smaller, we reflow from page 0
-     */
+    /** Migrating from a larger grid to a smaller, we reflow from page 0 */
     @Test
     @Throws(Exception::class)
     fun migrateFromLargerGrid() {
@@ -672,25 +705,27 @@
         val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
         val destReader = DbReader(db, TABLE_NAME, context, validPackages)
         GridSizeMigrationUtil.migrate(
-                context,
-                db,
-                srcReader,
-                destReader,
-                idp.numDatabaseHotseatIcons,
-                Point(idp.numColumns, idp.numRows),
-                DeviceGridState(context),
-                DeviceGridState(idp)
+            context,
+            db,
+            srcReader,
+            destReader,
+            idp.numDatabaseHotseatIcons,
+            Point(idp.numColumns, idp.numRows),
+            DeviceGridState(context),
+            DeviceGridState(idp)
         )
 
         // Get workspace items
-        val c = context.contentResolver.query(
-            CONTENT_URI,
-            arrayOf(INTENT, SCREEN),
-            "container=$CONTAINER_DESKTOP",
-            null,
-            null,
-            null
-        ) ?: throw IllegalStateException()
+        val c =
+            context.contentResolver.query(
+                CONTENT_URI,
+                arrayOf(INTENT, SCREEN),
+                "container=$CONTAINER_DESKTOP",
+                null,
+                null,
+                null
+            )
+                ?: throw IllegalStateException()
         val intentIndex = c.getColumnIndex(INTENT)
         val screenIndex = c.getColumnIndex(SCREEN)
 
@@ -714,11 +749,13 @@
     }
 
     private fun enableNewMigrationLogic(srcGridSize: String) {
-        context.getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
+        context
+            .getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
             .edit()
             .putBoolean(FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.key, true)
             .commit()
-        context.getSharedPreferences(LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
+        context
+            .getSharedPreferences(LauncherFiles.SHARED_PREFERENCES_KEY, Context.MODE_PRIVATE)
             .edit()
             .putString(DeviceGridState.KEY_WORKSPACE_SIZE, srcGridSize)
             .commit()
@@ -726,9 +763,10 @@
     }
 
     private fun disableNewMigrationLogic() {
-        context.getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
+        context
+            .getSharedPreferences(FeatureFlags.FLAGS_PREF_NAME, Context.MODE_PRIVATE)
             .edit()
             .putBoolean(FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.key, false)
             .commit()
     }
-}
\ No newline at end of file
+}
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
index bfb1ac6..b3d02be 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemSpaceFinderTest.kt
@@ -24,9 +24,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
-/**
- * Tests for [WorkspaceItemSpaceFinder]
- */
+/** Tests for [WorkspaceItemSpaceFinder] */
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class WorkspaceItemSpaceFinderTest : AbstractWorkspaceModelTest() {
@@ -44,17 +42,27 @@
     }
 
     private fun findSpace(spanX: Int, spanY: Int): NewItemSpace =
-        mItemSpaceFinder.findSpaceForItem(
-            mAppState, mModelHelper.bgDataModel,
-            mExistingScreens, mNewScreens, spanX, spanY
-        )
+        mItemSpaceFinder
+            .findSpaceForItem(
+                mAppState,
+                mModelHelper.bgDataModel,
+                mExistingScreens,
+                mNewScreens,
+                spanX,
+                spanY
+            )
             .let { NewItemSpace.fromIntArray(it) }
 
     private fun assertRegionVacant(newItemSpace: NewItemSpace, spanX: Int, spanY: Int) {
         assertThat(
-            mScreenOccupancy[newItemSpace.screenId]
-                .isRegionVacant(newItemSpace.cellX, newItemSpace.cellY, spanX, spanY)
-        ).isTrue()
+                mScreenOccupancy[newItemSpace.screenId].isRegionVacant(
+                    newItemSpace.cellX,
+                    newItemSpace.cellY,
+                    spanX,
+                    spanY
+                )
+            )
+            .isTrue()
     }
 
     @Test
diff --git a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
index c99ad76..951f5f8 100644
--- a/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
+++ b/tests/src/com/android/launcher3/nonquickstep/HotseatWidthCalculationTest.kt
@@ -29,8 +29,8 @@
 class HotseatWidthCalculationTest : DeviceProfileBaseTest() {
 
     /**
-     * This is a case when after setting the hotseat, the space needs to be recalculated
-     * but it doesn't need to change QSB width or remove icons
+     * This is a case when after setting the hotseat, the space needs to be recalculated but it
+     * doesn't need to change QSB width or remove icons
      */
     @Test
     fun distribute_border_space_when_space_is_enough_portrait() {
@@ -51,8 +51,8 @@
     }
 
     /**
-     * This is a case when after setting the hotseat, and recalculating spaces
-     * it still needs to remove icons for everything to fit
+     * This is a case when after setting the hotseat, and recalculating spaces it still needs to
+     * remove icons for everything to fit
      */
     @Test
     fun decrease_num_of_icons_when_not_enough_space_portrait() {
@@ -73,8 +73,8 @@
     }
 
     /**
-     * This is a case when after setting the hotseat, the space needs to be recalculated
-     * but it doesn't need to change QSB width or remove icons
+     * This is a case when after setting the hotseat, the space needs to be recalculated but it
+     * doesn't need to change QSB width or remove icons
      */
     @Test
     fun distribute_border_space_when_space_is_enough_landscape() {
@@ -94,8 +94,8 @@
     }
 
     /**
-     * This is a case when the hotseat spans a certain amount of columns
-     * and the nav buttons push the hotseat to the side, but not enough to change the border space.
+     * This is a case when the hotseat spans a certain amount of columns and the nav buttons push
+     * the hotseat to the side, but not enough to change the border space.
      */
     @Test
     fun nav_buttons_dont_interfere_with_required_hotseat_width() {
@@ -118,9 +118,7 @@
         assertThat(dp.hotseatQsbWidth).isEqualTo(1224)
     }
 
-    /**
-     * This is a case when after setting the hotseat, the QSB width needs to be changed to fit
-     */
+    /** This is a case when after setting the hotseat, the QSB width needs to be changed to fit */
     @Test
     fun decrease_qsb_when_not_enough_space_landscape() {
         initializeVarsForTablet(isGestureMode = false, isLandscape = true)
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 50e0990..e1a2c1b 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -195,6 +195,15 @@
 
     @Test
     @PortraitLandscape
+    public void testAllAppsSwitchToWorkspace() {
+        assertNotNull("switchToWorkspace() returned null",
+                mLauncher.getWorkspace().switchToAllApps().switchToWorkspace());
+        assertTrue("Launcher internal state is not Workspace",
+                isInState(() -> LauncherState.NORMAL));
+    }
+
+    @Test
+    @PortraitLandscape
     public void testAllAppsDeadzoneForTablet() throws Exception {
         assumeTrue(mLauncher.isTablet());
 
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index 302bd2f..c7628cc 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -38,6 +38,7 @@
 
 import org.junit.After;
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Test;
 
 import java.util.Objects;
@@ -118,6 +119,7 @@
     }
 
     @Test
+    @Ignore("b/243855320")
     public void toggleWorks() {
         assumeTrue(mWorkProfileSetupSuccessful);
         waitForWorkTabSetup();
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 3f4a1c1..2c9785c 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -37,7 +37,6 @@
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -65,7 +64,6 @@
         mAppWidgetManager = AppWidgetManager.getInstance(mTargetContext);
     }
 
-    @Ignore
     @Test
     @PortraitLandscape
     public void testWidgetConfig() throws Throwable {
diff --git a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
index 9d5763b..7ba0b53 100644
--- a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
@@ -36,9 +36,7 @@
 import com.android.launcher3.ui.AbstractLauncherUiTest;
 import com.android.launcher3.ui.TaplTestsLauncher3;
 import com.android.launcher3.util.Executors;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
 
-import org.junit.Ignore;
 import org.junit.Test;
 
 import java.util.ArrayDeque;
@@ -52,7 +50,7 @@
 @LargeTest
 public class ThemeIconsTest extends AbstractLauncherUiTest {
 
-    private static final String APP_NAME = "ThemeIconTestActivity";
+    private static final String APP_NAME = "IconThemedActivity";
     private static final String SHORTCUT_APP_NAME = "LauncherTestApp";
     private static final String SHORTCUT_NAME = "Shortcut 1";
 
@@ -111,9 +109,7 @@
         }
     }
 
-    @Ignore
     @Test
-    @ScreenRecord // b/260722220
     public void testShortcutIconWithTheme() throws Exception {
         setThemeEnabled(true);
         TaplTestsLauncher3.initialize(this);
diff --git a/tests/src/com/android/launcher3/util/KotlinMockitoHelpers.kt b/tests/src/com/android/launcher3/util/KotlinMockitoHelpers.kt
index 57db13a..4303bfb 100644
--- a/tests/src/com/android/launcher3/util/KotlinMockitoHelpers.kt
+++ b/tests/src/com/android/launcher3/util/KotlinMockitoHelpers.kt
@@ -22,43 +22,41 @@
  * be null"). To fix this, we can use methods that modify the return type to be nullable. This
  * causes Kotlin to skip the null checks.
  */
-
 import org.mockito.ArgumentCaptor
 import org.mockito.Mockito
 
 /**
- * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when
- * null is returned.
+ * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when null is
+ * returned.
  *
  * Generic T is nullable because implicitly bounded by Any?.
  */
 fun <T> eq(obj: T): T = Mockito.eq<T>(obj)
 
 /**
- * Returns Mockito.same() as nullable type to avoid java.lang.IllegalStateException when
- * null is returned.
+ * Returns Mockito.same() as nullable type to avoid java.lang.IllegalStateException when null is
+ * returned.
  *
  * Generic T is nullable because implicitly bounded by Any?.
  */
 fun <T> same(obj: T): T = Mockito.same<T>(obj)
 
 /**
- * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when
- * null is returned.
+ * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when null is
+ * returned.
  *
  * Generic T is nullable because implicitly bounded by Any?.
  */
 fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
+
 inline fun <reified T> any(): T = any(T::class.java)
 
-/**
- * Kotlin type-inferred version of Mockito.nullable()
- */
+/** Kotlin type-inferred version of Mockito.nullable() */
 inline fun <reified T> nullable(): T? = Mockito.nullable(T::class.java)
 
 /**
- * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException
- * when null is returned.
+ * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException when
+ * null is returned.
  *
  * Generic T is nullable because implicitly bounded by Any?.
  */
@@ -82,8 +80,9 @@
 /**
  * A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when
  * kotlin tests are mocking kotlin objects and the methods take non-null parameters:
- *
+ * ```
  *     java.lang.NullPointerException: capture() must not be null
+ * ```
  */
 class KotlinArgumentCaptor<T> constructor(clazz: Class<T>) {
     private val wrapped: ArgumentCaptor<T> = ArgumentCaptor.forClass(clazz)
@@ -102,15 +101,15 @@
 
 /**
  * Helper function for creating and using a single-use ArgumentCaptor in kotlin.
- *
+ * ```
  *    val captor = argumentCaptor<Foo>()
  *    verify(...).someMethod(captor.capture())
  *    val captured = captor.value
- *
+ * ```
  * becomes:
- *
+ * ```
  *    val captured = withArgCaptor<Foo> { verify(...).someMethod(capture()) }
- *
+ * ```
  * NOTE: this uses the KotlinArgumentCaptor to avoid the NullPointerException.
  */
 inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T =
diff --git a/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt b/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt
index bf3a092..a63136e 100644
--- a/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt
+++ b/tests/src/com/android/launcher3/util/MultiPropertyFactoryTest.kt
@@ -30,18 +30,18 @@
 
     private val received = mutableListOf<Float>()
 
-    private val receiveProperty: FloatProperty<Any> = object : FloatProperty<Any>("receive") {
-        override fun setValue(obj: Any?, value: Float) {
-            received.add(value)
+    private val receiveProperty: FloatProperty<Any> =
+        object : FloatProperty<Any>("receive") {
+            override fun setValue(obj: Any?, value: Float) {
+                received.add(value)
+            }
+            override fun get(o: Any): Float {
+                return 0f
+            }
         }
-        override fun get(o: Any): Float {
-            return 0f
-        }
-    }
 
-    private val factory = MultiPropertyFactory(null, receiveProperty, 3) {
-        x: Float, y: Float -> x + y
-    }
+    private val factory =
+        MultiPropertyFactory(null, receiveProperty, 3) { x: Float, y: Float -> x + y }
 
     private val p1 = factory.get(0)
     private val p2 = factory.get(1)
diff --git a/tests/src/com/android/launcher3/util/TouchUtilTest.kt b/tests/src/com/android/launcher3/util/TouchUtilTest.kt
index d6c6e91..235d6ec 100644
--- a/tests/src/com/android/launcher3/util/TouchUtilTest.kt
+++ b/tests/src/com/android/launcher3/util/TouchUtilTest.kt
@@ -18,9 +18,9 @@
 
 import android.view.InputDevice
 import android.view.MotionEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.google.common.truth.Truth.assertThat
-import androidx.test.ext.junit.runners.AndroidJUnit4
 import org.junit.Test
 import org.junit.runner.RunWith
 
diff --git a/tests/src/com/android/launcher3/util/WidgetUtils.java b/tests/src/com/android/launcher3/util/WidgetUtils.java
index e514142..b0df055 100644
--- a/tests/src/com/android/launcher3/util/WidgetUtils.java
+++ b/tests/src/com/android/launcher3/util/WidgetUtils.java
@@ -70,7 +70,7 @@
             pendingInfo.minSpanY = item.minSpanY;
             Bundle options = pendingInfo.getDefaultSizeOptions(targetContext);
 
-            LauncherWidgetHolder holder = new LauncherWidgetHolder(targetContext);
+            LauncherWidgetHolder holder = LauncherWidgetHolder.newInstance(targetContext);
             try {
                 int widgetId = holder.allocateAppWidgetId();
                 if (!new WidgetManagerHelper(targetContext)
diff --git a/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java b/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
index 98eb32e..10afe13 100644
--- a/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
+++ b/tests/tapl/com/android/launcher3/tapl/AddToHomeScreenPrompt.java
@@ -45,7 +45,8 @@
             mLauncher.clickObject(
                     mLauncher.waitForObjectInContainer(
                             mWidgetCell.getParent().getParent().getParent().getParent(),
-                            By.text(ADD_AUTOMATICALLY)));
+                            By.text(ADD_AUTOMATICALLY)),
+                    LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER);
             mLauncher.waitUntilLauncherObjectGone(getSelector());
         }
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java
index b0cf20f..6f6428a 100644
--- a/tests/tapl/com/android/launcher3/tapl/AllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java
@@ -244,7 +244,7 @@
         return mLauncher.waitForObjectInContainer(allAppsContainer, "apps_list_view");
     }
 
-    private UiObject2 getSearchBox(UiObject2 allAppsContainer) {
+    protected UiObject2 getSearchBox(UiObject2 allAppsContainer) {
         return mLauncher.waitForObjectInContainer(allAppsContainer, "search_container_all_apps");
     }
 
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
index 9a4c6d4..50b03aa 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAllApps.java
@@ -15,11 +15,17 @@
  */
 package com.android.launcher3.tapl;
 
+import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
+
+import android.graphics.Rect;
+
 import androidx.annotation.NonNull;
 import androidx.test.uiautomator.UiObject2;
 
 import com.android.launcher3.testing.shared.TestProtocol;
 
+import java.util.Objects;
+
 public class HomeAllApps extends AllApps {
     private static final String BOTTOM_SHEET_RES_ID = "bottom_sheet_background";
 
@@ -27,6 +33,42 @@
         super(launcher);
     }
 
+    /**
+     * Swipes down to Workspace.
+     *
+     * @return the Workspace object.
+     */
+    @NonNull
+    public Workspace switchToWorkspace() {
+        try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+             LauncherInstrumentation.Closable c =
+                     mLauncher.addContextLayer("want to switch from all apps to workspace")) {
+            UiObject2 allAppsContainer = verifyActiveContainer();
+
+            final Rect searchBoxBounds = Objects.requireNonNull(
+                    mLauncher.getVisibleBounds(getSearchBox(allAppsContainer)));
+            final int startX = searchBoxBounds.centerX();
+            final int startY = searchBoxBounds.bottom;
+            final int endY = mLauncher.getDevice().getDisplayHeight();
+            LauncherInstrumentation.log(
+                    "switchToWorkspace: startY = " + startY + ", endY = " + endY
+                            + ", slop = " + mLauncher.getTouchSlop());
+
+            mLauncher.swipeToState(
+                    startX,
+                    startY,
+                    startX,
+                    endY,
+                    12 /* steps */,
+                    NORMAL_STATE_ORDINAL, LauncherInstrumentation.GestureScope.INSIDE);
+
+            try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
+                    "swiped to workspace")) {
+                return mLauncher.getWorkspace();
+            }
+        }
+    }
+
     @Override
     protected LauncherInstrumentation.ContainerType getContainerType() {
         return LauncherInstrumentation.ContainerType.HOME_ALL_APPS;
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 302fabd..ae9ba67 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1466,19 +1466,22 @@
         return getRealDisplaySize().x - getWindowInsets().right - 1;
     }
 
-    void clickObject(UiObject2 object) {
-        waitForObjectEnabled(object, "clickObject");
-        if (!isLauncher3() && getNavigationModel() != NavigationModel.THREE_BUTTON) {
-            expectEvent(TestProtocol.SEQUENCE_TIS, LauncherInstrumentation.EVENT_TOUCH_DOWN_TIS);
-            expectEvent(TestProtocol.SEQUENCE_TIS, LauncherInstrumentation.EVENT_TOUCH_UP_TIS);
-        }
-        object.click();
+    /**
+     * Click on the ui object right away without waiting for animation.
+     *
+     * [UiObject2.click] would wait for all animations finished before clicking. Not waiting for
+     * animations because in some scenarios there is a playing animations when the click is
+     * attempted.
+     */
+    void clickObject(UiObject2 uiObject, GestureScope gestureScope) {
+        final long clickTime = SystemClock.uptimeMillis();
+        final Point center = uiObject.getVisibleCenter();
+        sendPointer(clickTime, clickTime, MotionEvent.ACTION_DOWN, center, gestureScope);
+        sendPointer(clickTime, clickTime, MotionEvent.ACTION_UP, center, gestureScope);
     }
 
     void clickLauncherObject(UiObject2 object) {
-        expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_TOUCH_DOWN);
-        expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_TOUCH_UP);
-        clickObject(object);
+        clickObject(object, GestureScope.INSIDE);
     }
 
     void scrollToLastVisibleRow(
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index b2a2937..2c82c50 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -385,7 +385,7 @@
                     Until.hasObject(installerAlert), LauncherInstrumentation.WAIT_TIME_MS));
             final UiObject2 ok = device.findObject(By.text("OK"));
             assertNotNull("OK button is not shown", ok);
-            launcher.clickObject(ok);
+            launcher.clickObject(ok, LauncherInstrumentation.GestureScope.OUTSIDE_WITHOUT_PILFER);
             assertTrue("Uninstall alert is not dismissed after clicking OK", device.wait(
                     Until.gone(installerAlert), LauncherInstrumentation.WAIT_TIME_MS));