Merge "Import translations. DO NOT MERGE ANYWHERE" into sc-dev
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 046b3a0..0a82e04 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -74,14 +74,10 @@
     <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Probeer weer"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Mooi so!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutoriaal <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <!-- no translation found for allset_title (5021126669778966707) -->
-    <skip />
-    <!-- no translation found for allset_hint (459504134589971527) -->
-    <skip />
-    <!-- no translation found for allset_description (6350320429953234580) -->
-    <skip />
-    <!-- no translation found for allset_navigation_settings (417773244979225071) -->
-    <skip />
+    <string name="allset_title" msgid="5021126669778966707">"Gereed!"</string>
+    <string name="allset_hint" msgid="459504134589971527">"Swiep op om na die tuisskerm toe te gaan"</string>
+    <string name="allset_description" msgid="6350320429953234580">"Jy is gereed om jou foon te begin gebruik"</string>
+    <string name="allset_navigation_settings" msgid="417773244979225071"><annotation id="link">"Navigasie-instellings vir toeganklikheid"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Deel"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Skermkiekie"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Jou organisasie laat nie hierdie program toe nie"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 048ced1..f4519b8 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -74,14 +74,10 @@
     <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Prøv igen"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Sådan!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Selvstudie <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <!-- no translation found for allset_title (5021126669778966707) -->
-    <skip />
-    <!-- no translation found for allset_hint (459504134589971527) -->
-    <skip />
-    <!-- no translation found for allset_description (6350320429953234580) -->
-    <skip />
-    <!-- no translation found for allset_navigation_settings (417773244979225071) -->
-    <skip />
+    <string name="allset_title" msgid="5021126669778966707">"Alt er parat!"</string>
+    <string name="allset_hint" msgid="459504134589971527">"Stryg opad for at gå til startsiden"</string>
+    <string name="allset_description" msgid="6350320429953234580">"Du er klar til at bruge din telefon"</string>
+    <string name="allset_navigation_settings" msgid="417773244979225071"><annotation id="link">"Navigationsindstillinger for hjælpefunktioner"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Del"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller din organisation tillader ikke denne handling"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 2cb0429..10f4479 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -74,14 +74,10 @@
     <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Reintentar"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"¡Genial!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Instructivo <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <!-- no translation found for allset_title (5021126669778966707) -->
-    <skip />
-    <!-- no translation found for allset_hint (459504134589971527) -->
-    <skip />
-    <!-- no translation found for allset_description (6350320429953234580) -->
-    <skip />
-    <!-- no translation found for allset_navigation_settings (417773244979225071) -->
-    <skip />
+    <string name="allset_title" msgid="5021126669778966707">"Todo listo"</string>
+    <string name="allset_hint" msgid="459504134589971527">"Desliza el dedo hacia arriba para ir a la página principal"</string>
+    <string name="allset_description" msgid="6350320429953234580">"Ya puedes empezar a usar tu teléfono"</string>
+    <string name="allset_navigation_settings" msgid="417773244979225071"><annotation id="link">"Configuración de la navegación para accesibilidad"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Compartir"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"La app o tu organización no permiten realizar esta acción"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index f0bdc4f..bd8f3b8 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -74,14 +74,10 @@
     <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>
-    <!-- no translation found for allset_title (5021126669778966707) -->
-    <skip />
-    <!-- no translation found for allset_hint (459504134589971527) -->
-    <skip />
-    <!-- no translation found for allset_description (6350320429953234580) -->
-    <skip />
-    <!-- no translation found for allset_navigation_settings (417773244979225071) -->
-    <skip />
+    <string name="allset_title" msgid="5021126669778966707">"همه چیز آماده است!"</string>
+    <string name="allset_hint" msgid="459504134589971527">"برای رفتن به صفحه اصلی، تند به‌بالا بکشید"</string>
+    <string name="allset_description" msgid="6350320429953234580">"آماده‌اید از تلفنتان استفاده کنید"</string>
+    <string name="allset_navigation_settings" msgid="417773244979225071"><annotation id="link">"تنظیمات پیمایش برای دسترس‌پذیری"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"هم‌رسانی"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"نماگرفت"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"برنامه یا سازمان شما اجازه نمی‌دهد این کنش انجام شود."</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 1c5f893..3cf37b4 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -74,14 +74,10 @@
     <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>
-    <!-- no translation found for allset_title (5021126669778966707) -->
-    <skip />
-    <!-- no translation found for allset_hint (459504134589971527) -->
-    <skip />
-    <!-- no translation found for allset_description (6350320429953234580) -->
-    <skip />
-    <!-- no translation found for allset_navigation_settings (417773244979225071) -->
-    <skip />
+    <string name="allset_title" msgid="5021126669778966707">"ಎಲ್ಲವೂ ಸಿದ್ಧವಾಗಿದೆ!"</string>
+    <string name="allset_hint" msgid="459504134589971527">"ಮುಖಪುಟಕ್ಕೆ ಹೋಗಲು ಮೇಲೆ ಸ್ವೈಪ್ ಮಾಡಿ"</string>
+    <string name="allset_description" msgid="6350320429953234580">"ನಿಮ್ಮ ಫೋನ್ ಬಳಸುವುದನ್ನು ಪ್ರಾರಂಭಿಸಲು ನೀವು ಸಿದ್ದರಾಗಿರುವಿರಿ"</string>
+    <string name="allset_navigation_settings" msgid="417773244979225071"><annotation id="link">"ಅಕ್ಸೆಸಿಬಿಲಿಟಿಗಾಗಿ ನ್ಯಾವಿಗೇಶನ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"ಆ್ಯಪ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಕ್ರಿಯೆಯನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 1f53ad4..d80e6b3 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -74,14 +74,10 @@
     <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Cuba lagi"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Bagus!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <!-- no translation found for allset_title (5021126669778966707) -->
-    <skip />
-    <!-- no translation found for allset_hint (459504134589971527) -->
-    <skip />
-    <!-- no translation found for allset_description (6350320429953234580) -->
-    <skip />
-    <!-- no translation found for allset_navigation_settings (417773244979225071) -->
-    <skip />
+    <string name="allset_title" msgid="5021126669778966707">"Siap!"</string>
+    <string name="allset_hint" msgid="459504134589971527">"Leret ke atas untuk mencapai laman utama"</string>
+    <string name="allset_description" msgid="6350320429953234580">"Anda sudah sedia untuk mula menggunakan telefon anda"</string>
+    <string name="allset_navigation_settings" msgid="417773244979225071"><annotation id="link">"Tetapan navigasi untuk kebolehaksesan"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Kongsi"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Tangkapan skrin"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak dibenarkan oleh apl atau organisasi anda"</string>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 49daf19..ebf8485 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -74,14 +74,10 @@
     <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Opnieuw"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Dat gaat lekker."</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <!-- no translation found for allset_title (5021126669778966707) -->
-    <skip />
-    <!-- no translation found for allset_hint (459504134589971527) -->
-    <skip />
-    <!-- no translation found for allset_description (6350320429953234580) -->
-    <skip />
-    <!-- no translation found for allset_navigation_settings (417773244979225071) -->
-    <skip />
+    <string name="allset_title" msgid="5021126669778966707">"Klaar!"</string>
+    <string name="allset_hint" msgid="459504134589971527">"Swipe omhoog om naar het startscherm te gaan"</string>
+    <string name="allset_description" msgid="6350320429953234580">"Je bent klaar om je telefoon te gebruiken"</string>
+    <string name="allset_navigation_settings" msgid="417773244979225071"><annotation id="link">"Navigatie-instellingen voor toegankelijkheid"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Delen"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Deze actie wordt niet toegestaan door de app of je organisatie"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 1b5a81d..e01dc08 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -74,14 +74,10 @@
     <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Spróbuj ponownie"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Super!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Samouczek <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <!-- no translation found for allset_title (5021126669778966707) -->
-    <skip />
-    <!-- no translation found for allset_hint (459504134589971527) -->
-    <skip />
-    <!-- no translation found for allset_description (6350320429953234580) -->
-    <skip />
-    <!-- no translation found for allset_navigation_settings (417773244979225071) -->
-    <skip />
+    <string name="allset_title" msgid="5021126669778966707">"Wszystko gotowe"</string>
+    <string name="allset_hint" msgid="459504134589971527">"Aby przejść na stronę główną, przesuń w górę"</string>
+    <string name="allset_description" msgid="6350320429953234580">"Teraz możesz zacząć używać telefonu"</string>
+    <string name="allset_navigation_settings" msgid="417773244979225071"><annotation id="link">"Ustawienia nawigacji na potrzeby ułatwień dostępu"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Udostępnij"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Zrzut ekranu"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Nie możesz wykonać tego działania, bo nie zezwala na to aplikacja lub Twoja organizacja"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index c254986..704afb6 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -74,14 +74,10 @@
     <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Tentar novamente"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Muito bem!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <!-- no translation found for allset_title (5021126669778966707) -->
-    <skip />
-    <!-- no translation found for allset_hint (459504134589971527) -->
-    <skip />
-    <!-- no translation found for allset_description (6350320429953234580) -->
-    <skip />
-    <!-- no translation found for allset_navigation_settings (417773244979225071) -->
-    <skip />
+    <string name="allset_title" msgid="5021126669778966707">"Tudo pronto!"</string>
+    <string name="allset_hint" msgid="459504134589971527">"Deslize para cima para acessar a tela inicial"</string>
+    <string name="allset_description" msgid="6350320429953234580">"Você já pode começar a usar seu smartphone"</string>
+    <string name="allset_navigation_settings" msgid="417773244979225071"><annotation id="link">"Configurações de navegação para acessibilidade"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Compartilhar"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Capturar tela"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Essa ação não é permitida pelo app ou pela organização"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 810b909..56f0616 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -74,14 +74,10 @@
     <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Skúste to znova"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Výborne!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Návod <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <!-- no translation found for allset_title (5021126669778966707) -->
-    <skip />
-    <!-- no translation found for allset_hint (459504134589971527) -->
-    <skip />
-    <!-- no translation found for allset_description (6350320429953234580) -->
-    <skip />
-    <!-- no translation found for allset_navigation_settings (417773244979225071) -->
-    <skip />
+    <string name="allset_title" msgid="5021126669778966707">"Hotovo"</string>
+    <string name="allset_hint" msgid="459504134589971527">"Potiahnutím nahor prejdete na plochu"</string>
+    <string name="allset_description" msgid="6350320429953234580">"Telefón môžete začať používať"</string>
+    <string name="allset_navigation_settings" msgid="417773244979225071"><annotation id="link">"Nastavenia navigácie pre dostupnosť"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Zdieľať"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Snímka obrazovky"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Aplikácia alebo vaša organizácia túto akciu nepovoľuje"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index a171650..7f61e7d 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -74,14 +74,10 @@
     <string name="gesture_tutorial_try_again" msgid="65962545858556697">"Zama futhi"</string>
     <string name="gesture_tutorial_nice" msgid="2936275692616928280">"Kuhle!"</string>
     <string name="gesture_tutorial_step" msgid="1279786122817620968">"Okokufundisa <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string>
-    <!-- no translation found for allset_title (5021126669778966707) -->
-    <skip />
-    <!-- no translation found for allset_hint (459504134589971527) -->
-    <skip />
-    <!-- no translation found for allset_description (6350320429953234580) -->
-    <skip />
-    <!-- no translation found for allset_navigation_settings (417773244979225071) -->
-    <skip />
+    <string name="allset_title" msgid="5021126669778966707">"Konke kusethiwe!"</string>
+    <string name="allset_hint" msgid="459504134589971527">"Swayiphela phezulu ukuze uye ekhaya"</string>
+    <string name="allset_description" msgid="6350320429953234580">"Usulungele ukuqala ukusebenzisa ifoni yakho"</string>
+    <string name="allset_navigation_settings" msgid="417773244979225071"><annotation id="link">"Amasethingi wokufinyelela ukuzulazula"</annotation></string>
     <string name="action_share" msgid="2648470652637092375">"Yabelana"</string>
     <string name="action_screenshot" msgid="8171125848358142917">"Isithombe-skrini"</string>
     <string name="blocked_by_policy" msgid="2071401072261365546">"Lesi senzo asivunyelwanga uhlelo lokusebenza noma inhlangano yakho"</string>
diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
index 2aac877..6966fb6 100644
--- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java
@@ -23,6 +23,7 @@
 import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
 import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
 import static com.android.quickstep.SysUINavigationMode.Mode.TWO_BUTTONS;
+import static com.android.quickstep.util.NavigationModeFeatureFlag.LIVE_TILE;
 import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
 
 import android.animation.AnimatorSet;
@@ -190,6 +191,15 @@
     }
 
     @Override
