Merge "Do not run unfold taskbar animation when in portrait" into tm-dev
diff --git a/Android.bp b/Android.bp
index f5a38b4..c980a2e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -31,6 +31,7 @@
         "androidx.test.uiautomator_uiautomator",
         "androidx.preference_preference",
         "SystemUISharedLib",
+        "SystemUIAnimationLib",
     ],
     srcs: [
         "tests/tapl/**/*.java",
@@ -196,6 +197,7 @@
         "lottie",
         "SystemUISharedLib",
         "SystemUI-statsd",
+        "SystemUIAnimationLib",
     ],
     manifest: "quickstep/AndroidManifest.xml",
     min_sdk_version: "current",
@@ -287,6 +289,7 @@
         "SystemUISharedLib",
         "Launcher3CommonDepsLib",
         "QuickstepResLib",
+        "SystemUIAnimationLib",
     ],
     manifest: "quickstep/AndroidManifest.xml",
     platform_apis: true,
diff --git a/go/quickstep/res/values-or/strings.xml b/go/quickstep/res/values-or/strings.xml
index 36204a3..2e76e2d 100644
--- a/go/quickstep/res/values-or/strings.xml
+++ b/go/quickstep/res/values-or/strings.xml
@@ -7,13 +7,13 @@
     <string name="action_search" msgid="6269564710943755464">"Lens"</string>
     <string name="dialog_acknowledge" msgid="2804025517675853172">"ବୁଝିଗଲି"</string>
     <string name="dialog_cancel" msgid="6464336969134856366">"ବାତିଲ୍ କରନ୍ତୁ"</string>
-    <string name="dialog_settings" msgid="6564397136021186148">"ସେଟିଂସ୍"</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="niu_actions_confirmation_text" msgid="2105271481950866089">"ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଟେକ୍ସଟ, ୱେବ ଠିକଣା ଏବଂ ସ୍କ୍ରିନସଟଗୁଡ଼ିକ ପରି ସୂଚନାକୁ Google ସହ ସେୟାର କରାଯାଇପାରେ।\n\nଆପଣ କେଉଁ ସୂଚନାକୁ ସେୟାର କରନ୍ତି ତାହା ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ, "<b>"ସେଟିଂସ &gt; ଆପ୍ସ &gt; ଡିଫଲ୍ଟ ଆପ୍ସ &gt; Digital assistant ଆପ"</b>"କୁ ଯାଆନ୍ତୁ।"</string>
     <string name="assistant_not_selected_title" msgid="5017072974603345228">"ଏହି ଫିଚର୍ ବ୍ୟବହାର କରିବାକୁ ଏକ ଆସିଷ୍ଟାଣ୍ଟ ବାଛନ୍ତୁ"</string>
-    <string name="assistant_not_selected_text" msgid="3244613673884359276">"ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଥିବା ଟେକ୍ସଟକୁ ଶୁଣିବା ପାଇଁ କିମ୍ବା ଅନୁବାଦ କରିବାକୁ, ସେଟିଂସରେ ଏକ ଡିଜିଟାଲ୍ ଆସିଷ୍ଟାଣ୍ଟ ଆପ୍ ଚୟନ କରନ୍ତୁ"</string>
+    <string name="assistant_not_selected_text" msgid="3244613673884359276">"ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଥିବା ଟେକ୍ସଟକୁ ଶୁଣିବା କିମ୍ବା ଅନୁବାଦ କରିବା ପାଇଁ, ସେଟିଂସରେ ଏକ digital assistant ଆପ ବାଛନ୍ତୁ"</string>
     <string name="assistant_not_supported_title" msgid="1675788067597484142">"ଏହି ଫିଚର୍ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପଣଙ୍କ ଆସିଷ୍ଟାଣ୍ଟକୁ ବଦଳାନ୍ତୁ"</string>
-    <string name="assistant_not_supported_text" msgid="1708031078549268884">"ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଥିବା ଟେକ୍ସଟକୁ ଶୁଣିବା ପାଇଁ କିମ୍ବା ଅନୁବାଦ କରିବାକୁ, ସେଟିଂସରେ ଆପଣଙ୍କ ଡିଜିଟାଲ୍ ଆସିଷ୍ଟାଣ୍ଟ ଆପକୁ ବଦଳାନ୍ତୁ"</string>
+    <string name="assistant_not_supported_text" msgid="1708031078549268884">"ଆପଣଙ୍କ ସ୍କ୍ରିନରେ ଥିବା ଟେକ୍ସଟକୁ ଶୁଣିବା କିମ୍ବା ଅନୁବାଦ କରିବା ପାଇଁ, ସେଟିଂସରେ ଆପଣଙ୍କ Digital assistant ଆପକୁ ବଦଳାନ୍ତୁ"</string>
     <string name="tooltip_listen" msgid="7634466447860989102">"ଏହି ସ୍କ୍ରିନରେ ଥିବା ଟେକ୍ସଟକୁ ଶୁଣିବା ପାଇଁ ଏଠାରେ ଟାପ୍ କରନ୍ତୁ"</string>
     <string name="tooltip_translate" msgid="4184845868901542567">"ଏହି ସ୍କ୍ରିନରେ ଥିବା ଟେକ୍ସଟକୁ ଅନୁବାଦ କରିବା ପାଇଁ ଏଠାରେ ଟାପ୍ କରନ୍ତୁ"</string>
     <string name="toast_p2p_app_not_shareable" msgid="7229739094132131536">"ଏହି ଆପ ସେୟାର କରାଯାଇପାରିବ ନାହିଁ"</string>
diff --git a/protos/launcher_atom.proto b/protos/launcher_atom.proto
index c559988..a61e430 100644
--- a/protos/launcher_atom.proto
+++ b/protos/launcher_atom.proto
@@ -23,6 +23,8 @@
 //
 // ItemInfos
 message ItemInfo {
+  reserved 8;
+
   oneof Item {
     Application application = 1;
     Task task = 2;
@@ -42,7 +44,14 @@
   optional ContainerInfo container_info = 7;
 
   // Stores the origin of the Item
-  optional Attribute attribute = 8;
+  repeated Attribute item_attributes = 12;
+}
+
+message LauncherAttributes{
+
+  // Integer value of item attribute enum
+  // (e.g. SUGGESTED_LABEL, ALL_APPS_SEARCH_RESULT_SETTING etc)
+  repeated int32 item_attributes = 1;
 }
 
 // Represents various launcher surface where items are placed.
@@ -156,6 +165,13 @@
   ALL_APPS_SEARCH_RESULT_LEGACY_SHORTCUT = 30;
   ALL_APPS_SEARCH_RESULT_ASSISTANT_MEMORY = 31;
 
+  // Suggestion Type provided by AGA
+  ONE_SEARCH_WEB_QUERY = 32;
+  ONE_SEARCH_WEB_TRENDING = 33;
+  ONE_SEARCH_WEB_ENTITY = 34;
+  ONE_SEARCH_WEB_ANSWER = 35;
+  ONE_SEARCH_WEB_PERSONAL = 36;
+
   WIDGETS_BOTTOM_TRAY = 28;
   WIDGETS_TRAY_PREDICTION = 29;
 }
diff --git a/quickstep/protos_overrides/launcher_atom_extension.proto b/quickstep/protos_overrides/launcher_atom_extension.proto
index ff050ea..a1566f0 100644
--- a/quickstep/protos_overrides/launcher_atom_extension.proto
+++ b/quickstep/protos_overrides/launcher_atom_extension.proto
@@ -42,5 +42,18 @@
 
     // True if the item's title/content is a direct match to the search query, false otherwise.
     optional bool direct_match = 2;
+
+    // Entry point for this on-device search session
+    optional EntryState entry_state = 3;
+
+    enum EntryState{
+      ENTRY_STATE_UNKNOWN = 0;
+
+      // User entered using swipe-up gesture from homescreen and searchbox in AllApps drawer.
+      ALL_APPS = 1;
+
+      // User entered by tapping on QSB bar on homescreen.
+      QSB = 2;
+    }
   }
 }
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 58b26d1..5deea3b 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"الإشعارات"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"إعدادات سريعة"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"الانتقال إلى يمين الشاشة أو أعلاها"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"الانتقال إلى يسار الشاشة أو أسفلها"</string>
 </resources>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 38a506f..d48c2f1 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"জাননী"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ক্ষিপ্ৰ ছেটিং"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ওপৰৰ বাঁওফাললৈ নিয়ক"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"তলৰ সোঁফাললৈ নিয়ক"</string>
 </resources>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 74fcb63..9cea3c6 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Geriyə"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME keçiricisi"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Sonuncular"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Bildirişlər"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Sürətli Ayarlar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuxarı/sola köçürün"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Aşağı/sağa köçürün"</string>
 </resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 4872f7d..16aec9b 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Апавяшчэнні"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Хуткія налады"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перамясціць уверх/улева"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перамясціць уніз/управа"</string>
 </resources>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 3fea5ee..2d3dc60 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Назад"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Редактор за метода на въвежд.: Превключвател"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Скорошни"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Известия"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Бързи настройки"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Преместване горе/вляво"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Преместване долу/вдясно"</string>
 </resources>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 0f6c486..8a6d153 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Enrere"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Selector d\'IME"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Recents"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notificacions"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Config. ràpida"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mou a la part superior o a l\'esquerra"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mou a la part inferior o a la dreta"</string>
 </resources>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 6aef1a4..c207103 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Zpět"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Přepínač IME"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Poslední"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Oznámení"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Rychlé nastavení"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Přesunout doleva nahoru"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Přesunout doprava dolů"</string>
 </resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index c2e6681..e53dfb0 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Tilbage"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME-vælger"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Seneste"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifikationer"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Kvikmenu"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flyt til toppen eller venstre side"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flyt til bunden eller højre side"</string>
 </resources>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index b5dc6e6..0916fc2 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Atrás"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Interruptor IME"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Recientes"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notificaciones"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ajustes rápidos"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover arriba/a la izquierda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover abajo/a la derecha"</string>
 </resources>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 950263f..5b4b1ce 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Tagasi"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME vahetaja"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Hiljutised"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Märguanded"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Kiirseaded"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Teisalda üles/vasakule"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Teisalda alla/paremale"</string>
 </resources>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 9505039..4677eda 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Takaisin"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME-vaihtopalvelu"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Viimeaikaiset"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Ilmoitukset"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Pika-asetukset"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Siirrä ylös tai vasemmalle"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Siirrä alas tai oikealle"</string>
 </resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index e34cb5d..2a38ff8 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Retour"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Sélecteur IME"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Récents"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifications"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Paramètres rapides"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer vers le coin supérieur gauche de l\'écran"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer vers le coin inférieur droit de l\'écran"</string>
 </resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 3c28c46..c1dd76e 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Retour"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Sélecteur IME"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Récents"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifications"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Réglages rapides"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer en haut ou à gauche"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer en bas ou à droite"</string>
 </resources>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 4095f7d..8702947 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Atrás"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Selector do IME"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Recentes"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notificacións"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Configuración rápida"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover á parte superior ou á esquerda"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover á parte inferior ou á dereita"</string>
 </resources>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 5b1aff9..a84dadd 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Vissza"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME-váltó"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Legutóbbiak"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Értesítések"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Gyorsbeállítások"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mozgatás felülre vagy a bal oldalra"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mozgatás alulra vagy a jobb oldalra"</string>
 </resources>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index 1327552..f888bea 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Til baka"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Breyta innsláttaraðferð"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Nýlegt"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Tilkynningar"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Flýtistillingar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Færa efst/til vinstri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Færa neðst/til hægri"</string>
 </resources>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index a555636..344c2a1 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Indietro"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Selettore IME"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Recenti"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Notifiche"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Impostazioni rapide"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sposta in alto/a sinistra"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sposta in basso/a destra"</string>
 </resources>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index cd97903..25d92cb 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"התראות"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"הגדרות מהירות"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"העברה לפינה השמאלית/העליונה"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"העברה לפינה הימנית/התחתונה"</string>
 </resources>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 3295a63..e006c6a 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"ការ​ជូនដំណឹង"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ការកំណត់រហ័ស"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ផ្លាស់ទីទៅខាងលើ/ឆ្វេង"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ផ្លាស់ទីទៅខាងក្រោម/ស្ដាំ"</string>
 </resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 08e5642..d9ff591 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"알림"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"빠른 설정"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"상단/왼쪽으로 이동"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"하단/오른쪽으로 이동"</string>
 </resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 4c1791f..5c95b03 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"ການແຈ້ງເຕືອນ"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ການຕັ້ງຄ່າດ່ວນ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ຍ້າຍໄປຊ້າຍ/ເທິງ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ຍ້າຍໄປຂວາ/ລຸ່ມ"</string>
 </resources>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index 95a7e86..8b3d2ce 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Atgal"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IMRP perjungiklis"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Naujausi"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Pranešimai"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Spartieji nustatymai"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Perkelti aukštyn, kairėn"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Perkelti žemyn, dešinėn"</string>
 </resources>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index f3de0b7..99a71fb 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Atpakaļ"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME pārslēdzējs"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Nesenie"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Paziņojumi"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Ātrie iestatīj."</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pārvietot uz augšējo/kreiso stūri"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pārvietot uz apakšējo/labo stūri"</string>
 </resources>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index d09165a..ef6052e 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"အကြောင်းကြားချက်"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"အမြန်ဆက်တင်များ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"အပေါ်/ဘယ်ဘက်သို့ ရွှေ့ရန်"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"အောက်ခြေ/ညာဘက်သို့ ရွှေ့ရန်"</string>
 </resources>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 6d143bd..a81c779 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Tilbake"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME-veksler"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Nylige"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Varsler"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Hurtiginnst."</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytt til øverst/venstre"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytt til nederst/høyre"</string>
 </resources>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index cd3383b..3c5d64f 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"सूचनाहरू"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"द्रुत सेटिङ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सिरान/बायाँतिर सार्नुहोस्"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"फेद/दायाँतिर सार्नुहोस्"</string>
 </resources>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 7740783..bb810f0 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -22,7 +22,7 @@
     <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="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>
@@ -38,7 +38,7 @@
     <string name="hotseat_edu_message_migrate_alt" msgid="3042360119039646356">"ଆପଣଙ୍କର ସବୁଠାରୁ ଅଧିକ-ବ୍ୟବହୃତ ଆପଗୁଡ଼ିକୁ, ସିଧା ମୂଳ ସ୍କ୍ରିନରେ ସହଜରେ ଆକ୍ସେସ୍ କରନ୍ତୁ। ଆପଣଙ୍କ ରୁଟିନଗୁଡ଼ିକ ଆଧାରରେ ପରାମର୍ଶଗୁଡ଼ିକ ପରିବର୍ତ୍ତିତ ହେବ। ତଳ ଧାଡ଼ିରେ ଥିବା ଆପଗୁଡ଼ିକ ଏକ ନୂଆ ଫୋଲ୍ଡରକୁ ମୁଭ୍ କରିଯିବ।"</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_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>
@@ -69,14 +69,14 @@
     <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"ଆପଗୁଡ଼ିକ ମଧ୍ୟରେ ସ୍ୱିଚ୍ କରିବାକୁ, ସ୍କ୍ରିନର ତଳୁ ଉପରକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ, ଧରି ରଖନ୍ତୁ, ତା\'ପରେ ରିଲିଜ୍ କରନ୍ତୁ।"</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_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_description" msgid="6350320429953234580">"ଆପଣ ଆପଣଙ୍କ ଫୋନ୍ ବ୍ୟବହାର କରିବା ପାଇଁ ପ୍ରସ୍ତୁତ ଅଛନ୍ତି"</string>
-    <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"ସିଷ୍ଟମ୍ ନାଭିଗେସନ୍ ସେଟିଂସ୍"</annotation></string>
+    <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"ସିଷ୍ଟମ ନାଭିଗେସନ ସେଟିଂସ"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"ସେୟାର୍ କରନ୍ତୁ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ସ୍କ୍ରିନସଟ୍"</string>
     <string name="action_split" msgid="2098009717623550676">"ସ୍ପ୍ଲିଟ୍"</string>
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"କ୍ୱିକ ସେଟିଂସ"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ଶୀର୍ଷ/ବାମକୁ ମୁଭ କରନ୍ତୁ"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ନିମ୍ନ/ଡାହାଣକୁ ମୁଭ କରନ୍ତୁ"</string>
 </resources>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 990017e..3c15a85 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"දැනුම්දීම්"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"ඉක්මන් සැකසීම්"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ඉහළ/වම වෙත ගෙන යන්න"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"පහළ/දකුණ වෙත ගෙන යන්න"</string>
 </resources>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index a18f72c..155da05 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Späť"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Prepínač IME"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Nedávne"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Upozornenia"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Rýchle nastavenia"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Presunúť hore alebo doľava"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Presunúť dole alebo doprava"</string>
 </resources>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index f2b2fa8..999768c 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Pas"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Çelësi IME"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Të fundit"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Njoftimet"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Cilësimet shpejt"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Lëviz në krye/majtas"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Lëviz në fund/djathtas"</string>
 </resources>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 2f1b75a..49f20c0 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Tillbaka"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME-väljare"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Senaste"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Aviseringar"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Snabbinställn."</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytta högst upp/till vänster"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytta längst ned/till höger"</string>
 </resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 3ecae96..71b01b6 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Bumalik"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME switcher"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Mga Kamakailan"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Mga Notification"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Quick Settings"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Ilipat sa itaas/kaliwa"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Ilipat sa ibaba/kanan"</string>
 </resources>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 19ced47..5e9a84b 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Geri"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME değiştirici"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Son Kullanılanlar"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Bildirimler"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Hızlı Ayarlar"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sol üste taşı"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sağ alta taşı"</string>
 </resources>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 231d128..2e0d3f7 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Сповіщення"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Швидкі налаштув."</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перемістити вгору або вліво"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перемістити вниз або вправо"</string>
 </resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 1072c3a..e3c6698 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"Quay lại"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"Trình chuyển đổi IME"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"Gần đây"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"Thông báo"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"Cài đặt nhanh"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Chuyển lên trên cùng/sang bên trái"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Chuyển xuống dưới cùng/sang bên phải"</string>
 </resources>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 4587d58..a42476c 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -102,10 +102,8 @@
     <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>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"通知"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"快捷设置"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到顶部/左侧"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右侧"</string>
 </resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 2810771..f2fd544 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"返回"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"輸入法編輯器切換工具"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"最近"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"通知"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"快速設定"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移至上方/左側"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移至底部/右側"</string>
 </resources>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 847cb91..f1fe624 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -102,10 +102,8 @@
     <string name="taskbar_button_back" msgid="8558862226461164514">"返回"</string>
     <string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"輸入法編輯器切換器"</string>
     <string name="taskbar_button_recents" msgid="7273376136216613134">"最近使用"</string>
-    <!-- no translation found for taskbar_button_notifications (7471740351507357318) -->
-    <skip />
-    <!-- no translation found for taskbar_button_quick_settings (227662894293189391) -->
-    <skip />
+    <string name="taskbar_button_notifications" msgid="7471740351507357318">"通知"</string>
+    <string name="taskbar_button_quick_settings" msgid="227662894293189391">"快速設定"</string>
     <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到上方/左側"</string>
     <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右側"</string>
 </resources>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index cb6094b..8fb085d 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -25,9 +25,11 @@
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
 import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
+import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
+import static com.android.launcher3.util.DisplayController.NavigationMode.NO_BUTTON;
+import static com.android.launcher3.util.DisplayController.NavigationMode.TWO_BUTTONS;
+import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
-import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
 
 import android.animation.AnimatorSet;
@@ -64,6 +66,7 @@
 import com.android.launcher3.uioverrides.RecentsViewStateController;
 import com.android.launcher3.util.ActivityOptionsWrapper;
 import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.launcher3.util.IntSet;
 import com.android.launcher3.util.ObjectWrapper;
 import com.android.launcher3.util.RunnableList;
@@ -71,9 +74,6 @@
 import com.android.launcher3.util.UiThreadHelper;
 import com.android.quickstep.OverviewCommandHelper;
 import com.android.quickstep.RecentsModel;
-import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.SysUINavigationMode.Mode;
-import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.TouchInteractionService.TISBinder;
@@ -101,8 +101,7 @@
 /**
  * Extension of Launcher activity to provide quickstep specific functionality
  */
-public abstract class BaseQuickstepLauncher extends Launcher
-        implements NavigationModeChangeListener {
+public abstract class BaseQuickstepLauncher extends Launcher {
 
     private DepthController mDepthController = new DepthController(this);
     private QuickstepTransitionManager mAppTransitionManager;
@@ -130,7 +129,6 @@
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this);
         addMultiWindowModeChangedListener(mDepthController);
         initUnfoldTransitionProgressProvider();
     }
@@ -160,8 +158,6 @@
             mUnfoldTransitionProgressProvider.destroy();
         }
 
-        SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this);
-
         mTISBindHelper.onDestroy();
         if (mTaskbarManager != null) {
             mTaskbarManager.clearActivity(this);
@@ -188,14 +184,6 @@
     }
 
     @Override
-    public void onNavigationModeChanged(Mode newMode) {
-        getDragLayer().recreateControllers();
-        if (mActionsView != null) {
-            mActionsView.updateVerticalMargin(newMode);
-        }
-    }
-
-    @Override
     public void onEnterAnimationComplete() {
         super.onEnterAnimationComplete();
         // After the transition to home, enable the high-res thumbnail loader if it wasn't enabled
@@ -304,7 +292,6 @@
     protected void setupViews() {
         super.setupViews();
 
-        SysUINavigationMode.INSTANCE.get(this).updateMode();
         mActionsView = findViewById(R.id.overview_actions_view);
         RecentsView overviewPanel = (RecentsView) getOverviewPanel();
         SplitSelectStateController controller =
@@ -312,7 +299,7 @@
                         getStateManager(), getDepthController());
         overviewPanel.init(mActionsView, controller);
         mActionsView.setDp(getDeviceProfile());
-        mActionsView.updateVerticalMargin(SysUINavigationMode.getMode(this));
+        mActionsView.updateVerticalMargin(DisplayController.getNavigationMode(this));
 
         mAppTransitionManager = new QuickstepTransitionManager(this);
         mAppTransitionManager.registerRemoteAnimations();
@@ -344,6 +331,7 @@
                             getSystemService(SensorManager.class),
                             getMainThreadHandler(),
                             getMainExecutor(),
+                            /* backgroundExecutor= */ THREAD_POOL_EXECUTOR,
                             /* tracingTagPrefix= */ "launcher"
                     );
 
@@ -432,7 +420,7 @@
 
     @Override
     public float[] getNormalOverviewScaleAndOffset() {
-        return SysUINavigationMode.getMode(this).hasGestures
+        return DisplayController.getNavigationMode(this).hasGestures
                 ? new float[] {1, 1} : new float[] {1.1f, NO_OFFSET};
     }
 
@@ -462,7 +450,7 @@
     }
 
     public boolean shouldBackButtonBeHidden(LauncherState toState) {
-        Mode mode = SysUINavigationMode.getMode(this);
+        NavigationMode mode = DisplayController.getNavigationMode(this);
         boolean shouldBackButtonBeHidden = mode.hasGestures
                 && toState.hasFlag(FLAG_HIDE_BACK_BUTTON)
                 && hasWindowFocus()
@@ -480,7 +468,7 @@
      */
     private void onLauncherStateOrFocusChanged() {
         boolean shouldBackButtonBeHidden = shouldBackButtonBeHidden(getStateManager().getState());
-        if (SysUINavigationMode.getMode(this) == TWO_BUTTONS) {
+        if (DisplayController.getNavigationMode(this) == TWO_BUTTONS) {
             UiThreadHelper.setBackButtonAlphaAsync(this, SET_BACK_BUTTON_ALPHA,
                     shouldBackButtonBeHidden ? 0f : 1f, true /* animate */);
         }
@@ -610,6 +598,13 @@
         if ((flags & CHANGE_ACTIVE_SCREEN) != 0) {
             getStateManager().moveToRestState();
         }
+
+        if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
+            getDragLayer().recreateControllers();
+            if (mActionsView != null) {
+                mActionsView.updateVerticalMargin(info.navigationMode);
+            }
+        }
     }
 
     @Override
@@ -625,7 +620,7 @@
             WindowInsets oldInsets) {
         // Override the tappable insets to be 0 on the bottom for gesture nav (otherwise taskbar
         // would count towards it). This is used for the bottom protection in All Apps for example.
-        if (SysUINavigationMode.getMode(this) == NO_BUTTON) {
+        if (DisplayController.getNavigationMode(this) == NO_BUTTON) {
             Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement());
             Insets newTappableInsets = Insets.of(oldTappableInsets.left, oldTappableInsets.top,
                     oldTappableInsets.right, 0);
diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
index 661053a..62603e9 100644
--- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
+++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java
@@ -16,9 +16,9 @@
 package com.android.launcher3;
 
 import static com.android.launcher3.Utilities.postAsyncCallback;
-import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 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.window.RefreshRateTracker.getSingleFrameMs;
 import static com.android.systemui.shared.recents.utilities.Utilities.postAtFrontOfQueueAsynchronously;
 
 import android.animation.Animator;
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 3eb1935e..803dee4 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -44,7 +44,7 @@
 import static com.android.launcher3.dragndrop.DragLayer.ALPHA_INDEX_TRANSITIONS;
 import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
 import static com.android.launcher3.statehandlers.DepthController.DEPTH;
-import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
+import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 import static com.android.launcher3.views.FloatingIconView.getFloatingIconView;
 import static com.android.quickstep.TaskViewUtils.findTaskViewToLaunch;
@@ -579,8 +579,8 @@
                 }
             }
 