+    protected void onScreenOff() {
+        super.onScreenOff();
+        if (LIVE_TILE.get()) {
+            RecentsView recentsView = getOverviewPanel();
+            recentsView.finishRecentsAnimation(true /* toRecents */, null);
+        }
+    }
+
+    @Override
     public void startIntentSenderForResult(IntentSender intent, int requestCode,
             Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags, Bundle options) {
         if (requestCode != -1) {
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 14382d6..1b54211 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -491,7 +491,7 @@
             List<View> viewsToAnimate = new ArrayList<>();
 
             Workspace workspace = mLauncher.getWorkspace();
-            workspace.getVisiblePages().forEach(
+            workspace.forEachVisiblePage(
                     view -> viewsToAnimate.add(((CellLayout) view).getShortcutsAndWidgets()));
 
             viewsToAnimate.add(mLauncher.getHotseat());
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 5513c16..3af51d5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -16,12 +16,24 @@
 package com.android.launcher3.taskbar;
 
 import android.content.ContextWrapper;
+import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.view.LayoutInflater;
+import android.view.View;
+
+import androidx.annotation.Nullable;
 
 import com.android.launcher3.BaseQuickstepLauncher;
 import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget;
 import com.android.launcher3.R;
+import com.android.launcher3.dragndrop.DragController;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.dragndrop.DraggableView;
+import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.views.BaseDragLayer;
 
@@ -35,6 +47,7 @@
     private final DeviceProfile mDeviceProfile;
     private final LayoutInflater mLayoutInflater;
     private final TaskbarContainerView mTaskbarContainerView;
+    private final MyDragController mDragController;
 
     public TaskbarActivityContext(BaseQuickstepLauncher launcher) {
         super(launcher);
@@ -47,6 +60,7 @@
 
         mTaskbarContainerView = (TaskbarContainerView) mLayoutInflater
                 .inflate(R.layout.taskbar, null, false);
+        mDragController = new MyDragController(this);
     }
 
     public TaskbarContainerView getTaskbarContainerView() {
@@ -72,4 +86,31 @@
     public Rect getFolderBoundingBox() {
         return mTaskbarContainerView.getFolderBoundingBox();
     }
+
+    @Override
+    public DragController getDragController() {
+        return mDragController;
+    }
+
+    private static class MyDragController extends DragController<TaskbarActivityContext> {
+        MyDragController(TaskbarActivityContext activity) {
+            super(activity);
+        }
+
+        @Override
+        protected DragView startDrag(@Nullable Drawable drawable, @Nullable View view,
+                DraggableView originalView, int dragLayerX, int dragLayerY, DragSource source,
+                ItemInfo dragInfo, Point dragOffset, Rect dragRegion, float initialDragViewScale,
+                float dragViewScaleOnDrop, DragOptions options) {
+            return null;
+        }
+
+        @Override
+        protected void exitDrag() { }
+
+        @Override
+        protected DropTarget getDefaultDropTarget(int[] dropCoordinates) {
+            return null;
+        }
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
index b0d0b15..e2747df 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java
@@ -78,18 +78,9 @@
             return true;
         }
         if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.TWO_BUTTON_NORMAL_NOT_OVERVIEW,
-                        "Didn't intercept touch due to top view: "
-                                + AbstractFloatingView.getTopOpenView(mLauncher));
-            }
             return false;
         }
         if ((ev.getEdgeFlags() & EDGE_NAV_BAR) == 0) {
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.TWO_BUTTON_NORMAL_NOT_OVERVIEW,
-                        "Didn't intercept touch because event wasn't from nav bar");
-            }
             return false;
         }
         if (!mIsTransposed && mLauncher.isInState(OVERVIEW)) {
@@ -101,10 +92,6 @@
     @Override
     public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
         boolean intercept = super.onControllerInterceptTouchEvent(ev);
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.TWO_BUTTON_NORMAL_NOT_OVERVIEW,
-                    "2 button touch controller intercept touch? " + intercept);
-        }
         return intercept;
     }
 
@@ -123,10 +110,6 @@
     @Override
     protected void onReinitToState(LauncherState newToState) {
         super.onReinitToState(newToState);
-
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.TWO_BUTTON_NORMAL_NOT_OVERVIEW, "onReinitToState: " + newToState);
-        }
     }
 
     @Override
@@ -175,9 +158,6 @@
     @Override
     protected void onSwipeInteractionCompleted(LauncherState targetState) {
         super.onSwipeInteractionCompleted(targetState);
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.TWO_BUTTON_NORMAL_NOT_OVERVIEW, "Reached state: " + targetState);
-        }
         if (!mIsTransposed) {
             mContinuousTouchCount++;
         }
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index fe10908..25be30f 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1211,6 +1211,7 @@
                 TaskInfoCompat.getWindowConfigurationBounds(taskInfo),
                 startBounds,
                 destinationBounds,
+                mRecentsView.getPipCornerRadius(),
                 mRecentsView);
         // We would assume home and app window always in the same rotation While homeRotation
         // is not ROTATION_0 (which implies the rotation is turned on in launcher settings).
diff --git a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
index 62b821c..35a851a 100644
--- a/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/OrientationTouchTransformer.java
@@ -35,7 +35,6 @@
 
 import com.android.launcher3.R;
 import com.android.launcher3.ResourceUtils;
-import com.android.launcher3.testing.TestProtocol;
 import com.android.launcher3.util.DisplayController.Info;
 
 import java.io.PrintWriter;
@@ -92,7 +91,7 @@
     };
 
     private static final String TAG = "OrientationTouchTransformer";
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
 
     private static final int QUICKSTEP_ROTATION_UNINITIALIZED = -1;
 
@@ -161,11 +160,9 @@
         resetSwipeRegions(info);
     }
 
-    void setNavigationMode(SysUINavigationMode.Mode newMode, Info info,
-            Resources newRes) {
+    void setNavigationMode(SysUINavigationMode.Mode newMode, Info info, Resources newRes) {
         if (DEBUG) {
-            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "setNavigationMode new: " + newMode
-                    + " oldMode: " + mMode + " " + this);
+            Log.d(TAG, "setNavigationMode new: " + newMode + " oldMode: " + mMode + " " + this);
         }
         if (mMode == newMode) {
             return;
@@ -258,18 +255,10 @@
 
         mCurrentDisplay = new CurrentDisplay(region.currentSize, region.rotation);
         OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCurrentDisplay);
-        if (DEBUG) {
-            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "cached region: " + regionToKeep
-                    + " mCurrentDisplay: " + mCurrentDisplay + " " + this);
-        }
         if (regionToKeep == null) {
             regionToKeep = createRegionForDisplay(region);
         }
         mSwipeTouchRegions.clear();
-        if (DEBUG) {
-            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "adding region: " + regionToKeep
-                    + " mCurrentDisplay: " + mCurrentDisplay + " " + this);
-        }
         mSwipeTouchRegions.put(mCurrentDisplay, regionToKeep);
         updateAssistantRegions(regionToKeep);
     }
@@ -301,10 +290,6 @@
             mAssistantLeftRegion.setEmpty();
             mAssistantRightRegion.setEmpty();
             int navbarSize = getNavbarSize(ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE);
-            if (DEBUG) {
-                Log.d(TestProtocol.NO_SWIPE_TO_HOME, "else case mode: " + mMode
-                        + " getNavbarSize: " + navbarSize + " rotation: " + rotation + " " + this);
-            }
             switch (rotation) {
                 case Surface.ROTATION_90:
                     orientationRectF.left = orientationRectF.right
@@ -355,8 +340,8 @@
     }
 
     boolean touchInValidSwipeRegions(float x, float y) {
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "touchInValidSwipeRegions " + x + "," + y + " in "
+        if (DEBUG) {
+            Log.d(TAG, "touchInValidSwipeRegions " + x + "," + y + " in "
                     + mLastRectTouched + " this: " + this);
         }
         if (mLastRectTouched != null) {
@@ -399,16 +384,10 @@
                 }
 
                 for (OrientationRectF rect : mSwipeTouchRegions.values()) {
-                    if (TestProtocol.sDebugTracing) {
-                        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "transform:DOWN, rect=" + rect);
-                    }
                     if (rect == null) {
                         continue;
                     }
                     if (rect.applyTransform(event, false)) {
-                        if (TestProtocol.sDebugTracing) {
-                            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "setting mLastRectTouched");
-                        }
                         mLastRectTouched = rect;
                         mActiveTouchRotation = rect.mRotation;
                         if (mEnableMultipleRegions
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 2f1538b..3302da0 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -93,10 +93,6 @@
      * @return The change id of the current task list
      */
     public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<Task>> callback) {
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.GET_RECENTS_FAILED, "getTasks: keysOnly=" + loadKeysOnly
-                    + " callback=" + callback);
-        }
         final int requestLoadId = mChangeId;
         if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) {
             // The list is up to date, send the callback on the next frame,
@@ -105,9 +101,6 @@
                 // Copy synchronously as the changeId might change by next frame
                 ArrayList<Task> result = copyOf(mResultsUi);
                 mMainThreadExecutor.post(() -> {
-                    if (TestProtocol.sDebugTracing) {
-                        Log.d(TestProtocol.GET_RECENTS_FAILED, "getTasks: no new tasks");
-                    }
                     callback.accept(result);
                 });
             }
@@ -118,24 +111,15 @@
         // Kick off task loading in the background
         mLoadingTasksInBackground = true;
         UI_HELPER_EXECUTOR.execute(() -> {
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.GET_RECENTS_FAILED, "getTasks: loading in bg start");
-            }
             if (!mResultsBg.isValidForRequest(requestLoadId, loadKeysOnly)) {
                 mResultsBg = loadTasksInBackground(Integer.MAX_VALUE, requestLoadId, loadKeysOnly);
             }
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.GET_RECENTS_FAILED, "getTasks: loading in bg end");
-            }
             TaskLoadResult loadResult = mResultsBg;
             mMainThreadExecutor.execute(() -> {
                 mLoadingTasksInBackground = false;
                 mResultsUi = loadResult;
                 if (callback != null) {
                     ArrayList<Task> result = copyOf(mResultsUi);
-                    if (TestProtocol.sDebugTracing) {
-                        Log.d(TestProtocol.GET_RECENTS_FAILED, "getTasks: callback w/ bg results");
-                    }
                     callback.accept(result);
                 }
             });
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index e271203..110b356 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -229,7 +229,6 @@
      * Cleans up all the registered listeners and receivers.
      */
     public void destroy() {
-        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "destroying RADS", new Throwable());
         for (Runnable r : mOnDestroyActions) {
             r.run();
         }
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index 7629862..070d725 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -133,8 +133,6 @@
 
     private RotationTouchHelper(Context context) {
         mContext = context;
-        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "RotationTouchHelper ctor init? " + mNeedsInit
-                + " " + this);
         if (mNeedsInit) {
             init();
         }
@@ -142,11 +140,8 @@
 
     public void init() {
         if (!mNeedsInit) {
-            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "Did not need init? " + " " + this);
             return;
         }
-        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "RotationTouchHelper init() " + this,
-                new Throwable());
         mDisplayController = DisplayController.INSTANCE.get(mContext);
         Resources resources = mContext.getResources();
         mSysUiNavMode = SysUINavigationMode.INSTANCE.get(mContext);
@@ -157,8 +152,6 @@
 
         // Register for navigation mode changes
         SysUINavigationMode.Mode newMode = mSysUiNavMode.addModeChangeListener(this);
-        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "AddedModeChangeListener: " + this +
-                " currentMode: " + newMode);
         onNavigationModeChanged(newMode);
         runOnDestroy(() -> mSysUiNavMode.removeModeChangeListener(this));
 
@@ -204,7 +197,6 @@
      * Cleans up all the registered listeners and receivers.
      */
     public void destroy() {
-        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "destroying " + this);
         for (Runnable r : mOnDestroyActions) {
             r.run();
         }
@@ -253,7 +245,6 @@
 
     @Override
     public void onNavigationModeChanged(SysUINavigationMode.Mode newMode) {
-        Log.d(TestProtocol.NO_SWIPE_TO_HOME, "nav mode changed: " + newMode);
         mDisplayController.removeChangeListener(this);
         mDisplayController.addChangeListener(this);
         onDisplayInfoChanged(mContext, mDisplayController.getInfo(), CHANGE_ALL);
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index f6018d1..39d8888 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -68,6 +68,12 @@
         MAIN_EXECUTOR.execute(() -> clearProxy());
     };
 
+    // Save the listeners passed into the proxy since when set/register these listeners,
+    // setProxy may not have been called, eg. OverviewProxyService is not connected yet.
+    private IPipAnimationListener mPendingPipAnimationListener;
+    private ISplitScreenListener mPendingSplitScreenListener;
+    private IStartingWindowListener mPendingStartingWindowListener;
+
     // Used to dedupe calls to SystemUI
     private int mLastShelfHeight;
     private boolean mLastShelfVisible;
@@ -116,6 +122,19 @@
         mShellTransitions = shellTransitions;
         mStartingWindow = startingWindow;
         linkToDeath();
+        // re-attach the listeners once missing due to setProxy has not been initialized yet.
+        if (mPendingPipAnimationListener != null && mPip != null) {
+            setPinnedStackAnimationListener(mPendingPipAnimationListener);
+            mPendingPipAnimationListener = null;
+        }
+        if (mPendingSplitScreenListener != null && mSplitScreen != null) {
+            registerSplitScreenListener(mPendingSplitScreenListener);
+            mPendingSplitScreenListener = null;
+        }
+        if (mPendingStartingWindowListener != null && mStartingWindow != null) {
+            setStartingWindowListener(mPendingStartingWindowListener);
+            mPendingStartingWindowListener = null;
+        }
     }
 
     public void clearProxy() {
@@ -390,6 +409,8 @@
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed call setPinnedStackAnimationListener", e);
             }
+        } else {
+            mPendingPipAnimationListener = listener;
         }
     }
 
@@ -427,6 +448,8 @@
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed call registerSplitScreenListener");
             }
+        } else {
+            mPendingSplitScreenListener = listener;
         }
     }
 
@@ -438,6 +461,7 @@
                 Log.w(TAG, "Failed call unregisterSplitScreenListener");
             }
         }
+        mPendingSplitScreenListener = null;
     }
 
     public void setSideStageVisibility(boolean visible) {
@@ -590,6 +614,8 @@
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed call setStartingWindowListener", e);
             }
+        } else {
+            mPendingStartingWindowListener = listener;
         }
     }
 }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 5fe0fc7..027dd1c 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -165,8 +165,6 @@
 
         @BinderThread
         public void onInitialize(Bundle bundle) {
-            Log.d(TAG + " b/182478748", "TouchInteractionService.onInitialize: user="
-                    + getUserId());
             ISystemUiProxy proxy = ISystemUiProxy.Stub.asInterface(
                     bundle.getBinder(KEY_EXTRA_SYSUI_PROXY));
             IPip pip = IPip.Stub.asInterface(bundle.getBinder(KEY_EXTRA_SHELL_PIP));
@@ -350,8 +348,6 @@
         mMainChoreographer = Choreographer.getInstance();
         mAM = ActivityManagerWrapper.getInstance();
         mDeviceState = new RecentsAnimationDeviceState(this, true);
-            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "RADS OTT instance: " +
-                    mDeviceState.getRotationTouchHelper().getOrientationTouchTransformer());
         mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
         mDeviceState.addNavigationModeChangedCallback(this::onNavigationModeChanged);
         mDeviceState.addOneHandedModeChangedCallback(this::onOneHandedModeOverlayChanged);
@@ -363,8 +359,6 @@
     }
 
     private void disposeEventHandlers() {
-        Log.d(TAG + " b/182478748", "TouchInteractionService.disposeEventHandlers: user="
-                + getUserId());
         if (mInputEventReceiver != null) {
             mInputEventReceiver.dispose();
             mInputEventReceiver = null;
@@ -376,21 +370,12 @@
     }
 
     private void initInputMonitor() {
-        Log.d(TAG + " b/182478748", "TouchInteractionService.initInputMonitor: user="
-                + getUserId());
         disposeEventHandlers();
 
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.TIS_NO_EVENTS, "initInputMonitor: isButtonMode? "
-                    + mDeviceState.isButtonNavMode());
-        }
-
         if (mDeviceState.isButtonNavMode()) {
-            Log.d(TAG + " b/182478748", "isButtonNav: user=" + getUserId());
             return;
         }
 
-        Log.d(TAG + " b/182478748", "create swipe-up input monitor: user=" + getUserId());
         mInputMonitorCompat = new InputMonitorCompat("swipe-up", mDeviceState.getDisplayId());
         mInputEventReceiver = mInputMonitorCompat.getInputReceiver(Looper.getMainLooper(),
                 mMainChoreographer, this::onInputEvent);
@@ -572,17 +557,10 @@
 
         final int action = event.getAction();
         if (action == ACTION_DOWN) {
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.NO_SWIPE_TO_HOME, "TouchInteractionService.onInputEvent:DOWN");
-            }
             mRotationTouchHelper.setOrientationTransformIfNeeded(event);
 
             if (!mDeviceState.isOneHandedModeActive()
                     && mRotationTouchHelper.isInSwipeUpTouchRegion(event)) {
-                if (TestProtocol.sDebugTracing) {
-                    Log.d(TestProtocol.NO_SWIPE_TO_HOME,
-                            "TouchInteractionService.onInputEvent:isInSwipeUpTouchRegion");
-                }
                 // Clone the previous gesture state since onConsumerAboutToBeSwitched might trigger
                 // onConsumerInactive and wipe the previous gesture state
                 GestureState prevGestureState = new GestureState(mGestureState);
@@ -678,9 +656,6 @@
 
     private InputConsumer newConsumer(GestureState previousGestureState,
             GestureState newGestureState, MotionEvent event) {
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "newConsumer");
-        }
         boolean canStartSystemGesture = mDeviceState.canStartSystemGesture();
 
         if (!mDeviceState.isUserUnlocked()) {
@@ -692,9 +667,6 @@
                 return mResetGestureInputConsumer;
             }
         }
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.NO_SWIPE_TO_HOME, "newConsumer:user is unlocked");
-        }
 
         // When there is an existing recents animation running, bypass systemState check as this is
         // a followup gesture and the first gesture started in a valid system state.
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 1bb8e96..ac3fb27 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -140,10 +140,6 @@
         // as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to
         // track the index of the next task appropriately, as if we are switching on any other app.
         if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == mRunningTaskId && !tasks.isEmpty()) {
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.GET_RECENTS_FAILED,
-                        "FallbackRecentsView.applyLoadPlan: running task is home");
-            }
             // Check if the task list has running task
             boolean found = false;
             for (Task t : tasks) {
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index ab95138..0ea1fca 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -89,8 +89,7 @@
         int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2);
 
         // Add animation for all the visible workspace pages
-        workspace.getVisiblePages()
-                .forEach(page -> addAnimationForPage((CellLayout) page, totalRows));
+        workspace.forEachVisiblePage(page -> addAnimationForPage((CellLayout) page, totalRows));
 
         boolean workspaceClipChildren = workspace.getClipChildren();
         boolean workspaceClipToPadding = workspace.getClipToPadding();
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index a1240e0..b5570a7 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -89,6 +89,7 @@
      *                    different from the appBounds if user has swiped a certain distance and
      *                    Launcher has performed transform on the leash.
      * @param destinationBounds Bounds of the destination this animator ends to
+     * @param cornerRadius Corner radius in pixel value for PiP window
      */
     public SwipePipToHomeAnimator(int taskId,
             @NonNull ComponentName componentName,
@@ -97,6 +98,7 @@
             @NonNull Rect appBounds,
             @NonNull Rect startBounds,
             @NonNull Rect destinationBounds,
+            int cornerRadius,
             @NonNull View view) {
         mTaskId = taskId;
         mComponentName = componentName;
@@ -106,7 +108,7 @@
         mDestinationBounds.set(destinationBounds);
         mDestinationBoundsTransformed.set(mDestinationBounds);
         mDestinationBoundsAnimation.set(mDestinationBounds);
-        mSurfaceTransactionHelper = new PipSurfaceTransactionHelper();
+        mSurfaceTransactionHelper = new PipSurfaceTransactionHelper(cornerRadius);
 
         if (sourceRectHint == null) {
             mSourceHintRectInsets = null;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 5958832..385612c 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -63,7 +63,9 @@
 import android.app.ActivityManager.RunningTaskInfo;
 import android.content.Context;
 import android.content.res.Configuration;
+import android.graphics.BlendMode;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Matrix;
 import android.graphics.Point;
 import android.graphics.PointF;
@@ -98,6 +100,7 @@
 
 import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
+import androidx.core.graphics.ColorUtils;
 
 import com.android.launcher3.BaseActivity;
 import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener;
@@ -244,6 +247,24 @@
             };
 
     /**
+     * Can be used to tint the color of the RecentsView to simulate a scrim that can views
+     * excluded from. Really should be a proper scrim.
+     * TODO(b/187528071): Remove this and replace with a real scrim.
+     */
+    private static final FloatProperty<RecentsView> COLOR_TINT =
+            new FloatProperty<RecentsView>("colorTint") {
+                @Override
+                public void setValue(RecentsView recentsView, float v) {
+                    recentsView.setColorTint(v);
+                }
+
+                @Override
+                public Float get(RecentsView recentsView) {
+                    return recentsView.getColorTint();
+                }
+            };
+
+    /**
      * Even though {@link TaskView} has distinct offsetTranslationX/Y and resistance property, they
      * are currently both used to apply secondary translation. Should their use cases change to be
      * more specific, we'd want to create a similar FloatProperty just for a TaskView's
@@ -404,6 +425,10 @@
     // The GestureEndTarget that is still in progress.
     protected GestureState.GestureEndTarget mCurrentGestureEndTarget;
 
+    // TODO(b/187528071): Remove these and replace with a real scrim.
+    private float mColorTint;
+    private final int mTintingColor;
+
     private int mOverScrollShift = 0;
 
     /**
@@ -469,6 +494,7 @@
 
     private final PinnedStackAnimationListener mIPipAnimationListener =
             new PinnedStackAnimationListener();
+    private int mPipCornerRadius;
 
     // Used to keep track of the last requested task list id, so that we do not request to load the
     // tasks again if we have already requested it and the task list has not changed
@@ -616,6 +642,8 @@
         mLiveTileTaskViewSimulator.recentsViewScale.value = 1;
         mLiveTileTaskViewSimulator.setOrientationState(mOrientationState);
         mLiveTileTaskViewSimulator.setDrawsBelowRecents(true);
+
+        mTintingColor = getForegroundScrimDimColor(context);
     }
 
     public OverScroller getScroller() {
@@ -768,7 +796,7 @@
         mSyncTransactionApplier = new SurfaceTransactionApplier(this);
         mLiveTileParams.setSyncTransactionApplier(mSyncTransactionApplier);
         RecentsModel.INSTANCE.get(getContext()).addThumbnailChangeListener(this);
-        mIPipAnimationListener.setActivity(mActivity);
+        mIPipAnimationListener.setActivityAndRecentsView(mActivity, this);
         SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(
                 mIPipAnimationListener);
         mOrientationState.initListeners();
@@ -788,7 +816,7 @@
         RecentsModel.INSTANCE.get(getContext()).removeThumbnailChangeListener(this);
         SystemUiProxy.INSTANCE.get(getContext()).setPinnedStackAnimationListener(null);
         SplitScreenBounds.INSTANCE.removeOnChangeListener(this);
-        mIPipAnimationListener.setActivity(null);
+        mIPipAnimationListener.setActivityAndRecentsView(null, null);
         mOrientationState.destroyListeners();
         mTaskOverlayFactory.removeListeners();
     }
@@ -1060,12 +1088,6 @@
     }
 
     protected void applyLoadPlan(ArrayList<Task> tasks) {
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.GET_RECENTS_FAILED, "applyLoadPlan: taskCount=" + tasks.size());
-            for (Task t : tasks) {
-                Log.d(TestProtocol.GET_RECENTS_FAILED, "\t" + t);
-            }
-        }
         if (mPendingAnimation != null) {
             mPendingAnimation.addEndListener(success -> applyLoadPlan(tasks));
             return;
@@ -1127,11 +1149,6 @@
         resetTaskVisuals();
         onTaskStackUpdated();
         updateEnabledOverlays();
-
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.GET_RECENTS_FAILED, "applyLoadPlan: taskViewCount="
-                    + getTaskViewCount());
-        }
     }
 
     private boolean isModal() {
@@ -1152,12 +1169,6 @@
     }
 
     public int getTaskViewCount() {
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.GET_RECENTS_FAILED, "getTaskViewCount:"
-                    + " numChildren=" + getChildCount()
-                    + " start=" + mTaskViewStartIndex
-                    + " clearAll=" + indexOfChild(mClearAllButton));
-        }
         int taskViewCount = getChildCount() - mTaskViewStartIndex;
         if (indexOfChild(mClearAllButton) != -1) {
             taskViewCount--;
@@ -1203,6 +1214,7 @@
         loadVisibleTaskData(TaskView.FLAG_UPDATE_ALL);
         setTaskModalness(0);
         updateVerticalPageOffsets();
+        setColorTint(0);
     }
 
     public void setFullscreenProgress(float fullscreenProgress) {
@@ -3678,9 +3690,34 @@
      * tasks to be dimmed while other elements in the recents view are left alone.
      */
     public void showForegroundScrim(boolean show) {
+        ObjectAnimator anim = ObjectAnimator.ofFloat(this, COLOR_TINT, show ? 0.5f : 0f);
+        anim.setAutoCancel(true);
+        anim.start();
+    }
+
+    /** Tint the RecentsView and TaskViews in to simulate a scrim. */
+    // TODO(b/187528071): Replace this tinting with a scrim on top of RecentsView
+    private void setColorTint(float tintAmount) {
+        mColorTint = tintAmount;
+
         for (int i = 0; i < getTaskViewCount(); i++) {
-            getTaskViewAt(i).showColorTint(show);
+            getTaskViewAt(i).setColorTint(mColorTint, mTintingColor);
         }
+
+        Drawable scrimBg = mActivity.getScrimView().getBackground();
+        if (scrimBg != null) {
+            if (tintAmount == 0f) {
+                scrimBg.setTintList(null);
+            } else {
+                scrimBg.setTintBlendMode(BlendMode.SRC_OVER);
+                scrimBg.setTint(
+                        ColorUtils.setAlphaComponent(mTintingColor, (int) (255 * tintAmount)));
+            }
+        }
+    }
+
+    private float getColorTint() {
+        return mColorTint;
     }
 
     private boolean showAsGrid() {
@@ -3724,6 +3761,14 @@
         mScrollListeners.remove(listener);
     }
 
+    /**
+     * @return Corner radius in pixel value for PiP window, which is updated via
+     *         {@link #mIPipAnimationListener}
+     */
+    public int getPipCornerRadius() {
+        return mPipCornerRadius;
+    }
+
     @Override
     protected void onScrollChanged(int l, int t, int oldl, int oldt) {
         super.onScrollChanged(l, t, oldl, oldt);
@@ -3740,9 +3785,11 @@
     private static class PinnedStackAnimationListener<T extends BaseActivity> extends
             IPipAnimationListener.Stub {
         private T mActivity;
+        private RecentsView mRecentsView;
 
-        public void setActivity(T activity) {
+        public void setActivityAndRecentsView(T activity, RecentsView recentsView) {
             mActivity = activity;
+            mRecentsView = recentsView;
         }
 
         @Override
@@ -3755,5 +3802,19 @@
                 }
             });
         }
+
+        @Override
+        public void onPipCornerRadiusChanged(int cornerRadius) {
+            if (mRecentsView != null) {
+                mRecentsView.mPipCornerRadius = cornerRadius;
+            }
+        }
+    }
+
+    /** Get the color used for foreground scrimming the RecentsView for sharing. */
+    public static int getForegroundScrimDimColor(Context context) {
+        int baseColor = Themes.getAttrColor(context, R.attr.overviewScrimColor);
+        // The Black blending is temporary until we have the proper color token.
+        return ColorUtils.blendARGB(Color.BLACK, baseColor, 0.25f);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 685f725..5b8d4ce 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -53,7 +53,6 @@
 import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
 import com.android.launcher3.util.MainThreadInitializedObject;
 import com.android.launcher3.util.SystemUiController;
-import com.android.launcher3.util.Themes;
 import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
 import com.android.quickstep.views.TaskView.FullscreenDrawParams;
 import com.android.systemui.plugins.OverviewScreenshotActions;
@@ -121,7 +120,7 @@
         // Initialize with placeholder value. It is overridden later by TaskView
         mFullscreenParams = TEMP_PARAMS.get(context);
 
-        mDimColor = Themes.getColorBackgroundFloating(context);
+        mDimColor = RecentsView.getForegroundScrimDimColor(context);
         mDimmingPaintAfterClearing.setColor(mDimColor);
     }
 
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 6f3aade..f8be5b6 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -32,7 +32,6 @@
 import static com.android.launcher3.Utilities.comp;
 import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
 import static com.android.launcher3.anim.Interpolators.ACCEL_DEACCEL;
-import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
 import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
@@ -65,6 +64,7 @@
 import android.view.ViewGroup;
 import android.view.ViewOutlineProvider;
 import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import android.widget.Toast;
 
@@ -88,7 +88,6 @@
 import com.android.launcher3.util.ComponentKey;
 import com.android.launcher3.util.RunnableList;
 import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
-import com.android.launcher3.util.Themes;
 import com.android.launcher3.util.TransformingTouchDelegate;
 import com.android.launcher3.util.ViewPool.Reusable;
 import com.android.quickstep.RecentsModel;
@@ -147,6 +146,9 @@
 
     public static final long SCALE_ICON_DURATION = 120;
     private static final long DIM_ANIM_DURATION = 700;