-            // Pause page indicator animations as they lead to layer trashing.
-            mLauncher.getWorkspace().getPageIndicator().pauseAnimations();
+            // Pause expensive view updates as they can lead to layer thrashing and skipped frames.
+            mLauncher.pauseExpensiveViewUpdates();
 
             endListener = () -> {
                 viewsToAnimate.forEach(view -> {
@@ -590,7 +590,7 @@
                 if (scrimEnabled) {
                     mLauncher.getScrimView().setBackgroundColor(Color.TRANSPARENT);
                 }
-                mLauncher.getWorkspace().getPageIndicator().skipAnimationsToEnd();
+                mLauncher.resumeExpensiveViewUpdates();
             };
         }
 
diff --git a/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java b/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
index 1f268cc..07d3a51 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/BackButtonAlphaHandler.java
@@ -17,17 +17,17 @@
 package com.android.launcher3.statehandlers;
 
 import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.util.DisplayController.NavigationMode.TWO_BUTTONS;
 import static com.android.quickstep.AnimatedFloat.VALUE;
-import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
 
 import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.statemanager.StateManager.StateHandler;
 import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.UiThreadHelper;
 import com.android.quickstep.AnimatedFloat;
-import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.SystemUiProxy;
 
 /**
@@ -48,7 +48,7 @@
     @Override
     public void setStateWithAnimation(LauncherState toState, StateAnimationConfig config,
             PendingAnimation animation) {
-        if (SysUINavigationMode.getMode(mLauncher) != TWO_BUTTONS) {
+        if (DisplayController.getNavigationMode(mLauncher) != TWO_BUTTONS) {
             return;
         }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
index 17635df..27e89ba 100644
--- a/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/BaseTaskbarContext.java
@@ -64,6 +64,9 @@
     /** Callback invoked when a drag is initiated within this context. */
     public abstract void onDragStart();
 
+    /** Callback invoked when a drag is finished within this context. */
+    public abstract void onDragEnd();
+
     /** Callback invoked when a popup is shown or closed within this context. */
     public abstract void onPopupVisibilityChanged(boolean isVisible);
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index af53ae2..768a348 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -34,7 +34,6 @@
 import com.android.launcher3.QuickstepTransitionManager;
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.logging.InstanceIdSequence;
 import com.android.launcher3.model.data.ItemInfo;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 46640e2..5387b1a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -21,6 +21,8 @@
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
 
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.launcher3.ResourceUtils.getBoolByName;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
@@ -70,13 +72,13 @@
 import com.android.launcher3.popup.PopupDataProvider;
 import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
 import com.android.launcher3.touch.ItemClickHandler;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.SettingsCache;
 import com.android.launcher3.util.TraceHelper;
 import com.android.launcher3.util.ViewCache;
 import com.android.launcher3.views.ActivityContext;
-import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.systemui.shared.recents.model.Task;
 import com.android.systemui.shared.rotation.RotationButtonController;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -92,6 +94,8 @@
  */
 public class TaskbarActivityContext extends BaseTaskbarContext {
 
+    private static final String IME_DRAWS_IME_NAV_BAR_RES_NAME = "config_imeDrawsImeNavBar";
+
     private static final boolean ENABLE_THREE_BUTTON_TASKBAR =
             SystemProperties.getBoolean("persist.debug.taskbar_three_button", false);
     private static final String TAG = "TaskbarActivityContext";
@@ -109,12 +113,13 @@
     // The size we should return to when we call setTaskbarWindowFullscreen(false)
     private int mLastRequestedNonFullscreenHeight;
 
-    private final SysUINavigationMode.Mode mNavMode;
+    private final NavigationMode mNavMode;
     private final boolean mImeDrawsImeNavBar;
     private final ViewCache mViewCache = new ViewCache();
 
     private final boolean mIsSafeModeEnabled;
     private final boolean mIsUserSetupComplete;
+    private final boolean mIsNavBarForceVisible;
     private final boolean mIsNavBarKidsMode;
     private boolean mIsDestroyed = false;
     // The flag to know if the window is excluded from magnification region computation.
@@ -129,18 +134,20 @@
         super(windowContext);
         mDeviceProfile = dp;
 
-        mNavMode = SysUINavigationMode.getMode(windowContext);
-        mImeDrawsImeNavBar = SysUINavigationMode.getImeDrawsImeNavBar(windowContext);
+        final Resources resources = getResources();
+
+        mNavMode = DisplayController.getNavigationMode(windowContext);
+        mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
         mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
                 () -> getPackageManager().isSafeMode());
         mIsUserSetupComplete = SettingsCache.INSTANCE.get(this).getValue(
                 Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
+        mIsNavBarForceVisible = SettingsCache.INSTANCE.get(this).getValue(
+                Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_FORCE_VISIBLE), 0);
         mIsNavBarKidsMode = SettingsCache.INSTANCE.get(this).getValue(
                 Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
 
-        final Resources resources = getResources();
         updateIconSize(resources);
-
         mTaskbarHeightForIme = resources.getDimensionPixelSize(R.dimen.taskbar_ime_size);
 
         // Inflate views.
@@ -255,11 +262,11 @@
     }
 
     public boolean isThreeButtonNav() {
-        return mNavMode == Mode.THREE_BUTTONS;
+        return mNavMode == NavigationMode.THREE_BUTTONS;
     }
 
     public boolean isGestureNav() {
-        return mNavMode == Mode.NO_BUTTON;
+        return mNavMode == NavigationMode.NO_BUTTON;
     }
 
     public boolean imeDrawsImeNavBar() {
@@ -384,6 +391,11 @@
     }
 
     @Override
+    public void onDragEnd() {
+        maybeSetTaskbarWindowNotFullscreen();
+    }
+
+    @Override
     public void onPopupVisibilityChanged(boolean isVisible) {
         setTaskbarWindowFocusable(isVisible);
     }
@@ -486,6 +498,17 @@
         setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight);
     }
 
+    /**
+     * Reverts Taskbar window to its original size, if all floating views are closed and there is
+     * no system drag operation in progress.
+     */
+    void maybeSetTaskbarWindowNotFullscreen() {
+        if (AbstractFloatingView.getAnyView(this, TYPE_ALL) == null
+                && !mControllers.taskbarDragController.isSystemDragInProgress()) {
+            setTaskbarWindowFullscreen(false);
+        }
+    }
+
     public boolean isTaskbarWindowFullscreen() {
         return mIsFullscreen;
     }
@@ -695,6 +718,10 @@
         return mIsNavBarKidsMode && isThreeButtonNav();
     }
 
+    protected boolean isNavBarForceVisible() {
+        return mIsNavBarForceVisible;
+    }
+
     /**
      * Called when we determine the touchable region.
      *
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 12b1195..af98b7f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.taskbar;
 
 import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
@@ -55,20 +56,20 @@
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
 import com.android.launcher3.dragndrop.DraggableView;
-import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.graphics.DragPreviewProvider;
 import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.model.data.FolderInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.popup.PopupContainerWithArrow;
 import com.android.launcher3.shortcuts.DeepShortcutView;
 import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
-import com.android.launcher3.util.LauncherBindableItemsContainer;
+import com.android.launcher3.util.IntSet;
+import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.systemui.shared.recents.model.Task;
 
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.Collections;
 
 /**
  * Handles long click on Taskbar items to start a system drag and drop operation.
@@ -391,11 +392,17 @@
         return super.isDragging() || mIsSystemDragInProgress;
     }
 
+    /** {@code true} if the system is currently handling the drag. */
+    public boolean isSystemDragInProgress() {
+        return mIsSystemDragInProgress;
+    }
+
     private void maybeOnDragEnd() {
         if (!isDragging()) {
             ((BubbleTextView) mDragObject.originalView).getIcon().setIsDisabled(false);
             mControllers.taskbarAutohideSuspendController.updateFlag(
                     TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING, false);
+            mActivity.onDragEnd();
         }
     }
 