+
+    private static final Interpolator FULLSCREEN_INTERPOLATOR = ACCEL_DEACCEL;
+
     /**
      * This technically can be a vanilla {@link TouchDelegate} class, however that class requires
      * setting the touch bounds at construction, so we'd repeatedly be created many instances
@@ -328,19 +330,6 @@
                 }
             };
 
-    private static final FloatProperty<TaskView> COLOR_TINT =
-            new FloatProperty<TaskView>("colorTint") {
-                @Override
-                public void setValue(TaskView taskView, float v) {
-                    taskView.setColorTint(v);
-                }
-
-                @Override
-                public Float get(TaskView taskView) {
-                    return taskView.getColorTint();
-                }
-            };
-
     private final TaskOutlineProvider mOutlineProvider;
 
     private Task mTask;
@@ -393,11 +382,6 @@
     private final float[] mIconCenterCoords = new float[2];
     private final float[] mChipCenterCoords = new float[2];
 
-    // Colored tint for the task view and all its supplementary views (like the task icon and well
-    // being banner.
-    private final int mTintingColor;
-    private float mTintAmount;
-
     private boolean mIsClickableAsLiveTile = true;
 
     public TaskView(Context context) {
@@ -419,8 +403,6 @@
         mOutlineProvider = new TaskOutlineProvider(getContext(), mCurrentFullscreenParams,
                 mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx);
         setOutlineProvider(mOutlineProvider);
-
-        mTintingColor = Themes.getColorBackgroundFloating(context);
     }
 
     /**
@@ -864,7 +846,7 @@
         setTranslationZ(0);
         setAlpha(mStableAlpha);
         setIconScaleAndDim(1);
-        setColorTint(0);
+        setColorTint(0, 0);
     }
 
     public void setStableAlpha(float parentAlpha) {
@@ -982,7 +964,7 @@
 
     private void applyScale() {
         float scale = 1;
-        float fullScreenProgress = EXAGGERATED_EASE.getInterpolation(mFullscreenProgress);
+        float fullScreenProgress = FULLSCREEN_INTERPOLATOR.getInterpolation(mFullscreenProgress);
         scale *= Utilities.mapRange(fullScreenProgress, 1f, mFullscreenScale);
         setScaleX(scale);
         setScaleY(scale);
@@ -1425,7 +1407,7 @@
     }
 
     private float getFullscreenTrans(float endTranslation) {
-        float progress = ACCEL_DEACCEL.getInterpolation(mFullscreenProgress);
+        float progress = FULLSCREEN_INTERPOLATOR.getInterpolation(mFullscreenProgress);
         return Utilities.mapRange(progress, 0, endTranslation);
     }
 
@@ -1472,25 +1454,13 @@
         getRecentsView().initiateSplitSelect(this, splitPositionOption);
     }
 
-    private void setColorTint(float amount) {
-        mTintAmount = amount;
-        mSnapshotView.setDimAlpha(mTintAmount);
-        mIconView.setIconColorTint(mTintingColor, mTintAmount);
-        mDigitalWellBeingToast.setBannerColorTint(mTintingColor, mTintAmount);
-    }
-
-    private float getColorTint() {
-        return mTintAmount;
-    }
-
     /**
-     * Show the task view with a color tint (animates value).
+     * Set a color tint on the snapshot and supporting views.
      */
-    public void showColorTint(boolean enable) {
-        ObjectAnimator tintAnimator = ObjectAnimator.ofFloat(
-                this, COLOR_TINT, enable ? MAX_PAGE_SCRIM_ALPHA : 0);
-        tintAnimator.setAutoCancel(true);
-        tintAnimator.start();
+    public void setColorTint(float amount, int tintColor) {
+        mSnapshotView.setDimAlpha(amount);
+        mIconView.setIconColorTint(tintColor, amount);
+        mDigitalWellBeingToast.setBannerColorTint(tintColor, amount);
     }
 
     /**
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index f93d87c..9630d27 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -62,6 +62,7 @@
 import com.android.quickstep.views.RecentsView;
 
 import org.junit.After;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.RuleChain;
@@ -142,10 +143,19 @@
         }
     }
 
+    @Before
+    public void setUp() {
+        mLauncher.onTestStart();
+    }
+
     @After
-    public void verifyLauncherState() {
-        // Limits UI tests affecting tests running after them.
-        AbstractQuickStepTest.checkDetectedLeaks(mLauncher);
+    public void tearDown() {
+        try {
+            // Limits UI tests affecting tests running after them.
+            AbstractQuickStepTest.checkDetectedLeaks(mLauncher);
+        } finally {
+            mLauncher.onTestFinish();
+        }
     }
 
     // b/143488140
@@ -178,13 +188,13 @@
     protected <T> T getFromRecents(Function<RecentsActivity, T> f) {
         if (!TestHelpers.isInLauncherProcess()) return null;
         if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.GET_RECENTS_FAILED, "getFromRecents");
+            Log.d(TestProtocol.FALLBACK_ACTIVITY_NO_SET, "getFromRecents");
         }
         Object[] result = new Object[1];
         Wait.atMost("Failed to get from recents", () -> MAIN_EXECUTOR.submit(() -> {
             RecentsActivity activity = RecentsActivity.ACTIVITY_TRACKER.getCreatedActivity();
             if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.GET_RECENTS_FAILED, "activity=" + activity);
+                Log.d(TestProtocol.FALLBACK_ACTIVITY_NO_SET, "activity=" + activity);
             }
             if (activity == null) {
                 return false;
@@ -212,10 +222,6 @@
 
         BaseOverview overview = mLauncher.getBackground().switchToOverview();
         executeOnRecents(recents -> {
-            if (TestProtocol.sDebugTracing) {
-                Log.d(TestProtocol.GET_RECENTS_FAILED, "isLoading=" +
-                        recents.<RecentsView>getOverviewPanel().isLoadingTasks());
-            }
             assertTrue("Don't have at least 3 tasks", getTaskCount(recents) >= 3);
         });
 
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index a700e16..a5038a1 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -189,12 +189,10 @@
     @NavigationModeSwitch
     @PortraitLandscape
     public void testSwitchToOverview() throws Exception {
-        Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED, "testSwitchToOverview");
         assertNotNull("Workspace.switchToOverview() returned null",
                 mLauncher.pressHome().switchToOverview());
         assertTrue("Launcher internal state didn't switch to Overview",
                 isInState(() -> LauncherState.OVERVIEW));
-        Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED, "testSwitchToOverview finished");
     }
 
     @Test
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 77f0118..b3b0d2b 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -97,8 +97,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Vouer: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> items"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Vouer: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> of meer items"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Muurpapiere"</string>
-    <!-- no translation found for styles_wallpaper_button_text (8216961355289236794) -->
-    <skip />
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Muurpapier en styl"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Tuis-instellings"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Gedeaktiveer deur jou administrateur"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Laat toe dat tuisskerm gedraai word"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 4030f1f..502d5eb 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -97,8 +97,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Mappe: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> elementer"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Mappe: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> eller flere elementer"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Baggrunde"</string>
-    <!-- no translation found for styles_wallpaper_button_text (8216961355289236794) -->
-    <skip />
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Baggrund og stil"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Indstillinger for startskærm"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Deaktiveret af din administrator"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Tillad rotation af startskærmen"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index d506136..56f31bf 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -97,8 +97,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Carpeta: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> elementos"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Carpeta: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> o más elementos"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Fondos de pantalla"</string>
-    <!-- no translation found for styles_wallpaper_button_text (8216961355289236794) -->
-    <skip />
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Fondo de pantalla y estilo"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Configuración de pantalla principal"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"El administrador inhabilitó esta función"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Permitir la rotación de la pantalla principal"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 066d54f..f1ae4d5 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -97,8 +97,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"پوشه: <xliff:g id="NAME">%1$s</xliff:g>، <xliff:g id="SIZE">%2$d</xliff:g> مورد"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"پوشه: <xliff:g id="NAME">%1$s</xliff:g>، <xliff:g id="SIZE">%2$d</xliff:g> مورد یا بیشتر"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"کاغذدیواری‌ها"</string>
-    <!-- no translation found for styles_wallpaper_button_text (8216961355289236794) -->
-    <skip />
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"کاغذدیواری و سبک"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"تنظیمات صفحه اصلی"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"توسط سرپرست سیستم غیرفعال شده است"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"قابل‌چرخش بودن صفحه اصلی"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index b4f4706..27f045e 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -97,8 +97,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"ಫೋಲ್ಡರ್: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> ಐಟಂಗಳು"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"ಫೋಲ್ಡರ್: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> ಅಥವಾ ಹೆಚ್ಚಿನ ಐಟಂಗಳು"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"ವಾಲ್‌ಪೇಪರ್‌ಗಳು"</string>
-    <!-- no translation found for styles_wallpaper_button_text (8216961355289236794) -->
-    <skip />
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"ವಾಲ್‌ಪೇಪರ್ ಮತ್ತು ಶೈಲಿ"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"ಮುಖಪುಟ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಿದ್ದಾರೆ"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"ಮುಖಪುಟ ತಿರುಗುವಿಕೆಯನ್ನು ಅನುಮತಿಸಿ"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 5893ceb..9465be5 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -97,8 +97,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> item"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> atau lebih banyak item"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Kertas dinding"</string>
-    <!-- no translation found for styles_wallpaper_button_text (8216961355289236794) -->
-    <skip />
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Kertas dinding &amp; gaya"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Tetapan laman utama"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Dilumpuhkan oleh pentadbir anda"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Benarkan putaran Skrin Utama"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index bfbd011..58d1d98 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -97,8 +97,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Map: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> items"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Map: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> of meer items"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Achtergrond"</string>
-    <!-- no translation found for styles_wallpaper_button_text (8216961355289236794) -->
-    <skip />
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Achtergrond en stijl"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Instellingen start"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Uitgezet door je beheerder"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Draaien van startscherm toestaan"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index bfa7973..acce00a 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -103,8 +103,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> elementy"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Folder: <xliff:g id="NAME">%1$s</xliff:g>, liczba elementów: <xliff:g id="SIZE">%2$d</xliff:g> lub więcej"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Tapety"</string>
-    <!-- no translation found for styles_wallpaper_button_text (8216961355289236794) -->
-    <skip />
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Tapeta i styl"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Ustawienia ekranu głównego"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Funkcja wyłączona przez administratora"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Zezwalaj na obrót ekranu głównego"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index f7f7aa1..fd793d4 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -97,8 +97,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Pasta: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> itens"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Pasta: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> ou mais itens"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Planos de fundo"</string>
-    <!-- no translation found for styles_wallpaper_button_text (8216961355289236794) -->
-    <skip />
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Plano de fundo e estilo"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Configurações da tela inicial"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Desativado pelo administrador"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Permitir rotação da tela inicial"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 6c4810e..e23e7a9 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -103,8 +103,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Priečinok: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> položky"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Priečinok: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> alebo viac položiek"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Tapety"</string>
-    <!-- no translation found for styles_wallpaper_button_text (8216961355289236794) -->
-    <skip />
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Tapeta a štýl"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Nastavenia plochy"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Zakázané vaším správcom"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Povoliť otáčanie plochy"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index d29e15d..dbdcf17 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -97,8 +97,7 @@
     <string name="folder_name_format_exact" msgid="8626242716117004803">"Ifolda: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> izinto"</string>
     <string name="folder_name_format_overflow" msgid="4270108890534995199">"Ifolda: <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> noma izinto eziningi"</string>
     <string name="wallpaper_button_text" msgid="8404103075899945851">"Izithombe zangemuva"</string>
-    <!-- no translation found for styles_wallpaper_button_text (8216961355289236794) -->
-    <skip />
+    <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Isithombe sangemuva nesitayela"</string>
     <string name="settings_button_text" msgid="8873672322605444408">"Izilungiselelo zasekhaya"</string>
     <string name="msg_disabled_by_admin" msgid="6898038085516271325">"Kukhutshazwe umlawuli wakho"</string>
     <string name="allow_rotation_title" msgid="7728578836261442095">"Vumela ukuphendukiswa kwesikrini sasekhaya"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 2e5ecba..0a4549e 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -137,7 +137,7 @@
     <item name="swipe_up_trans_y_stiffness" type="dimen" format="float">200</item>
 
     <item name="swipe_up_rect_xy_damping_ratio" type="dimen" format="float">0.8</item>
-    <item name="swipe_up_rect_xy_stiffness" type="dimen" format="float">100</item>
+    <item name="swipe_up_rect_xy_stiffness" type="dimen" format="float">200</item>
 
 
     <item name="swipe_up_rect_2_x_damping_ratio" type="dimen" format="float">1</item>
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index f64ce5c..9778b61 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -132,6 +132,7 @@
 
     private final ViewCache mViewCache = new ViewCache();
 
+    @Override
     public ViewCache getViewCache() {
         return mViewCache;
     }
diff --git a/src/com/android/launcher3/ExtendedEditText.java b/src/com/android/launcher3/ExtendedEditText.java
index 4312939..20c6938 100644
--- a/src/com/android/launcher3/ExtendedEditText.java
+++ b/src/com/android/launcher3/ExtendedEditText.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3;
 
+import static com.android.launcher3.util.UiThreadHelper.hideKeyboardAsync;
+
 import android.content.Context;
 import android.text.TextUtils;
 import android.util.AttributeSet;
@@ -25,7 +27,7 @@
 import android.widget.EditText;
 
 import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.util.UiThreadHelper;
+import com.android.launcher3.views.ActivityContext;
 
 
 /**
@@ -99,7 +101,7 @@
     }
 
     public void hideKeyboard() {
-        UiThreadHelper.hideKeyboardAsync(Launcher.getLauncher(getContext()), getWindowToken());
+        hideKeyboardAsync(ActivityContext.lookupContext(getContext()), getWindowToken());
     }
 
     private boolean showSoftInput() {
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 7836fa3..318dde1 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -369,10 +369,6 @@
     }
 
     private void onConfigChanged(Context context) {
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED, "IDP.onConfigChanged");
-        }
-
         // Re-init grid
         String gridName = getCurrentGridName(context);
         initGrid(context, gridName);
@@ -527,11 +523,6 @@
         float availableWidth = config.screenWidthDp * res.getDisplayMetrics().density;
         float availableHeight = config.screenHeightDp * res.getDisplayMetrics().density;
 
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED,
-                    "getDeviceProfile: orientation=" + config.orientation
-                            + " size=" + availableWidth + "x" + availableHeight);
-        }
         DeviceProfile bestMatch = supportedProfiles.get(0);
         float minDiff = Float.MAX_VALUE;
 
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5896f5a..5ecdca6 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -124,6 +124,7 @@
 import com.android.launcher3.dragndrop.DragLayer;
 import com.android.launcher3.dragndrop.DragOptions;
 import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.dragndrop.LauncherDragController;
 import com.android.launcher3.folder.FolderGridOrganizer;
 import com.android.launcher3.folder.FolderIcon;
 import com.android.launcher3.icons.BitmapRenderer;
@@ -428,7 +429,7 @@
         mIconCache = app.getIconCache();
         mAccessibilityDelegate = createAccessibilityDelegate();
 
-        mDragController = new DragController(this);
+        mDragController = new LauncherDragController(this);
         mAllAppsController = new AllAppsTransitionController(this);
         mStateManager = new StateManager<>(this, NORMAL);
 
@@ -554,21 +555,12 @@
             onIdpChanged(mDeviceProfile.inv);
         }
 
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED, "onConfigurationChanged: diff=" + diff);
-            Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED, "newConfig=" + newConfig);
-            Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED, "oldConfig=" + mOldConfig);
-        }
-
         mOldConfig.setTo(newConfig);
         super.onConfigurationChanged(newConfig);
     }
 
     @Override
     public void onIdpChanged(InvariantDeviceProfile idp) {
-        if (TestProtocol.sDebugTracing) {
-            Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED, "onIdpChanged");
-        }
         initDeviceProfile(idp);
         dispatchDeviceProfileChanged();
         reapplyUi();
@@ -1346,14 +1338,7 @@
     private final BroadcastReceiver mScreenOffReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            // Reset AllApps to its initial state only if we are not in the middle of
-            // processing a multi-step drop
-            if (mPendingRequestArgs == null) {
-                if (!isInState(NORMAL)) {
-                    onUiChangedWhileSleeping();
-                }
-                mStateManager.goToState(NORMAL);
-            }
+            onScreenOff();
         }
     };
 
@@ -1923,6 +1908,17 @@
         }
     }
 
+    protected void onScreenOff() {
+        // Reset AllApps to its initial state only if we are not in the middle of
+        // processing a multi-step drop
+        if (mPendingRequestArgs == null) {
+            if (!isInState(NORMAL)) {
+                onUiChangedWhileSleeping();
+            }
+            mStateManager.goToState(NORMAL);
+        }
+    }
+
     @TargetApi(Build.VERSION_CODES.M)
     @Override
     protected boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
@@ -2159,12 +2155,29 @@
      */
     @Override
     public void bindItems(final List<ItemInfo> items, final boolean forceAnimateIcons) {
+        bindItems(items, forceAnimateIcons, /* focusFirstItemForAccessibility= */ false);
+    }
+
+
+    /**
+     * Bind the items start-end from the list.
+     *
+     * Implementation of the method from LauncherModel.Callbacks.
+     *
+     * @param focusFirstItemForAccessibility true iff the first item to be added to the workspace
+     *                                       should be focused for accessibility.
+     */
+    public void bindItems(
+            final List<ItemInfo> items,
+            final boolean forceAnimateIcons,
+            final boolean focusFirstItemForAccessibility) {
         // Get the list of added items and intersect them with the set of items here
         final Collection<Animator> bounceAnims = new ArrayList<>();
         final boolean animateIcons = forceAnimateIcons && canRunNewAppsAnimation();
         Workspace workspace = mWorkspace;
         int newItemsScreenId = -1;
         int end = items.size();
+        View newView = null;
         for (int i = 0; i < end; i++) {
             final ItemInfo item = items.get(i);
 
@@ -2229,12 +2242,25 @@
                 bounceAnims.add(createNewAppBounceAnimation(view, i));
                 newItemsScreenId = item.screenId;
             }
+
+            if (newView == null) {
+                newView = view;
+            }
         }
 
-        // Animate to the correct page
+        View viewToFocus = newView;
+        // Animate to the correct pager
         if (animateIcons && newItemsScreenId > -1) {
             AnimatorSet anim = new AnimatorSet();
             anim.playTogether(bounceAnims);
+            if (focusFirstItemForAccessibility && viewToFocus != null) {
+                anim.addListener(new AnimatorListenerAdapter() {
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        viewToFocus.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+                    }
+                });
+            }
 
             int currentScreenId = mWorkspace.getScreenIdForPageIndex(mWorkspace.getNextPage());
             final int newScreenIndex = mWorkspace.getPageIndexForScreenId(newItemsScreenId);
@@ -2257,6 +2283,8 @@
             } else {
                 mWorkspace.postDelayed(startBounceAnimRunnable, NEW_APPS_ANIMATION_DELAY);
             }
+        } else if (focusFirstItemForAccessibility && viewToFocus != null) {
+            viewToFocus.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
         }
         workspace.requestLayout();
     }
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index fb21698..52a6cef 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -59,7 +59,7 @@
 import com.android.launcher3.views.ActivityContext;
 
 import java.util.ArrayList;
-import java.util.List;
+import java.util.function.Consumer;
 
 /**
  * An abstraction of the original Workspace which supports browsing through a
@@ -295,18 +295,16 @@
     }
 
     /**
-     * Returns the currently visible pages.
+     * Executes the callback against each visible page
      */
-    public Iterable<View> getVisiblePages() {
+    public void forEachVisiblePage(Consumer<View> callback) {
         int panelCount = getPanelCount();
-        List<View> visiblePages = new ArrayList<>(panelCount);
         for (int i = mCurrentPage; i < mCurrentPage + panelCount; i++) {
             View page = getPageAt(i);
             if (page != null) {
-                visiblePages.add(page);
+                callback.accept(page);
             }
         }
-        return visiblePages;
     }
 
     /**
@@ -1034,7 +1032,7 @@
         // Try canceling the long press. It could also have been scheduled
         // by a distant descendant, so use the mAllowLongPress flag to block
         // everything
-        getVisiblePages().forEach(View::cancelLongPress);
+        forEachVisiblePage(View::cancelLongPress);
     }
 
     protected float getScrollProgress(int screenCenter, View v, int page) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 7c5f99e..f846d14 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -2974,7 +2974,7 @@
 
         List<CellLayout> cellLayouts = new ArrayList<>(getPanelCount() + 1);
         cellLayouts.add(getHotseat());
-        getVisiblePages().forEach(page -> cellLayouts.add((CellLayout) page));
+        forEachVisiblePage(page -> cellLayouts.add((CellLayout) page));
 
         // Order: App icons, app in folder. Items in hotseat get returned first.
         if (ADAPTIVE_ICON_WINDOW_ANIM.get()) {
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index dbdfb2b..c580d47 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -230,7 +230,10 @@
                                 Favorites.CONTAINER_DESKTOP,
                                 screenId, coordinates[0], coordinates[1]);
 
-                        mLauncher.bindItems(Collections.singletonList(info), true);
+                        mLauncher.bindItems(
+                                Collections.singletonList(info),
+                                /* forceAnimateIcons= */ true,
+                                /* focusFirstItemForAccessibility= */ true);
                         announceConfirmation(R.string.item_added_to_workspace);
                     } else if (item instanceof PendingAddItemInfo) {
                         PendingAddItemInfo info = (PendingAddItemInfo) item;
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 6957850..88d95fa 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -30,6 +30,7 @@
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.TreeMap;
 
 /**
@@ -181,11 +182,10 @@
      * Sets results list for search
      */
     public boolean setSearchResults(ArrayList<AdapterItem> results) {
-        if (results == null || mSearchResults != results) {
-            boolean same = mSearchResults != null && mSearchResults.equals(results);
+        if (!Objects.equals(results, mSearchResults)) {
             mSearchResults = results;
             updateAdapterItems();
-            return !same;
+            return true;
         }
         return false;
     }
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index ba5101b..6b42d98 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -88,7 +88,7 @@
             "ENABLE_QUICKSTEP_LIVE_TILE", true, "Enable live tile in Quickstep overview");
 
     public static final BooleanFlag ENABLE_QUICKSTEP_WIDGET_APP_START = getDebugFlag(
-            "ENABLE_QUICKSTEP_WIDGET_APP_START", false,
+            "ENABLE_QUICKSTEP_WIDGET_APP_START", true,
             "Enable Quickstep animation when launching activities from an app widget");
 
     // Keep as DeviceFlag to allow remote disable in emergency.
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index 575b8fd..5731db4 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -16,45 +16,37 @@
 
 package com.android.launcher3.dragndrop;
 
-import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
-import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
-import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.Utilities.ATLEAST_Q;
-import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
 import android.content.ComponentName;
-import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.view.DragEvent;
-import android.view.HapticFeedbackConstants;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.AbstractFloatingView;
 import com.android.launcher3.DragSource;
 import com.android.launcher3.DropTarget;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.accessibility.DragViewStateAnnouncer;
 import com.android.launcher3.logging.InstanceId;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.ItemInfoMatcher;
 import com.android.launcher3.util.TouchController;
+import com.android.launcher3.views.ActivityContext;
 
 import java.util.ArrayList;
 import java.util.Optional;
 
 /**
  * Class for initiating a drag within a view or across multiple views.
+ * @param <T>
  */
-public class DragController implements DragDriver.EventListener, TouchController {
-    private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
+public abstract class DragController<T extends ActivityContext>
+        implements DragDriver.EventListener, TouchController {
 
     /**
      * When a drag is started from a deep press, you need to drag this much farther than normal to
@@ -62,8 +54,7 @@
      */
     private static final int DEEP_PRESS_DISTANCE_FACTOR = 3;
 
-    private final Launcher mLauncher;
-    private final FlingToDeleteHelper mFlingToDeleteHelper;
+    protected final T mActivity;
 
     // temporaries to avoid gc thrash
     private final Rect mRectTemp = new Rect();
@@ -73,30 +64,30 @@
      * Drag driver for the current drag/drop operation, or null if there is no active DND operation.
      * It's null during accessible drag operations.
      */
-    private DragDriver mDragDriver = null;
+    protected DragDriver mDragDriver = null;
 
     /** Options controlling the drag behavior. */
-    private DragOptions mOptions;
+    protected DragOptions mOptions;
 
     /** Coordinate for motion down event */
-    private final Point mMotionDown = new Point();
+    protected final Point mMotionDown = new Point();
     /** Coordinate for last touch event **/
-    private final Point mLastTouch = new Point();
+    protected final Point mLastTouch = new Point();
 
     private final Point mTmpPoint = new Point();
 
-    private DropTarget.DragObject mDragObject;
+    protected DropTarget.DragObject mDragObject;
 
     /** Who can receive drop events */
     private final ArrayList<DropTarget> mDropTargets = new ArrayList<>();
     private final ArrayList<DragListener> mListeners = new ArrayList<>();
 
-    private DropTarget mLastDropTarget;
+    protected DropTarget mLastDropTarget;
 
     private int mLastTouchClassification;
-    private int mDistanceSinceScroll = 0;
+    protected int mDistanceSinceScroll = 0;
 
-    private boolean mIsInPreDrag;
+    protected boolean mIsInPreDrag;
 
     /**
      * Interface to receive notifications when a drag starts or stops
@@ -119,9 +110,8 @@
     /**
      * Used to create a new DragLayer from XML.
      */
-    public DragController(Launcher launcher) {
-        mLauncher = launcher;
-        mFlingToDeleteHelper = new FlingToDeleteHelper(launcher);
+    public DragController(T activity) {
+        mActivity = activity;
     }
 
     /**
@@ -198,7 +188,7 @@
                 options);
     }
 
-    private DragView startDrag(
+    protected abstract DragView startDrag(
             @Nullable Drawable drawable,
             @Nullable View view,
             DraggableView originalView,
@@ -210,98 +200,9 @@
             Rect dragRegion,
             float initialDragViewScale,
             float dragViewScaleOnDrop,
-            DragOptions options) {
-        if (PROFILE_DRAWING_DURING_DRAG) {
-            android.os.Debug.startMethodTracing("Launcher");
-        }
+            DragOptions options);
 
-        mLauncher.hideKeyboard();
-        AbstractFloatingView.closeOpenViews(mLauncher, false, TYPE_DISCOVERY_BOUNCE);
-
-        mOptions = options;
-        if (mOptions.simulatedDndStartPoint != null) {
-            mLastTouch.x = mMotionDown.x = mOptions.simulatedDndStartPoint.x;
-            mLastTouch.y = mMotionDown.y = mOptions.simulatedDndStartPoint.y;
-        }
-
-        final int registrationX = mMotionDown.x - dragLayerX;
-        final int registrationY = mMotionDown.y - dragLayerY;
-
-        final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
-        final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
-
-        mLastDropTarget = null;
-
-        mDragObject = new DropTarget.DragObject(mLauncher.getApplicationContext());
-        mDragObject.originalView = originalView;
-
-        mIsInPreDrag = mOptions.preDragCondition != null
-                && !mOptions.preDragCondition.shouldStartDrag(0);
-
-        final Resources res = mLauncher.getResources();
-        final float scaleDps = mIsInPreDrag
-                ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f;
-        final DragView dragView = mDragObject.dragView = drawable != null
-                ? new DragView(
-                    mLauncher,
-                    drawable,
-                    registrationX,
-                    registrationY,
-                    initialDragViewScale,
-                    dragViewScaleOnDrop,
-                    scaleDps)
-                : new DragView(
-                    mLauncher,
-                    view,
-                    view.getMeasuredWidth(),
-                    view.getMeasuredHeight(),
-                    registrationX,
-                    registrationY,
-                    initialDragViewScale,
-                    dragViewScaleOnDrop,
-                    scaleDps);
-        dragView.setItemInfo(dragInfo);
-        mDragObject.dragComplete = false;
-
-        mDragObject.xOffset = mMotionDown.x - (dragLayerX + dragRegionLeft);
-        mDragObject.yOffset = mMotionDown.y - (dragLayerY + dragRegionTop);
-
-        mDragDriver = DragDriver.create(this, mOptions, mFlingToDeleteHelper::recordMotionEvent);
-        if (!mOptions.isAccessibleDrag) {
-            mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView);
-        }
-
-        mDragObject.dragSource = source;
-        mDragObject.dragInfo = dragInfo;
-        mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy();
-
-        if (dragOffset != null) {
-            dragView.setDragVisualizeOffset(new Point(dragOffset));
-        }
-        if (dragRegion != null) {
-            dragView.setDragRegion(new Rect(dragRegion));
-        }
-
-        mLauncher.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
-        dragView.show(mLastTouch.x, mLastTouch.y);
-        mDistanceSinceScroll = 0;
-
-        if (!mIsInPreDrag) {
-            callOnDragStart();
-        } else if (mOptions.preDragCondition != null) {
-            mOptions.preDragCondition.onPreDragStart(mDragObject);
-        }
-
-        handleMoveEvent(mLastTouch.x, mLastTouch.y);
-
-        if (!mLauncher.isTouchInProgress() && options.simulatedDndStartPoint == null) {
-            // If it is an internal drag and the touch is already complete, cancel immediately
-            MAIN_EXECUTOR.submit(this::cancelDrag);
-        }
-        return dragView;
-    }
-
-    private void callOnDragStart() {
+    protected void callOnDragStart() {
         if (mOptions.preDragCondition != null) {
             mOptions.preDragCondition.onPreDragEnd(mDragObject, true /* dragStarted*/);
         }
@@ -357,13 +258,15 @@
         if (!accepted) {
             // If it was not accepted, cleanup the state. If it was accepted, it is the
             // responsibility of the drop target to cleanup the state.
-            mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
+            exitDrag();
             mDragObject.deferDragViewCleanupPostAnimation = false;
         }
 
         mDragObject.dragSource.onDropCompleted(dropTarget, mDragObject, accepted);
     }
 
+    protected abstract void exitDrag();
+
     public void onAppsRemoved(ItemInfoMatcher matcher) {
         // Cancel the current drag if we are removing an app that we are dragging
         if (mDragObject != null) {
@@ -377,7 +280,7 @@
         }
     }
 
-    private void endDrag() {
+    protected void endDrag() {
         if (isDragging()) {
             mDragDriver = null;
             boolean isDeferred = false;
@@ -396,8 +299,6 @@
                 callOnDragEnd();
             }
         }
-
-        mFlingToDeleteHelper.releaseVelocityTracker();
     }
 
     public void animateDragViewToOriginalPosition(final Runnable onComplete,
@@ -443,7 +344,7 @@
      * Clamps the position to the drag layer bounds.
      */
     private Point getClampedDragLayerPos(float x, float y) {
-        mLauncher.getDragLayer().getLocalVisibleRect(mRectTemp);
+        mActivity.getDragLayer().getLocalVisibleRect(mRectTemp);
         mTmpPoint.x = (int) Math.max(mRectTemp.left, Math.min(x, mRectTemp.right - 1));
         mTmpPoint.y = (int) Math.max(mRectTemp.top, Math.min(y, mRectTemp.bottom - 1));
         return mTmpPoint;
@@ -465,19 +366,16 @@
 
     @Override
     public void onDriverDragEnd(float x, float y) {
-        DropTarget dropTarget;
-        Runnable flingAnimation = mFlingToDeleteHelper.getFlingAnimation(mDragObject, mOptions);
-        if (flingAnimation != null) {
-            dropTarget = mFlingToDeleteHelper.getDropTarget();
-        } else {
-            dropTarget = findDropTarget((int) x, (int) y, mCoordinatesTemp);
+        if (!endWithFlingAnimation()) {
+            drop(findDropTarget((int) x, (int) y, mCoordinatesTemp), null);
         }
-
-        drop(dropTarget, flingAnimation);
-
         endDrag();
     }
 
+    protected boolean endWithFlingAnimation() {
+        return false;
+    }
+
     @Override
     public void onDriverDragCancel() {
         cancelDrag();
@@ -520,7 +418,7 @@
         return mDragDriver != null && mDragDriver.onDragEvent(event);
     }
 
-    private void handleMoveEvent(int x, int y) {
+    protected void handleMoveEvent(int x, int y) {
         mDragObject.dragView.move(x, y);
 
         // Drop on someone?
@@ -592,7 +490,7 @@
         endDrag();
     }
 
-    private void drop(DropTarget dropTarget, Runnable flingAnimation) {
+    protected void drop(DropTarget dropTarget, Runnable flingAnimation) {
         final int[] coordinates = mCoordinatesTemp;
         mDragObject.x = coordinates[0];
         mDragObject.y = coordinates[1];
@@ -649,7 +547,7 @@
             if (r.contains(x, y)) {
                 dropCoordinates[0] = x;
                 dropCoordinates[1] = y;
-                mLauncher.getDragLayer().mapCoordInSelfToDescendant((View) target, dropCoordinates);
+                mActivity.getDragLayer().mapCoordInSelfToDescendant((View) target, dropCoordinates);
                 return target;
             }
         }
@@ -657,11 +555,11 @@
         // cell layout to drop to in the existing drag/drop logic.
         dropCoordinates[0] = x;
         dropCoordinates[1] = y;
-        mLauncher.getDragLayer().mapCoordInSelfToDescendant(mLauncher.getWorkspace(),
-                dropCoordinates);
-        return mLauncher.getWorkspace();
+        return getDefaultDropTarget(dropCoordinates);
     }
 
+    protected abstract DropTarget getDefaultDropTarget(int[] dropCoordinates);
+
     /**
      * Sets the drag listener which will be notified when a drag starts or ends.
      */
diff --git a/src/com/android/launcher3/dragndrop/LauncherDragController.java b/src/com/android/launcher3/dragndrop/LauncherDragController.java
new file mode 100644
index 0000000..a98d70c
--- /dev/null
+++ b/src/com/android/launcher3/dragndrop/LauncherDragController.java
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.dragndrop;
+
+import static com.android.launcher3.AbstractFloatingView.TYPE_DISCOVERY_BOUNCE;
+import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+import android.view.HapticFeedbackConstants;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.accessibility.DragViewStateAnnouncer;
+import com.android.launcher3.model.data.ItemInfo;
+
+/**
+ * Drag controller for Launcher activity
+ */
+public class LauncherDragController extends DragController<Launcher> {
+
+    private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
+
+    private final FlingToDeleteHelper mFlingToDeleteHelper;
+
+    public LauncherDragController(Launcher launcher) {
+        super(launcher);
+        mFlingToDeleteHelper = new FlingToDeleteHelper(launcher);
+    }
+
+    @Override
+    protected DragView startDrag(
+            @Nullable Drawable drawable,
+            @Nullable View view,
+            DraggableView originalView,
+            int dragLayerX,
+            int dragLayerY,
+            DragSource source,
+            ItemInfo dragInfo,
+            Point dragOffset,
+            Rect dragRegion,
+            float initialDragViewScale,
+            float dragViewScaleOnDrop,
+            DragOptions options) {
+        if (PROFILE_DRAWING_DURING_DRAG) {
+            android.os.Debug.startMethodTracing("Launcher");
+        }
+
+        mActivity.hideKeyboard();
+        AbstractFloatingView.closeOpenViews(mActivity, false, TYPE_DISCOVERY_BOUNCE);
+
+        mOptions = options;
+        if (mOptions.simulatedDndStartPoint != null) {
+            mLastTouch.x = mMotionDown.x = mOptions.simulatedDndStartPoint.x;
+            mLastTouch.y = mMotionDown.y = mOptions.simulatedDndStartPoint.y;
+        }
+
+        final int registrationX = mMotionDown.x - dragLayerX;
+        final int registrationY = mMotionDown.y - dragLayerY;
+
+        final int dragRegionLeft = dragRegion == null ? 0 : dragRegion.left;
+        final int dragRegionTop = dragRegion == null ? 0 : dragRegion.top;
+
+        mLastDropTarget = null;
+
+        mDragObject = new DropTarget.DragObject(mActivity.getApplicationContext());
+        mDragObject.originalView = originalView;
+
+        mIsInPreDrag = mOptions.preDragCondition != null
+                && !mOptions.preDragCondition.shouldStartDrag(0);
+
+        final Resources res = mActivity.getResources();
+        final float scaleDps = mIsInPreDrag
+                ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f;
+        final DragView dragView = mDragObject.dragView = drawable != null
+                ? new DragView(
+                mActivity,
+                drawable,
+                registrationX,
+                registrationY,
+                initialDragViewScale,
+                dragViewScaleOnDrop,
+                scaleDps)
+                : new DragView(
+                        mActivity,
+                        view,
+                        view.getMeasuredWidth(),
+                        view.getMeasuredHeight(),
+                        registrationX,
+                        registrationY,
+                        initialDragViewScale,
+                        dragViewScaleOnDrop,
+                        scaleDps);
+        dragView.setItemInfo(dragInfo);
+        mDragObject.dragComplete = false;
+
+        mDragObject.xOffset = mMotionDown.x - (dragLayerX + dragRegionLeft);
+        mDragObject.yOffset = mMotionDown.y - (dragLayerY + dragRegionTop);
+
+        mDragDriver = DragDriver.create(this, mOptions, mFlingToDeleteHelper::recordMotionEvent);
+        if (!mOptions.isAccessibleDrag) {
+            mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView);
+        }
+
+        mDragObject.dragSource = source;
+        mDragObject.dragInfo = dragInfo;
+        mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy();
+
+        if (dragOffset != null) {
+            dragView.setDragVisualizeOffset(new Point(dragOffset));
+        }
+        if (dragRegion != null) {
+            dragView.setDragRegion(new Rect(dragRegion));
+        }
+
+        mActivity.getDragLayer().performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
+        dragView.show(mLastTouch.x, mLastTouch.y);
+        mDistanceSinceScroll = 0;
+
+        if (!mIsInPreDrag) {
+            callOnDragStart();
+        } else if (mOptions.preDragCondition != null) {
+            mOptions.preDragCondition.onPreDragStart(mDragObject);
+        }
+
+        handleMoveEvent(mLastTouch.x, mLastTouch.y);
+
+        if (!mActivity.isTouchInProgress() && options.simulatedDndStartPoint == null) {
+            // If it is an internal drag and the touch is already complete, cancel immediately
+            MAIN_EXECUTOR.submit(this::cancelDrag);
+        }
+        return dragView;
+    }
+
+    @Override
+    protected void exitDrag() {
+        mActivity.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
+    }
+
+    @Override
+    protected boolean endWithFlingAnimation() {
+        Runnable flingAnimation = mFlingToDeleteHelper.getFlingAnimation(mDragObject, mOptions);
+        if (flingAnimation != null) {
+            drop(mFlingToDeleteHelper.getDropTarget(), flingAnimation);
+            return true;
+        }
+        return super.endWithFlingAnimation();
+    }
+
+    @Override
+    protected void endDrag() {
+        super.endDrag();
+        mFlingToDeleteHelper.releaseVelocityTracker();
+    }
+
+    @Override
+    protected DropTarget getDefaultDropTarget(int[] dropCoordinates) {
+        mActivity.getDragLayer().mapCoordInSelfToDescendant(mActivity.getWorkspace(),
+                dropCoordinates);
+        return mActivity.getWorkspace();
+    }
+}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 92d891f..22d1b1c 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -23,7 +23,6 @@
 import static com.android.launcher3.LauncherState.NORMAL;
 import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
 import static com.android.launcher3.config.FeatureFlags.ALWAYS_USE_HARDWARE_OPTIMIZATION_FOR_FOLDER_ANIMATIONS;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
 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;
@@ -109,7 +108,6 @@
 import com.android.launcher3.widget.PendingAddShortcutInfo;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
@@ -177,8 +175,9 @@
     private boolean mIsAnimatingClosed = false;
 
     // Folder can be displayed in Launcher's activity or a separate window (e.g. Taskbar).
-    // Anything specific to Launcher should use mLauncher, otherwise should use mActivityContext.
-    protected final Launcher mLauncher;
+    // Anything specific to Launcher should use mLauncherDelegate, otherwise should
+    // use mActivityContext.
+    protected final LauncherDelegate mLauncherDelegate;
     protected final ActivityContext mActivityContext;
 
     protected DragController mDragController;
@@ -235,8 +234,6 @@
     // Wallpaper local color extraction
     @Nullable private LocalColorExtractor mColorExtractor;
     @Nullable private LocalColorExtractor.Listener mColorListener;
-    private final Rect mTempRect = new Rect();
-    private final RectF mTempRectF = new RectF();
 
     // For simplicity, we start the color change only after the open animation has started.
     private Runnable mColorChangeRunnable;
@@ -255,8 +252,9 @@
         super(context, attrs);
         setAlwaysDrawnWithCacheEnabled(false);
 
-        mLauncher = Launcher.getLauncher(context);
         mActivityContext = ActivityContext.lookupContext(context);
+        mLauncherDelegate = LauncherDelegate.from(mActivityContext);
+
         mStatsLogManager = StatsLogManager.newInstance(context);
         // We need this view to be focusable in touch mode so that when text editing of the folder
         // name is complete, we have something to focus on, thus hiding the cursor and giving
@@ -267,7 +265,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        final DeviceProfile dp = mLauncher.getDeviceProfile();
+        final DeviceProfile dp = mActivityContext.getDeviceProfile();
         final int paddingLeftRight = dp.folderContentPaddingLeftRight;
 
         mContent = findViewById(R.id.folder_content);
@@ -298,7 +296,7 @@
         }
 
         if (Utilities.ATLEAST_S) {
-            mColorExtractor = LocalColorExtractor.newInstance(mLauncher);
+            mColorExtractor = LocalColorExtractor.newInstance(getContext());
             mColorListener = (RectF rect, SparseIntArray extractedColors) -> {
                 mColorChangeRunnable = () -> {
                     mColorChangeRunnable = null;
@@ -339,7 +337,7 @@
 
     public boolean onLongClick(View v) {
         // Return if global dragging is not enabled
-        if (!mLauncher.isDraggingEnabled()) return true;
+        if (!mLauncherDelegate.isDraggingEnabled()) return true;
         return startDrag(v, new DragOptions());
     }
 
@@ -365,7 +363,7 @@
                         });
             }
 
-            mLauncher.getWorkspace().beginDragShared(v, this, options);
+            mLauncherDelegate.beginDragShared(v, this, options);
         }
         return true;
     }
@@ -421,7 +419,7 @@
         if (DEBUG) {
             Log.d(TAG, "onBackKey newTitle=" + newTitle);
         }
-        mInfo.setTitle(newTitle, mLauncher.getModelWriter());
+        mInfo.setTitle(newTitle, mLauncherDelegate.getModelWriter());
         mFolderIcon.onTitleChanged(newTitle);
 
         if (TextUtils.isEmpty(mInfo.title)) {
@@ -486,6 +484,7 @@
 
     public void setFolderIcon(FolderIcon icon) {
         mFolderIcon = icon;
+        mLauncherDelegate.init(this, icon);
     }
 
     @Override
@@ -592,8 +591,8 @@
     }
 
     private void startAnimation(final AnimatorSet a) {
-        mLauncher.getWorkspace().getVisiblePages()
-                .forEach(visiblePage -> addAnimatorListenerForPage(a, (CellLayout) visiblePage));
+        mLauncherDelegate.forEachVisibleWorkspacePage(
+                visiblePage -> addAnimatorListenerForPage(a, (CellLayout) visiblePage));
 
         a.addListener(new AnimatorListenerAdapter() {
             @Override
@@ -754,12 +753,12 @@
                     mFolderName.animate().setDuration(FOLDER_NAME_ANIMATION_DURATION)
                         .translationX(0)
                         .setInterpolator(AnimationUtils.loadInterpolator(
-                                mLauncher, android.R.interpolator.fast_out_slow_in));
+                                getContext(), android.R.interpolator.fast_out_slow_in));
                     mPageIndicator.playEntryAnimation();
 
                     if (updateAnimationFlag) {
                         mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true,
-                                mLauncher.getModelWriter());
+                                mLauncherDelegate.getModelWriter());
                     }
                 }
             });