@@ -416,23 +423,18 @@
             ItemInfo item = (ItemInfo) tag;
             TaskbarViewController taskbarViewController = mControllers.taskbarViewController;
             if (item.container == CONTAINER_ALL_APPS) {
-                // Since all apps closes when the drag starts, target the all apps button instead
+                // Since all apps closes when the drag starts, target the all apps button instead.
                 target = taskbarViewController.getAllAppsButtonView();
             } else if (item.container >= 0) {
-                // Since folders close when the drag starts, target the folder icon instead
-                LauncherBindableItemsContainer.ItemOperator op = (info, v) -> {
-                    if (info instanceof FolderInfo && v instanceof FolderIcon) {
-                        FolderInfo fi = (FolderInfo) info;
-                        for (WorkspaceItemInfo si : fi.contents) {
-                            if (si.id == item.id) {
-                                // Found the parent
-                                return true;
-                            }
-                        }
-                    }
-                    return false;
-                };
-                target = taskbarViewController.mapOverItems(op);
+                // Since folders close when the drag starts, target the folder icon instead.
+                ItemInfoMatcher matcher = ItemInfoMatcher.forFolderMatch(
+                        ItemInfoMatcher.ofItemIds(IntSet.wrap(item.id)));
+                target = taskbarViewController.getFirstIconMatch(matcher);
+            } else if (item.itemType == ITEM_TYPE_DEEP_SHORTCUT) {
+                // Find first icon with same package/user as the deep shortcut.
+                ItemInfoMatcher packageUserMatcher = ItemInfoMatcher.ofPackages(
+                        Collections.singleton(item.getTargetPackage()), item.user);
+                target = taskbarViewController.getFirstIconMatch(packageUserMatcher);
             }
         }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 1bd76b9..cdac497 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -181,6 +181,9 @@
             } else if (!mControllers.uiController.isTaskbarTouchable()) {
                 // Let touches pass through us.
                 insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
+            } else if (mControllers.taskbarDragController.isSystemDragInProgress()) {
+                // Let touches pass through us.
+                insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
             } else if (mControllers.taskbarViewController.areIconsVisible()
                     || AbstractFloatingView.getOpenView(mActivity, TYPE_ALL) != null
                     || mActivity.isNavBarKidsModeActive()) {
@@ -208,9 +211,7 @@
          * Called when a child is removed from TaskbarDragLayer.
          */
         public void onDragLayerViewRemoved() {
-            if (AbstractFloatingView.getAnyView(mActivity, TYPE_ALL) == null) {
-                mActivity.setTaskbarWindowFullscreen(false);
-            }
+            mActivity.maybeSetTaskbarWindowNotFullscreen();
         }
 
         /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
index 385090f..c99cebb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
@@ -71,7 +71,7 @@
     /** Update values tracked via sysui flags. */
     public void updateSysuiFlags(int sysuiFlags) {
         mIsImmersiveMode = (sysuiFlags & SYSUI_STATE_IMMERSIVE_MODE) != 0;
-        if (mContext.isNavBarKidsModeActive()) {
+        if (mContext.isNavBarForceVisible()) {
             if (mIsImmersiveMode) {
                 startIconDimming();
             } else {
@@ -113,7 +113,7 @@
      * Returns whether the taskbar is always visible in immersive mode.
      */
     private boolean isNavbarShownInImmersiveMode() {
-        return mIsImmersiveMode && mContext.isNavBarKidsModeActive();
+        return mIsImmersiveMode && mContext.isNavBarForceVisible();
     }
 
     private void updateIconDimmingAlpha() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index ebe6a04..ce468d0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -29,6 +29,7 @@
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.util.MultiValueAlpha;
@@ -36,6 +37,7 @@
 import com.android.quickstep.RecentsAnimationCallbacks;
 import com.android.quickstep.RecentsAnimationController;
 import com.android.quickstep.views.RecentsView;
+import com.android.systemui.animation.ViewRootSync;
 import com.android.systemui.shared.recents.model.ThumbnailData;
 
 import java.util.HashMap;
@@ -76,6 +78,9 @@
 
     private boolean mShouldDelayLauncherStateAnim;
 
+    // We skip any view synchronizations during init/destroy.
+    private boolean mCanSyncViews;
+
     private final StateManager.StateListener<LauncherState> mStateListener =
             new StateManager.StateListener<LauncherState>() {
 
@@ -102,6 +107,8 @@
             };
 
     public void init(TaskbarControllers controllers, BaseQuickstepLauncher launcher) {
+        mCanSyncViews = false;
+
         mControllers = controllers;
         mLauncher = launcher;
 
@@ -121,9 +128,13 @@
         updateStateForFlag(FLAG_RESUMED, launcher.hasBeenResumed());
         mLauncherState = launcher.getStateManager().getState();
         applyState(0);
+
+        mCanSyncViews = true;
     }
 
     public void onDestroy() {
+        mCanSyncViews = false;
+
         mIconAlignmentForResumedState.finishAnimation();
         mIconAlignmentForGestureState.finishAnimation();
         mIconAlignmentForLauncherState.finishAnimation();
@@ -131,6 +142,8 @@
         mIconAlphaForHome.setConsumer(null);
         mLauncher.getHotseat().setIconsAlpha(1f);
         mLauncher.getStateManager().removeStateListener(mStateListener);
+
+        mCanSyncViews = true;
     }
 
     public Animator createAnimToLauncher(@NonNull LauncherState toState,
@@ -380,6 +393,27 @@
             return;
         }
         float alignment = alignmentSupplier.get();
+        float currentValue = mIconAlphaForHome.getValue();
+        boolean taskbarWillBeVisible = alignment < 1;
+        boolean firstFrameVisChanged = (taskbarWillBeVisible && Float.compare(currentValue, 1) != 0)
+                || (!taskbarWillBeVisible && Float.compare(currentValue, 0) != 0);
+
+        // Sync the first frame where we swap taskbar and hotseat.
+        if (firstFrameVisChanged && mCanSyncViews) {
+            DeviceProfile dp = mLauncher.getDeviceProfile();
+
+            // Do all the heavy work before the sync.
+            mControllers.taskbarViewController.createIconAlignmentControllerIfNotExists(dp);
+
+            ViewRootSync.synchronizeNextDraw(mLauncher.getHotseat(),
+                    mControllers.taskbarActivityContext.getDragLayer(),
+                    () -> updateIconAlignment(alignment));
+        } else {
+            updateIconAlignment(alignment);
+        }
+    }
+
+    private void updateIconAlignment(float alignment) {
         mControllers.taskbarViewController.setLauncherIconAlignment(
                 alignment, mLauncher.getDeviceProfile());
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 16cf883..5ce4fa7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -21,6 +21,7 @@
 
 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
 import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
+import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
 
 import android.content.ComponentCallbacks;
@@ -47,8 +48,6 @@
 import com.android.launcher3.util.SettingsCache;
 import com.android.launcher3.util.SimpleBroadcastReceiver;
 import com.android.quickstep.RecentsActivity;
-import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TouchInteractionService;
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
@@ -59,8 +58,7 @@
 /**
  * Class to manage taskbar lifecycle
  */
-public class TaskbarManager implements DisplayController.DisplayInfoChangeListener,
-        SysUINavigationMode.NavigationModeChangeListener {
+public class TaskbarManager implements DisplayController.DisplayInfoChangeListener {
 
     private static final Uri USER_SETUP_COMPLETE_URI = Settings.Secure.getUriFor(
             Settings.Secure.USER_SETUP_COMPLETE);
@@ -70,7 +68,6 @@
 
     private final Context mContext;
     private final DisplayController mDisplayController;
-    private final SysUINavigationMode mSysUINavigationMode;
     private final TaskbarNavButtonController mNavButtonController;
     private final SettingsCache.OnChangeListener mUserSetupCompleteListener;
     private final SettingsCache.OnChangeListener mNavBarKidsModeListener;
@@ -92,14 +89,13 @@
      */
     private final TaskbarSharedState mSharedState = new TaskbarSharedState();
 
-    private static final int CHANGE_FLAGS =
-            CHANGE_ACTIVE_SCREEN | CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS;
+    private static final int CHANGE_FLAGS = CHANGE_ACTIVE_SCREEN | CHANGE_DENSITY
+            | CHANGE_SUPPORTED_BOUNDS | CHANGE_NAVIGATION_MODE;
 
     private boolean mUserUnlocked = false;
 
     public TaskbarManager(TouchInteractionService service) {
         mDisplayController = DisplayController.INSTANCE.get(service);
-        mSysUINavigationMode = SysUINavigationMode.INSTANCE.get(service);
         Display display =
                 service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
         mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null);
@@ -140,7 +136,6 @@
         mShutdownReceiver = new SimpleBroadcastReceiver(i -> destroyExistingTaskbar());
 
         mDisplayController.addChangeListener(this);
-        mSysUINavigationMode.addModeChangeListener(this);
         SettingsCache.INSTANCE.get(mContext).register(USER_SETUP_COMPLETE_URI,
                 mUserSetupCompleteListener);
         SettingsCache.INSTANCE.get(mContext).register(NAV_BAR_KIDS_MODE,
@@ -152,11 +147,6 @@
     }
 
     @Override
-    public void onNavigationModeChanged(Mode newMode) {
-        recreateTaskbar();
-    }
-
-    @Override
     public void onDisplayInfoChanged(Context context, Info info, int flags) {
         if ((flags & CHANGE_FLAGS) != 0) {
             recreateTaskbar();
@@ -304,7 +294,6 @@
     public void destroy() {
         destroyExistingTaskbar();
         mDisplayController.removeChangeListener(this);
-        mSysUINavigationMode.removeModeChangeListener(this);
         SettingsCache.INSTANCE.get(mContext).unregister(USER_SETUP_COMPLETE_URI,
                 mUserSetupCompleteListener);
         SettingsCache.INSTANCE.get(mContext).unregister(NAV_BAR_KIDS_MODE,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 1d5fa4d..6bc4c0a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -29,10 +29,12 @@
 import android.content.SharedPreferences;
 import android.view.ViewConfiguration;
 
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
 import com.android.quickstep.AnimatedFloat;
 import com.android.quickstep.SystemUiProxy;
+import com.android.systemui.shared.system.WindowManagerWrapper;
 
 import java.io.PrintWriter;
 import java.util.StringJoiner;
@@ -60,15 +62,16 @@
 
     // If any of these flags are enabled, inset apps by our stashed height instead of our unstashed
     // height. This way the reported insets are consistent even during transitions out of the app.
-    // Currently any flag that causes us to stash in an app is included, except for IME since that
-    // covers the underlying app anyway and thus the app shouldn't change insets.
+    // Currently any flag that causes us to stash in an app is included, except for IME or All Apps
+    // since those cover the underlying app anyway and thus the app shouldn't change insets.
     private static final int FLAGS_REPORT_STASHED_INSETS_TO_APP = FLAGS_STASHED_IN_APP
-            & ~FLAG_STASHED_IN_APP_IME;
+            & ~FLAG_STASHED_IN_APP_IME & ~FLAG_STASHED_IN_APP_ALL_APPS;
 
     /**
      * How long to stash/unstash when manually invoked via long press.
      */
-    public static final long TASKBAR_STASH_DURATION = 300;
+    public static final long TASKBAR_STASH_DURATION =
+            WindowManagerWrapper.ANIMATION_DURATION_RESIZE;
 
     /**
      * How long to stash/unstash when keyboard is appearing/disappearing.
@@ -187,7 +190,7 @@
      * Returns whether the taskbar can visually stash into a handle based on the current device
      * state.
      */
-    private boolean supportsVisualStashing() {
+    public boolean supportsVisualStashing() {
         return !mActivity.isThreeButtonNav();
     }
 
@@ -254,7 +257,14 @@
      * Returns the height that taskbar will inset when inside apps.
      */
     public int getContentHeightToReportToApps() {
-        if (hasAnyFlag(FLAGS_REPORT_STASHED_INSETS_TO_APP)) {
+        if (supportsVisualStashing() && hasAnyFlag(FLAGS_REPORT_STASHED_INSETS_TO_APP)) {
+            DeviceProfile dp = mActivity.getDeviceProfile();
+            if (hasAnyFlag(FLAG_STASHED_IN_APP_SETUP) && dp.isTaskbarPresent && !dp.isLandscape) {
+                // We always show the back button in SUW but in portrait the SUW layout may not
+                // be wide enough to support overlapping the nav bar with its content.  For now,
+                // just inset by the bar height.
+                return mUnstashedHeight;
+            }
             boolean isAnimating = mAnimator != null && mAnimator.isStarted();
             return mControllers.stashedHandleViewController.isStashedHandleVisible() || isAnimating
                     ? mStashedHeight : 0;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 07b851f..6bc2a93 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -68,4 +68,11 @@
     public void setSystemGestureInProgress(boolean inProgress) {
         mControllers.taskbarStashController.setSystemGestureInProgress(inProgress);
     }
+
+    /**
+     * Manually closes the all apps window.
+     */
+    public void hideAllApps() {
+        mControllers.taskbarAllAppsController.hide();
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index ade58a9..0b537e2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -39,6 +39,7 @@
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.AllAppsButton;
@@ -367,17 +368,36 @@
     }
 
     /**
-     * Maps {@code op} over all the child views, returning the view that {@code op} evaluates
-     * {@code true} for, or {@code null} if none satisfy {@code op}.
+     * Maps {@code op} over all the child views.
      */
-    protected View mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
+    public void mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
         // map over all the shortcuts on the taskbar
         for (int i = 0; i < getChildCount(); i++) {
             View item = getChildAt(i);
             if (op.evaluate((ItemInfo) item.getTag(), item)) {
-                return item;
+                return;
             }
         }
-        return null;
+    }
+
+    /**
+     * Finds the first icon to match one of the given matchers, from highest to lowest priority.
+     * @return The first match, or All Apps button if no match was found.
+     */
+    public View getFirstMatch(ItemInfoMatcher... matchers) {
+        for (ItemInfoMatcher matcher : matchers) {
+            for (int i = 0; i < getChildCount(); i++) {
+                View item = getChildAt(i);
+                if (!(item.getTag() instanceof ItemInfo)) {
+                    // Should only happen for All Apps button.
+                    continue;
+                }
+                ItemInfo info = (ItemInfo) item.getTag();
+                if (matcher.matchesInfo(info)) {
+                    return item;
+                }
+            }
+        }
+        return mAllAppsButton;
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 3575dc1..1320060 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -38,6 +38,7 @@
 import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.LauncherBindableItemsContainer;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.quickstep.AnimatedFloat;
@@ -182,15 +183,23 @@
     }
 
     /**
+     * Creates the icon alignment controller if it does not already exist.
+     * @param launcherDp Launcher device profile.
+     */
+    public void createIconAlignmentControllerIfNotExists(DeviceProfile launcherDp) {
+        if (mIconAlignControllerLazy == null) {
+            mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
+        }
+    }
+
+    /**
      * Sets the taskbar icon alignment relative to Launcher hotseat icons
      * @param alignmentRatio [0, 1]
      *                       0 => not aligned
      *                       1 => fully aligned
      */
     public void setLauncherIconAlignment(float alignmentRatio, DeviceProfile launcherDp) {
-        if (mIconAlignControllerLazy == null) {
-            mIconAlignControllerLazy = createIconAlignmentController(launcherDp);
-        }
+        createIconAlignmentControllerIfNotExists(launcherDp);
         mIconAlignControllerLazy.setPlayFraction(alignmentRatio);
         if (alignmentRatio <= 0 || alignmentRatio >= 1) {
             // Cleanup lazy controller so that it is created again in next animation
@@ -265,8 +274,22 @@
         mTaskbarNavButtonTranslationY.updateValue(-deviceProfile.getTaskbarOffsetY());
     }
 
-    public View mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
-        return mTaskbarView.mapOverItems(op);
+    /**
+     * Maps the given operator to all the top-level children of TaskbarView.
+     */
+    public void mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
+        mTaskbarView.mapOverItems(op);
+    }
+
+    /**
+     * Returns the first icon to match the given parameter, in priority from:
+     * 1) Icons directly on Taskbar
+     * 2) FolderIcon of the Folder containing the given icon
+     * 3) All Apps button
+     */
+    public View getFirstIconMatch(ItemInfoMatcher matcher) {
+        ItemInfoMatcher folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
+        return mTaskbarView.getFirstMatch(matcher, folderMatcher);
     }
 
     /**
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java
index 4245119..a67ca70 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContext.java
@@ -19,9 +19,13 @@
 import static android.view.KeyEvent.KEYCODE_BACK;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
+import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION;
+
 import android.content.Context;
+import android.graphics.Insets;
 import android.view.KeyEvent;
 import android.view.View;
+import android.view.WindowInsets;
 
 import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DeviceProfile;
@@ -37,6 +41,9 @@
 import com.android.launcher3.util.OnboardingPrefs;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
+import com.android.systemui.shared.system.ViewTreeObserverWrapper;
+import com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo;
+import com.android.systemui.shared.system.ViewTreeObserverWrapper.OnComputeInsetsListener;
 
 /**
  * Window context for the taskbar all apps overlay.
@@ -48,11 +55,16 @@
     private final TaskbarActivityContext mTaskbarContext;
     private final OnboardingPrefs<TaskbarAllAppsContext> mOnboardingPrefs;
 
+    private final TaskbarAllAppsController mWindowController;
     private final TaskbarAllAppsViewController mAllAppsViewController;
     private final TaskbarDragController mDragController;
     private final TaskbarAllAppsDragLayer mDragLayer;
     private final TaskbarAllAppsContainerView mAppsView;
 
+    // We automatically stash taskbar when all apps is opened in gesture navigation mode.
+    private final boolean mWillTaskbarBeVisuallyStashed;
+    private final int mStashedTaskbarHeight;
+
     TaskbarAllAppsContext(
             TaskbarActivityContext taskbarContext,
             TaskbarAllAppsController windowController,
@@ -66,12 +78,16 @@
         mDragLayer = new TaskbarAllAppsDragLayer(this);
         TaskbarAllAppsSlideInView slideInView = (TaskbarAllAppsSlideInView) mLayoutInflater.inflate(
                 R.layout.taskbar_all_apps, mDragLayer, false);
+        mWindowController = windowController;
         mAllAppsViewController = new TaskbarAllAppsViewController(
                 this,
                 slideInView,
                 windowController,
                 taskbarStashController);
         mAppsView = slideInView.getAppsView();
+
+        mWillTaskbarBeVisuallyStashed = taskbarStashController.supportsVisualStashing();
+        mStashedTaskbarHeight = taskbarStashController.getStashedHeight();
     }
 
     TaskbarAllAppsViewController getAllAppsViewController() {
@@ -128,10 +144,16 @@
     public void onDragStart() {}
 
     @Override
+    public void onDragEnd() {
+        mWindowController.maybeCloseWindow();
+    }
+
+    @Override
     public void onPopupVisibilityChanged(boolean isVisible) {}
 
     /** Root drag layer for this context. */
-    private static class TaskbarAllAppsDragLayer extends BaseDragLayer<TaskbarAllAppsContext> {
+    private static class TaskbarAllAppsDragLayer extends
+            BaseDragLayer<TaskbarAllAppsContext> implements OnComputeInsetsListener {
 
         private TaskbarAllAppsDragLayer(Context context) {
             super(context, null, 1);
@@ -142,10 +164,18 @@
         @Override
         protected void onAttachedToWindow() {
             super.onAttachedToWindow();
+            ViewTreeObserverWrapper.addOnComputeInsetsListener(
+                    getViewTreeObserver(), this);
             mActivity.mAllAppsViewController.show();
         }
 
         @Override
+        protected void onDetachedFromWindow() {
+            super.onDetachedFromWindow();
+            ViewTreeObserverWrapper.removeOnComputeInsetsListener(this);
+        }
+
+        @Override
         public void recreateControllers() {
             mControllers = new TouchController[]{mActivity.mDragController};
         }
@@ -160,5 +190,45 @@
             }
             return super.dispatchKeyEvent(event);
         }
+
+        @Override
+        public void onComputeInsets(InsetsInfo inoutInfo) {
+            if (mActivity.mDragController.isSystemDragInProgress()) {
+                inoutInfo.touchableRegion.setEmpty();
+                inoutInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
+            }
+        }
+
+        @Override
+        public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+            return updateInsetsDueToStashing(insets);
+        }
+
+        /**
+         * Taskbar automatically stashes when opening all apps, but we don't report the insets as
+         * changing to avoid moving the underlying app. But internally, the apps view should still
+         * layout according to the stashed insets rather than the unstashed insets. So this method
+         * does two things:
+         * 1) Sets navigationBars bottom inset to stashedHeight.
+         * 2) Sets tappableInsets bottom inset to 0.
+         */
+        private WindowInsets updateInsetsDueToStashing(WindowInsets oldInsets) {
+            if (!mActivity.mWillTaskbarBeVisuallyStashed) {
+                return oldInsets;
+            }
+            WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets);
+
+            Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars());
+            Insets newNavInsets = Insets.of(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right,
+                    mActivity.mStashedTaskbarHeight);
+            updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), newNavInsets);
+
+            Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement());
+            Insets newTappableInsets = Insets.of(oldTappableInsets.left, oldTappableInsets.top,
+                    oldTappableInsets.right, 0);
+            updatedInsetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets);
+
+            return updatedInsetsBuilder.build();
+        }
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
index 9302452..cf9d778 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsController.java
@@ -15,8 +15,11 @@
  */
 package com.android.launcher3.taskbar.allapps;
 
+import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
 
+import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+
 import android.content.Context;
 import android.graphics.PixelFormat;
 import android.view.Gravity;
@@ -128,12 +131,22 @@
                 .setPredictedApps(mPredictedApps);
     }
 
+    /** Closes the {@link TaskbarAllAppsContainerView}. */
+    public void hide() {
+        mProxyView.close(true);
+    }
+
     /**
-     * Removes the all apps window from the hierarchy.
+     * Removes the all apps window from the hierarchy, if all floating views are closed and there is
+     * no system drag operation in progress.
      * <p>
      * This method should be called after an exit animation finishes, if applicable.
      */
-    void closeWindow() {
+    void maybeCloseWindow() {
+        if (AbstractFloatingView.getOpenView(mAllAppsContext, TYPE_ALL) != null
+                || mAllAppsContext.getDragController().isSystemDragInProgress()) {
+            return;
+        }
         mProxyView.close(false);
         mTaskbarContext.removeOnDeviceProfileChangeListener(this);
         Optional.ofNullable(mAllAppsContext)
@@ -151,6 +164,7 @@
         layoutParams.gravity = Gravity.BOTTOM;
         layoutParams.packageName = mTaskbarContext.getPackageName();
         layoutParams.setFitInsetsTypes(0); // Handled by container view.
+        layoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         layoutParams.setSystemApplicationOverlay(true);
         return layoutParams;
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index c1abaac..648c486 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -49,7 +49,7 @@
         setUpIconLongClick();
         setUpAppDivider();
         setUpTaskbarStashing();
-        mSlideInView.addOnCloseListener(windowController::closeWindow);
+        mSlideInView.addOnCloseListener(windowController::maybeCloseWindow);
     }
 
     /** Starts the {@link TaskbarAllAppsSlideInView} enter transition. */
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index aa26645..9240fb8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -24,8 +24,8 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.Utilities;
-import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.SysUINavigationMode.Mode;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 
 public class ApiWrapper {
 
@@ -54,7 +54,7 @@
      * Returns the minimum space that should be left empty at the end of hotseat
      */
     public static int getHotseatEndOffset(Context context) {
-        if (SysUINavigationMode.INSTANCE.get(context).getMode() == Mode.THREE_BUTTONS) {
+        if (DisplayController.getNavigationMode(context) == NavigationMode.THREE_BUTTONS) {
             Resources res = context.getResources();
             /*
             * 3 nav buttons +
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
index be7535a..08d147f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
@@ -79,7 +79,7 @@
             }
         }
         activityOptions.options.setPendingIntentLaunchFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
-        activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_EMPTY);
+        activityOptions.options.setSplashScreenStyle(SplashScreen.SPLASH_SCREEN_STYLE_SOLID_COLOR);
         options = Pair.create(options.first, activityOptions.options);
         if (pendingIntent.isActivity()) {
             logAppLaunch(itemInfo);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 1073d76..829accc 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -68,14 +68,14 @@
 import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
 import com.android.launcher3.uioverrides.touchcontrollers.TransposedQuickSwitchTouchController;
 import com.android.launcher3.uioverrides.touchcontrollers.TwoButtonNavbarTouchController;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.PendingRequestArgs;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.util.UiThreadHelper;
 import com.android.launcher3.util.UiThreadHelper.AsyncCommand;
 import com.android.launcher3.widget.LauncherAppWidgetHost;
-import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.util.QuickstepOnboardingPrefs;
@@ -303,7 +303,7 @@
 
     @Override
     public TouchController[] createTouchControllers() {
-        Mode mode = SysUINavigationMode.getMode(this);
+        NavigationMode mode = DisplayController.getNavigationMode(this);
 
         ArrayList<TouchController> list = new ArrayList<>();
         list.add(getDragController());
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index bb13329..236454e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -26,8 +26,8 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.R;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Themes;
-import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.util.LayoutUtils;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
@@ -58,7 +58,7 @@
     @Override
     public int getTransitionDuration(Context context) {
         // In gesture modes, overview comes in all the way from the side, so give it more time.
-        return SysUINavigationMode.INSTANCE.get(context).getMode().hasGestures ? 380 : 250;
+        return DisplayController.getNavigationMode(context).hasGestures ? 380 : 250;
     }
 
     @Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index bd7e5de..4d05349 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -60,7 +60,7 @@
 import com.android.launcher3.anim.Interpolators;
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
-import com.android.quickstep.SysUINavigationMode;
+import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.util.RecentsAtomicAnimationFactory;
 import com.android.quickstep.views.RecentsView;
 
@@ -97,7 +97,7 @@
             config.setInterpolator(ANIM_WORKSPACE_SCALE, DEACCEL);
             config.setInterpolator(ANIM_WORKSPACE_FADE, ACCEL);
 
-            if (SysUINavigationMode.getMode(mActivity).hasGestures
+            if (DisplayController.getNavigationMode(mActivity).hasGestures
                     && overview.getTaskViewCount() > 0) {
                 // Overview is going offscreen, so keep it at its current scale and opacity.
                 config.setInterpolator(ANIM_OVERVIEW_SCALE, FINAL_FRAME);
@@ -139,7 +139,7 @@
             }
         } else if ((fromState == NORMAL || fromState == HINT_STATE
                 || fromState == HINT_STATE_TWO_BUTTON) && toState == OVERVIEW) {
-            if (SysUINavigationMode.getMode(mActivity).hasGestures) {
+            if (DisplayController.getNavigationMode(mActivity).hasGestures) {
                 config.setInterpolator(ANIM_WORKSPACE_SCALE,
                         fromState == NORMAL ? ACCEL : OVERSHOOT_1_2);
                 config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index f6148a7..d8f694e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -40,7 +40,7 @@
 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.DisplayController.getSingleFrameMs;
+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;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
index f0ef9cc..e5cd53a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java
@@ -44,8 +44,8 @@
 import com.android.launcher3.states.StateAnimationConfig;
 import com.android.launcher3.touch.AbstractStateChangeTouchController;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
-import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.SysUINavigationMode.Mode;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.quickstep.SystemUiProxy;
 import com.android.quickstep.TaskUtils;
 import com.android.quickstep.views.RecentsView;
@@ -125,7 +125,7 @@
     private void setupInterpolators(StateAnimationConfig stateAnimationConfig) {
         stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_FADE, DEACCEL_2);
         stateAnimationConfig.setInterpolator(ANIM_ALL_APPS_FADE, DEACCEL_2);
-        if (SysUINavigationMode.getMode(mLauncher) == Mode.NO_BUTTON) {
+        if (DisplayController.getNavigationMode(mLauncher) == NavigationMode.NO_BUTTON) {
             // Overview lives to the left of workspace, so translate down later than over
             stateAnimationConfig.setInterpolator(ANIM_WORKSPACE_TRANSLATE, ACCEL_2);
             stateAnimationConfig.setInterpolator(ANIM_VERTICAL_PROGRESS, ACCEL_2);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
index 308bca6..ca7f633 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TaskViewTouchController.java
@@ -38,10 +38,10 @@
 import com.android.launcher3.touch.BaseSwipeDetector;
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.touch.SingleAxisSwipeDetector;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.FlingBlockCheck;
 import com.android.launcher3.util.TouchController;
 import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.util.VibratorWrapper;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
@@ -177,7 +177,7 @@
                         // - It's the focused task if in grid view
                         // - The task is snapped
                         mAllowGoingDown = i == mRecentsView.getCurrentPage()
-                                && SysUINavigationMode.getMode(mActivity).hasGestures
+                                && DisplayController.getNavigationMode(mActivity).hasGestures
                                 && (!mRecentsView.showAsGrid() || mTaskBeingDragged.isFocusedTask())
                                 && mRecentsView.isTaskInExpectedScrollPosition(i);
 
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 2cb7100..253903c 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -32,10 +32,10 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_GESTURE;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
-import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
 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.window.RefreshRateTracker.getSingleFrameMs;
 import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
 import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
 import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
@@ -833,12 +833,9 @@
         // Notify when the animation starts
         flushOnRecentsAnimationAndLauncherBound();
 
-        // Start hiding the divider
-        setDividerShown(false /* shown */, false /* immediate */);
-
         // Only add the callback to enable the input consumer after we actually have the controller
         mStateCallback.runOnceAtState(STATE_APP_CONTROLLER_RECEIVED | STATE_GESTURE_STARTED,
-                mRecentsAnimationController::enableInputConsumer);
+                this::startInterceptingTouchesForGesture);
         mStateCallback.setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
 
         mPassedOverviewThreshold = false;
@@ -1457,6 +1454,17 @@
         return swipePipToHomeAnimator;
     }
 
+    private void startInterceptingTouchesForGesture() {
+        if (mRecentsAnimationController == null) {
+            return;
+        }
+
+        mRecentsAnimationController.enableInputConsumer();
+
+        // Start hiding the divider
+        setDividerShown(false /* shown */, true /* immediate */);
+    }
+
     private void computeRecentsScrollIfInvisible() {
         if (mRecentsView != null && mRecentsView.getVisibility() != View.VISIBLE) {
             // Views typically don't compute scroll when invisible as an optimization,
@@ -1760,6 +1768,7 @@
     private void maybeFinishSwipeToHome() {
         if (mIsSwipingPipToHome && mSwipePipToHomeAnimators[0] != null) {
             SystemUiProxy.INSTANCE.get(mContext).stopSwipePipToHome(
+                    mSwipePipToHomeAnimator.getTaskId(),
                     mSwipePipToHomeAnimator.getComponentName(),
                     mSwipePipToHomeAnimator.getDestinationBounds(),
                     mSwipePipToHomeAnimator.getContentOverlay());
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 0f707c0..6584f88 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -19,9 +19,9 @@
 import static com.android.launcher3.anim.Interpolators.ACCEL_2;
 import static com.android.launcher3.anim.Interpolators.INSTANT;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.util.DisplayController.getNavigationMode;
 import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION;
 import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
-import static com.android.quickstep.SysUINavigationMode.getMode;
 import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
 import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
 import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
@@ -55,9 +55,10 @@
 import com.android.launcher3.statemanager.StatefulActivity;
 import com.android.launcher3.taskbar.TaskbarUIController;
 import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.launcher3.util.WindowBounds;
 import com.android.launcher3.views.ScrimView;
-import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.SplitScreenBounds;
@@ -68,6 +69,7 @@
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 
 import java.util.HashMap;
+import java.util.Optional;
 import java.util.function.Consumer;
 import java.util.function.Predicate;
 
@@ -192,7 +194,12 @@
         activity.getStateManager().moveToRestState();
     }
 
-    public void closeOverlay() { }
+    /**
+     * Closes any overlays.
+     */
+    public void closeOverlay() {
+        Optional.ofNullable(getTaskbarController()).ifPresent(TaskbarUIController::hideAllApps);
+    }
 
     public void switchRunningTaskViewToScreenshot(HashMap<Integer, ThumbnailData> thumbnailDatas,
             Runnable runnable) {
@@ -356,8 +363,8 @@
     /** Gets the space that the overview actions will take, including bottom margin. */
     private int getOverviewActionsHeight(Context context, DeviceProfile dp) {
         Resources res = context.getResources();
-        return OverviewActionsView.getOverviewActionsBottomMarginPx(getMode(context), dp)
-                + OverviewActionsView.getOverviewActionsTopMarginPx(getMode(context), dp)
+        return OverviewActionsView.getOverviewActionsBottomMarginPx(getNavigationMode(context), dp)
+                + OverviewActionsView.getOverviewActionsTopMarginPx(getNavigationMode(context), dp)
                 + res.getDimensionPixelSize(R.dimen.overview_actions_height);
     }
 
@@ -480,7 +487,7 @@
             // Creating the activity controller animation sometimes reapplies the launcher state
             // (because we set the animation as the current state animation), so we reapply the
             // attached state here as well to ensure recents is shown/hidden appropriately.
-            if (SysUINavigationMode.getMode(mActivity) == Mode.NO_BUTTON) {
+            if (DisplayController.getNavigationMode(mActivity) == NavigationMode.NO_BUTTON) {
                 setRecentsAttachedToAppWindow(mIsAttachedToWindow, false);
             }
         }
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index ffdfa43..7feec2c 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -16,7 +16,7 @@
 package com.android.quickstep;
 
 import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
-import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
+import static com.android.launcher3.util.DisplayController.NavigationMode.NO_BUTTON;
 import static com.android.quickstep.fallback.RecentsState.BACKGROUND_APP;
 import static com.android.quickstep.fallback.RecentsState.DEFAULT;
 import static com.android.quickstep.fallback.RecentsState.HOME;
@@ -33,6 +33,7 @@
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.taskbar.FallbackTaskbarUIController;
 import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.GestureState.GestureEndTarget;
 import com.android.quickstep.fallback.RecentsState;
 import com.android.quickstep.util.ActivityInitListener;
@@ -62,8 +63,7 @@
     public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
             PagedOrientationHandler orientationHandler) {
         calculateTaskSize(context, dp, outRect);
-        if (dp.isVerticalBarLayout()
-                && SysUINavigationMode.INSTANCE.get(context).getMode() != NO_BUTTON) {
+        if (dp.isVerticalBarLayout() && DisplayController.getNavigationMode(context) != NO_BUTTON) {
             return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
         } else {
             return dp.heightPx - outRect.bottom;
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index a82137e..4eb190a 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -56,6 +56,7 @@
 import com.android.launcher3.anim.AnimatorPlaybackController;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.anim.SpringAnimationBuilder;
+import com.android.launcher3.util.DisplayController;
 import com.android.quickstep.fallback.FallbackRecentsView;
 import com.android.quickstep.fallback.RecentsState;
 import com.android.quickstep.util.RectFSpringAnim;
@@ -176,7 +177,7 @@
     @Override
     protected void notifyGestureAnimationStartToRecents() {
         if (mRunningOverHome) {
-            if (SysUINavigationMode.getMode(mContext).hasGestures) {
+            if (DisplayController.getNavigationMode(mContext).hasGestures) {
                 mRecentsView.onGestureAnimationStartOnHome(
                         new ActivityManager.RunningTaskInfo[]{mGestureState.getRunningTask()});
             }
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 38331a9..10a3a2e 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -44,8 +44,9 @@
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.taskbar.LauncherTaskbarUIController;
 import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.quickstep.GestureState.GestureEndTarget;
-import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.util.ActivityInitListener;
 import com.android.quickstep.util.AnimatorControllerWithResistance;
 import com.android.quickstep.util.LayoutUtils;
@@ -72,7 +73,8 @@
     public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
             PagedOrientationHandler orientationHandler) {
         calculateTaskSize(context, dp, outRect);
-        if (dp.isVerticalBarLayout() && SysUINavigationMode.getMode(context) != Mode.NO_BUTTON) {
+        if (dp.isVerticalBarLayout()
+                && DisplayController.getNavigationMode(context) != NavigationMode.NO_BUTTON) {
             return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
         } else {
             return LayoutUtils.getShelfTrackingDistance(context, dp, orientationHandler);
@@ -278,6 +280,7 @@
 
     @Override
     public void closeOverlay() {
+        super.closeOverlay();
         Launcher launcher = getCreatedActivity();
         if (launcher == null) {
             return;
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 4d13253..e5c7b0e 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -34,6 +34,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.ResourceUtils;
 import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 
 import java.io.PrintWriter;
 import java.util.HashMap;
@@ -112,7 +113,7 @@
      * mQuickstepStartingRotation only updates when device rotation matches touch rotation.
      */
     private int mActiveTouchRotation;
-    private SysUINavigationMode.Mode mMode;
+    private NavigationMode mMode;
     private QuickStepContractInfo mContractInfo;
 
     /**
@@ -135,7 +136,7 @@
     }
 
 
-    OrientationTouchTransformer(Resources resources, SysUINavigationMode.Mode mode,
+    OrientationTouchTransformer(Resources resources, NavigationMode mode,
             QuickStepContractInfo contractInfo) {
         mResources = resources;
         mMode = mode;
@@ -155,7 +156,7 @@
         resetSwipeRegions(info);
     }
 
-    void setNavigationMode(SysUINavigationMode.Mode newMode, Info info, Resources newRes) {
+    void setNavigationMode(NavigationMode newMode, Info info, Resources newRes) {
         if (DEBUG) {
             Log.d(TAG, "setNavigationMode new: " + newMode + " oldMode: " + mMode + " " + this);
         }
@@ -212,8 +213,7 @@
      * @param info The current displayInfo which will be the start of the quickswitch gesture
      */
     void enableMultipleRegions(boolean enableMultipleRegions, Info info) {
-        mEnableMultipleRegions = enableMultipleRegions &&
-                mMode != SysUINavigationMode.Mode.TWO_BUTTONS;
+        mEnableMultipleRegions = enableMultipleRegions && mMode != NavigationMode.TWO_BUTTONS;
         if (mEnableMultipleRegions) {
             mQuickStepStartingRotation = info.rotation;
         } else {
@@ -276,9 +276,8 @@
         Point size = display.currentSize;
         int rotation = display.rotation;
         int touchHeight = mNavBarGesturalHeight;
-        OrientationRectF orientationRectF =
-                new OrientationRectF(0, 0, size.x, size.y, rotation);
-        if (mMode == SysUINavigationMode.Mode.NO_BUTTON) {
+        OrientationRectF orientationRectF = new OrientationRectF(0, 0, size.x, size.y, rotation);
+        if (mMode == NavigationMode.NO_BUTTON) {
             orientationRectF.top = orientationRectF.bottom - touchHeight;
             updateAssistantRegions(orientationRectF);
         } else {
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
index f343485..c120b32 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java
@@ -17,9 +17,13 @@
 
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
 
+import android.os.RemoteException;
+import android.util.Log;
 import android.view.IRecentsAnimationController;
 import android.view.SurfaceControl;
+import android.view.WindowManagerGlobal;
 import android.window.PictureInPictureSurfaceTransaction;
 
 import androidx.annotation.NonNull;
@@ -39,6 +43,7 @@
  */
 public class RecentsAnimationController {
 
+    private static final String TAG = "RecentsAnimationController";
     private final RecentsAnimationControllerCompat mController;
     private final Consumer<RecentsAnimationController> mOnFinishedListener;
     private final boolean mAllowMinimizeSplitScreen;
@@ -74,7 +79,16 @@
         if (mUseLauncherSysBarFlags != useLauncherSysBarFlags) {
             mUseLauncherSysBarFlags = useLauncherSysBarFlags;
             UI_HELPER_EXECUTOR.execute(() -> {
-                mController.setAnimationTargetsBehindSystemBars(!useLauncherSysBarFlags);
+                if (!ENABLE_SHELL_TRANSITIONS) {
+                    mController.setAnimationTargetsBehindSystemBars(!useLauncherSysBarFlags);
+                } else {
+                    try {
+                        WindowManagerGlobal.getWindowManagerService().setRecentsAppBehindSystemBars(
+                                useLauncherSysBarFlags);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Unable to reach window manager", e);
+                    }
+                }
             });
         }
     }
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index ad57683..f1ace49 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -21,12 +21,13 @@
 import static android.view.Display.DEFAULT_DISPLAY;
 
 import static com.android.launcher3.util.DisplayController.CHANGE_ALL;
+import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION;
+import static com.android.launcher3.util.DisplayController.NavigationMode.NO_BUTTON;
+import static com.android.launcher3.util.DisplayController.NavigationMode.THREE_BUTTONS;
+import static com.android.launcher3.util.DisplayController.NavigationMode.TWO_BUTTONS;
 import static com.android.launcher3.util.SettingsCache.ONE_HANDED_ENABLED;
 import static com.android.launcher3.util.SettingsCache.ONE_HANDED_SWIPE_BOTTOM_TO_NOTIFICATION_ENABLED;
-import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
-import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
-import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY;
@@ -71,9 +72,8 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
 import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.launcher3.util.SettingsCache;
-import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
-import com.android.quickstep.SysUINavigationMode.OneHandedModeChangeListener;
 import com.android.quickstep.util.NavBarPosition;
 import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -89,15 +89,11 @@
 /**
  * Manages the state of the system during a swipe up gesture.
  */
-public class RecentsAnimationDeviceState implements
-        NavigationModeChangeListener,
-        DisplayInfoChangeListener,
-        OneHandedModeChangeListener {
+public class RecentsAnimationDeviceState implements DisplayInfoChangeListener {
 
     static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
 
     private final Context mContext;
-    private final SysUINavigationMode mSysUiNavMode;
     private final DisplayController mDisplayController;
     private final int mDisplayId;
     private final RotationTouchHelper mRotationTouchHelper;
@@ -110,7 +106,7 @@
     private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>();
 
     private @SystemUiStateFlags int mSystemUiStateFlags;
-    private SysUINavigationMode.Mode mMode = THREE_BUTTONS;
+    private NavigationMode mMode = THREE_BUTTONS;
     private NavBarPosition mNavBarPosition;
 
     private final Region mDeferredGestureRegion = new Region();
@@ -148,10 +144,8 @@
     public RecentsAnimationDeviceState(Context context, boolean isInstanceForTouches) {
         mContext = context;
         mDisplayController = DisplayController.INSTANCE.get(context);
-        mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context);
         mDisplayId = DEFAULT_DISPLAY;
         mIsOneHandedModeSupported = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false);
-        runOnDestroy(() -> mDisplayController.removeChangeListener(this));
         mRotationTouchHelper = RotationTouchHelper.INSTANCE.get(context);
         if (isInstanceForTouches) {
             // rotationTouchHelper doesn't get initialized after being destroyed, so only destroy
@@ -180,9 +174,10 @@
         };
         runOnDestroy(mExclusionListener::unregister);
 
-        // Register for navigation mode changes
-        onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(this));
-        runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(this));
+        // Register for display changes changes
+        mDisplayController.addChangeListener(this);
+        onDisplayInfoChanged(context, mDisplayController.getInfo(), CHANGE_ALL);
+        runOnDestroy(() -> mDisplayController.removeChangeListener(this));
 
         // Add any blocked activities
         String[] blockingActivities;
@@ -267,47 +262,36 @@
      * Adds a listener for the nav mode change, guaranteed to be called after the device state's
      * mode has changed.
      */
-    public void addNavigationModeChangedCallback(NavigationModeChangeListener listener) {
-        listener.onNavigationModeChanged(mSysUiNavMode.addModeChangeListener(listener));
-        runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(listener));
-    }
-
-    @Override
-    public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
-        mDisplayController.removeChangeListener(this);
-        mDisplayController.addChangeListener(this);
-        onDisplayInfoChanged(mContext, mDisplayController.getInfo(), CHANGE_ALL);
-
-        if (newMode == NO_BUTTON) {
-            mExclusionListener.register();
-        } else {
-            mExclusionListener.unregister();
-        }
-
-        mNavBarPosition = new NavBarPosition(newMode, mDisplayController.getInfo());
-        mMode = newMode;
+    public void addNavigationModeChangedCallback(Runnable callback) {
+        DisplayController.DisplayInfoChangeListener listener = (context, info, flags) -> {
+            if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
+                callback.run();
+            }
+        };
+        mDisplayController.addChangeListener(listener);
+        callback.run();
+        runOnDestroy(() -> mDisplayController.removeChangeListener(listener));
     }
 
     @Override
     public void onDisplayInfoChanged(Context context, Info info, int flags) {
-        if ((flags & CHANGE_ROTATION) != 0) {
+        if ((flags & (CHANGE_ROTATION | CHANGE_NAVIGATION_MODE)) != 0) {
+            mMode = info.navigationMode;
             mNavBarPosition = new NavBarPosition(mMode, info);
+
+            if (mMode == NO_BUTTON) {
+                mExclusionListener.register();
+            } else {
+                mExclusionListener.unregister();
+            }
         }
     }
 
-    @Override
     public void onOneHandedModeChanged(int newGesturalHeight) {
         mRotationTouchHelper.setGesturalHeight(newGesturalHeight);
     }
 
     /**
-     * @return the current navigation mode for the device.
-     */
-    public SysUINavigationMode.Mode getNavMode() {
-        return mMode;
-    }
-
-    /**
      * @return the nav bar position for the current nav bar mode and display rotation.
      */
     public NavBarPosition getNavBarPosition() {
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index 35efddf..dad5071 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -20,9 +20,10 @@
 
 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
 import static com.android.launcher3.util.DisplayController.CHANGE_ALL;
+import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION;
+import static com.android.launcher3.util.DisplayController.NavigationMode.THREE_BUTTONS;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
 
 import android.content.Context;
 import android.content.res.Resources;
@@ -33,6 +34,7 @@
 import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
 import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.quickstep.util.RecentsOrientedState;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -42,22 +44,22 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
-public class RotationTouchHelper implements
-        SysUINavigationMode.NavigationModeChangeListener,
-        DisplayInfoChangeListener {
+/**
+ * Helper class for transforming touch events
+ */
+public class RotationTouchHelper implements DisplayInfoChangeListener {
 
     public static final MainThreadInitializedObject<RotationTouchHelper> INSTANCE =
             new MainThreadInitializedObject<>(RotationTouchHelper::new);
 
     private OrientationTouchTransformer mOrientationTouchTransformer;
     private DisplayController mDisplayController;
-    private SysUINavigationMode mSysUiNavMode;
     private int mDisplayId;
     private int mDisplayRotation;
 
     private final ArrayList<Runnable> mOnDestroyActions = new ArrayList<>();
 
-    private SysUINavigationMode.Mode mMode = THREE_BUTTONS;
+    private NavigationMode mMode = THREE_BUTTONS;
 
     private TaskStackChangeListener mFrozenTaskListener = new TaskStackChangeListener() {
         @Override
@@ -144,16 +146,16 @@
         }
         mDisplayController = DisplayController.INSTANCE.get(mContext);
         Resources resources = mContext.getResources();
-        mSysUiNavMode = SysUINavigationMode.INSTANCE.get(mContext);
         mDisplayId = DEFAULT_DISPLAY;
 
         mOrientationTouchTransformer = new OrientationTouchTransformer(resources, mMode,
                 () -> QuickStepContract.getWindowCornerRadius(mContext));
 
         // Register for navigation mode changes
-        SysUINavigationMode.Mode newMode = mSysUiNavMode.addModeChangeListener(this);
-        onNavModeChangedInternal(newMode, newMode.hasGestures);
-        runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(this));
+        mDisplayController.addChangeListener(this);
+        DisplayController.Info info = mDisplayController.getInfo();
+        onDisplayInfoChangedInternal(info, CHANGE_ALL, info.navigationMode.hasGestures);
+        runOnDestroy(() -> mDisplayController.removeChangeListener(this));
 
         mOrientationListener = new OrientationEventListener(mContext) {
             @Override
@@ -242,66 +244,56 @@
                 event.getY(pointerIndex));
     }
 
-
     @Override
-    public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
-        onNavModeChangedInternal(newMode, false);
+    public void onDisplayInfoChanged(Context context, Info info, int flags) {
+        onDisplayInfoChangedInternal(info, flags, false);
     }
 
-    /**
-     * @param forceRegister if {@code true}, this will register {@link #mFrozenTaskListener} via
-     *                      {@link #setupOrientationSwipeHandler()}
-     */
-    private void onNavModeChangedInternal(SysUINavigationMode.Mode newMode, boolean forceRegister) {
-        mDisplayController.removeChangeListener(this);
-        mDisplayController.addChangeListener(this);
-        onDisplayInfoChanged(mContext, mDisplayController.getInfo(), CHANGE_ALL);
+    private void onDisplayInfoChangedInternal(Info info, int flags, boolean forceRegister) {
+        if ((flags & (CHANGE_ROTATION | CHANGE_ACTIVE_SCREEN | CHANGE_NAVIGATION_MODE)) != 0) {
+            mDisplayRotation = info.rotation;
 
-        mOrientationTouchTransformer.setNavigationMode(newMode, mDisplayController.getInfo(),
-                mContext.getResources());
+            if (mMode.hasGestures) {
+                updateGestureTouchRegions();
+                mOrientationTouchTransformer.createOrAddTouchRegion(info);
+                mCurrentAppRotation = mDisplayRotation;
 
-        if (forceRegister || (!mMode.hasGestures && newMode.hasGestures)) {
-            setupOrientationSwipeHandler();
-        } else if (mMode.hasGestures && !newMode.hasGestures){
-            destroyOrientationSwipeHandlerCallback();
+                /* Update nav bars on the following:
+                 * a) if this is coming from an activity rotation OR
+                 *   aa) we launch an app in the orientation that user is already in
+                 * b) We're not in overview, since overview will always be portrait (w/o home
+                 *   rotation)
+                 * c) We're actively in quickswitch mode
+                 */
+                if ((mPrioritizeDeviceRotation
+                        || mCurrentAppRotation == mSensorRotation)
+                        // switch to an app of orientation user is in
+                        && !mInOverview
+                        && mTaskListFrozen) {
+                    toggleSecondaryNavBarsForRotation();
+                }
+            }
         }
 
-        mMode = newMode;
+        if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
+            NavigationMode newMode = info.navigationMode;
+            mOrientationTouchTransformer.setNavigationMode(newMode, mDisplayController.getInfo(),
+                    mContext.getResources());
+
+            if (forceRegister || (!mMode.hasGestures && newMode.hasGestures)) {
+                setupOrientationSwipeHandler();
+            } else if (mMode.hasGestures && !newMode.hasGestures) {
+                destroyOrientationSwipeHandlerCallback();
+            }
+
+            mMode = newMode;
+        }
     }
 
     public int getDisplayRotation() {
         return mDisplayRotation;
     }
 
-    @Override
-    public void onDisplayInfoChanged(Context context, Info info, int flags) {
-        if ((flags & (CHANGE_ROTATION | CHANGE_ACTIVE_SCREEN)) == 0) {
-            return;
-        }
-
-        mDisplayRotation = info.rotation;
-
-        if (!mMode.hasGestures) {
-            return;
-        }
-        updateGestureTouchRegions();
-        mOrientationTouchTransformer.createOrAddTouchRegion(info);
-        mCurrentAppRotation = mDisplayRotation;
-
-        /* Update nav bars on the following:
-         * a) if this is coming from an activity rotation OR
-         *   aa) we launch an app in the orientation that user is already in
-         * b) We're not in overview, since overview will always be portrait (w/o home rotation)
-         * c) We're actively in quickswitch mode
-         */
-        if ((mPrioritizeDeviceRotation
-                || mCurrentAppRotation == mSensorRotation) // switch to an app of orientation user is in
-                && !mInOverview
-                && mTaskListFrozen) {
-            toggleSecondaryNavBarsForRotation();
-        }
-    }
-
     /**
      * Sets the gestural height.
      */
diff --git a/quickstep/src/com/android/quickstep/SysUINavigationMode.java b/quickstep/src/com/android/quickstep/SysUINavigationMode.java
deleted file mode 100644
index 406414c..0000000
--- a/quickstep/src/com/android/quickstep/SysUINavigationMode.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep;
-
-import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_2_BUTTON;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_3_BUTTON;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON;
-import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter;
-
-import android.content.BroadcastReceiver;
-import android.content.Context;
-import android.content.Intent;
-import android.util.Log;
-
-import com.android.launcher3.ResourceUtils;
-import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
-import com.android.launcher3.util.MainThreadInitializedObject;
-
-import java.io.PrintWriter;
-import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
-
-/**
- * Observer for the resource config that specifies the navigation bar mode.
- */
-public class SysUINavigationMode {
-
-    public enum Mode {
-        THREE_BUTTONS(false, 0, LAUNCHER_NAVIGATION_MODE_3_BUTTON),
-        TWO_BUTTONS(true, 1, LAUNCHER_NAVIGATION_MODE_2_BUTTON),
-        NO_BUTTON(true, 2, LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON);
-
-        public final boolean hasGestures;
-        public final int resValue;
-        public final LauncherEvent launcherEvent;
-
-        Mode(boolean hasGestures, int resValue, LauncherEvent launcherEvent) {
-            this.hasGestures = hasGestures;
-            this.resValue = resValue;
-            this.launcherEvent = launcherEvent;
-        }
-    }
-
-    public static Mode getMode(Context context) {
-        return INSTANCE.get(context).getMode();
-    }
-
-    public static boolean getImeDrawsImeNavBar(Context context) {
-        return INSTANCE.get(context).getImeDrawsImeNavBar();
-    }
-
-    public static final MainThreadInitializedObject<SysUINavigationMode> INSTANCE =
-            new MainThreadInitializedObject<>(SysUINavigationMode::new);
-
-    private static final String TAG = "SysUINavigationMode";
-    private static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED";
-    private static final String NAV_BAR_INTERACTION_MODE_RES_NAME = "config_navBarInteractionMode";
-    private static final String IME_DRAWS_IME_NAV_BAR_RES_NAME = "config_imeDrawsImeNavBar";
-    private static final String TARGET_OVERLAY_PACKAGE = "android";
-
-    private final Context mContext;
-    private Mode mMode;
-    private boolean mImeDrawsImeNavBar;
-
-    private int mNavBarGesturalHeight;
-    private int mNavBarLargerGesturalHeight;
-
-    private final List<NavigationModeChangeListener> mChangeListeners =
-            new CopyOnWriteArrayList<>();
-
-    public SysUINavigationMode(Context context) {
-        mContext = context;
-        initializeMode();
-
-        mContext.registerReceiver(new BroadcastReceiver() {
-            @Override
-            public void onReceive(Context context, Intent intent) {
-                updateMode();
-                updateGesturalHeight();
-            }
-        }, getPackageFilter(TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED));
-    }
-
-    /** Updates navigation mode when needed. */
-    public void updateMode() {
-        Mode oldMode = mMode;
-        initializeMode();
-        if (mMode != oldMode) {
-            dispatchModeChange();
-        }
-    }
-
-    private void updateGesturalHeight() {
-        int newGesturalHeight = ResourceUtils.getDimenByName(
-                ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mContext.getResources(),
-                INVALID_RESOURCE_HANDLE);
-
-        if (newGesturalHeight == INVALID_RESOURCE_HANDLE) {
-            Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
-            return;
-        }
-
-        if (mNavBarGesturalHeight != newGesturalHeight) {
-            mNavBarGesturalHeight = newGesturalHeight;
-        }
-
-        int newLargerGesturalHeight = ResourceUtils.getDimenByName(
-                ResourceUtils.NAVBAR_BOTTOM_GESTURE_LARGER_SIZE, mContext.getResources(),
-                INVALID_RESOURCE_HANDLE);
-        if (newLargerGesturalHeight == INVALID_RESOURCE_HANDLE) {
-            Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
-            return;
-        }
-        if (mNavBarLargerGesturalHeight != newLargerGesturalHeight) {
-            mNavBarLargerGesturalHeight = newLargerGesturalHeight;
-        }
-    }
-
-    private void initializeMode() {
-        int modeInt = ResourceUtils.getIntegerByName(NAV_BAR_INTERACTION_MODE_RES_NAME,
-                mContext.getResources(), INVALID_RESOURCE_HANDLE);
-        mNavBarGesturalHeight = ResourceUtils.getDimenByName(
-                ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE, mContext.getResources(),
-                INVALID_RESOURCE_HANDLE);
-        mNavBarLargerGesturalHeight = ResourceUtils.getDimenByName(
-                ResourceUtils.NAVBAR_BOTTOM_GESTURE_LARGER_SIZE, mContext.getResources(),
-                mNavBarGesturalHeight);
-        mImeDrawsImeNavBar = ResourceUtils.getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME,
-                mContext.getResources(), false);
-
-        if (modeInt == INVALID_RESOURCE_HANDLE) {
-            Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
-            return;
-        }
-
-        for (Mode m : Mode.values()) {
-            if (m.resValue == modeInt) {
-                mMode = m;
-            }
-        }
-    }
-
-    private void dispatchModeChange() {
-        for (NavigationModeChangeListener listener : mChangeListeners) {
-            listener.onNavigationModeChanged(mMode);
-        }
-    }
-
-    public Mode addModeChangeListener(NavigationModeChangeListener listener) {
-        mChangeListeners.add(listener);
-        return mMode;
-    }
-
-    public void removeModeChangeListener(NavigationModeChangeListener listener) {
-        mChangeListeners.remove(listener);
-    }
-
-    public Mode getMode() {
-        return mMode;
-    }
-
-    public boolean getImeDrawsImeNavBar() {
-        return mImeDrawsImeNavBar;
-    }
-
-    public void dump(PrintWriter pw) {
-        pw.println("SysUINavigationMode:");
-        pw.println("  mode=" + mMode.name());
-        pw.println("  mImeDrawsImeNavBar=:" + mImeDrawsImeNavBar);
-        pw.println("  mNavBarGesturalHeight=:" + mNavBarGesturalHeight);
-    }
-
-    public interface NavigationModeChangeListener {
-        void onNavigationModeChanged(Mode newMode);
-    }
-
-    public interface OneHandedModeChangeListener {
-        void onOneHandedModeChanged(int newGesturalHeight);
-    }
-}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 8b00f45..667ea14 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -17,6 +17,7 @@
 
 import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
 
+import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.app.PendingIntent;
@@ -39,6 +40,8 @@
 import android.view.RemoteAnimationTarget;
 import android.view.SurfaceControl;
 
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.Info;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SplitConfigurationOptions;
 import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -65,8 +68,7 @@
 /**
  * Holds the reference to SystemUI.
  */
-public class SystemUiProxy implements ISystemUiProxy,
-        SysUINavigationMode.NavigationModeChangeListener {
+public class SystemUiProxy implements ISystemUiProxy, DisplayController.DisplayInfoChangeListener {
     private static final String TAG = SystemUiProxy.class.getSimpleName();
 
     public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =
@@ -107,13 +109,15 @@
     private int mLastSystemUiStateFlags;
 
     public SystemUiProxy(Context context) {
-        SysUINavigationMode.INSTANCE.get(context).addModeChangeListener(this);
+        DisplayController.INSTANCE.get(context).addChangeListener(this);
     }
 
     @Override
-    public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
-        // Whenever the nav mode changes, force reset the nav button alpha
-        setNavBarButtonAlpha(1f, false);
+    public void onDisplayInfoChanged(Context context, Info info, int flags) {
+        if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
+            // Whenever the nav mode changes, force reset the nav button alpha
+            setNavBarButtonAlpha(1f, false);
+        }
     }
 
     @Override
@@ -541,11 +545,16 @@
         return null;
     }
 
-    public void stopSwipePipToHome(ComponentName componentName, Rect destinationBounds,
+    /**
+     * Notifies WM Shell that launcher has finished all the animation for swipe to home. WM Shell
+     * can choose to fade out the overlay when entering PIP is finished, and WM Shell should be
+     * responsible for cleaning up the overlay.
+     */
+    public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
             SurfaceControl overlay) {
         if (mPip != null) {
             try {
-                mPip.stopSwipePipToHome(componentName, destinationBounds, overlay);
+                mPip.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed call stopSwipePipToHome");
             }
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 5e298f4..57b42f8 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -44,14 +44,14 @@
 import com.android.systemui.shared.system.TaskStackChangeListener;
 import com.android.systemui.shared.system.TaskStackChangeListeners;
 
-import java.util.Arrays;
+import java.util.ArrayList;
 import java.util.HashMap;
 
 public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
     public static final boolean ENABLE_SHELL_TRANSITIONS =
-            SystemProperties.getBoolean("persist.debug.shell_transit", false);
+            SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
     public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
-            && SystemProperties.getBoolean("persist.debug.shell_transit_rotate", false);
+            && SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
 
     private RecentsAnimationController mController;
     private RecentsAnimationCallbacks mCallbacks;
@@ -156,12 +156,26 @@
                 RemoteAnimationTargetCompat appearedTaskTarget = appearedTaskTargets[0];
                 BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
                 // Convert appTargets to type RemoteAnimationTarget for all apps except Home app
-                RemoteAnimationTarget[] nonHomeApps = Arrays.stream(appearedTaskTargets)
-                        .filter(remoteAnimationTarget ->
-                                remoteAnimationTarget.activityType != ACTIVITY_TYPE_HOME)
+                final ArrayList<RemoteAnimationTargetCompat> tmpNonHomeApps = new ArrayList<>();
+                final ArrayList<RemoteAnimationTargetCompat> tmpHomeApps = new ArrayList<>();
+                for (RemoteAnimationTargetCompat compat : appearedTaskTargets) {
+                    if (compat.activityType != ACTIVITY_TYPE_HOME) {
+                        tmpNonHomeApps.add(compat);
+                    } else {
+                        tmpHomeApps.add(compat);
+                    }
+                }
+                RemoteAnimationTarget[] nonHomeApps = tmpNonHomeApps.stream()
                         .map(RemoteAnimationTargetCompat::unwrap)
                         .toArray(RemoteAnimationTarget[]::new);
-
+                RemoteAnimationTarget[] homeApps = tmpHomeApps.stream()
+                        .map(RemoteAnimationTargetCompat::unwrap)
+                        .toArray(RemoteAnimationTarget[]::new);
+                if (homeApps.length > 0
+                        && activityInterface.getCreatedActivity() instanceof RecentsActivity) {
+                    ((RecentsActivity) activityInterface.getCreatedActivity()).startHome();
+                    return;
+                }
                 RemoteAnimationTarget[] nonAppTargets =
                         SystemUiProxy.INSTANCE.getNoCreate()
                                 .onGoingToRecentsLegacy(false, nonHomeApps);
@@ -198,8 +212,16 @@
             RemoteTransitionCompat transition = new RemoteTransitionCompat(mCallbacks,
                     mController != null ? mController.getController() : null,
                     mCtx.getIApplicationThread());
-            final ActivityOptions options = ActivityOptionsCompat.makeRemoteTransition(transition)
-                    .setTransientLaunch();
+            final ActivityOptions options = ActivityOptionsCompat.makeRemoteTransition(transition);
+            // Allowing to pause Home if Home is top activity and Recents is not Home. So when user
+            // start home when recents animation is playing, the home activity can be resumed again
+            // to let the transition controller collect Home activity.
+            ActivityManager.RunningTaskInfo rti = gestureState.getRunningTask();
+            boolean homeIsOnTop = rti != null && rti.topActivity != null
+                    && rti.topActivity.equals(gestureState.getHomeIntent().getComponent());
+            if (!homeIsOnTop) {
+                options.setTransientLaunch();
+            }
             options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
             UI_HELPER_EXECUTOR.execute(() -> mCtx.startActivity(intent, options.toBundle()));
         } else {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index fc5f34d..021048a 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -47,7 +47,6 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.drawable.Icon;
-import android.hardware.display.DisplayManager;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -77,6 +76,7 @@
 import com.android.launcher3.tracing.LauncherTraceProto;
 import com.android.launcher3.tracing.TouchInteractionServiceProto;
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.OnboardingPrefs;
 import com.android.launcher3.util.TraceHelper;
 import com.android.launcher3.util.WindowBounds;
@@ -344,8 +344,6 @@
     private InputMonitorCompat mInputMonitorCompat;
     private InputEventReceiver mInputEventReceiver;
 
-    private DisplayManager mDisplayManager;
-
     private TaskbarManager mTaskbarManager;
     private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null;
 
@@ -357,7 +355,6 @@
         mMainChoreographer = Choreographer.getInstance();
         mAM = ActivityManagerWrapper.getInstance();
         mDeviceState = new RecentsAnimationDeviceState(this, true);
-        mDisplayManager = getSystemService(DisplayManager.class);
         mTaskbarManager = new TaskbarManager(this);
         mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
 
@@ -399,7 +396,7 @@
     /**
      * Called when the navigation mode changes, guaranteed to be after the device state has updated.
      */
-    private void onNavigationModeChanged(SysUINavigationMode.Mode mode) {
+    private void onNavigationModeChanged() {
         initInputMonitor();
         resetHomeBounceSeenOnQuickstepEnabledFirstTime();
     }
@@ -762,7 +759,10 @@
         } else if (gestureState.getRunningTask() == null) {
             return getDefaultInputConsumer();
         } else if (previousGestureState.isRunningAnimationToLauncher()
-                || gestureState.getActivityInterface().isResumed()
+                || (gestureState.getActivityInterface().isResumed()
+                        // with shell-transitions, home is resumed during recents animation, so
+                        // explicitly check against recents animation too.
+                        && !previousGestureState.isRecentsAnimationRunning())
                 || forceOverviewInputConsumer) {
             return createOverviewInputConsumer(
                     previousGestureState, gestureState, event, forceOverviewInputConsumer);
@@ -945,7 +945,7 @@
             pw.println("Input state:");
             pw.println("  mInputMonitorCompat=" + mInputMonitorCompat);
             pw.println("  mInputEventReceiver=" + mInputEventReceiver);
-            SysUINavigationMode.INSTANCE.get(this).dump(pw);
+            DisplayController.INSTANCE.get(this).dump(pw);
             pw.println("TouchState:");
             BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
                     : mOverviewComponentObserver.getActivityInterface().getCreatedActivity();
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
index 9d9ef94..3e01ed0 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
@@ -22,9 +22,9 @@
 
 import com.android.launcher3.Utilities;
 import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.launcher3.util.TouchController;
 import com.android.quickstep.RecentsActivity;
-import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.util.NavBarPosition;
 import com.android.quickstep.util.TriggerSwipeUpTouchTracker;
 
@@ -40,8 +40,8 @@
 
     public FallbackNavBarTouchController(RecentsActivity activity) {
         mActivity = activity;
-        SysUINavigationMode.Mode sysUINavigationMode = SysUINavigationMode.getMode(mActivity);
-        if (sysUINavigationMode == SysUINavigationMode.Mode.NO_BUTTON) {
+        NavigationMode sysUINavigationMode = DisplayController.getNavigationMode(mActivity);
+        if (sysUINavigationMode == NavigationMode.NO_BUTTON) {
             NavBarPosition navBarPosition = new NavBarPosition(sysUINavigationMode,
                     DisplayController.INSTANCE.get(mActivity).getInfo());
             mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(mActivity,
diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
index 851cccf..a8163af 100644
--- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
@@ -47,7 +47,7 @@
 import com.android.launcher3.R;
 import com.android.launcher3.ResourceUtils;
 import com.android.launcher3.anim.Interpolators;
-import com.android.quickstep.SysUINavigationMode.Mode;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.quickstep.util.MotionPauseDetector;
 import com.android.quickstep.util.NavBarPosition;
 import com.android.quickstep.util.TriggerSwipeUpTouchTracker;
@@ -101,7 +101,7 @@
         }
         mSwipeUpTouchTracker =
                 new TriggerSwipeUpTouchTracker(context, true /*disableHorizontalSwipe*/,
-                        new NavBarPosition(Mode.NO_BUTTON, displayRotation),
+                        new NavBarPosition(NavigationMode.NO_BUTTON, displayRotation),
                         null /*onInterceptTouch*/, this);
         mMotionPauseDetector = new MotionPauseDetector(context);
 
diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 672687d..2db4c20 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -16,7 +16,7 @@
 package com.android.quickstep.interaction;
 
 import static com.android.launcher3.anim.Interpolators.ACCEL;
-import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
+import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
 import static com.android.quickstep.AbsSwipeUpHandler.MAX_SWIPE_DURATION;
 import static com.android.quickstep.interaction.TutorialController.TutorialType.HOME_NAVIGATION_COMPLETE;
@@ -336,8 +336,7 @@
                             1f - SHAPE_PROGRESS_DURATION /* shapeProgressStart */,
                             radius, 255,
                             false, /* isOpening */
-                            mFakeIconView, mDp,
-                            false /* isVerticalBarLayout */);
+                            mFakeIconView, mDp);
                     mFakeIconView.setAlpha(1);
                     mFakeTaskView.setAlpha(getWindowAlpha(progress));
                     mFakePreviousTaskView.setAlpha(getWindowAlpha(progress));
diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
index a0cd0d7..bd0250d 100644
--- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
+++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
@@ -26,6 +26,7 @@
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_ENABLED;
 import static com.android.launcher3.model.DeviceGridState.KEY_WORKSPACE_SIZE;
 import static com.android.launcher3.model.QuickstepModelDelegate.LAST_PREDICTION_ENABLED_STATE;
+import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
 import static com.android.launcher3.util.Themes.KEY_THEMED_ICONS;
 
@@ -44,11 +45,11 @@
 import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.logging.StatsLogManager.StatsLogger;
 import com.android.launcher3.model.DeviceGridState;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.Info;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SettingsCache;
-import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.SysUINavigationMode.Mode;
-import com.android.quickstep.SysUINavigationMode.NavigationModeChangeListener;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -60,8 +61,8 @@
  * Utility class to log launcher settings changes
  */
 public class SettingsChangeLogger implements
-        NavigationModeChangeListener, OnSharedPreferenceChangeListener {
-  
+        DisplayController.DisplayInfoChangeListener, OnSharedPreferenceChangeListener {
+
     /**
      * Singleton instance
      */
@@ -76,7 +77,7 @@
     private final ArrayMap<String, LoggablePref> mLoggablePrefs;
     private final StatsLogManager mStatsLogManager;
 
-    private Mode mNavMode;
+    private NavigationMode mNavMode;
     private StatsLogManager.LauncherEvent mNotificationDotsEvent;
     private StatsLogManager.LauncherEvent mHomeScreenSuggestionEvent;
 
@@ -84,7 +85,8 @@
         mContext = context;
         mStatsLogManager = StatsLogManager.newInstance(mContext);
         mLoggablePrefs = loadPrefKeys(context);
-        mNavMode = SysUINavigationMode.INSTANCE.get(context).addModeChangeListener(this);
+        DisplayController.INSTANCE.get(context).addChangeListener(this);
+        mNavMode = DisplayController.getNavigationMode(context);
 
         getPrefs(context).registerOnSharedPreferenceChangeListener(this);
         getDevicePrefs(context).registerOnSharedPreferenceChangeListener(this);
@@ -141,9 +143,11 @@
     }
 
     @Override
-    public void onNavigationModeChanged(Mode newMode) {
-        mNavMode = newMode;
-        mStatsLogManager.logger().log(newMode.launcherEvent);
+    public void onDisplayInfoChanged(Context context, Info info, int flags) {
+        if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
+            mNavMode = info.navigationMode;
+            mStatsLogManager.logger().log(mNavMode.launcherEvent);
+        }
     }
 
     @Override
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index 12a638a..d85515a 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -42,10 +42,12 @@
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.Utilities;
 import com.android.launcher3.logger.LauncherAtom;
+import com.android.launcher3.logger.LauncherAtom.Attribute;
 import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
 import com.android.launcher3.logger.LauncherAtom.FolderContainer.ParentContainerCase;
 import com.android.launcher3.logger.LauncherAtom.FolderIcon;
 import com.android.launcher3.logger.LauncherAtom.FromState;
+import com.android.launcher3.logger.LauncherAtom.LauncherAttributes;
 import com.android.launcher3.logger.LauncherAtom.ToState;
 import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer;
 import com.android.launcher3.logger.LauncherAtomExtensions.DeviceSearchResultContainer.SearchAttributes;
@@ -88,13 +90,14 @@
     private static final int FOLDER_HIERARCHY_OFFSET = 100;
     private static final int SEARCH_RESULT_HIERARCHY_OFFSET = 200;
     private static final int EXTENDED_CONTAINERS_HIERARCHY_OFFSET = 300;
-    private static final int ATTRIBUTE_MULTIPLIER = 100;
 
     /**
      * Flags for converting SearchAttribute to integer value.
      */
-    private static final int SEARCH_ATTRIBUTES_CORRECTED_QUERY = 1;
+    private static final int SEARCH_ATTRIBUTES_CORRECTED_QUERY = 1 << 0;
     private static final int SEARCH_ATTRIBUTES_DIRECT_MATCH = 1 << 1;
+    private static final int SEARCH_ATTRIBUTES_ENTRY_STATE_ALL_APPS = 1 << 2;
+    private static final int SEARCH_ATTRIBUTES_ENTRY_STATE_QSB = 1 << 3;
 
     public static final CopyOnWriteArrayList<StatsLogConsumer> LOGS_CONSUMER =
             new CopyOnWriteArrayList<>();
@@ -110,6 +113,11 @@
         return new StatsCompatLogger(mContext, mActivityContext);
     }
 
+    @Override
+    protected StatsLatencyLogger createLatencyLogger() {
+        return new StatsCompatLatencyLogger(mContext, mActivityContext);
+    }
+
     /**
      * Synchronously writes an itemInfo to stats log
      */
@@ -123,8 +131,7 @@
         }
         SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_SNAPSHOT,
                 LAUNCHER_WORKSPACE_SNAPSHOT.getId() /* event_id */,
-                info.getAttribute().getNumber() * ATTRIBUTE_MULTIPLIER
-                        + info.getItemCase().getNumber()  /* target_id */,
+                info.getItemCase().getNumber()  /* target_id */,
                 instanceId.getId() /* instance_id */,
                 0 /* uid */,
                 getPackageName(info) /* package_name */,
@@ -137,11 +144,20 @@
                 getParentPageId(info) /* page_id_parent */,
                 getHierarchy(info) /* hierarchy */,
                 info.getIsWork() /* is_work_profile */,
-                info.getAttribute().getNumber() /* origin */,
+                0 /* origin */,
                 getCardinality(info) /* cardinality */,
                 info.getWidget().getSpanX(),
                 info.getWidget().getSpanY(),
-                getFeatures(info));
+                getFeatures(info),
+                getAttributes(info) /* attributes */
+        );
+    }
+
+    private static byte[] getAttributes(LauncherAtom.ItemInfo itemInfo) {
+        LauncherAttributes.Builder responseBuilder = LauncherAttributes.newBuilder();
+        itemInfo.getItemAttributesList().stream().map(Attribute::getNumber).forEach(
+                responseBuilder::addItemAttributes);
+        return responseBuilder.build().toByteArray();
     }
 
     /**
@@ -153,8 +169,7 @@
         return SysUiStatsLog.buildStatsEvent(
                 SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT, // atom ID,
                 LAUNCHER_WORKSPACE_SNAPSHOT.getId(), // event_id = 1;
-                info.getAttribute().getNumber() * ATTRIBUTE_MULTIPLIER
-                        + info.getItemCase().getNumber(), // item_id = 2;
+                info.getItemCase().getNumber(), // item_id = 2;
                 instanceId == null ? 0 : instanceId.getId(), //instance_id = 3;
                 0, //uid = 4 [(is_uid) = true];
                 getPackageName(info), // package_name = 5;
@@ -167,10 +182,11 @@
                 getParentPageId(info), //page_id_parent = 12 [default = -2];
                 getHierarchy(info), // container_id = 13;
                 info.getIsWork(), // is_work_profile = 14;
-                info.getAttribute().getNumber(), // attribute_id = 15;
+                0, // attribute_id = 15;
                 getCardinality(info), // cardinality = 16;
                 info.getWidget().getSpanX(), // span_x = 17 [default = 1];
-                info.getWidget().getSpanY() // span_y = 18 [default = 1];
+                info.getWidget().getSpanY(), // span_y = 18 [default = 1];
+                getAttributes(info) /* attributes */
         );
     }
 
@@ -393,8 +409,7 @@
                     null /* launcher extensions, deprecated */,
                     false /* quickstep_enabled, deprecated */,
                     event.getId() /* event_id */,
-                    atomInfo.getAttribute().getNumber() * ATTRIBUTE_MULTIPLIER
-                            + atomInfo.getItemCase().getNumber() /* target_id */,
+                    atomInfo.getItemCase().getNumber() /* target_id */,
                     instanceId.getId() /* instance_id TODO */,
                     0 /* uid TODO */,
                     getPackageName(atomInfo) /* package_name */,
@@ -413,7 +428,70 @@
                     atomInfo.getFolderIcon().getLabelInfo() /* edittext */,
                     getCardinality(atomInfo) /* cardinality */,
                     getFeatures(atomInfo) /* features */,
-                    getSearchAttributes(atomInfo) /* searchAttributes */
+                    getSearchAttributes(atomInfo) /* searchAttributes */,
+                    getAttributes(atomInfo) /* attributes */
+            );
+        }
+    }
+
+    /**
+     * Helps to construct and log statsd compatible latency events.
+     */
+    private static class StatsCompatLatencyLogger implements StatsLatencyLogger {
+        private final Context mContext;
+        private final Optional<ActivityContext> mActivityContext;
+        private InstanceId mInstanceId = DEFAULT_INSTANCE_ID;
+        private LatencyType mType = LatencyType.UNKNOWN;
+        private int mPackageId = 0;
+        private long mLatencyInMillis;
+
+        StatsCompatLatencyLogger(Context context, ActivityContext activityContext) {
+            mContext = context;
+            mActivityContext = Optional.ofNullable(activityContext);
+        }
+
+        @Override
+        public StatsLatencyLogger withInstanceId(InstanceId instanceId) {
+            this.mInstanceId = instanceId;
+            return this;
+        }
+
+        @Override
+        public StatsLatencyLogger withType(LatencyType type) {
+            this.mType = type;
+            return this;
+        }
+
+        @Override
+        public StatsLatencyLogger withPackageId(int packageId) {
+            this.mPackageId = packageId;
+            return this;
+        }
+
+        @Override
+        public StatsLatencyLogger withLatency(long latencyInMillis) {
+            this.mLatencyInMillis = latencyInMillis;
+            return this;
+        }
+
+        @Override
+        public void log(EventEnum event) {
+            if (IS_VERBOSE) {
+                String name = (event instanceof Enum) ? ((Enum) event).name() :
+                        event.getId() + "";
+
+                Log.d(TAG, mInstanceId == DEFAULT_INSTANCE_ID
+                        ? String.format("\n%s = %dms\n", name, mLatencyInMillis)
+                        : String.format("\n%s = %dms (InstanceId:%s)\n", name,
+                                mLatencyInMillis, mInstanceId));
+            }
+
+            SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_LATENCY,
+                    event.getId(), // event_id
+                    mInstanceId.getId(), // instance_id
+                    mPackageId, // package_id
+                    mLatencyInMillis, // latency_in_millis
+                    mType.getId() //type
             );
         }
     }
@@ -592,6 +670,12 @@
         if (searchAttributes.getDirectMatch()) {
             response = response | SEARCH_ATTRIBUTES_DIRECT_MATCH;
         }
+        if (searchAttributes.getEntryState() == SearchAttributes.EntryState.ALL_APPS) {
+            response = response | SEARCH_ATTRIBUTES_ENTRY_STATE_ALL_APPS;
+        } else if (searchAttributes.getEntryState() == SearchAttributes.EntryState.QSB) {
+            response = response | SEARCH_ATTRIBUTES_ENTRY_STATE_QSB;
+        }
+
         return response;
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
index 51a9915..63d5b0d 100644
--- a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
+++ b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
@@ -48,10 +48,10 @@
 import androidx.core.content.FileProvider;
 
 import com.android.internal.app.ChooserActivity;
+import com.android.internal.util.ScreenshotHelper;
 import com.android.launcher3.BuildConfig;
 import com.android.quickstep.SystemUiProxy;
 import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.recents.utilities.BitmapUtil;
 
 import java.io.File;
 import java.io.FileOutputStream;
@@ -77,7 +77,8 @@
     public static void saveScreenshot(SystemUiProxy systemUiProxy, Bitmap screenshot,
             Rect screenshotBounds,
             Insets visibleInsets, Task.TaskKey task) {
-        systemUiProxy.handleImageBundleAsScreenshot(BitmapUtil.hardwareBitmapToBundle(screenshot),
+        systemUiProxy.handleImageBundleAsScreenshot(
+                ScreenshotHelper.HardwareBitmapBundler.hardwareBitmapToBundle(screenshot),
                 screenshotBounds, visibleInsets, task);
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
index 91ba909..6f171f9 100644
--- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
+++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
@@ -144,6 +144,7 @@
 
         @Override
         public void onTransitionStarted() {
+            mLauncher.getWorkspace().setPivotToScaleWithSelf(mLauncher.getHotseat());
         }
 
         @Override
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
index 302526d..d0856be 100644
--- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -22,8 +22,9 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.touch.PagedOrientationHandler;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.quickstep.LauncherActivityInterface;
-import com.android.quickstep.SysUINavigationMode;
 
 public class LayoutUtils {
 
@@ -32,7 +33,7 @@
      */
     public static float getDefaultSwipeHeight(Context context, DeviceProfile dp) {
         float swipeHeight = dp.allAppsCellHeightPx - dp.allAppsIconTextSizePx;
-        if (SysUINavigationMode.getMode(context) == SysUINavigationMode.Mode.NO_BUTTON) {
+        if (DisplayController.getNavigationMode(context) == NavigationMode.NO_BUTTON) {
             swipeHeight -= dp.getInsets().bottom;
         }
         return swipeHeight;
diff --git a/quickstep/src/com/android/quickstep/util/NavBarPosition.java b/quickstep/src/com/android/quickstep/util/NavBarPosition.java
index 449dba8..527a6d2 100644
--- a/quickstep/src/com/android/quickstep/util/NavBarPosition.java
+++ b/quickstep/src/com/android/quickstep/util/NavBarPosition.java
@@ -15,27 +15,27 @@
  */
 package com.android.quickstep.util;
 
-import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
+import static com.android.launcher3.util.DisplayController.NavigationMode.NO_BUTTON;
 
 import android.view.Surface;
 
 import com.android.launcher3.util.DisplayController.Info;
-import com.android.quickstep.SysUINavigationMode;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 
 /**
  * Utility class to check nav bar position.
  */
 public class NavBarPosition {
 
-    private final SysUINavigationMode.Mode mMode;
+    private final NavigationMode mMode;
     private final int mDisplayRotation;
 
-    public NavBarPosition(SysUINavigationMode.Mode mode, Info info) {
+    public NavBarPosition(NavigationMode mode, Info info) {
         mMode = mode;
         mDisplayRotation = info.rotation;
     }
 
-    public NavBarPosition(SysUINavigationMode.Mode mode, int displayRotation) {
+    public NavBarPosition(NavigationMode mode, int displayRotation) {
         mMode = mode;
         mDisplayRotation = displayRotation;
     }
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index 54642a2..fb32581 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -21,7 +21,7 @@
 import static com.android.launcher3.LauncherState.HINT_STATE;
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
+import static com.android.launcher3.util.DisplayController.NavigationMode.NO_BUTTON;
 
 import android.content.SharedPreferences;
 
@@ -34,8 +34,8 @@
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.statemanager.StateManager.StateListener;
 import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.OnboardingPrefs;
-import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.views.AllAppsEduView;
 
 /**
@@ -51,8 +51,8 @@
             stateManager.addStateListener(new StateListener<LauncherState>() {
                 @Override
                 public void onStateTransitionComplete(LauncherState finalState) {
-                    boolean swipeUpEnabled = SysUINavigationMode.INSTANCE
-                            .get(mLauncher).getMode().hasGestures;
+                    boolean swipeUpEnabled =
+                            DisplayController.getNavigationMode(mLauncher).hasGestures;
                     LauncherState prevState = stateManager.getLastState();
 
                     if (((swipeUpEnabled && finalState == OVERVIEW) || (!swipeUpEnabled
@@ -88,7 +88,7 @@
             });
         }
 
-        if (SysUINavigationMode.getMode(launcher) == NO_BUTTON
+        if (DisplayController.getNavigationMode(launcher) == NO_BUTTON
                 && FeatureFlags.ENABLE_ALL_APPS_EDU.get()) {
             stateManager.addStateListener(new StateListener<LauncherState>() {
                 private static final int MAX_NUM_SWIPES_TO_TRIGGER_EDU = 3;
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
new file mode 100644
index 0000000..cfb0056
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskThumbnailView.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapShader;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Shader;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+/**
+ * A child view of {@link com.android.quickstep.views.FloatingTaskView} to draw the thumbnail in a
+ * rounded corner frame. While the purpose of this class sounds similar to
+ * {@link TaskThumbnailView}, it doesn't need a lot of complex logic in {@link TaskThumbnailView}
+ * in relation to moving with {@link RecentsView}.
+ */
+public class FloatingTaskThumbnailView extends View {
+
+    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+    private final Matrix mMatrix = new Matrix();
+
+    private @Nullable BitmapShader mBitmapShader;
+    private @Nullable Bitmap mBitmap;
+
+    private FloatingTaskView.FullscreenDrawParams mFullscreenParams;
+
+    public FloatingTaskThumbnailView(Context context) {
+        this(context, null);
+    }
+
+    public FloatingTaskThumbnailView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public FloatingTaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
+        super(context, attrs, defStyleAttr);
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        if (mFullscreenParams == null || mBitmap == null) {
+            return;
+        }
+
+        // Scale down the bitmap to fix x, and crop in y.
+        float scale = 1.0f * getMeasuredWidth() / mBitmap.getWidth();
+        mMatrix.postScale(scale, scale);
+        mBitmapShader.setLocalMatrix(mMatrix);
+
+        canvas.drawRoundRect(0, 0, getMeasuredWidth(),  getMeasuredHeight(),
+                mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleX,
+                mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleY, mPaint);
+    }
+
+    public void setThumbnail(Bitmap bitmap) {
+        mBitmap = bitmap;
+        if (bitmap != null) {
+            mBitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
+            mPaint.setShader(mBitmapShader);
+        }
+    }
+
+    public void setFullscreenParams(FloatingTaskView.FullscreenDrawParams fullscreenParams) {
+        mFullscreenParams = fullscreenParams;
+    }
+}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index f2f1c3f..c59dc18 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -15,7 +15,6 @@
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
-import android.widget.ImageView;
 
 import androidx.annotation.Nullable;
 
@@ -29,6 +28,8 @@
 import com.android.launcher3.touch.PagedOrientationHandler;
 import com.android.launcher3.views.BaseDragLayer;
 import com.android.quickstep.util.MultiValueUpdateListener;
+import com.android.quickstep.util.TaskCornerRadius;
+import com.android.systemui.shared.system.QuickStepContract;
 
 import java.util.function.Consumer;
 
@@ -50,9 +51,9 @@
     private RectF mStartingPosition;
     private final StatefulActivity mActivity;
     private final boolean mIsRtl;
-    private final Rect mOutline = new Rect();
+    private final FullscreenDrawParams mCurrentFullscreenParams;
     private PagedOrientationHandler mOrientationHandler;
-    private ImageView mImageView;
+    private FloatingTaskThumbnailView mThumbnailView;
 
     public FloatingTaskView(Context context) {
         this(context, null);
@@ -66,16 +67,17 @@
         super(context, attrs, defStyleAttr);
         mActivity = BaseActivity.fromContext(context);
         mIsRtl = Utilities.isRtl(getResources());
+        mCurrentFullscreenParams = new FullscreenDrawParams(context);
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mImageView = findViewById(R.id.thumbnail);
-        mImageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
-        mImageView.setLayerType(LAYER_TYPE_HARDWARE, null);
+        mThumbnailView = findViewById(R.id.thumbnail);
+        mThumbnailView.setFullscreenParams(mCurrentFullscreenParams);
         mSplitPlaceholderView = findViewById(R.id.split_placeholder);
         mSplitPlaceholderView.setAlpha(0);
+        mSplitPlaceholderView.setFullscreenParams(mCurrentFullscreenParams);
     }
 
     private void init(StatefulActivity launcher, View originalView, @Nullable Bitmap thumbnail,
@@ -86,13 +88,11 @@
                 (InsettableFrameLayout.LayoutParams) getLayoutParams();
 
         mSplitPlaceholderView.setLayoutParams(new FrameLayout.LayoutParams(lp.width, lp.height));
-        positionOut.round(mOutline);
         setPivotX(0);
         setPivotY(0);
 
         // Copy bounds of exiting thumbnail into ImageView
-        mImageView.setImageBitmap(thumbnail);
-        mImageView.setVisibility(VISIBLE);
+        mThumbnailView.setThumbnail(thumbnail);
 
         RecentsView recentsView = launcher.getOverviewPanel();
         mOrientationHandler = recentsView.getPagedOrientationHandler();
@@ -133,27 +133,24 @@
         setLayoutParams(lp);
     }
 
-    // TODO(194414938) set correct corner radii
-    public void update(RectF position, float progress, float windowRadius) {
+    public void update(RectF position, float progress) {
         MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();
 
         float dX = position.left - mStartingPosition.left;
         float dY = position.top - lp.topMargin;
+        float scaleX = position.width() / lp.width;
+        float scaleY = position.height() / lp.height;
+
+        mCurrentFullscreenParams.updateParams(position, progress, scaleX, scaleY);
 
         setTranslationX(dX);
         setTranslationY(dY);
-
-        float scaleX = position.width() / lp.width;
-        float scaleY = position.height() / lp.height;
         setScaleX(scaleX);
         setScaleY(scaleY);
+        mSplitPlaceholderView.invalidate();
+
         float childScaleX = 1f / scaleX;
         float childScaleY = 1f / scaleY;
-
-        invalidate();
-        // TODO(194414938) seems like this scale value could be fine tuned, some stretchiness
-        mImageView.setScaleX(1f / scaleX + scaleX * progress);
-        mImageView.setScaleY(1f / scaleY + scaleY * progress);
         mOrientationHandler.setPrimaryScale(mSplitPlaceholderView.getIconView(), childScaleX);
         mOrientationHandler.setSecondaryScale(mSplitPlaceholderView.getIconView(), childScaleY);
     }
@@ -181,7 +178,8 @@
     }
 
     public void addAnimation(PendingAnimation animation, RectF startingBounds, Rect endBounds,
-            boolean fadeWithThumbnail) {
+            boolean fadeWithThumbnail, boolean isInitialSplit) {
+        mCurrentFullscreenParams.setIsInitialSplit(isInitialSplit);
         final BaseDragLayer dragLayer = mActivity.getDragLayer();
         int[] dragLayerBounds = new int[2];
         dragLayer.getLocationOnScreen(dragLayerBounds);
@@ -191,22 +189,16 @@
         ValueAnimator transitionAnimator = ValueAnimator.ofFloat(0, 1);
         animation.add(transitionAnimator);
         long animDuration = animation.getDuration();
-        Rect crop = new Rect();
         RectF floatingTaskViewBounds = new RectF();
-        final float initialWindowRadius = supportsRoundedCornersOnWindows(getResources())
-                ? Math.max(crop.width(), crop.height()) / 2f
-                : 0f;
 
         if (fadeWithThumbnail) {
             animation.addFloat(mSplitPlaceholderView, SplitPlaceholderView.ALPHA_FLOAT,
                     0, 1, ACCEL);
-            animation.addFloat(mImageView, LauncherAnimUtils.VIEW_ALPHA,
+            animation.addFloat(mThumbnailView, LauncherAnimUtils.VIEW_ALPHA,
                     1, 0, DEACCEL_3);
         }
 
         MultiValueUpdateListener listener = new MultiValueUpdateListener() {
-            final FloatProp mWindowRadius = new FloatProp(initialWindowRadius,
-                    initialWindowRadius, 0, animDuration, LINEAR);
             final FloatProp mDx = new FloatProp(0, prop.dX, 0, animDuration, LINEAR);
             final FloatProp mDy = new FloatProp(0, prop.dY, 0, animDuration, LINEAR);
             final FloatProp mTaskViewScaleX = new FloatProp(1f, prop.finalTaskViewScaleX, 0,
@@ -221,7 +213,7 @@
                 Utilities.scaleRectFAboutCenter(floatingTaskViewBounds, mTaskViewScaleX.value,
                         mTaskViewScaleY.value);
 
-                update(floatingTaskViewBounds, percent, mWindowRadius.value * 1);
+                update(floatingTaskViewBounds, percent);
             }
         };
         transitionAnimator.addUpdateListener(listener);
@@ -250,4 +242,36 @@
             dY = centerY - startTaskViewBounds.centerY();
         }
     }
+
+    public static class FullscreenDrawParams {
+
+        private final float mCornerRadius;
+        private final float mWindowCornerRadius;
+
+        public boolean mIsInitialSplit = true;
+        public final RectF mFloatingTaskViewBounds = new RectF();
+        public float mCurrentDrawnCornerRadius;
+        public float mScaleX = 1;
+        public float mScaleY = 1;
+
+        public FullscreenDrawParams(Context context) {
+            mCornerRadius = TaskCornerRadius.get(context);
+            mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context);
+
+            mCurrentDrawnCornerRadius = mCornerRadius;
+        }
+
+        public void updateParams(RectF floatingTaskViewBounds, float progress, float scaleX,
+                float scaleY) {
+            mFloatingTaskViewBounds.set(floatingTaskViewBounds);
+            mScaleX = scaleX;
+            mScaleY = scaleY;
+            mCurrentDrawnCornerRadius = mIsInitialSplit ? 0 :
+                    Utilities.mapRange(progress, mCornerRadius, mWindowCornerRadius);
+        }
+
+        public void setIsInitialSplit(boolean isInitialSplit) {
+            mIsInitialSplit = isInitialSplit;
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 6a3286b..0fa2b24 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -16,7 +16,7 @@
 
 package com.android.quickstep.views;
 
-import static com.android.quickstep.SysUINavigationMode.Mode.THREE_BUTTONS;
+import static com.android.launcher3.util.DisplayController.NavigationMode.THREE_BUTTONS;
 
 import android.content.Context;
 import android.content.res.Configuration;
@@ -36,10 +36,10 @@
 import com.android.launcher3.Insettable;
 import com.android.launcher3.R;
 import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.DisplayController.NavigationMode;
 import com.android.launcher3.util.MultiValueAlpha;
 import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
-import com.android.quickstep.SysUINavigationMode;
-import com.android.quickstep.SysUINavigationMode.Mode;
 import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
 import com.android.quickstep.util.LayoutUtils;
 
@@ -148,13 +148,13 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
+        updateVerticalMargin(DisplayController.getNavigationMode(getContext()));
     }
 
     @Override
     public void setInsets(Rect insets) {
         mInsets.set(insets);
-        updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
+        updateVerticalMargin(DisplayController.getNavigationMode(getContext()));
         updatePaddingAndTranslations();
     }
 
@@ -204,7 +204,7 @@
      */
     private void updatePaddingAndTranslations() {
         boolean alignFor3ButtonTaskbar = mDp.isTaskbarPresent &&
-                SysUINavigationMode.getMode(getContext()) == THREE_BUTTONS;
+                DisplayController.getNavigationMode(getContext()) == THREE_BUTTONS;
         if (alignFor3ButtonTaskbar) {
             // Add extra horizontal spacing
             int additionalPadding = ApiWrapper.getHotseatEndOffset(getContext());
@@ -218,7 +218,7 @@
             // the button nav top is.
             View startActionView = findViewById(R.id.action_screenshot);
             int marginBottom = getOverviewActionsBottomMarginPx(
-                    SysUINavigationMode.getMode(getContext()), mDp);
+                    DisplayController.getNavigationMode(getContext()), mDp);
             int actionsTop =
                     (mDp.heightPx - marginBottom - mInsets.bottom) - startActionView.getHeight();
             int navTop = mDp.heightPx - (mDp.taskbarSize + mDp.getTaskbarOffsetY());
@@ -233,7 +233,7 @@
     }
 
     /** Updates vertical margins for different navigation mode or configuration changes. */
-    public void updateVerticalMargin(Mode mode) {
+    public void updateVerticalMargin(NavigationMode mode) {
         if (mDp == null) {
             return;
         }
@@ -249,7 +249,7 @@
      */
     public void setDp(DeviceProfile dp) {
         mDp = dp;
-        updateVerticalMargin(SysUINavigationMode.getMode(getContext()));
+        updateVerticalMargin(DisplayController.getNavigationMode(getContext()));
 
         LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
                 dp.isVerticalBarLayout() ? 0 : dp.overviewActionsButtonSpacing,
@@ -274,14 +274,13 @@
     }
 
     /** Get the top margin associated with the action buttons in Overview. */
-    public static int getOverviewActionsTopMarginPx(
-            SysUINavigationMode.Mode mode, DeviceProfile dp) {
+    public static int getOverviewActionsTopMarginPx(NavigationMode mode, DeviceProfile dp) {
         // In vertical bar, use the smaller task margin for the top regardless of mode
         if (dp.isVerticalBarLayout()) {
             return dp.overviewTaskMarginPx;
         }
 
-        if (mode == SysUINavigationMode.Mode.THREE_BUTTONS) {
+        if (mode == NavigationMode.THREE_BUTTONS) {
             return dp.overviewActionsMarginThreeButtonPx;
         }
 
@@ -289,8 +288,7 @@
     }
 
     /** Get the bottom margin associated with the action buttons in Overview. */
-    public static int getOverviewActionsBottomMarginPx(
-            SysUINavigationMode.Mode mode, DeviceProfile dp) {
+    public static int getOverviewActionsBottomMarginPx(NavigationMode mode, DeviceProfile dp) {
         int inset = dp.getInsets().bottom;
 
         if (dp.isVerticalBarLayout()) {
@@ -298,7 +296,7 @@
         }
 
         // Actions button will be aligned with nav buttons in updatePaddingAndTranslations().
-        if (mode == SysUINavigationMode.Mode.THREE_BUTTONS) {
+        if (mode == NavigationMode.THREE_BUTTONS) {
             return dp.overviewActionsMarginThreeButtonPx + inset;
         }
 
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index cb7e08a..5e331e2 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2732,7 +2732,7 @@
                     mSplitHiddenTaskView.getIconView().getDrawable(), startingTaskRect);
             mFirstFloatingTaskView.setAlpha(1);
             mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
-                    mTempRect, true /*fadeWithThumbnail*/);
+                    mTempRect, true /* fadeWithThumbnail */, true /* isInitialSplit */);
         } else {
             mSplitSelectSource.view.setVisibility(INVISIBLE);
             mFirstFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
@@ -2740,7 +2740,7 @@
                     mSplitSelectSource.drawable, startingTaskRect);
             mFirstFloatingTaskView.setAlpha(1);
             mFirstFloatingTaskView.addAnimation(anim, startingTaskRect,
-                    mTempRect, true /*fadeWithThumbnail*/);
+                    mTempRect, true /* fadeWithThumbnail */, true /* isInitialSplit */);
         }
         anim.addEndListener(success -> {
             if (success) {
@@ -4030,14 +4030,14 @@
         mFirstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds);
         mFirstFloatingTaskView.addAnimation(pendingAnimation,
                 new RectF(firstTaskStartingBounds), firstTaskEndingBounds,
-                false /*fadeWithThumbnail*/);
+                false /* fadeWithThumbnail */, false /* isInitialSplit */);
 
         mSecondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mActivity,
                 thumbnailView, thumbnailView.getThumbnail(),
                 iconView.getDrawable(), secondTaskStartingBounds);
         mSecondFloatingTaskView.setAlpha(1);
         mSecondFloatingTaskView.addAnimation(pendingAnimation, secondTaskStartingBounds,
-                secondTaskEndingBounds, true /* fadeWithThumbnail */);
+                secondTaskEndingBounds, true /* fadeWithThumbnail */, false /* isInitialSplit */);
         pendingAnimation.addEndListener(aBoolean ->
                 mSplitSelectStateController.setSecondTaskId(task.key.id,
                 aBoolean1 -> RecentsView.this.resetFromSplitSelectionState()));
@@ -4110,7 +4110,7 @@
         mTempRectF.set(mTempRect);
         // TODO(194414938) set correct corner radius
         mFirstFloatingTaskView.updateOrientationHandler(mOrientationHandler);
-        mFirstFloatingTaskView.update(mTempRectF, /*progress=*/1f, /*windowRadius=*/0f);
+        mFirstFloatingTaskView.update(mTempRectF, /*progress=*/1f);
 
         PagedOrientationHandler orientationHandler = getPagedOrientationHandler();
         Pair<FloatProperty, FloatProperty> taskViewsFloat =
diff --git a/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java b/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
index cfa482f..d37dfbf 100644
--- a/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
@@ -17,9 +17,12 @@
 package com.android.quickstep.views;
 
 import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
 import android.util.FloatProperty;
+import android.util.TypedValue;
 import android.view.Gravity;
 import android.widget.FrameLayout;
 
@@ -27,6 +30,10 @@
 
 public class SplitPlaceholderView extends FrameLayout {
 
+    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+
+    private FloatingTaskView.FullscreenDrawParams mFullscreenParams;
+
     public static final FloatProperty<SplitPlaceholderView> ALPHA_FLOAT =
             new FloatProperty<SplitPlaceholderView>("SplitViewAlpha") {
                 @Override
@@ -46,6 +53,17 @@
 
     public SplitPlaceholderView(Context context, AttributeSet attrs) {
         super(context, attrs);
+
+        mPaint.setColor(getThemePrimaryColor(context));
+        setWillNotDraw(false);
+    }
+
+    @Override
+    protected void dispatchDraw(Canvas canvas) {
+        // Call this before super call to draw below the children.
+        drawBackground(canvas);
+
+        super.dispatchDraw(canvas);
     }
 
     @Nullable
@@ -53,6 +71,10 @@
         return mIconView;
     }
 
+    public void setFullscreenParams(FloatingTaskView.FullscreenDrawParams fullscreenParams) {
+        mFullscreenParams = fullscreenParams;
+    }
+
     public void setIcon(Drawable drawable, int iconSize) {
         if (mIconView == null) {
             mIconView = new IconView(getContext());
@@ -64,4 +86,20 @@
         params.gravity = Gravity.CENTER;
         mIconView.setLayoutParams(params);
     }
+
+    private void drawBackground(Canvas canvas) {
+        if (mFullscreenParams == null) {
+            return;
+        }
+
+        canvas.drawRoundRect(0, 0, getMeasuredWidth(),  getMeasuredHeight(),
+                mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleX,
+                mFullscreenParams.mCurrentDrawnCornerRadius / mFullscreenParams.mScaleY, mPaint);
+    }
+
+    private static int getThemePrimaryColor(Context context) {
+        final TypedValue value = new TypedValue();
+        context.getTheme().resolveAttribute(android.R.attr.colorPrimary, value, true);
+        return value.data;
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 60b0d17..11f9ddd 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -50,6 +50,7 @@
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.icons.BitmapRenderer;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SystemUiController;
 import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
@@ -161,6 +162,23 @@
         setThumbnail(task, thumbnailData, true /* refreshNow */);
     }
 
+    /**
+     * By combining the two in a single bitmap then we only have to do a single draw
+     * call in the onDraw function. Also, this fixes a bug where the background was
+     * visible in the corners because of anti-aliasing.
+     */
+    public Bitmap combineThumbnailAndBackground(Bitmap bm) {
+        return BitmapRenderer.createHardwareBitmap(bm.getWidth(), bm.getHeight(), c -> {
+            final boolean drawBackgroundOnly = mTask == null || mTask.isLocked;
+            if (drawBackgroundOnly) {
+                c.drawPaint(mBackgroundPaint);
+            } else {
+                c.drawPaint(mBackgroundPaint);
+                c.drawBitmap(bm, 0, 0, null);
+            }
+        });
+    }
+
     /** Updates the shader, paint, matrix to redraw. */
     public void refresh() {
         refresh(false);
@@ -173,6 +191,7 @@
     private void refresh(boolean shouldRefreshOverlay) {
         if (mThumbnailData != null && mThumbnailData.thumbnail != null) {
             Bitmap bm = mThumbnailData.thumbnail;
+            bm = combineThumbnailAndBackground(bm);
             bm.prepareToDraw();
             mBitmapShader = new BitmapShader(bm, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
             mPaint.setShader(mBitmapShader);
@@ -194,7 +213,6 @@
      * <p>
      * If dimAlpha is 0, no dimming is applied; if dimAlpha is 1, the thumbnail will be the
      * extracted background color.
-     *
      */
     public void setDimAlpha(float dimAlpha) {
         mDimAlpha = dimAlpha;
@@ -296,18 +314,6 @@
                 return;
             }
         }
-
-        // Always draw the background since the snapshots might be translucent or partially empty
-        // (For example, tasks been reparented out of dismissing split root when drag-to-dismiss
-        // split screen).
-        canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mBackgroundPaint);
-
-        final boolean drawBackgroundOnly = mTask == null || mTask.isLocked || mBitmapShader == null
-                || mThumbnailData == null;
-        if (drawBackgroundOnly) {
-            return;
-        }
-
         canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mPaint);
     }
 
@@ -338,7 +344,6 @@
 
     private void updateThumbnailPaintFilter() {
         ColorFilter filter = getColorFilter(mDimAlpha);
-        mBackgroundPaint.setColorFilter(filter);
         int alpha = (int) (mDimAlpha * 255);
         mDimmingPaintAfterClearing.setAlpha(alpha);
         if (mBitmapShader != null) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index f716965..1d621dc 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -725,7 +725,8 @@
             TestLogging.recordEvent(
                     TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
             ActivityOptionsWrapper opts =  mActivity.getActivityLaunchOptions(this, null);
-            opts.options.setLaunchDisplayId(getRootViewDisplayId());
+            opts.options.setLaunchDisplayId(
+                    getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
             if (ActivityManagerWrapper.getInstance()
                     .startActivityFromRecents(mTask.key, opts.options)) {
                 RecentsView recentsView = getRecentsView();
@@ -766,7 +767,8 @@
             // Indicate success once the system has indicated that the transition has started
             ActivityOptions opts = ActivityOptionsCompat.makeCustomAnimation(
                     getContext(), 0, 0, () -> callback.accept(true), MAIN_EXECUTOR.getHandler());
-            opts.setLaunchDisplayId(getRootViewDisplayId());
+            opts.setLaunchDisplayId(
+                    getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
             if (freezeTaskList) {
                 ActivityOptionsCompat.setFreezeRecentTasksList(opts);
             }
@@ -912,31 +914,31 @@
     public void setOrientationState(RecentsOrientedState orientationState) {
         PagedOrientationHandler orientationHandler = orientationState.getOrientationHandler();
         boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
-        LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
         DeviceProfile deviceProfile = mActivity.getDeviceProfile();
-        snapshotParams.topMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
+
         boolean isGridTask = isGridTask();
+        LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
+
+        int thumbnailTopMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
         int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
         int taskMargin = isGridTask ? deviceProfile.overviewTaskMarginGridPx
                 : deviceProfile.overviewTaskMarginPx;
-        int taskIconMargin = snapshotParams.topMargin - taskIconHeight - taskMargin;
-        LayoutParams iconParams = (LayoutParams) mIconView.getLayoutParams();
-        orientationHandler.setIconAndSnapshotParams(mIconView, taskIconMargin, taskIconHeight,
-                snapshotParams, isRtl);
-        updateDwbPlacement();
-        mSnapshotView.setLayoutParams(snapshotParams);
+        int taskIconMargin = thumbnailTopMargin - taskIconHeight - taskMargin;
+        orientationHandler.setTaskIconParams(iconParams, taskIconMargin, taskIconHeight,
+                thumbnailTopMargin, isRtl);
         iconParams.width = iconParams.height = taskIconHeight;
         mIconView.setLayoutParams(iconParams);
+
         mIconView.setRotation(orientationHandler.getDegreesRotated());
         int iconDrawableSize = isGridTask ? deviceProfile.overviewTaskIconDrawableSizeGridPx
                 : deviceProfile.overviewTaskIconDrawableSizePx;
         mIconView.setDrawableSize(iconDrawableSize, iconDrawableSize);
-        snapshotParams.topMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
-        mSnapshotView.setLayoutParams(snapshotParams);
-        mSnapshotView.getTaskOverlay().updateOrientationState(orientationState);
-    }
 
-    private void updateDwbPlacement() {
+        LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
+        snapshotParams.topMargin = thumbnailTopMargin;
+        mSnapshotView.setLayoutParams(snapshotParams);
+
+        mSnapshotView.getTaskOverlay().updateOrientationState(orientationState);
         mDigitalWellBeingToast.initialize(mTask);
     }
 
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
index fb7fda1..09f0858 100644
--- a/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
+++ b/quickstep/tests/src/com/android/quickstep/AbstractQuickStepTest.java
@@ -36,7 +36,7 @@
  */
 public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest {
     static final boolean ENABLE_SHELL_TRANSITIONS =
-            SystemProperties.getBoolean("persist.debug.shell_transit", false);
+            SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
     @Override
     protected TestRule getRulesInsideActivityMonitor() {
         return RuleChain.
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 6be2ce6..4529217 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -61,7 +61,6 @@
 
 import org.junit.After;
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.RuleChain;
@@ -206,7 +205,6 @@
 
     // b/143488140
     //@NavigationModeSwitch
-    @Ignore("b/218403080")
     @Test
     public void testOverview() {
         startAppFast(getAppPackageName());
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index 1cb7529..e5e2cf3 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -33,6 +33,7 @@
 import com.android.launcher3.tapl.LauncherInstrumentation;
 import com.android.launcher3.tapl.TestHelpers;
 import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Wait;
 import com.android.launcher3.util.rule.FailureWatcher;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -71,8 +72,8 @@
 
     private final LauncherInstrumentation mLauncher;
 
-    static final SysUINavigationMode SYS_UI_NAVIGATION_MODE =
-            SysUINavigationMode.INSTANCE.get(getInstrumentation().getTargetContext());
+    static final DisplayController DISPLAY_CONTROLLER =
+            DisplayController.INSTANCE.get(getInstrumentation().getTargetContext());
 
     public NavigationModeSwitchRule(LauncherInstrumentation launcher) {
         mLauncher = launcher;
@@ -138,7 +139,7 @@
 
     private static LauncherInstrumentation.NavigationModel currentSysUiNavigationMode() {
         return LauncherInstrumentation.getNavigationModel(
-                SysUINavigationMode.getMode(
+                DisplayController.getNavigationMode(
                         getInstrumentation().
                                 getTargetContext()).
                         resValue);
@@ -159,18 +160,18 @@
         if (currentSysUiNavigationMode() != expectedMode) {
             final CountDownLatch latch = new CountDownLatch(1);
             final Context targetContext = getInstrumentation().getTargetContext();
-            final SysUINavigationMode.NavigationModeChangeListener listener =
-                    newMode -> {
-                        if (LauncherInstrumentation.getNavigationModel(newMode.resValue)
+            final DisplayController.DisplayInfoChangeListener listener =
+                    (context, info, flags) -> {
+                        if (LauncherInstrumentation.getNavigationModel(info.navigationMode.resValue)
                                 == expectedMode) {
                             latch.countDown();
                         }
                     };
             targetContext.getMainExecutor().execute(() ->
-                    SYS_UI_NAVIGATION_MODE.addModeChangeListener(listener));
+                    DISPLAY_CONTROLLER.addChangeListener(listener));
             latch.await(60, TimeUnit.SECONDS);
             targetContext.getMainExecutor().execute(() ->
-                    SYS_UI_NAVIGATION_MODE.removeModeChangeListener(listener));
+                    DISPLAY_CONTROLLER.removeChangeListener(listener));
 
             assertTrue(launcher, "Navigation mode didn't change to " + expectedMode,
                     currentSysUiNavigationMode() == expectedMode, description);
diff --git a/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java b/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
index 159a51f..6b3f699 100644
--- a/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
@@ -21,7 +21,7 @@
 
 import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 
-import static com.android.quickstep.SysUINavigationMode.Mode.NO_BUTTON;
+import static com.android.launcher3.util.DisplayController.NavigationMode.NO_BUTTON;
 
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
diff --git a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
index 9c5cfcd..6dc9f8d 100644
--- a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
+++ b/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
@@ -39,7 +39,6 @@
 import com.android.launcher3.util.LauncherModelHelper;
 import com.android.launcher3.util.ReflectionHelpers;
 import com.android.quickstep.FallbackActivityInterface;
-import com.android.quickstep.SysUINavigationMode;
 import com.android.quickstep.SystemUiProxy;
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
@@ -143,7 +142,6 @@
             LauncherModelHelper helper = new LauncherModelHelper();
             try {
                 helper.sandboxContext.allow(SystemUiProxy.INSTANCE);
-                helper.sandboxContext.allow(SysUINavigationMode.INSTANCE);
 
                 Display display = mock(Display.class);
                 doReturn(DEFAULT_DISPLAY).when(display).getDisplayId();
diff --git a/res/layout/floating_split_select_view.xml b/res/layout/floating_split_select_view.xml
index 8d47f4e..e4ca52e 100644
--- a/res/layout/floating_split_select_view.xml
+++ b/res/layout/floating_split_select_view.xml
@@ -4,7 +4,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
-    <ImageView
+    <com.android.quickstep.views.FloatingTaskThumbnailView
         android:id="@+id/thumbnail"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
@@ -14,7 +14,6 @@
         android:id="@+id/split_placeholder"
         android:layout_width="match_parent"
         android:layout_height="@dimen/split_placeholder_size"
-        android:background="?android:colorPrimary"
         android:visibility="gone" />
 
 </com.android.quickstep.views.FloatingTaskView>
\ No newline at end of file
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index a0c784f..1ddd652 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -103,7 +103,7 @@
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Ordner: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> oder mehr Elemente"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Hintergründe"</string>
     <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Hintergrund &amp; Stil"</string>
-    <string name="settings_button_text" msgid="8873672322605444408">"Startbildschirm-Einstellungen"</string>
+    <string name="settings_button_text" msgid="8873672322605444408">"Einstellungen"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Von deinem Administrator deaktiviert"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Drehen des Startbildschirms zulassen"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"Beim Drehen des Smartphones"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 1149e02..5612191 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -53,9 +53,9 @@
     <string name="widget_category_conversations" msgid="8894438636213590446">"ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ"</string>
     <string name="widget_education_header" msgid="4874760613775913787">"ଉପଯୋଗୀ ସୂଚନା ଆପଣଙ୍କ ପାଖରେ ସହଜରେ ଉପଲବ୍ଧ"</string>
     <string name="widget_education_content" msgid="745542879510751525">"ଆପଗୁଡ଼ିକୁ ନଖୋଲି ସୂଚନା ପାଇବା ପାଇଁ, ଆପଣ ଆପଣଙ୍କ ମୂଳସ୍କ୍ରିନରେ ୱିଜେଟଗୁଡ଼ିକୁ ଯୋଗ କରିପାରିବେ"</string>
-    <string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"ୱିଜେଟ୍ ସେଟିଂସ୍ ପରିବର୍ତ୍ତନ କରିବାକୁ ଟାପ୍ କରନ୍ତୁ"</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="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>
@@ -79,10 +79,10 @@
     <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="1941457408239617576">"ହୋମ୍‌ ସେଟିଙ୍ଗ ଏବଂ ଶର୍ଟକଟ୍‌ ପଢ଼ନ୍ତୁ"</string>
-    <string name="permdesc_read_settings" msgid="5833423719057558387">"ହୋମରେ ସେଟିଙ୍ଗ ପଢ଼ିବାକୁ ଆପ ଏବଂ ଶର୍ଟକଟକୁ ଅନୁମତି ଦିଏ।"</string>
-    <string name="permlab_write_settings" msgid="3574213698004620587">"ହୋମ୍‌ ସେଟିଙ୍ଗ ଏବଂ ଶର୍ଟକଟ୍‌ ଲେଖନ୍ତୁ"</string>
-    <string name="permdesc_write_settings" msgid="5440712911516509985">"ହୋମରେ ସେଟିଙ୍ଗ ଏବଂ ଶର୍ଟକଟ୍‌ ପରିବର୍ତ୍ତନ କରିବାକୁ ଆପକୁ ଅନୁମତି ଦିଏ।"</string>
+    <string name="permlab_read_settings" msgid="1941457408239617576">"ହୋମ ସେଟିଂସ ଏବଂ ସର୍ଟକଟ ପଢ଼ନ୍ତୁ"</string>
+    <string name="permdesc_read_settings" msgid="5833423719057558387">"ହୋମରେ ସେଟିଂସ ଏବଂ ସର୍ଟକଟକୁ ପଢ଼ିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ।"</string>
+    <string name="permlab_write_settings" msgid="3574213698004620587">"ହୋମ ସେଟିଂସ ଏବଂ ସର୍ଟକଟ ଲେଖନ୍ତୁ"</string>
+    <string name="permdesc_write_settings" msgid="5440712911516509985">"ହୋମରେ ସେଟିଂସ ଏବଂ ସର୍ଟକଟକୁ ପରିବର୍ତ୍ତନ କରିବା ପାଇଁ ଆପକୁ ଅନୁମତି ଦିଏ।"</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>
@@ -103,7 +103,7 @@
     <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="settings_button_text" msgid="8873672322605444408">"ହୋମ ସେଟିଂସ"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ଆପଣଙ୍କ ଆଡମିନଙ୍କ ଦ୍ୱାରା ଅକ୍ଷମ କରାଯାଇଛି"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"ହୋମ୍‌ ସ୍କ୍ରିନ୍ ବୁଲାଇବାକୁ ଅନୁମତି ଦିଅନ୍ତୁ"</string>
     <string name="allow_rotation_desc" msgid="8662546029078692509">"ଯେତେବେଳେ ଫୋନକୁ ବୁଲାଯାଇଥାଏ"</string>
@@ -112,7 +112,7 @@
     <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="title_change_settings" msgid="1376365968844349552">"ସେଟିଂସ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
     <string name="notification_dots_service_title" msgid="4284221181793592871">"ବିଜ୍ଞପ୍ତି ଡଟ୍‌ଗୁଡ଼ିକୁ ଦେଖାନ୍ତୁ"</string>
     <string name="auto_add_shortcuts_label" msgid="3698776050751790653">"ହୋମ୍ ସ୍କ୍ରିନରେ ଆପ୍ ଆଇକନଗୁଡ଼ିକୁ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ନୂଆ ଆପ୍‌ ପାଇଁ"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 99a337e..620eb7b 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -152,6 +152,9 @@
 
         <!-- numHotseatIcons defaults to numColumns, if not specified -->
         <attr name="numHotseatIcons" format="integer" />
+        <!-- Number of icons to use when shrinking the hotseat size,
+         defaults to numHotseatIcons / 2 -->
+        <attr name="numShrunkenHotseatIcons" format="integer" />
         <!-- Number of icons to use when extending the hotseat size,
          defaults to 2 * numHotseatIcons -->
         <attr name="numExtendedHotseatIcons" format="integer" />
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 97c0f38..cd9bbf7 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -34,7 +34,6 @@
 
 import com.android.launcher3.CellLayout.ContainerType;
 import com.android.launcher3.DevicePaddings.DevicePadding;
-import com.android.launcher3.config.FeatureFlags;
 import com.android.launcher3.icons.DotRenderer;
 import com.android.launcher3.icons.GraphicsUtils;
 import com.android.launcher3.icons.IconNormalizer;
@@ -59,6 +58,7 @@
 
     // Device properties
     public final boolean isTablet;
+    public final boolean isLargeTablet;
     public final boolean isPhone;
     public final boolean transposeLayoutWithOrientation;
     public final boolean isTwoPanels;
@@ -67,6 +67,7 @@
     // Device properties in current orientation
     public final boolean isLandscape;
     public final boolean isMultiWindowMode;
+    public final boolean isGestureMode;
 
     public final int windowX;
     public final int windowY;
@@ -229,12 +230,13 @@
     /** TODO: Once we fully migrate to staged split, remove "isMultiWindowMode" */
     DeviceProfile(Context context, InvariantDeviceProfile inv, Info info, WindowBounds windowBounds,
             boolean isMultiWindowMode, boolean transposeLayoutWithOrientation,
-            boolean useTwoPanels) {
+            boolean useTwoPanels, boolean isGestureMode) {
 
         this.inv = inv;
         this.isLandscape = windowBounds.isLandscape();
         this.isMultiWindowMode = isMultiWindowMode;
         this.transposeLayoutWithOrientation = transposeLayoutWithOrientation;
+        this.isGestureMode = isGestureMode;
         windowX = windowBounds.bounds.left;
         windowY = windowBounds.bounds.top;
 
@@ -243,6 +245,7 @@
         // Determine device posture.
         mInfo = info;
         isTablet = info.isTablet(windowBounds);
+        isLargeTablet = info.isLargeTablet(windowBounds);
         isPhone = !isTablet;
         isTwoPanels = isTablet && useTwoPanels;
         isTaskbarPresent = isTablet && ApiWrapper.TASKBAR_DRAWN_IN_PROCESS;
@@ -343,9 +346,15 @@
         workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x);
 
         hotseatQsbHeight = res.getDimensionPixelSize(R.dimen.qsb_widget_height);
-        isQsbInline = isTablet && isLandscape && !isTwoPanels && hotseatQsbHeight > 0;
-        numShownHotseatIcons =
-                isTwoPanels ? inv.numDatabaseHotseatIcons : inv.numShownHotseatIcons;
+        isQsbInline = isLargeTablet && isLandscape && hotseatQsbHeight > 0;
+
+        if (isTaskbarPresent && !isGestureMode && isQsbInline) {
+            numShownHotseatIcons = inv.numShrunkenHotseatIcons;
+        } else {
+            numShownHotseatIcons =
+                    isTwoPanels ? inv.numDatabaseHotseatIcons : inv.numShownHotseatIcons;
+        }
+
         numShownAllAppsColumns =
                 isTwoPanels ? inv.numDatabaseAllAppsColumns : inv.numAllAppsColumns;
         hotseatBarSizeExtraSpacePx = 0;
@@ -540,7 +549,8 @@
         return new Builder(context, inv, mInfo)
                 .setWindowBounds(bounds)
                 .setUseTwoPanels(isTwoPanels)
-                .setMultiWindowMode(isMultiWindowMode);
+                .setMultiWindowMode(isMultiWindowMode)
+                .setGestureMode(isGestureMode);
     }
 
     public DeviceProfile copy(Context context) {
@@ -1081,9 +1091,11 @@
         writer.println(prefix + "\t1 dp = " + mMetrics.density + " px");
 
         writer.println(prefix + "\tisTablet:" + isTablet);
+        writer.println(prefix + "\tisLargeTablet:" + isLargeTablet);
         writer.println(prefix + "\tisPhone:" + isPhone);
         writer.println(prefix + "\ttransposeLayoutWithOrientation:"
                 + transposeLayoutWithOrientation);
+        writer.println(prefix + "\tisGestureMode:" + isGestureMode);
 
         writer.println(prefix + "\tisLandscape:" + isLandscape);
         writer.println(prefix + "\tisMultiWindowMode:" + isMultiWindowMode);
@@ -1266,6 +1278,7 @@
 
         private boolean mIsMultiWindowMode = false;
         private Boolean mTransposeLayoutWithOrientation;
+        private Boolean mIsGestureMode;
 
         public Builder(Context context, InvariantDeviceProfile inv, Info info) {
             mContext = context;
@@ -1294,6 +1307,11 @@
             return this;
         }
 
+        public Builder setGestureMode(boolean isGestureMode) {
+            mIsGestureMode = isGestureMode;
+            return this;
+        }
+
         public DeviceProfile build() {
             if (mWindowBounds == null) {
                 throw new IllegalArgumentException("Window bounds not set");
@@ -1301,8 +1319,11 @@
             if (mTransposeLayoutWithOrientation == null) {
                 mTransposeLayoutWithOrientation = !mInfo.isTablet(mWindowBounds);
             }
-            return new DeviceProfile(mContext, mInv, mInfo, mWindowBounds,
-                    mIsMultiWindowMode, mTransposeLayoutWithOrientation, mUseTwoPanels);
+            if (mIsGestureMode == null) {
+                mIsGestureMode = DisplayController.getNavigationMode(mContext).hasGestures;
+            }
+            return new DeviceProfile(mContext, mInv, mInfo, mWindowBounds, mIsMultiWindowMode,
+                    mTransposeLayoutWithOrientation, mUseTwoPanels, mIsGestureMode);
         }
     }
 
diff --git a/src/com/android/launcher3/FirstFrameAnimatorHelper.java b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
index a199a57..fdf0101 100644
--- a/src/com/android/launcher3/FirstFrameAnimatorHelper.java
+++ b/src/com/android/launcher3/FirstFrameAnimatorHelper.java
@@ -15,7 +15,7 @@
  */
 package com.android.launcher3;
 
-import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
+import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index cb0cc11..e1680fc 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -173,9 +173,15 @@
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
-        int width = mActivity.getDeviceProfile().isQsbInline
-                ? mActivity.getDeviceProfile().qsbWidth
-                : getShortcutsAndWidgets().getMeasuredWidth();
+        int width;
+        if (mActivity.getDeviceProfile().isQsbInline) {
+            width = mActivity.getDeviceProfile().qsbWidth;
+        } else {
+            MarginLayoutParams qsbParams = (MarginLayoutParams) mQsb.getLayoutParams();
+            width = getShortcutsAndWidgets().getMeasuredWidth()
+                    - qsbParams.getMarginStart()
+                    - qsbParams.getMarginEnd();
+        }
 
         mQsb.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY),
                 MeasureSpec.makeMeasureSpec(mQsbHeight, MeasureSpec.EXACTLY));
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index dfe4bb0..886c657 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -19,6 +19,7 @@
 import static com.android.launcher3.Utilities.dpiFromPx;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_TWO_PANEL_HOME;
 import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
+import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
 import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
@@ -138,6 +139,11 @@
     public int numShownHotseatIcons;
 
     /**
+     * Number of icons inside the hotseat area when using 3 buttons navigation.
+     */
+    public int numShrunkenHotseatIcons;
+
+    /**
      * Number of icons inside the hotseat area that is stored in the database. This is greater than
      * or equal to numnShownHotseatIcons, allowing for a seamless transition between two hotseat
      * sizes that share the same DB.
@@ -188,7 +194,8 @@
 
         DisplayController.INSTANCE.get(context).setPriorityListener(
                 (displayContext, info, flags) -> {
-                    if ((flags & (CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS)) != 0) {
+                    if ((flags & (CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS
+                            | CHANGE_NAVIGATION_MODE)) != 0) {
                         onConfigChanged(displayContext);
                     }
                 });
@@ -336,6 +343,7 @@
         horizontalMargin = displayOption.horizontalMargin;
 
         numShownHotseatIcons = closestProfile.numHotseatIcons;
+        numShrunkenHotseatIcons = closestProfile.numShrunkenHotseatIcons;
         numDatabaseHotseatIcons = deviceType == TYPE_MULTI_DISPLAY
                 ? closestProfile.numDatabaseHotseatIcons : closestProfile.numHotseatIcons;
         hotseatBorderSpaces = displayOption.hotseatBorderSpaces;
@@ -365,7 +373,8 @@
         for (WindowBounds bounds : displayInfo.supportedBounds) {
             localSupportedProfiles.add(new DeviceProfile.Builder(context, this, displayInfo)
                     .setUseTwoPanels(deviceType == TYPE_MULTI_DISPLAY)
-                    .setWindowBounds(bounds).build());
+                    .setWindowBounds(bounds)
+                    .build());
 
             // Wallpaper size should be the maximum of the all possible sizes Launcher expects
             int displayWidth = bounds.bounds.width();
@@ -691,6 +700,7 @@
         private final int numAllAppsColumns;
         private final int numDatabaseAllAppsColumns;
         private final int numHotseatIcons;
+        private final int numShrunkenHotseatIcons;
         private final int numDatabaseHotseatIcons;
 
         private final String dbFile;
@@ -727,6 +737,8 @@
 
             numHotseatIcons = a.getInt(
                     R.styleable.GridDisplayOption_numHotseatIcons, numColumns);
+            numShrunkenHotseatIcons = a.getInt(
+                    R.styleable.GridDisplayOption_numShrunkenHotseatIcons, numHotseatIcons / 2);
             numDatabaseHotseatIcons = a.getInt(
                     R.styleable.GridDisplayOption_numExtendedHotseatIcons, 2 * numHotseatIcons);
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8fb2f53..5c5aee5 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -3192,4 +3192,15 @@
     public ArrowPopup<?> getOptionsPopup() {
         return findViewById(R.id.popup_container);
     }
+
+    /** Pauses view updates that should not be run during the app launch animation. */
+    public void pauseExpensiveViewUpdates() {
+        // Pause page indicator animations as they lead to layer trashing.
+        getWorkspace().getPageIndicator().pauseAnimations();
+    }
+
+    /** Resumes view updates at the end of the app launch animation. */
+    public void resumeExpensiveViewUpdates() {
+        getWorkspace().getPageIndicator().skipAnimationsToEnd();
+    }
 }
diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
index 85ca280..1cc0c21 100644
--- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -19,7 +19,7 @@
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.anim.Interpolators.clampToProgress;
 import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
+import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 
 import android.animation.Animator;
 import android.animation.Animator.AnimatorListener;
diff --git a/src/com/android/launcher3/anim/SpringAnimationBuilder.java b/src/com/android/launcher3/anim/SpringAnimationBuilder.java
index bd52158..40fa0cf 100644
--- a/src/com/android/launcher3/anim/SpringAnimationBuilder.java
+++ b/src/com/android/launcher3/anim/SpringAnimationBuilder.java
@@ -25,7 +25,7 @@
 import androidx.annotation.FloatRange;
 import androidx.dynamicanimation.animation.SpringForce;
 
-import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.window.RefreshRateTracker;
 
 /**
  * Utility class to build an object animator which follows the same path as a spring animation for
@@ -134,7 +134,7 @@
     }
 
     public SpringAnimationBuilder computeParams() {
-        int singleFrameMs = DisplayController.getSingleFrameMs(mContext);
+        int singleFrameMs = RefreshRateTracker.getSingleFrameMs(mContext);
         double naturalFreq = Math.sqrt(mStiffness);
         double dampedFreq = naturalFreq * Math.sqrt(1 - mDampingRatio * mDampingRatio);
 
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 8b2184d..278bcf2 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -96,6 +96,16 @@
             getDebugFlag("ENABLE_FLOATING_SEARCH_BAR", false,
                     "Keep All Apps search bar at the bottom (but above keyboard if open)");
 
+    public static final BooleanFlag INJECT_WEB_TOP = new DeviceFlag("INJECT_WEB_TOP", false,
+            "Show web suggestions on top of the search results");
+
+    public static final BooleanFlag USE_FALLBACK_APP_SEARCH = new DeviceFlag(
+            "USE_FALLBACK_APP_SEARCH", false,
+            "Use fallback launcher app search results instead of AiAi app results");
+
+    public static final BooleanFlag ENABLE_QUICK_SEARCH = new DeviceFlag("ENABLE_QUICK_SEARCH",
+            true, "Use quick search behavior.");
+
     public static final BooleanFlag COLLECT_SEARCH_HISTORY = new DeviceFlag(
             "COLLECT_SEARCH_HISTORY", false, "Allow launcher to collect search history for log");
 
@@ -246,6 +256,10 @@
             "ENABLE_ALL_APPS_IN_TASKBAR", true,
             "Enables accessing All Apps from the system Taskbar.");
 
+    public static final BooleanFlag ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR = getDebugFlag(
+            "ENABLE_ALL_APPS_ONE_SEARCH_IN_TASKBAR", false,
+            "Enables One Search box in Taskbar All Apps.");
+
     public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE = getDebugFlag(
             "ENABLE_SPLIT_FROM_WORKSPACE", true,
             "Enable initiating split screen from workspace.");
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 1e6342c..8916519 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -24,7 +24,7 @@
 import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_LABEL_UPDATED;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROP_COMPLETED;
-import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
+import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 0d2bc37..0c1ba8b 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -562,7 +562,7 @@
     }
 
     /**
-     * Helps to construct and write the log message.
+     * Helps to construct and log launcher event.
      */
     public interface StatsLogger {
 
@@ -662,6 +662,64 @@
     }
 
     /**
+     * Helps to construct and log latency event.
+     */
+    public interface StatsLatencyLogger {
+
+        enum LatencyType {
+            UNKNOWN(0),
+            COLD(1),
+            HOT(2);
+
+            private final int mId;
+
+            LatencyType(int id) {
+                this.mId = id;
+            }
+
+            public int getId() {
+                return mId;
+            }
+
+        }
+
+        /**
+         * Sets {@link InstanceId} of log message.
+         */
+        default StatsLatencyLogger withInstanceId(InstanceId instanceId) {
+            return this;
+        }
+
+
+        /**
+         * Sets latency of the event.
+         */
+        default StatsLatencyLogger withLatency(long latencyInMillis) {
+            return this;
+        }
+
+        /**
+         * Sets {@link LatencyType} of log message.
+         */
+        default StatsLatencyLogger withType(LatencyType type) {
+            return this;
+        }
+
+        /**
+         * Sets packageId of log message.
+         */
+        default StatsLatencyLogger withPackageId(int packageId) {
+            return this;
+        }
+
+        /**
+         * Builds the final message and logs it as {@link EventEnum}.
+         */
+        default void log(EventEnum event) {
+        }
+    }
+
+    /**
      * Returns new logger object.
      */
     public StatsLogger logger() {
@@ -672,11 +730,27 @@
         return logger;
     }
 
+    /**
+     * Returns new latency logger object.
+     */
+    public StatsLatencyLogger latencyLogger() {
+        StatsLatencyLogger logger = createLatencyLogger();
+        if (mInstanceId != null) {
+            logger.withInstanceId(mInstanceId);
+        }
+        return logger;
+    }
+
     protected StatsLogger createLogger() {
         return new StatsLogger() {
         };
     }
 
+    protected StatsLatencyLogger createLatencyLogger() {
+        return new StatsLatencyLogger() {
+        };
+    }
+
     /**
      * Sets InstanceId to every new {@link StatsLogger} object returned by {@link #logger()} when
      * not-null.
diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java
index cd2ef35..efebce3 100644
--- a/src/com/android/launcher3/model/data/FolderInfo.java
+++ b/src/com/android/launcher3/model/data/FolderInfo.java
@@ -217,7 +217,7 @@
         return getDefaultItemInfoBuilder()
                 .setFolderIcon(folderIcon)
                 .setRank(rank)
-                .setAttribute(getLabelState().mLogAttribute)
+                .addItemAttributes(getLabelState().mLogAttribute)
                 .setContainerInfo(getContainerInfo())
                 .build();
     }
diff --git a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
index 0283d5f..e57a895 100644
--- a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
@@ -288,7 +288,7 @@
         LauncherAtom.ItemInfo info = super.buildProto(folderInfo);
         return info.toBuilder()
                 .setWidget(info.getWidget().toBuilder().setWidgetFeatures(widgetFeatures))
-                .setAttribute(getAttribute(sourceContainer))
+                .addItemAttributes(getAttribute(sourceContainer))
                 .build();
     }
 }
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 05d6fc6..2fa7945 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -508,7 +508,9 @@
     @Override
     protected void closeComplete() {
         super.closeComplete();
-        mActivityContext.getDragController().removeDragListener(this);
+        if (mActivityContext.getDragController() != null) {
+            mActivityContext.getDragController().removeDragListener(this);
+        }
         PopupContainerWithArrow openPopup = getOpen(mActivityContext);
         if (openPopup == null || openPopup.mOriginalIcon != mOriginalIcon) {
             mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible());
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 61d488c..c00e174 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -26,7 +26,7 @@
 import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEDOWN;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEUP;
-import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
+import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 
 import android.animation.Animator.AnimatorListener;
 import android.animation.ValueAnimator;
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index 4a55d2e..2609e54 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -178,18 +178,6 @@
     }
 
     @Override
-    public int getSplitTaskViewDismissDirection(@StagePosition int stagePosition,
-            DeviceProfile dp) {
-        // Don't use device profile here because we know we're in fake landscape, only split option
-        // available is top/left
-        if (stagePosition == STAGE_POSITION_TOP_OR_LEFT) {
-            // Top (visually left) side
-            return SPLIT_TRANSLATE_PRIMARY_NEGATIVE;
-        }
-        throw new IllegalStateException("Invalid split stage position: " + stagePosition);
-    }
-
-    @Override
     public int getPrimaryScroll(View view) {
         return view.getScrollY();
     }
@@ -469,14 +457,12 @@
     }
 
     @Override
-    public void setIconAndSnapshotParams(View iconView, int taskIconMargin, int taskIconHeight,
-            FrameLayout.LayoutParams snapshotParams, boolean isRtl) {
-        FrameLayout.LayoutParams iconParams =
-                (FrameLayout.LayoutParams) iconView.getLayoutParams();
+    public void setTaskIconParams(FrameLayout.LayoutParams iconParams, int taskIconMargin,
+            int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
         iconParams.gravity = (isRtl ? START : END) | CENTER_VERTICAL;
         iconParams.rightMargin = -taskIconHeight - taskIconMargin / 2;
         iconParams.leftMargin = 0;
-        iconParams.topMargin = snapshotParams.topMargin / 2;
+        iconParams.topMargin = thumbnailTopMargin / 2;
     }
 
     @Override
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 923dcc6..6e594e9 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -47,10 +47,6 @@
  */
 public interface PagedOrientationHandler {
 
-    int SPLIT_TRANSLATE_PRIMARY_POSITIVE = 0;
-    int SPLIT_TRANSLATE_PRIMARY_NEGATIVE = 1;
-    int SPLIT_TRANSLATE_SECONDARY_NEGATIVE = 2;
-
     PagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler();
     PagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler();
     PagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler();
@@ -82,12 +78,6 @@
     FloatProperty<View> getPrimaryViewTranslate();
     FloatProperty<View> getSecondaryViewTranslate();
 
-    /**
-     * @param stagePosition The position where the view to be split will go
-     * @return {@link #SPLIT_TRANSLATE_*} constants to indicate which direction the
-     * dismissal should happen
-     */
-    int getSplitTaskViewDismissDirection(@StagePosition int stagePosition, DeviceProfile dp);
     int getPrimaryScroll(View view);
     float getPrimaryScale(View view);
     int getChildStart(View view);
@@ -152,8 +142,8 @@
             StagedSplitBounds splitBoundsConfig, DeviceProfile dp);
 
     // Overview TaskMenuView methods
-    void setIconAndSnapshotParams(View iconView, int taskIconMargin, int taskIconHeight,
-            FrameLayout.LayoutParams snapshotParams, boolean isRtl);
+    void setTaskIconParams(FrameLayout.LayoutParams iconParams,
+            int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl);
     void setSplitIconParams(View primaryIconView, View secondaryIconView,
             int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
             boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig);
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 0d92e25..2c9afd6 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -180,24 +180,6 @@
     }
 
     @Override
-    public int getSplitTaskViewDismissDirection(@StagePosition int stagePosition,
-            DeviceProfile dp) {
-        if (stagePosition == STAGE_POSITION_TOP_OR_LEFT) {
-            if (dp.isLandscape) {
-                // Left side
-                return SPLIT_TRANSLATE_PRIMARY_NEGATIVE;
-            } else {
-                // Top side
-                return SPLIT_TRANSLATE_SECONDARY_NEGATIVE;
-            }
-        } else if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
-            // We don't have a bottom option, so should be right
-            return SPLIT_TRANSLATE_PRIMARY_POSITIVE;
-        }
-        throw new IllegalStateException("Invalid split stage position: " + stagePosition);
-    }
-
-    @Override
     public int getPrimaryScroll(View view) {
         return view.getScrollX();
     }
@@ -567,10 +549,8 @@
     }
 
     @Override
-    public void setIconAndSnapshotParams(View iconView, int taskIconMargin, int taskIconHeight,
-            FrameLayout.LayoutParams snapshotParams, boolean isRtl) {
-        FrameLayout.LayoutParams iconParams =
-                (FrameLayout.LayoutParams) iconView.getLayoutParams();
+    public void setTaskIconParams(FrameLayout.LayoutParams iconParams, int taskIconMargin,
+            int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
         iconParams.gravity = TOP | CENTER_HORIZONTAL;
         iconParams.leftMargin = iconParams.rightMargin = 0;
         iconParams.topMargin = taskIconMargin;
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index 69e19f4..9151796 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -23,7 +23,6 @@
 
 import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
 import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
 
 import android.content.res.Resources;
@@ -168,14 +167,12 @@
     }
 
     @Override
-    public void setIconAndSnapshotParams(View mIconView, int taskIconMargin, int taskIconHeight,
-            FrameLayout.LayoutParams snapshotParams, boolean isRtl) {
-        FrameLayout.LayoutParams iconParams =
-                (FrameLayout.LayoutParams) mIconView.getLayoutParams();
+    public void setTaskIconParams(FrameLayout.LayoutParams iconParams,
+            int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
         iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
         iconParams.leftMargin = -taskIconHeight - taskIconMargin / 2;
         iconParams.rightMargin = 0;
-        iconParams.topMargin = snapshotParams.topMargin / 2;
+        iconParams.topMargin = thumbnailTopMargin / 2;
     }
 
     @Override
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index e8941e6..fe0bf6d 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -121,6 +121,9 @@
             mLongPressState = STATE_COMPLETED;
         }
 
+        boolean isInAllAppsBottomSheet = mLauncher.isInState(ALL_APPS)
+                && mLauncher.getDeviceProfile().isTablet;
+
         final boolean result;
         if (mLongPressState == STATE_COMPLETED) {
             // We have handled the touch, so workspace does not need to know anything anymore.
@@ -136,8 +139,9 @@
 
             result = true;
         } else {
-            // We don't want to handle touch, let workspace handle it as usual.
-            result = false;
+            // We don't want to handle touch unless we're in AllApps bottom sheet, let workspace
+            // handle it as usual.
+            result = isInAllAppsBottomSheet;
         }
 
         if (action == ACTION_UP || action == ACTION_POINTER_UP) {
@@ -153,9 +157,7 @@
         if (action == ACTION_UP || action == ACTION_CANCEL) {
             cancelLongPress();
         }
-        if (action == ACTION_UP
-                && mLauncher.isInState(ALL_APPS)
-                && mLauncher.getDeviceProfile().isTablet) {
+        if (action == ACTION_UP && isInAllAppsBottomSheet) {
             mLauncher.getStateManager().goToState(NORMAL);
             mLauncher.getStatsLogManager().logger()
                     .withSrcState(ALL_APPS.statsLogOrdinal)
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index ba925f5..f944d3c 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -15,12 +15,18 @@
  */
 package com.android.launcher3.util;
 
+import static android.content.Intent.ACTION_CONFIGURATION_CHANGED;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
 
+import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
 import static com.android.launcher3.Utilities.dpiFromPx;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_2_BUTTON;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_3_BUTTON;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON;
 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.PackageManagerHelper.getPackageFilter;
+import static com.android.launcher3.util.WindowManagerCompat.MIN_LARGE_TABLET_WIDTH;
 import static com.android.launcher3.util.WindowManagerCompat.MIN_TABLET_WIDTH;
 
 import static java.util.Collections.emptyMap;
@@ -30,11 +36,9 @@
 import android.content.ComponentCallbacks;
 import android.content.Context;
 import android.content.Intent;
-import android.content.IntentFilter;
 import android.content.res.Configuration;
 import android.graphics.Point;
 import android.hardware.display.DisplayManager;
-import android.hardware.display.DisplayManager.DisplayListener;
 import android.os.Build;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -44,11 +48,13 @@
 
 import androidx.annotation.AnyThread;
 import androidx.annotation.UiThread;
-import androidx.annotation.WorkerThread;
 
+import com.android.launcher3.ResourceUtils;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
 import com.android.launcher3.uioverrides.ApiWrapper;
 
+import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Map;
 import java.util.Objects;
@@ -58,7 +64,7 @@
  * Utility class to cache properties of default display to avoid a system RPC on every call.
  */
 @SuppressLint("NewApi")
-public class DisplayController implements DisplayListener, ComponentCallbacks, SafeCloseable {
+public class DisplayController implements ComponentCallbacks, SafeCloseable {
 
     private static final String TAG = "DisplayController";
 
@@ -69,9 +75,14 @@
     public static final int CHANGE_ROTATION = 1 << 1;
     public static final int CHANGE_DENSITY = 1 << 2;
     public static final int CHANGE_SUPPORTED_BOUNDS = 1 << 3;
+    public static final int CHANGE_NAVIGATION_MODE = 1 << 4;
 
     public static final int CHANGE_ALL = CHANGE_ACTIVE_SCREEN | CHANGE_ROTATION
-            | CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS;
+            | CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS | CHANGE_NAVIGATION_MODE;
+
+    private static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED";
+    private static final String NAV_BAR_INTERACTION_MODE_RES_NAME = "config_navBarInteractionMode";
+    private static final String TARGET_OVERLAY_PACKAGE = "android";
 
     private final Context mContext;
     private final DisplayManager mDM;
@@ -82,6 +93,8 @@
     private DisplayInfoChangeListener mPriorityListener;
     private final ArrayList<DisplayInfoChangeListener> mListeners = new ArrayList<>();
 
+    private final SimpleBroadcastReceiver mReceiver = new SimpleBroadcastReceiver(this::onIntent);
+
     private Info mInfo;
     private boolean mDestroyed = false;
 
@@ -95,14 +108,15 @@
             mWindowContext.registerComponentCallbacks(this);
         } else {
             mWindowContext = null;
-            SimpleBroadcastReceiver configChangeReceiver =
-                    new SimpleBroadcastReceiver(this::onConfigChanged);
-            mContext.registerReceiver(configChangeReceiver,
-                    new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED));
+            mReceiver.register(mContext, ACTION_CONFIGURATION_CHANGED);
         }
+
+        // Initialize navigation mode change listener
+        mContext.registerReceiver(mReceiver,
+                getPackageFilter(TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED));
+
         mInfo = new Info(getDisplayInfoContext(display), display,
                 getInternalDisplays(mDM), emptyMap());
-        mDM.registerDisplayListener(this, UI_HELPER_EXECUTOR.getHandler());
     }
 
     private static ArrayMap<String, PortraitSize> getInternalDisplays(
@@ -120,6 +134,13 @@
         return internalDisplays;
     }
 
+    /**
+     * Returns the current navigation mode
+     */
+    public static NavigationMode getNavigationMode(Context context) {
+        return INSTANCE.get(context).getInfo().navigationMode;
+    }
+
     @Override
     public void close() {
         mDestroyed = true;
@@ -128,35 +149,6 @@
         } else {
             // TODO: unregister broadcast receiver
         }
-        mDM.unregisterDisplayListener(this);
-    }
-
-    @Override
-    public final void onDisplayAdded(int displayId) { }
-
-    @Override
-    public final void onDisplayRemoved(int displayId) { }
-
-    @WorkerThread
-    @Override
-    public final void onDisplayChanged(int displayId) {
-        if (displayId != DEFAULT_DISPLAY) {
-            return;
-        }
-        Display display = mDM.getDisplay(DEFAULT_DISPLAY);
-        if (display == null) {
-            return;
-        }
-        if (Utilities.ATLEAST_S) {
-            // Only update refresh rate. Everything else comes from component callbacks
-            mInfo.mSingleFrameMs = getSingleFrameMs(display);
-            return;
-        }
-        handleInfoChange(display);
-    }
-
-    public static int getSingleFrameMs(Context context) {
-        return INSTANCE.get(context).getInfo().mSingleFrameMs;
     }
 
     /**
@@ -173,15 +165,20 @@
         void onDisplayInfoChanged(Context context, Info info, int flags);
     }
 
-    /**
-     * Only used for pre-S
-     */
-    private void onConfigChanged(Intent intent) {
+    private void onIntent(Intent intent) {
         if (mDestroyed) {
             return;
         }
-        Configuration config = mContext.getResources().getConfiguration();
-        if (mInfo.fontScale != config.fontScale || mInfo.densityDpi != config.densityDpi) {
+        boolean reconfigure = false;
+        if (ACTION_OVERLAY_CHANGED.equals(intent.getAction())) {
+            reconfigure = true;
+        } else if (ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
+            Configuration config = mContext.getResources().getConfiguration();
+            reconfigure = mInfo.fontScale != config.fontScale
+                    || mInfo.densityDpi != config.densityDpi;
+        }
+
+        if (reconfigure) {
             Log.d(TAG, "Configuration changed, notifying listeners");
             Display display = mDM.getDisplay(DEFAULT_DISPLAY);
             if (display != null) {
@@ -235,7 +232,8 @@
         Info newInfo = new Info(displayContext, display,
                 oldInfo.mInternalDisplays, oldInfo.mPerDisplayBounds);
 
-        if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale) {
+        if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale
+                || newInfo.navigationMode != oldInfo.navigationMode) {
             // Cache may not be valid anymore, recreate without cache
             newInfo = new Info(displayContext, display, getInternalDisplays(mDM), emptyMap());
         }
@@ -250,6 +248,9 @@
         if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale) {
             change |= CHANGE_DENSITY;
         }
+        if (newInfo.navigationMode != oldInfo.navigationMode) {
+            change |= CHANGE_NAVIGATION_MODE;
+        }
         if (!newInfo.supportedBounds.equals(oldInfo.supportedBounds)) {
             change |= CHANGE_SUPPORTED_BOUNDS;
 
@@ -280,19 +281,20 @@
         if (mPriorityListener != null) {
             mPriorityListener.onDisplayInfoChanged(context, mInfo, flags);
         }
-        for (int i = mListeners.size() - 1; i >= 0; i--) {
+
+        int count = mListeners.size();
+        for (int i = 0; i < count; i++) {
             mListeners.get(i).onDisplayInfoChanged(context, mInfo, flags);
         }
     }
 
     public static class Info {
 
-        private int mSingleFrameMs;
-
         // Configuration properties
         public final int rotation;
         public final float fontScale;
         public final int densityDpi;
+        public final NavigationMode navigationMode;
 
         private final PortraitSize mScreenSizeDp;
 
@@ -317,8 +319,8 @@
             fontScale = config.fontScale;
             densityDpi = config.densityDpi;
             mScreenSizeDp = new PortraitSize(config.screenHeightDp, config.screenWidthDp);
+            navigationMode = parseNavigationMode(context);
 
-            mSingleFrameMs = getSingleFrameMs(display);
             currentSize = new Point();
             display.getRealSize(currentSize);
 
@@ -368,12 +370,35 @@
         }
 
         /**
-         * Returns true if the bounds represent a tablet
+         * Returns {@code true} if the bounds represent a tablet.
          */
         public boolean isTablet(WindowBounds bounds) {
             return dpiFromPx(Math.min(bounds.bounds.width(), bounds.bounds.height()),
                     densityDpi) >= MIN_TABLET_WIDTH;
         }
+
+        /**
+         * Returns {@code true} if the bounds represent a large tablet.
+         */
+        public boolean isLargeTablet(WindowBounds bounds) {
+            return dpiFromPx(Math.min(bounds.bounds.width(), bounds.bounds.height()),
+                    densityDpi) >= MIN_LARGE_TABLET_WIDTH;
+        }
+    }
+
+    /**
+     * Dumps the current state information
+     */
+    public void dump(PrintWriter pw) {
+        Info info = mInfo;
+        pw.println("DisplayController.Info:");
+        pw.println("  id=" + info.displayId);
+        pw.println("  rotation=" + info.rotation);
+        pw.println("  fontScale=" + info.fontScale);
+        pw.println("  densityDpi=" + info.displayId);
+        pw.println("  navigationMode=" + info.navigationMode.name());
+        pw.println("  currentSize=" + info.currentSize);
+        pw.println("  supportedBounds=" + info.supportedBounds);
     }
 
     /**
@@ -401,8 +426,35 @@
         }
     }
 
-    private static int getSingleFrameMs(Display display) {
-        float refreshRate = display.getRefreshRate();
-        return refreshRate > 0 ? (int) (1000 / refreshRate) : 16;
+    public enum NavigationMode {
+        THREE_BUTTONS(false, 0, LAUNCHER_NAVIGATION_MODE_3_BUTTON),
+        TWO_BUTTONS(true, 1, LAUNCHER_NAVIGATION_MODE_2_BUTTON),
+        NO_BUTTON(true, 2, LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON);
+
+        public final boolean hasGestures;
+        public final int resValue;
+        public final LauncherEvent launcherEvent;
+
+        NavigationMode(boolean hasGestures, int resValue, LauncherEvent launcherEvent) {
+            this.hasGestures = hasGestures;
+            this.resValue = resValue;
+            this.launcherEvent = launcherEvent;
+        }
+    }
+
+    private static NavigationMode parseNavigationMode(Context context) {
+        int modeInt = ResourceUtils.getIntegerByName(NAV_BAR_INTERACTION_MODE_RES_NAME,
+                context.getResources(), INVALID_RESOURCE_HANDLE);
+
+        if (modeInt == INVALID_RESOURCE_HANDLE) {
+            Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
+        } else {
+            for (NavigationMode m : NavigationMode.values()) {
+                if (m.resValue == modeInt) {
+                    return m;
+                }
+            }
+        }
+        return Utilities.ATLEAST_S ? NavigationMode.NO_BUTTON : NavigationMode.THREE_BUTTONS;
     }
 }
diff --git a/src/com/android/launcher3/util/WindowManagerCompat.java b/src/com/android/launcher3/util/WindowManagerCompat.java
index e1b9478..873a518 100644
--- a/src/com/android/launcher3/util/WindowManagerCompat.java
+++ b/src/com/android/launcher3/util/WindowManagerCompat.java
@@ -45,6 +45,7 @@
 public class WindowManagerCompat {
 
     public static final int MIN_TABLET_WIDTH = 600;
+    public static final int MIN_LARGE_TABLET_WIDTH = 720;
 
     /**
      * Returns a set of supported render sizes for a internal display.
diff --git a/src/com/android/launcher3/util/window/RefreshRateTracker.java b/src/com/android/launcher3/util/window/RefreshRateTracker.java
new file mode 100644
index 0000000..7814617
--- /dev/null
+++ b/src/com/android/launcher3/util/window/RefreshRateTracker.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.util.window;
+
+import static android.view.Display.DEFAULT_DISPLAY;
+
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import android.content.Context;
+import android.hardware.display.DisplayManager;
+import android.hardware.display.DisplayManager.DisplayListener;
+import android.view.Display;
+
+import androidx.annotation.WorkerThread;
+
+import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
+
+/**
+ * Utility class to track refresh rate of the current device
+ */
+public class RefreshRateTracker implements DisplayListener, SafeCloseable {
+
+    private static final MainThreadInitializedObject<RefreshRateTracker> INSTANCE =
+            new MainThreadInitializedObject<>(RefreshRateTracker::new);
+
+    private int mSingleFrameMs = 1;
+
+    private final DisplayManager mDM;
+
+    private RefreshRateTracker(Context context) {
+        mDM = context.getSystemService(DisplayManager.class);
+        updateSingleFrameMs();
+        mDM.registerDisplayListener(this, UI_HELPER_EXECUTOR.getHandler());
+    }
+
+    /**
+     * Returns the single frame time in ms
+     */
+    public static int getSingleFrameMs(Context context) {
+        return INSTANCE.get(context).mSingleFrameMs;
+    }
+
+    @Override
+    public final void onDisplayAdded(int displayId) { }
+
+    @Override
+    public final void onDisplayRemoved(int displayId) { }
+
+    @WorkerThread
+    @Override
+    public final void onDisplayChanged(int displayId) {
+        if (displayId == DEFAULT_DISPLAY) {
+            updateSingleFrameMs();
+        }
+    }
+
+    private void updateSingleFrameMs() {
+        Display display = mDM.getDisplay(DEFAULT_DISPLAY);
+        if (display != null) {
+            float refreshRate = display.getRefreshRate();
+            mSingleFrameMs = refreshRate > 0 ? (int) (1000 / refreshRate) : 16;
+        }
+    }
+
+    @Override
+    public void close() {
+        mDM.unregisterDisplayListener(this);
+    }
+}
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 76dfb3c..f71aa13 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -20,7 +20,7 @@
 import static android.view.MotionEvent.ACTION_DOWN;
 import static android.view.MotionEvent.ACTION_UP;
 
-import static com.android.launcher3.util.DisplayController.getSingleFrameMs;
+import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
 
 import android.annotation.TargetApi;
 import android.app.WallpaperManager;
diff --git a/src/com/android/launcher3/views/BubbleTextHolder.java b/src/com/android/launcher3/views/BubbleTextHolder.java
index 1cb27e1..76c465c 100644
--- a/src/com/android/launcher3/views/BubbleTextHolder.java
+++ b/src/com/android/launcher3/views/BubbleTextHolder.java
@@ -22,7 +22,7 @@
 /**
  * Views that contain {@link BubbleTextView} should implement this interface.
  */
-public interface BubbleTextHolder {
+public interface BubbleTextHolder extends IconLabelDotView {
     BubbleTextView getBubbleText();
 
     /**
@@ -32,4 +32,14 @@
      */
     default void onItemInfoUpdated(ItemInfoWithIcon itemInfo) {
     }
+
+    @Override
+    default void setIconVisible(boolean visible) {
+        getBubbleText().setIconVisible(visible);
+    }
+
+    @Override
+    default void setForceHideDot(boolean hide) {
+        getBubbleText().setForceHideDot(hide);
+    }
 }
diff --git a/src/com/android/launcher3/views/ClipIconView.java b/src/com/android/launcher3/views/ClipIconView.java
index a66b3f9..d1f90e9 100644
--- a/src/com/android/launcher3/views/ClipIconView.java
+++ b/src/com/android/launcher3/views/ClipIconView.java
@@ -147,8 +147,7 @@
      * Update the icon UI to match the provided parameters during an animation frame
      */
     public void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
-            int fgIconAlpha, boolean isOpening, View container, DeviceProfile dp,
-            boolean isVerticalBarLayout) {
+            int fgIconAlpha, boolean isOpening, View container, DeviceProfile dp) {
         MarginLayoutParams lp = (MarginLayoutParams) container.getLayoutParams();
 
         float dX = mIsRtl
@@ -169,7 +168,7 @@
         }
 
         update(rect, progress, shapeProgressStart, cornerRadius, fgIconAlpha, isOpening, scale,
-                minSize, lp, isVerticalBarLayout, dp);
+                minSize, lp, dp);
 
         container.setPivotX(0);
         container.setPivotY(0);
@@ -181,7 +180,7 @@
 
     private void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
             int fgIconAlpha, boolean isOpening, float scale, float minSize,
-            MarginLayoutParams parentLp, boolean isVerticalBarLayout, DeviceProfile dp) {
+            MarginLayoutParams parentLp, DeviceProfile dp) {
         float dX = mIsRtl
                 ? rect.left - (dp.widthPx - parentLp.getMarginStart() - parentLp.width)
                 : rect.left - parentLp.getMarginStart();
@@ -193,7 +192,7 @@
         float shapeRevealProgress = boundToRange(mapToRange(max(shapeProgressStart, progress),
                 shapeProgressStart, 1f, 0, toMax, LINEAR), 0, 1);
 
-        if (isVerticalBarLayout) {
+        if (dp.isLandscape) {
             mOutline.right = (int) (rect.width() / scale);
         } else {
             mOutline.bottom = (int) (rect.height() / scale);
@@ -218,16 +217,16 @@
                 mRevealAnimator.setCurrentFraction(shapeRevealProgress);
             }
 
-            float drawableScale = (isVerticalBarLayout ? mOutline.width() : mOutline.height())
+            float drawableScale = (dp.isLandscape ? mOutline.width() : mOutline.height())
                     / minSize;
-            setBackgroundDrawableBounds(drawableScale, isVerticalBarLayout);
+            setBackgroundDrawableBounds(drawableScale, dp.isLandscape);
             if (isOpening) {
                 // Center align foreground
                 int height = mFinalDrawableBounds.height();
                 int width = mFinalDrawableBounds.width();
-                int diffY = isVerticalBarLayout ? 0
+                int diffY = dp.isLandscape ? 0
                         : (int) (((height * drawableScale) - height) / 2);
-                int diffX = isVerticalBarLayout ? (int) (((width * drawableScale) - width) / 2)
+                int diffX = dp.isLandscape ? (int) (((width * drawableScale) - width) / 2)
                         : 0;
                 sTmpRect.set(mFinalDrawableBounds);
                 sTmpRect.offset(diffX, diffY);
@@ -247,11 +246,11 @@
         invalidateOutline();
     }
 
-    private void setBackgroundDrawableBounds(float scale, boolean isVerticalBarLayout) {
+    private void setBackgroundDrawableBounds(float scale, boolean isLandscape) {
         sTmpRect.set(mFinalDrawableBounds);
         Utilities.scaleRectAboutCenter(sTmpRect, scale);
         // Since the drawable is at the top of the view, we need to offset to keep it centered.
-        if (isVerticalBarLayout) {
+        if (isLandscape) {
             sTmpRect.offsetTo((int) (mFinalDrawableBounds.left * scale), sTmpRect.top);
         } else {
             sTmpRect.offsetTo(sTmpRect.left, (int) (mFinalDrawableBounds.top * scale));
@@ -269,7 +268,7 @@
      * Sets the icon for this view as part of initial setup
      */
     public void setIcon(@Nullable Drawable drawable, int iconOffset, MarginLayoutParams lp,
-            boolean isOpening, boolean isVerticalBarLayout, DeviceProfile dp) {
+            boolean isOpening, DeviceProfile dp) {
         mIsAdaptiveIcon = drawable instanceof AdaptiveIconDrawable;
         if (mIsAdaptiveIcon) {
             boolean isFolderIcon = drawable instanceof FolderAdaptiveIcon;
@@ -304,7 +303,7 @@
                 Utilities.scaleRectAboutCenter(mStartRevealRect, IconShape.getNormalizationScale());
             }
 
-            if (isVerticalBarLayout) {
+            if (dp.isLandscape) {
                 lp.width = (int) Math.max(lp.width, lp.height * dp.aspectRatio);
             } else {
                 lp.height = (int) Math.max(lp.height, lp.width * dp.aspectRatio);
@@ -325,7 +324,7 @@
                 bgDrawableStartScale = scale;
                 mOutline.set(0, 0, lp.width, lp.height);
             }
-            setBackgroundDrawableBounds(bgDrawableStartScale, isVerticalBarLayout);
+            setBackgroundDrawableBounds(bgDrawableStartScale, dp.isLandscape);
             mEndRevealRect.set(0, 0, lp.width, lp.height);
             setOutlineProvider(new ViewOutlineProvider() {
                 @Override
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index 0f69530..56a1d37 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -43,6 +43,7 @@
 import androidx.annotation.WorkerThread;
 
 import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InsettableFrameLayout;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
@@ -82,7 +83,6 @@
     private final Launcher mLauncher;
     private final boolean mIsRtl;
 
-    private boolean mIsVerticalBarLayout = false;
     private boolean mIsOpening;
 
     private IconLoadResult mIconLoadResult;
@@ -150,7 +150,7 @@
             float shapeProgressStart, float cornerRadius, boolean isOpening) {
         setAlpha(alpha);
         mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, fgIconAlpha,
-                isOpening, this, mLauncher.getDeviceProfile(), mIsVerticalBarLayout);
+                isOpening, this, mLauncher.getDeviceProfile());
     }
 
     @Override
@@ -320,11 +320,11 @@
     @UiThread
     private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge,
             @Nullable Drawable btvIcon, int iconOffset) {
+        final DeviceProfile dp = mLauncher.getDeviceProfile();
         final InsettableFrameLayout.LayoutParams lp =
                 (InsettableFrameLayout.LayoutParams) getLayoutParams();
         mBadge = badge;
-        mClipIconView.setIcon(drawable, iconOffset, lp, mIsOpening, mIsVerticalBarLayout,
-                mLauncher.getDeviceProfile());
+        mClipIconView.setIcon(drawable, iconOffset, lp, mIsOpening, dp);
         if (drawable instanceof AdaptiveIconDrawable) {
             final int originalHeight = lp.height;
             final int originalWidth = lp.width;
@@ -332,7 +332,7 @@
             mFinalDrawableBounds.set(0, 0, originalWidth, originalHeight);
 
             float aspectRatio = mLauncher.getDeviceProfile().aspectRatio;
-            if (mIsVerticalBarLayout) {
+            if (dp.isLandscape) {
                 lp.width = (int) Math.max(lp.width, lp.height * aspectRatio);
             } else {
                 lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
@@ -565,7 +565,6 @@
         view.recycle();
 
         // Init properties before getting the drawable.
-        view.mIsVerticalBarLayout = launcher.getDeviceProfile().isVerticalBarLayout();
         view.mIsOpening = isOpening;
         view.mOriginalIcon = originalView;
         view.mPositionOut = positionOut;
@@ -587,7 +586,7 @@
         view.matchPositionOf(launcher, originalView, isOpening, positionOut);
 
         // We need to add it to the overlay, but keep it invisible until animation starts..
-        view.setVisibility(INVISIBLE);
+        setIconAndDotVisible(view, false);
         parent.addView(view);
         dragLayer.addView(view.mListenerView);
         view.mListenerView.setListener(view::fastFinish);
@@ -596,16 +595,8 @@
             view.mEndRunnable = null;
 
             if (hideOriginal) {
-                if (isOpening) {
-                    setIconAndDotVisible(originalView, true);
-                    view.finish(dragLayer);
-                } else {
-                    originalView.setVisibility(VISIBLE);
-                    if (originalView instanceof IconLabelDotView) {
-                        setIconAndDotVisible(originalView, true);
-                    }
-                    view.finish(dragLayer);
-                }
+                setIconAndDotVisible(originalView, true);
+                view.finish(dragLayer);
             } else {
                 view.finish(dragLayer);
             }
diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java
index e7cb3b3..7f54d6d 100644
--- a/src/com/android/launcher3/views/FloatingSurfaceView.java
+++ b/src/com/android/launcher3/views/FloatingSurfaceView.java
@@ -40,8 +40,8 @@
 import com.android.launcher3.Insettable;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
-import com.android.launcher3.util.DisplayController;
 import com.android.launcher3.util.Executors;
+import com.android.launcher3.util.window.RefreshRateTracker;
 
 /**
  * Similar to {@link FloatingIconView} but displays a surface with the targetIcon. It then passes
@@ -97,7 +97,7 @@
 
         // Remove after some time, to avoid flickering
         Executors.MAIN_EXECUTOR.getHandler().postDelayed(mRemoveViewRunnable,
-                DisplayController.getSingleFrameMs(mLauncher));
+                RefreshRateTracker.getSingleFrameMs(mLauncher));
     }
 
     private void removeViewFromParent() {
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
index cbec642..470a800 100644
--- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -70,7 +70,7 @@
     public LauncherAtom.ItemInfo buildProto(FolderInfo folderInfo) {
         LauncherAtom.ItemInfo info = super.buildProto(folderInfo);
         return info.toBuilder()
-                .setAttribute(LauncherAppWidgetInfo.getAttribute(sourceContainer))
+                .addItemAttributes(LauncherAppWidgetInfo.getAttribute(sourceContainer))
                 .build();
     }
 }
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index daa8fb7..6e97774 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -31,6 +31,7 @@
 import android.graphics.Rect;
 import android.os.Process;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.util.AttributeSet;
 import android.util.Pair;
 import android.util.SparseArray;
@@ -55,7 +56,9 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.PendingAnimation;
 import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.model.UserManagerState;
 import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.pm.UserCache;
 import com.android.launcher3.views.ArrowTipView;
 import com.android.launcher3.views.RecyclerViewFastScroller;
 import com.android.launcher3.views.SpringRelativeLayout;
@@ -94,13 +97,17 @@
             "launcher.widgets_education_dialog_seen";
 
     private final Rect mInsets = new Rect();
+
+    private final UserManagerState mUserManagerState = new UserManagerState();
+
     private final boolean mHasWorkProfile;
     private final SparseArray<AdapterHolder> mAdapters = new SparseArray();
     private final UserHandle mCurrentUser = Process.myUserHandle();
     private final Predicate<WidgetsListBaseEntry> mPrimaryWidgetsFilter =
             entry -> mCurrentUser.equals(entry.mPkgItem.user);
     private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter =
-            mPrimaryWidgetsFilter.negate();
+            entry -> !mCurrentUser.equals(entry.mPkgItem.user)
+                    && !mUserManagerState.isUserQuiet(entry.mPkgItem.user);
     @Nullable private ArrowTipView mLatestEducationalTip;
     private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
             new OnLayoutChangeListener() {
@@ -171,6 +178,9 @@
                 : 0;
         mWidgetSheetContentHorizontalPadding = 2 * resources.getDimensionPixelSize(
                 R.dimen.widget_cell_horizontal_padding);
+
+        mUserManagerState.init(UserCache.INSTANCE.get(context),
+                context.getSystemService(UserManager.class));
     }
 
     public WidgetsFullSheet(Context context, AttributeSet attrs) {
@@ -259,10 +269,15 @@
         boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.hasVisibleEntries();
         adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
 
-        mNoWidgetsView.setText(
-                adapterHolder.mAdapterType == AdapterHolder.SEARCH
-                        ? R.string.no_search_results
-                        : R.string.no_widgets_available);
+        if (adapterHolder.mAdapterType == AdapterHolder.SEARCH) {
+            mNoWidgetsView.setText(R.string.no_search_results);
+        } else if (adapterHolder.mAdapterType == AdapterHolder.WORK
+                && mUserManagerState.isAnyProfileQuietModeEnabled()
+                && mActivityContext.getStringCache() != null) {
+            mNoWidgetsView.setText(mActivityContext.getStringCache().workProfilePausedTitle);
+        } else {
+            mNoWidgetsView.setText(R.string.no_widgets_available);
+        }
         mNoWidgetsView.setVisibility(isWidgetAvailable ? GONE : VISIBLE);
     }
 
diff --git a/tests/src/com/android/launcher3/DeviceProfileTest.kt b/tests/src/com/android/launcher3/DeviceProfileTest.kt
index 6c99a21..60046a0 100644
--- a/tests/src/com/android/launcher3/DeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/DeviceProfileTest.kt
@@ -39,6 +39,7 @@
     private var isMultiWindowMode: Boolean = false
     private var transposeLayoutWithOrientation: Boolean = false
     private var useTwoPanels: Boolean = false
+    private var isGestureMode: Boolean = true
 
     @Before
     fun setUp() {
@@ -58,7 +59,8 @@
             windowBounds,
             isMultiWindowMode,
             transposeLayoutWithOrientation,
-            useTwoPanels
+            useTwoPanels,
+            isGestureMode
         )
 
         assertThat(dp.isQsbInline).isFalse()
@@ -67,7 +69,7 @@
 
     @Test
     fun qsbWidth_is_match_parent_for_tablet_portrait() {
-        initializeVarsForTablet()
+        initializeVarsForLargeTablet()
 
         val dp = DeviceProfile(
             context,
@@ -76,7 +78,8 @@
             windowBounds,
             isMultiWindowMode,
             transposeLayoutWithOrientation,
-            useTwoPanels
+            useTwoPanels,
+            isGestureMode
         )
 
         assertThat(dp.isQsbInline).isFalse()
@@ -84,8 +87,8 @@
     }
 
     @Test
-    fun qsbWidth_has_size_for_tablet_landscape() {
-        initializeVarsForTablet(true)
+    fun qsbWidth_has_size_for_large_tablet_landscape() {
+        initializeVarsForLargeTablet(true)
 
         val dp = DeviceProfile(
             context,
@@ -94,7 +97,8 @@
             windowBounds,
             isMultiWindowMode,
             transposeLayoutWithOrientation,
-            useTwoPanels
+            useTwoPanels,
+            isGestureMode
         )
 
         if (dp.hotseatQsbHeight > 0) {
@@ -110,8 +114,8 @@
      * This test is to make sure that two panels don't inline the QSB as tablets do
      */
     @Test
-    fun qsbWidth_is_match_parent_for_two_panel_landscape() {
-        initializeVarsForTablet(true)
+    fun qsbWidth_is_match_parent_for_small_two_panel_landscape() {
+        initializeVarsForSmallTablet(true)
         useTwoPanels = true
 
         val dp = DeviceProfile(
@@ -121,7 +125,8 @@
             windowBounds,
             isMultiWindowMode,
             transposeLayoutWithOrientation,
-            useTwoPanels
+            useTwoPanels,
+            isGestureMode
         )
 
         assertThat(dp.isQsbInline).isFalse()
@@ -137,11 +142,12 @@
         windowBounds = WindowBounds(x, y, x, y - 100)
 
         `when`(info.isTablet(any())).thenReturn(false)
+        `when`(info.isLargeTablet(any())).thenReturn(false)
 
         scalableInvariantDeviceProfile()
     }
 
-    private fun initializeVarsForTablet(isLandscape: Boolean = false) {
+    private fun initializeVarsForSmallTablet(isLandscape: Boolean = false) {
         val (x, y) = if (isLandscape)
             Pair(2560, 1600)
         else
@@ -150,6 +156,21 @@
         windowBounds = WindowBounds(x, y, x, y - 100)
 
         `when`(info.isTablet(any())).thenReturn(true)
+        `when`(info.isLargeTablet(any())).thenReturn(false)
+
+        scalableInvariantDeviceProfile()
+    }
+
+    private fun initializeVarsForLargeTablet(isLandscape: Boolean = false) {
+        val (x, y) = if (isLandscape)
+            Pair(2560, 1600)
+        else
+            Pair(1600, 2560)
+
+        windowBounds = WindowBounds(x, y, x, y - 100)
+
+        `when`(info.isTablet(any())).thenReturn(true)
+        `when`(info.isLargeTablet(any())).thenReturn(true)
 
         scalableInvariantDeviceProfile()
     }
diff --git a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
index f34a29e..92e3e64 100644
--- a/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
+++ b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
@@ -34,6 +34,7 @@
 import org.junit.runner.RunWith;
 
 import java.util.UUID;
+import java.util.concurrent.TimeUnit;
 
 
 /**
@@ -44,6 +45,8 @@
 public class PromiseIconUiTest extends AbstractLauncherUiTest {
 
     private int mSessionId = -1;
+    // TODO(b/202985412): Revert to default timeout when PackageManager bug is fixed.
+    private static final long PROMISE_ICON_TIMEOUT = TimeUnit.SECONDS.toMillis(60);
 
     @Override
     public void setUp() throws Exception {
@@ -85,7 +88,8 @@
 
         // Verify promise icon is added
         waitForLauncherCondition("Test Promise App not found on workspace", launcher ->
-                launcher.getWorkspace().getFirstMatch(findPromiseApp) != null);
+                launcher.getWorkspace().getFirstMatch(findPromiseApp) != null,
+                PROMISE_ICON_TIMEOUT);
 
         // Remove session
         mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);
@@ -93,7 +97,8 @@
 
         // Verify promise icon is removed
         waitForLauncherCondition("Test Promise App not removed from workspace", launcher ->
-                launcher.getWorkspace().getFirstMatch(findPromiseApp) == null);
+                launcher.getWorkspace().getFirstMatch(findPromiseApp) == null,
+                PROMISE_ICON_TIMEOUT);
     }
 
     @Test
@@ -111,6 +116,7 @@
 
         // Verify promise icon is not added
         waitForLauncherCondition("Test Promise App not found on workspace", launcher ->
-                launcher.getWorkspace().getFirstMatch(findPromiseApp) == null);
+                launcher.getWorkspace().getFirstMatch(findPromiseApp) == null,
+                PROMISE_ICON_TIMEOUT);
     }
 }
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 79a4673..c99c4f1 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -33,6 +33,7 @@
 import android.content.pm.LauncherApps;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.graphics.Point;
 import android.os.Debug;
 import android.os.Process;
 import android.os.RemoteException;
@@ -54,6 +55,8 @@
 import com.android.launcher3.Utilities;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.tapl.HomeAllApps;
+import com.android.launcher3.tapl.HomeAppIcon;
 import com.android.launcher3.tapl.LauncherInstrumentation;
 import com.android.launcher3.tapl.LauncherInstrumentation.ContainerType;
 import com.android.launcher3.tapl.TestHelpers;
@@ -600,4 +603,26 @@
 
     protected void onLauncherActivityClose(Launcher launcher) {
     }
+
+    protected HomeAppIcon createShortcutInCenterIfNotExist(String name) {
+        Point dimension = mLauncher.getWorkspace().getIconGridDimensions();
+        return createShortcutIfNotExist(name, dimension.x / 2, dimension.y / 2);
+    }
+
+    protected HomeAppIcon createShortcutIfNotExist(String name, int cellX, int cellY) {
+        HomeAppIcon homeAppIcon = mLauncher.getWorkspace().tryGetWorkspaceAppIcon(name);
+        if (homeAppIcon == null) {
+            HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+            allApps.freeze();
+            try {
+                allApps.getAppIcon(name).dragToWorkspace(cellX, cellY);
+            } finally {
+                allApps.unfreeze();
+            }
+            homeAppIcon = mLauncher.getWorkspace().getWorkspaceAppIcon(name);
+        }
+        return homeAppIcon;
+    }
+
+
 }
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index da8bf6e..61ec8bd 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -365,27 +365,11 @@
         }
     }
 
-    private HomeAppIcon createShortcutIfNotExist(String name) {
-        HomeAppIcon homeAppIcon = mLauncher.getWorkspace().tryGetWorkspaceAppIcon(name);
-        if (homeAppIcon == null) {
-            HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
-            allApps.freeze();
-            try {
-                allApps.getAppIcon(name).dragToWorkspace(false, false);
-            } finally {
-                allApps.unfreeze();
-            }
-            homeAppIcon = mLauncher.getWorkspace().getWorkspaceAppIcon(name);
-        }
-        return homeAppIcon;
-    }
-
-    @Ignore("b/205014516")
     @Test
     @PortraitLandscape
     public void testDragToFolder() throws Exception {
-        final HomeAppIcon playStoreIcon = createShortcutIfNotExist("Play Store");
-        final HomeAppIcon gmailIcon = createShortcutIfNotExist("Gmail");
+        final HomeAppIcon playStoreIcon = createShortcutIfNotExist("Play Store", 0, 1);
+        final HomeAppIcon gmailIcon = createShortcutIfNotExist("Gmail", 1, 1);
 
         FolderIcon folderIcon = gmailIcon.dragToIcon(playStoreIcon);
 
@@ -399,7 +383,7 @@
         assertNull("Play Store should be moved to a folder.",
                 workspace.tryGetWorkspaceAppIcon("Play Store"));
 
-        final HomeAppIcon youTubeIcon = createShortcutIfNotExist("YouTube");
+        final HomeAppIcon youTubeIcon = createShortcutInCenterIfNotExist("YouTube");
 
         folderIcon = youTubeIcon.dragToIcon(folderIcon);
         folder = folderIcon.open();
@@ -433,8 +417,8 @@
     @PortraitLandscape
     public void testDeleteFromWorkspace() throws Exception {
         // test delete both built-in apps and user-installed app from workspace
-        for (String appName : new String[] {"Gmail", "Play Store", APP_NAME}) {
-            final HomeAppIcon homeAppIcon = createShortcutIfNotExist(appName);
+        for (String appName : new String[]{"Gmail", "Play Store", APP_NAME}) {
+            final HomeAppIcon homeAppIcon = createShortcutInCenterIfNotExist(appName);
             Workspace workspace = mLauncher.getWorkspace().deleteAppIcon(homeAppIcon);
             assertNull(appName + " app was found after being deleted from workspace",
                     workspace.tryGetWorkspaceAppIcon(appName));
@@ -458,7 +442,7 @@
         TestUtil.installDummyApp();
         try {
             verifyAppUninstalledFromAllApps(
-                    createShortcutIfNotExist(DUMMY_APP_NAME).uninstall(), DUMMY_APP_NAME);
+                    createShortcutInCenterIfNotExist(DUMMY_APP_NAME).uninstall(), DUMMY_APP_NAME);
         } finally {
             TestUtil.uninstallDummyApp();
         }
@@ -509,7 +493,7 @@
         }
 
         // test to move a shortcut to other cell.
-        final HomeAppIcon launcherTestAppIcon = createShortcutIfNotExist(APP_NAME);
+        final HomeAppIcon launcherTestAppIcon = createShortcutInCenterIfNotExist(APP_NAME);
         for (Point target : targets) {
             launcherTestAppIcon.dragToWorkspace(target.x, target.y);
         }
diff --git a/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java b/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java
index 4b36dc0..baabe12 100644
--- a/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/HomeAppIcon.java
@@ -115,7 +115,7 @@
                      String.format("want to drag the icon to cell(%d, %d)", cellX, cellY))
         ) {
             final Supplier<Point> dest = () -> Workspace.getCellCenter(mLauncher, cellX, cellY);
-            Workspace.dragIconToWorkspace(mLauncher, this, dest, true, getLongPressIndicator(),
+            Workspace.dragIconToWorkspace(mLauncher, this, dest, getLongPressIndicator(),
                     () -> addExpectedEventsForLongClick(), null);
             try (LauncherInstrumentation.Closable ignore = mLauncher.addContextLayer("dragged")) {
                 WorkspaceAppIcon appIcon =
diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java
index 02a6b91..a28eac6 100644
--- a/tests/tapl/com/android/launcher3/tapl/Launchable.java
+++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java
@@ -139,7 +139,7 @@
         mLauncher.waitForLauncherObject(longPressIndicator);
         LauncherInstrumentation.log("movePointerForStartDrag: indicator");
         mLauncher.movePointer(iconCenter, dragStartCenter, DEFAULT_DRAG_STEPS, false,
-                downTime, true, LauncherInstrumentation.GestureScope.INSIDE);
+                downTime, downTime, true, LauncherInstrumentation.GestureScope.INSIDE);
     }
 
     private int getStartDragThreshold() {
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index f063191..bbfbc55 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -1107,11 +1107,13 @@
         }
     }
 
-    @NonNull UiObject2 waitForObjectInContainer(UiObject2 container, BySelector selector) {
+    @NonNull
+    UiObject2 waitForObjectInContainer(UiObject2 container, BySelector selector) {
         return waitForObjectsInContainer(container, selector).get(0);
     }
 
-    @NonNull List<UiObject2> waitForObjectsInContainer(
+    @NonNull
+    List<UiObject2> waitForObjectsInContainer(
             UiObject2 container, BySelector selector) {
         try {
             final List<UiObject2> objects = container.wait(
@@ -1406,13 +1408,13 @@
         final Point end = new Point(endX, endY);
         sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope);
         final long endTime = movePointer(
-                start, end, steps, false, downTime, slowDown, gestureScope);
+                start, end, steps, false, downTime, downTime, slowDown, gestureScope);
         sendPointer(downTime, endTime, MotionEvent.ACTION_UP, end, gestureScope);
     }
 
-    long movePointer(Point start, Point end, int steps, boolean isDecelerating,
-            long downTime, boolean slowDown, GestureScope gestureScope) {
-        long endTime = movePointer(downTime, downTime, steps * GESTURE_STEP_MS,
+    long movePointer(Point start, Point end, int steps, boolean isDecelerating, long downTime,
+            long startTime, boolean slowDown, GestureScope gestureScope) {
+        long endTime = movePointer(downTime, startTime, steps * GESTURE_STEP_MS,
                 isDecelerating, start, end, gestureScope);
         if (slowDown) {
             endTime = movePointer(downTime, endTime + GESTURE_STEP_MS, 5 * GESTURE_STEP_MS, end,
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 4f4ce30..3bc5389 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -178,10 +178,10 @@
      * pageDelta: 3, the latest page that can be created is 2) the icon will be dragged onto the
      * page that can be created and is closest to the target page.
      *
-     * @param homeAppIcon   - icon to drag.
-     * @param pageDelta - how many pages should the icon be dragged from the current page.
-     *                  It can be a negative value. currentPage + pageDelta should be greater
-     *                  than or equal to 0.
+     * @param homeAppIcon - icon to drag.
+     * @param pageDelta   - how many pages should the icon be dragged from the current page.
+     *                    It can be a negative value. currentPage + pageDelta should be greater
+     *                    than or equal to 0.
      */
     public void dragIcon(HomeAppIcon homeAppIcon, int pageDelta) {
         if (mHotseat.getVisibleBounds().height() > mHotseat.getVisibleBounds().width()) {
@@ -246,7 +246,6 @@
             dragIconToWorkspace(
                     mLauncher, homeAppIcon,
                     () -> getDropPointFromDropTargetBar(mLauncher, DELETE_TARGET_TEXT_ID),
-                    true, /* decelerating */
                     homeAppIcon.getLongPressIndicator(),
                     () -> mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT),
                     null);
@@ -261,8 +260,9 @@
     /**
      * Uninstall the appIcon by dragging it to the 'uninstall' drop point of the drop_target_bar.
      *
-     * @param launcher the root TAPL instrumentation object of {@link LauncherInstrumentation} type.
-     * @param homeAppIcon to be uninstalled.
+     * @param launcher              the root TAPL instrumentation object of {@link
+     *                              LauncherInstrumentation} type.
+     * @param homeAppIcon           to be uninstalled.
      * @param launcher              the root TAPL instrumentation object of {@link
      *                              LauncherInstrumentation} type.
      * @param homeAppIcon           to be uninstalled.
@@ -276,7 +276,6 @@
             dragIconToWorkspace(
                     launcher, homeAppIcon,
                     () -> getDropPointFromDropTargetBar(launcher, UNINSTALL_TARGET_TEXT_ID),
-                    true, /* decelerating */
                     homeAppIcon.getLongPressIndicator(),
                     expectLongClickEvents,
                     null);
@@ -353,23 +352,24 @@
             expectDropEvents = () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN,
                     LauncherInstrumentation.EVENT_START);
         }
-        dragIconToWorkspace(launcher, launchable, () -> dest, false, longPressIndicator,
+        dragIconToWorkspace(launcher, launchable, () -> dest, longPressIndicator,
                 expectLongClickEvents, expectDropEvents);
     }
 
     /**
-     * Drag icon in workspace to else where.
+     * Drag icon in workspace to else where and drop it immediately.
+     * (There is no slow down time before drop event)
      * This function expects the launchable is inside the workspace and there is no drop event.
      */
     static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable,
             Supplier<Point> destSupplier, String longPressIndicator) {
-        dragIconToWorkspace(launcher, launchable, destSupplier, false, longPressIndicator,
+        dragIconToWorkspace(launcher, launchable, destSupplier, longPressIndicator,
                 () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT), null);
     }
 
     static void dragIconToWorkspace(
             LauncherInstrumentation launcher, Launchable launchable, Supplier<Point> dest,
-            boolean isDecelerating, String longPressIndicator, Runnable expectLongClickEvents,
+            String longPressIndicator, Runnable expectLongClickEvents,
             @Nullable Runnable expectDropEvents) {
         try (LauncherInstrumentation.Closable ignored = launcher.addContextLayer(
                 "want to drag icon to workspace")) {
@@ -391,7 +391,7 @@
                 Point finalDragStart = dragStart;
                 executeAndWaitForPageScroll(launcher,
                         () -> launcher.movePointer(finalDragStart, screenEdge, DEFAULT_DRAG_STEPS,
-                                isDecelerating, downTime, true,
+                                true, downTime, downTime, true,
                                 LauncherInstrumentation.GestureScope.INSIDE));
                 targetDest.x += displayX * (targetDest.x > 0 ? -1 : 1);
                 dragStart = screenEdge;
@@ -399,8 +399,9 @@
 
             // targetDest.x is now between 0 and displayX so we found the target page,
             // we just have to put move the icon to the destination and drop it
-            launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, isDecelerating,
-                    downTime, true, LauncherInstrumentation.GestureScope.INSIDE);
+            launcher.movePointer(dragStart, targetDest, DEFAULT_DRAG_STEPS, true,
+                    downTime, SystemClock.uptimeMillis(), false,
+                    LauncherInstrumentation.GestureScope.INSIDE);
             dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
         }
     }
@@ -488,4 +489,4 @@
             return widget != null ? new Widget(mLauncher, widget) : null;
         }
     }
-}
\ No newline at end of file
+}