@@ -1115,7 +1114,7 @@
         if (getItemCount() <= mContent.itemsPerPage()) {
             // Show the animation, next time something is added to the folder.
             mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, false,
-                    mLauncher.getModelWriter());
+                    mLauncherDelegate.getModelWriter());
         }
     }
 
@@ -1133,7 +1132,7 @@
         }
 
         if (!items.isEmpty()) {
-            mLauncher.getModelWriter().moveItemsInDatabase(items, mInfo.id, 0);
+            mLauncherDelegate.getModelWriter().moveItemsInDatabase(items, mInfo.id, 0);
         }
         if (FeatureFlags.FOLDER_NAME_SUGGEST.get() && !isBind
                 && total > 1 /* no need to update if there's one icon */) {
@@ -1190,12 +1189,7 @@
         if (mColorExtractor != null) {
             mColorExtractor.removeLocations();
             mColorExtractor.setListener(mColorListener);
-            mTempRect.set(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
-            mColorExtractor.getExtractedRectForViewRect(mLauncher,
-                    mLauncher.getWorkspace().getCurrentPage(), mTempRect, mTempRectF);
-            if (!mTempRectF.isEmpty()) {
-                mColorExtractor.addLocation(Arrays.asList(mTempRectF));
-            }
+            mLauncherDelegate.addRectForColorExtraction(lp, mColorExtractor);
         }
     }
 
@@ -1236,7 +1230,7 @@
 
         if (mContent.getChildCount() > 0) {
             int cellIconGap = (mContent.getPageAt(0).getCellWidth()
-                    - mLauncher.getDeviceProfile().iconSizePx) / 2;
+                    - mActivityContext.getDeviceProfile().iconSizePx) / 2;
             mFooter.setPadding(mContent.getPaddingLeft() + cellIconGap,
                     mFooter.getPaddingTop(),
                     mContent.getPaddingRight() + cellIconGap,
@@ -1266,56 +1260,7 @@
     }
 
     @Thunk void replaceFolderWithFinalItem() {
-        // Add the last remaining child to the workspace in place of the folder
-        Runnable onCompleteRunnable = new Runnable() {
-            @Override
-            public void run() {
-                int itemCount = getItemCount();
-                if (itemCount <= 1) {
-                    View newIcon = null;
-                    WorkspaceItemInfo finalItem = null;
-
-                    if (itemCount == 1) {
-                        // Move the item from the folder to the workspace, in the position of the
-                        // folder
-                        CellLayout cellLayout = mLauncher.getCellLayout(mInfo.container,
-                                mInfo.screenId);
-                        finalItem =  mInfo.contents.remove(0);
-                        newIcon = mLauncher.createShortcut(cellLayout, finalItem);
-                        mLauncher.getModelWriter().addOrMoveItemInDatabase(finalItem,
-                                mInfo.container, mInfo.screenId, mInfo.cellX, mInfo.cellY);
-                    }
-
-                    // Remove the folder
-                    mLauncher.removeItem(mFolderIcon, mInfo, true /* deleteFromDb */);
-                    if (mFolderIcon instanceof DropTarget) {
-                        mDragController.removeDropTarget((DropTarget) mFolderIcon);
-                    }
-
-                    if (newIcon != null) {
-                        // We add the child after removing the folder to prevent both from existing
-                        // at the same time in the CellLayout.  We need to add the new item with
-                        // addInScreenFromBind() to ensure that hotseat items are placed correctly.
-                        mLauncher.getWorkspace().addInScreenFromBind(newIcon, mInfo);
-
-                        // Focus the newly created child
-                        newIcon.requestFocus();
-                    }
-                    if (finalItem != null) {
-                        StatsLogger logger = mStatsLogManager.logger().withItemInfo(finalItem);
-                        mDragController.getLogInstanceId().map(logger::withInstanceId)
-                                .orElse(logger)
-                                .log(LAUNCHER_FOLDER_CONVERTED_TO_ICON);
-                    }
-                }
-            }
-        };
-        View finalChild = mContent.getLastItem();
-        if (finalChild != null) {
-            mFolderIcon.performDestroyAnimation(onCompleteRunnable);
-        } else {
-            onCompleteRunnable.run();
-        }
+        mLauncherDelegate.replaceFolderWithFinalItem(this);
         mDestroyed = true;
     }
 
@@ -1374,6 +1319,10 @@
             mScrollPauseAlarm.cancelAlarm();
         }
         mContent.completePendingPageChanges();
+        Launcher launcher = mLauncherDelegate.getLauncher();
+        if (launcher == null) {
+            return;
+        }
 
         PendingAddShortcutInfo pasi = d.dragInfo instanceof PendingAddShortcutInfo
                 ? (PendingAddShortcutInfo) d.dragInfo : null;
@@ -1383,7 +1332,7 @@
             pasi.container = mInfo.id;
             pasi.rank = mEmptyCellRank;
 
-            mLauncher.addPendingItem(pasi, pasi.container, pasi.screenId, null, pasi.spanX,
+            launcher.addPendingItem(pasi, pasi.container, pasi.screenId, null, pasi.spanX,
                     pasi.spanY);
             d.deferDragViewCleanupPostAnimation = false;
             mRearrangeOnClose = true;
@@ -1405,7 +1354,7 @@
 
                 // Actually move the item in the database if it was an external drag. Call this
                 // before creating the view, so that WorkspaceItemInfo is updated appropriately.
-                mLauncher.getModelWriter().addOrMoveItemInDatabase(
+                mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase(
                         si, mInfo.id, 0, si.cellX, si.cellY);
                 mIsExternalDrag = false;
             } else {
@@ -1420,7 +1369,7 @@
                 float scaleY = getScaleY();
                 setScaleX(1.0f);
                 setScaleY(1.0f);
-                mLauncher.getDragLayer().animateViewIntoPosition(d.dragView, currentDragView, null);
+                launcher.getDragLayer().animateViewIntoPosition(d.dragView, currentDragView, null);
                 setScaleX(scaleX);
                 setScaleY(scaleY);
             } else {
@@ -1448,10 +1397,11 @@
 
         if (mContent.getPageCount() > 1) {
             // The animation has already been shown while opening the folder.
-            mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true, mLauncher.getModelWriter());
+            mInfo.setOption(FolderInfo.FLAG_MULTI_PAGE_ANIMATION, true,
+                    mLauncherDelegate.getModelWriter());
         }
 
-        mLauncher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
+        launcher.getStateManager().goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
         if (d.stateAnnouncer != null) {
             d.stateAnnouncer.completeAction(R.string.item_moved);
         }
@@ -1480,7 +1430,7 @@
         FolderGridOrganizer verifier = new FolderGridOrganizer(
                 mActivityContext.getDeviceProfile().inv).setFolderInfo(mInfo);
         verifier.updateRankAndPos(item, rank);
-        mLauncher.getModelWriter().addOrMoveItemInDatabase(item, mInfo.id, 0, item.cellX,
+        mLauncherDelegate.getModelWriter().addOrMoveItemInDatabase(item, mInfo.id, 0, item.cellX,
                 item.cellY);
         updateItemLocationsInDatabaseBatch(false);
 
@@ -1713,17 +1663,9 @@
                     return true;
                 }
                 return false;
-            } else if (!dl.isEventOverView(this, ev)) {
-                if (mLauncher.getAccessibilityDelegate().isInAccessibleDrag()) {
-                    // Do not close the container if in drag and drop.
-                    if (!dl.isEventOverView(mLauncher.getDropTargetBar(), ev)) {
-                        return true;
-                    }
-                } else {
-                    // TODO: add ww log if need to gather tap outside to close folder
-                    close(true);
-                    return true;
-                }
+            } else if (!dl.isEventOverView(this, ev)
+                    && mLauncherDelegate.interceptOutsideTouch(ev, dl, this)) {
+                return true;
             }
         }
         return false;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 6b02021..279c445 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -169,14 +169,11 @@
     public static <T extends Context & ActivityContext> FolderIcon inflateFolderAndIcon(int resId,
             T activityContext, ViewGroup group, FolderInfo folderInfo) {
         Folder folder = Folder.fromXml(activityContext);
-        folder.setDragController(folder.mLauncher.getDragController());
 
         FolderIcon icon = inflateIcon(resId, activityContext, group, folderInfo);
         folder.setFolderIcon(icon);
         folder.bind(folderInfo);
         icon.setFolder(folder);
-
-        icon.setOnFocusChangeListener(folder.mLauncher.getFocusHandler());
         icon.mBackground.paddingY = icon.isInHotseat()
                 ? 0 : activityContext.getDeviceProfile().cellYPaddingPx;
         return icon;
@@ -467,7 +464,7 @@
         CharSequence newTitle = nameInfos.getLabels()[0];
         FromState fromState = mInfo.getFromLabelState();
 
-        mInfo.setTitle(newTitle, mFolder.mLauncher.getModelWriter());
+        mInfo.setTitle(newTitle, mFolder.mLauncherDelegate.getModelWriter());
         onTitleChanged(mInfo.title);
         mFolder.mFolderName.setText(mInfo.title);
 
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index a4e8be6..7fc3740 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -31,7 +31,6 @@
 import android.view.ViewDebug;
 
 import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.BaseActivity;
 import com.android.launcher3.BubbleTextView;
 import com.android.launcher3.CellLayout;
 import com.android.launcher3.DeviceProfile;
@@ -49,6 +48,7 @@
 import com.android.launcher3.touch.ItemClickHandler;
 import com.android.launcher3.util.Thunk;
 import com.android.launcher3.util.ViewCache;
+import com.android.launcher3.views.ActivityContext;
 
 import java.util.ArrayList;
 import java.util.Iterator;
@@ -102,7 +102,7 @@
         setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
 
         mFocusIndicatorHelper = new ViewGroupFocusHelper(this);
-        mViewCache = BaseActivity.fromContext(context).getViewCache();
+        mViewCache = ActivityContext.lookupContext(context).getViewCache();
     }
 
     public void setFolder(Folder folder) {
diff --git a/src/com/android/launcher3/folder/LauncherDelegate.java b/src/com/android/launcher3/folder/LauncherDelegate.java
new file mode 100644
index 0000000..f7d8e8c
--- /dev/null
+++ b/src/com/android/launcher3/folder/LauncherDelegate.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.folder;
+
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_CONVERTED_TO_ICON;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.view.MotionEvent;
+import android.view.View;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DragSource;
+import com.android.launcher3.DropTarget;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.logging.StatsLogManager.StatsLogger;
+import com.android.launcher3.model.ModelWriter;
+import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.views.BaseDragLayer.LayoutParams;
+import com.android.launcher3.widget.LocalColorExtractor;
+
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+/**
+ * Wrapper around Launcher methods to allow folders in non-launcher context
+ */
+public class LauncherDelegate {
+
+    private final Launcher mLauncher;
+    private final Rect mTempRect = new Rect();
+    private final RectF mTempRectF = new RectF();
+
+    private LauncherDelegate(Launcher launcher) {
+        mLauncher = launcher;
+    }
+
+    void init(Folder folder, FolderIcon icon) {
+        folder.setDragController(mLauncher.getDragController());
+        icon.setOnFocusChangeListener(mLauncher.getFocusHandler());
+    }
+
+    boolean isDraggingEnabled() {
+        return mLauncher.isDraggingEnabled();
+    }
+
+    void beginDragShared(View child, DragSource source, DragOptions options) {
+        mLauncher.getWorkspace().beginDragShared(child, source, options);
+    }
+
+    ModelWriter getModelWriter() {
+        return mLauncher.getModelWriter();
+    }
+
+    void forEachVisibleWorkspacePage(Consumer<View> callback) {
+        mLauncher.getWorkspace().forEachVisiblePage(callback);
+    }
+
+    @Nullable
+    Launcher getLauncher() {
+        return mLauncher;
+    }
+
+    void addRectForColorExtraction(BaseDragLayer.LayoutParams lp, LocalColorExtractor target) {
+        mTempRect.set(lp.x, lp.y, lp.x + lp.width, lp.y + lp.height);
+        target.getExtractedRectForViewRect(mLauncher,
+                mLauncher.getWorkspace().getCurrentPage(), mTempRect, mTempRectF);
+        if (!mTempRectF.isEmpty()) {
+            target.addLocation(Arrays.asList(mTempRectF));
+        }
+    }
+
+    void replaceFolderWithFinalItem(Folder folder) {
+        // Add the last remaining child to the workspace in place of the folder
+        Runnable onCompleteRunnable = new Runnable() {
+            @Override
+            public void run() {
+                int itemCount = folder.getItemCount();
+                FolderInfo info = folder.mInfo;
+                if (itemCount <= 1) {
+                    View newIcon = null;
+                    WorkspaceItemInfo finalItem = null;
+
+                    if (itemCount == 1) {
+                        // Move the item from the folder to the workspace, in the position of the
+                        // folder
+                        CellLayout cellLayout = mLauncher.getCellLayout(info.container,
+                                info.screenId);
+                        finalItem =  info.contents.remove(0);
+                        newIcon = mLauncher.createShortcut(cellLayout, finalItem);
+                        mLauncher.getModelWriter().addOrMoveItemInDatabase(finalItem,
+                                info.container, info.screenId, info.cellX, info.cellY);
+                    }
+
+                    // Remove the folder
+                    mLauncher.removeItem(folder.mFolderIcon, info, true /* deleteFromDb */);
+                    if (folder.mFolderIcon instanceof DropTarget) {
+                        folder.mDragController.removeDropTarget((DropTarget) folder.mFolderIcon);
+                    }
+
+                    if (newIcon != null) {
+                        // We add the child after removing the folder to prevent both from existing
+                        // at the same time in the CellLayout.  We need to add the new item with
+                        // addInScreenFromBind() to ensure that hotseat items are placed correctly.
+                        mLauncher.getWorkspace().addInScreenFromBind(newIcon, info);
+
+                        // Focus the newly created child
+                        newIcon.requestFocus();
+                    }
+                    if (finalItem != null) {
+                        StatsLogger logger = mLauncher.getStatsLogManager().logger()
+                                .withItemInfo(finalItem);
+                        ((Optional<InstanceId>) folder.mDragController.getLogInstanceId())
+                                .map(logger::withInstanceId)
+                                .orElse(logger)
+                                .log(LAUNCHER_FOLDER_CONVERTED_TO_ICON);
+                    }
+                }
+            }
+        };
+        View finalChild = folder.mContent.getLastItem();
+        if (finalChild != null) {
+            folder.mFolderIcon.performDestroyAnimation(onCompleteRunnable);
+        } else {
+            onCompleteRunnable.run();
+        }
+    }
+
+
+    boolean interceptOutsideTouch(MotionEvent ev, BaseDragLayer dl, Folder folder) {
+        if (mLauncher.getAccessibilityDelegate().isInAccessibleDrag()) {
+            // Do not close the container if in drag and drop.
+            if (!dl.isEventOverView(mLauncher.getDropTargetBar(), ev)) {
+                return true;
+            }
+        } else {
+            // TODO: add ww log if need to gather tap outside to close folder
+            folder.close(true);
+            return true;
+        }
+        return false;
+    }
+
+    private static class FallbackDelegate extends LauncherDelegate {
+
+        private final ActivityContext mContext;
+        private ModelWriter mWriter;
+
+        FallbackDelegate(ActivityContext context) {
+            super(null);
+            mContext = context;
+        }
+
+        @Override
+        void init(Folder folder, FolderIcon icon) {
+            folder.setDragController(mContext.getDragController());
+        }
+
+        @Override
+        boolean isDraggingEnabled() {
+            return false;
+        }
+
+        @Override
+        void beginDragShared(View child, DragSource source, DragOptions options) { }
+
+        @Override
+        ModelWriter getModelWriter() {
+            if (mWriter == null) {
+                mWriter = LauncherAppState.getInstance((Context) mContext).getModel()
+                        .getWriter(false, false);
+            }
+            return mWriter;
+        }
+
+        @Override
+        void forEachVisibleWorkspacePage(Consumer<View> callback) { }
+
+        @Override
+        Launcher getLauncher() {
+            return null;
+        }
+
+        @Override
+        void replaceFolderWithFinalItem(Folder folder) { }
+
+        @Override
+        boolean interceptOutsideTouch(MotionEvent ev, BaseDragLayer dl, Folder folder) {
+            folder.close(true);
+            return true;
+        }
+
+        @Override
+        void addRectForColorExtraction(LayoutParams lp, LocalColorExtractor target) { }
+    }
+
+    static LauncherDelegate from(ActivityContext context) {
+        return context instanceof Launcher
+                ? new LauncherDelegate((Launcher) context)
+                : new FallbackDelegate(context);
+    }
+}
diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java
index 897b02e..7e3bcee 100644
--- a/src/com/android/launcher3/model/LoaderCursor.java
+++ b/src/com/android/launcher3/model/LoaderCursor.java
@@ -52,6 +52,7 @@
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.shortcuts.ShortcutKey;
 import com.android.launcher3.util.ContentWriter;
 import com.android.launcher3.util.GridOccupancy;
 import com.android.launcher3.util.IntArray;
@@ -394,6 +395,11 @@
      * otherwise marks it for deletion.
      */
     public void checkAndAddItem(ItemInfo info, BgDataModel dataModel) {
+        if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
+            // Ensure that it is a valid intent. An exception here will
+            // cause the item loading to get skipped
+            ShortcutKey.fromItemInfo(info);
+        }
         if (checkItemPlacement(info)) {
             dataModel.addItem(mContext, info, false);
         } else {
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 03351af..73ac8f2 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -179,7 +179,7 @@
                         (int) argb.evaluate((i + 1) * step, primaryColor, secondaryColor);
             }
 
-            if (Utilities.ATLEAST_S) {
+            if (supportsColorExtraction()) {
                 setupColorExtraction();
             }
         }
@@ -676,6 +676,13 @@
     }
 
     /**
+     * Returns whether color extraction is supported.
+     */
+    public boolean supportsColorExtraction() {
+        return Utilities.ATLEAST_S;
+    }
+
+    /**
      * Callback to be called when the popup is closed
      */
     public void setOnCloseCallback(@NonNull Runnable callback) {
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 3296ea5..4012e89 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -109,10 +109,6 @@
     public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
 
     public static final String PERMANENT_DIAG_TAG = "TaplTarget";
-    public static final String LAUNCHER_NOT_TRANSPOSED = "b/185820525";
-    public static final String NO_SWIPE_TO_HOME = "b/158017601";
     public static final String WORK_PROFILE_REMOVED = "b/159671700";
-    public static final String TIS_NO_EVENTS = "b/180915942";
-    public static final String GET_RECENTS_FAILED = "b/177472267";
-    public static final String TWO_BUTTON_NORMAL_NOT_OVERVIEW = "b/177316094";
+    public static final String FALLBACK_ACTIVITY_NO_SET = "b/181019015";
 }
diff --git a/src/com/android/launcher3/util/UiThreadHelper.java b/src/com/android/launcher3/util/UiThreadHelper.java
index f5e1234..523f3d6 100644
--- a/src/com/android/launcher3/util/UiThreadHelper.java
+++ b/src/com/android/launcher3/util/UiThreadHelper.java
@@ -23,11 +23,12 @@
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Message;
+import android.view.View;
 import android.view.WindowInsets;
 import android.view.inputmethod.InputMethodManager;
 
-import com.android.launcher3.Launcher;
 import com.android.launcher3.Utilities;
+import com.android.launcher3.views.ActivityContext;
 
 /**
  * Utility class for offloading some class from UI thread
@@ -43,21 +44,21 @@
     private static final int MSG_RUN_COMMAND = 3;
 
     @SuppressLint("NewApi")
-    public static void hideKeyboardAsync(Launcher launcher, IBinder token) {
+    public static void hideKeyboardAsync(ActivityContext activityContext, IBinder token) {
+        View root = activityContext.getDragLayer();
         if (Utilities.ATLEAST_R) {
-            WindowInsets rootInsets = launcher.getRootView().getRootWindowInsets();
+            WindowInsets rootInsets = root.getRootWindowInsets();
             boolean isImeShown = rootInsets != null && rootInsets.isVisible(
                     WindowInsets.Type.ime());
             if (isImeShown) {
                 // this call is already asynchronous
-                launcher.getAppsView().getWindowInsetsController().hide(
-                        WindowInsets.Type.ime()
-                );
+                root.getWindowInsetsController().hide(WindowInsets.Type.ime());
             }
             return;
         }
 
-        Message.obtain(HANDLER.get(launcher), MSG_HIDE_KEYBOARD, token).sendToTarget();
+        Message.obtain(HANDLER.get(root.getContext()),
+                MSG_HIDE_KEYBOARD, token).sendToTarget();
     }
 
     public static void setOrientationAsync(Activity activity, int orientation) {
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index 71aa4ac..646b669 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -23,7 +23,9 @@
 
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.dot.DotInfo;
+import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.ViewCache;
 
 /**
  * An interface to be used along with a context for various activities in Launcher. This allows a
@@ -86,6 +88,17 @@
 
     DeviceProfile getDeviceProfile();
 
+    default ViewCache getViewCache() {
+        return new ViewCache();
+    }
+
+    /**
+     * Controller for supporting item drag-and-drop
+     */
+    default <T extends DragController> T getDragController() {
+        return null;
+    }
+
     /**
      * Returns the ActivityContext associated with the given Context.
      */
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 2a0f7bb..8936f39 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -249,6 +249,7 @@
 
     @Before
     public void setUp() throws Exception {
+        mLauncher.onTestStart();
         Assert.assertTrue("Keyguard is visible, which is likely caused by a crash in SysUI",
                 TestHelpers.wait(
                         Until.gone(By.res(SYSTEMUI_PACKAGE, "keyguard_status_view")), 60000));
@@ -288,13 +289,17 @@
 
     @After
     public void verifyLauncherState() {
-        // Limits UI tests affecting tests running after them.
-        mLauncher.waitForLauncherInitialized();
-        if (mLauncherPid != 0) {
-            assertEquals("Launcher crashed, pid mismatch:",
-                    mLauncherPid, mLauncher.getPid().intValue());
+        try {
+            // Limits UI tests affecting tests running after them.
+            mLauncher.waitForLauncherInitialized();
+            if (mLauncherPid != 0) {
+                assertEquals("Launcher crashed, pid mismatch:",
+                        mLauncherPid, mLauncher.getPid().intValue());
+            }
+            checkDetectedLeaks(mLauncher);
+        } finally {
+            mLauncher.onTestFinish();
         }
-        checkDetectedLeaks(mLauncher);
     }
 
     protected void clearLauncherData() {
diff --git a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index 6c68daa..8f2d528 100644
--- a/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -55,23 +55,19 @@
             }
 
             private void evaluateInPortrait() throws Throwable {
-                Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED, "evaluateInPortrait");
                 mTest.mDevice.setOrientationNatural();
                 mTest.mLauncher.setExpectedRotation(Surface.ROTATION_0);
                 AbstractLauncherUiTest.checkDetectedLeaks(mTest.mLauncher);
                 base.evaluate();
                 mTest.getDevice().pressHome();
-                Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED, "evaluateInPortrait finished");
             }
 
             private void evaluateInLandscape() throws Throwable {
-                Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED, "evaluateInLandscape");
                 mTest.mDevice.setOrientationLeft();
                 mTest.mLauncher.setExpectedRotation(Surface.ROTATION_90);
                 AbstractLauncherUiTest.checkDetectedLeaks(mTest.mLauncher);
                 base.evaluate();
                 mTest.getDevice().pressHome();
-                Log.d(TestProtocol.LAUNCHER_NOT_TRANSPOSED, "evaluateInLandscape finished");
             }
         };
     }
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index e5b93b1..c77583c 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -95,7 +95,6 @@
     private static final String TAG = "Tapl";
     private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 20;
     private static final int GESTURE_STEP_MS = 16;
-    private static long START_TIME = System.currentTimeMillis();
 
     private static final Pattern EVENT_TOUCH_DOWN = getTouchEventPattern("ACTION_DOWN");
     private static final Pattern EVENT_TOUCH_UP = getTouchEventPattern("ACTION_UP");
@@ -107,6 +106,7 @@
     static final Pattern EVENT_TOUCH_UP_TIS = getTouchEventPatternTIS("ACTION_UP");
     private final String mLauncherPackage;
     private final boolean mIsLauncher3;
+    private long mTestStartTime = -1;
 
     // Types for launcher containers that the user is interacting with. "Background" is a
     // pseudo-container corresponding to inactive launcher covered by another app.
@@ -422,6 +422,14 @@
         mOnSettledStateAction = onSettledStateAction;
     }
 
+    public void onTestStart() {
+        mTestStartTime = System.currentTimeMillis();
+    }
+
+    public void onTestFinish() {
+        mTestStartTime = -1;
+    }
+
     private String formatSystemHealthMessage(String message) {
         final String testPackage = getContext().getPackageName();
 
@@ -430,14 +438,16 @@
         mInstrumentation.getUiAutomation().grantRuntimePermission(
                 testPackage, "android.permission.PACKAGE_USAGE_STATS");
 
-        final String systemHealth = mSystemHealthSupplier != null
-                ? mSystemHealthSupplier.apply(START_TIME)
-                : TestHelpers.getSystemHealthMessage(getContext(), START_TIME);
+        if (mTestStartTime > 0) {
+            final String systemHealth = mSystemHealthSupplier != null
+                    ? mSystemHealthSupplier.apply(mTestStartTime)
+                    : TestHelpers.getSystemHealthMessage(getContext(), mTestStartTime);
 
-        if (systemHealth != null) {
-            return message
-                    + ",\nperhaps linked to system health problems:\n<<<<<<<<<<<<<<<<<<\n"
-                    + systemHealth + "\n>>>>>>>>>>>>>>>>>>";
+            if (systemHealth != null) {
+                return message
+                        + ",\nperhaps linked to system health problems:\n<<<<<<<<<<<<<<<<<<\n"
+                        + systemHealth + "\n>>>>>>>>>>>>>>>>>>";
+            }
         }
 
         return message;
@@ -1349,6 +1359,8 @@
     }
 
     public int getTotalPssKb() {
+        // GC the system & sysui first before gc'ing launcher
+        logShellCommand("cmd statusbar run-gc");
         return getTestInfo(TestProtocol.REQUEST_TOTAL_PSS_KB).
                 getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }