Merge "Fix animation problem when swipeing up app to screen edge and release" into sc-v2-dev
diff --git a/Android.bp b/Android.bp
index 45d022f..43d28c9 100644
--- a/Android.bp
+++ b/Android.bp
@@ -224,7 +224,6 @@
     srcs: ["proguard.flags"],
 }
 
-
 // Library with all the dependencies for building Launcher Go
 android_library {
     name: "LauncherGoResLib",
@@ -253,3 +252,24 @@
     },
 }
 
+// Build rule for Quickstep library
+android_library {
+    name: "Launcher3QuickStepLib",
+    srcs: [
+        ":launcher-src-no-build-config",
+    ],
+    resource_dirs: [
+        "quickstep/res",
+    ],
+    static_libs: [
+        "SystemUI-statsd",
+        "SystemUISharedLib",
+        "Launcher3CommonDepsLib"
+    ],
+    manifest: "quickstep/AndroidManifest.xml",
+    platform_apis: true,
+    min_sdk_version: "current",
+    lint: {
+        baseline_filename: "lint-baseline-launcher3.xml",
+    },
+}
diff --git a/Android.mk b/Android.mk
index c222f24..c1dbc53 100644
--- a/Android.mk
+++ b/Android.mk
@@ -53,42 +53,6 @@
 include $(BUILD_PACKAGE)
 
 #
-# Build rule for Quickstep library.
-#
-include $(CLEAR_VARS)
-LOCAL_USE_AAPT2 := true
-LOCAL_AAPT2_ONLY := true
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    SystemUI-statsd \
-    SystemUISharedLib
-ifneq (,$(wildcard frameworks/base))
-  LOCAL_PRIVATE_PLATFORM_APIS := true
-else
-  LOCAL_SDK_VERSION := system_current
-  LOCAL_MIN_SDK_VERSION := 26
-endif
-LOCAL_MODULE := Launcher3QuickStepLib
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/NOTICE
-LOCAL_PRIVILEGED_MODULE := true
-LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
-
-LOCAL_SRC_FILES := \
-    $(call all-java-files-under, src) \
-    $(call all-java-files-under, quickstep/src) \
-    $(call all-java-files-under, src_shortcuts_overrides)
-
-LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/quickstep/res
-LOCAL_PROGUARD_ENABLED := disabled
-
-
-LOCAL_MANIFEST_FILE := quickstep/AndroidManifest.xml
-include $(BUILD_STATIC_JAVA_LIBRARY)
-
-#
 # Build rule for Quickstep app.
 #
 include $(CLEAR_VARS)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 8066816..c72f62d 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -31,6 +31,7 @@
         android:fullBackupOnly="true"
         android:fullBackupContent="@xml/backupscheme"
         android:hardwareAccelerated="true"
+        android:debuggable="true"
         android:icon="@drawable/ic_launcher_home"
         android:label="@string/derived_app_name"
         android:theme="@style/AppTheme"
diff --git a/quickstep/Android.bp b/quickstep/Android.bp
index 38c9919..7b3e6c4 100644
--- a/quickstep/Android.bp
+++ b/quickstep/Android.bp
@@ -26,3 +26,19 @@
     path: "robolectric_tests",
     srcs: ["robolectric_tests/src/**/*.java"],
 }
+
+filegroup {
+    name: "launcher3-quickstep-tests-src",
+    path: "tests",
+    srcs: ["tests/src/**/*.java"],
+}
+
+filegroup {
+    name: "launcher3-quickstep-oop-tests-src",
+    path: "tests",
+    srcs: [
+        "tests/src/com/android/quickstep/NavigationModeSwitchRule.java",
+        "tests/src/com/android/quickstep/AbstractQuickStepTest.java",
+        "tests/src/com/android/quickstep/TaplTestsQuickstep.java",
+    ]
+}
diff --git a/quickstep/res/interpolator/app_open_x.xml b/quickstep/res/interpolator/app_open_x.xml
new file mode 100644
index 0000000..5fa0bcb
--- /dev/null
+++ b/quickstep/res/interpolator/app_open_x.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0, 0 C 0.1217, 0.0462, 0.15, 0.4686, 0.1667, 0.66 C 0.1834, 0.8878, 0.1667, 1, 1, 1"/>
diff --git a/quickstep/res/interpolator/three_point_fast_out_extra_slow_in.xml b/quickstep/res/interpolator/three_point_fast_out_extra_slow_in.xml
new file mode 100644
index 0000000..70c4231
--- /dev/null
+++ b/quickstep/res/interpolator/three_point_fast_out_extra_slow_in.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 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.
+*/
+-->
+
+<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"
+    android:pathData="M 0,0 C 0.05, 0, 0.133333, 0.06, 0.166666, 0.4 C 0.208333, 0.82, 0.25, 1, 1, 1"/>
diff --git a/quickstep/res/layout/taskbar.xml b/quickstep/res/layout/taskbar.xml
index c0e0862..b4c168c 100644
--- a/quickstep/res/layout/taskbar.xml
+++ b/quickstep/res/layout/taskbar.xml
@@ -65,13 +65,12 @@
             android:layout_gravity="end"/>
     </FrameLayout>
 
-    <View
+    <com.android.launcher3.taskbar.StashedHandleView
         android:id="@+id/stashed_handle"
         tools:comment1="The actual size and shape will be set as a ViewOutlineProvider at runtime"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        tools:comment2="TODO: Tint dynamically"
-        android:background="?android:attr/textColorPrimary"
+        android:background="@color/taskbar_stashed_handle_dark_color"
         android:clipToOutline="true"
         android:layout_gravity="bottom"/>
 
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 433ef86..4a83a4b 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Jy kan dit later in die <xliff:g id="NAME">%1$s</xliff:g>-program kry"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Kanselleer"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Slaan oor"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Gebruik 2 programme tegelyk en wissel programme met die taakbalk"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Volgende"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Maak toe"</string>
 </resources>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 838dd60..4bb9c15 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ይህን በኋላ በ<xliff:g id="NAME">%1$s</xliff:g> መተግበሪያው ውስጥ ማግኘት ይችላሉ"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ይቅር"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ዝለል"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"በአንድ ጊዜ 2 መተግበሪያዎችን ይጠቀሙ እና በተግባር አሞሌው አማካኝነት መተግበሪያዎችን ይቀያይሩ"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"ቀጣይ"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"ዝጋ"</string>
 </resources>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 3f26977..6557abb 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"يمكنك العثور على هذا الدليل التوجيهي لاحقًا في التطبيق \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"إلغاء"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"التخطي"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"يمكنك استخدام تطبيقين في الوقت نفسه والتبديل بينهما من شريط المهام."</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"الشاشة التالية"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"إغلاق"</string>
 </resources>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 2551fc4..a506618 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"আপুনি এয়া পাছত <xliff:g id="NAME">%1$s</xliff:g> এপ্‌টোত বিচাৰিব পাৰিব"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"বাতিল কৰক"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"এৰি যাওক"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"এবাৰতে ২ টা এপ্‌ ব্যৱহাৰ কৰক আৰু টাস্কবাৰ ব্যৱহাৰ কৰি এপ্‌ সলনি কৰক"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"পৰৱৰ্তী"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"বন্ধ কৰক"</string>
 </resources>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index d01bf3f..ba235f4 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Bunu sonra <xliff:g id="NAME">%1$s</xliff:g> tətbiqində tapa bilərsiniz"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Ləğv edin"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ötürün"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Eyni anda 2 tətbiqdən istifadə edin və tapşırıq paneli ilə tətbiqlər arasında keçid edin"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Sonra"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Bağlayın"</string>
 </resources>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index bde409f..5001491 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Možete da pronađete ovo kasnije u aplikaciji <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Otkaži"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Koristite 2 aplikacije odjednom i menjajte aplikacije pomoću trake zadataka"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Dalje"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
 </resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 8e57bd8..1662423 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Знайсці дапаможнік можна ў праграме \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Скасаваць"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Прапусціць"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Адначасова выкарыстоўвайце 2 праграмы і пераключайцеся паміж імі на панэлі задач"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Далей"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Закрыць"</string>
 </resources>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 7305d9d..7712020 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Урокът е налице в приложението <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Отказ"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Пропускане"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Използвайте две приложения едновременно и превключвайте между приложенията посредством лентата на задачите"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Напред"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Затваряне"</string>
 </resources>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 1d0b45f..83f6656 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -84,4 +84,10 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"আপনি <xliff:g id="NAME">%1$s</xliff:g> অ্যাপে পরে এটি খুঁজে পাবেন"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"বাতিল করুন"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"এড়িয়ে যান"</string>
+    <!-- no translation found for taskbar_edu_header_1 (5323217563328273689) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_next (4007618274426775841) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_close (887022990168191073) -->
+    <skip />
 </resources>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index acd7b10..eba8275 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"To možete pronaći kasnije u aplikaciji <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Otkaži"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Koristite 2 aplikacije odjednom i prebacujte između aplikacija putem programske trake"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Naprijed"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
 </resources>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index a0d6aee..62d1ed0 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Pots trobar-lo més tard a l\'aplicació <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel·la"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omet"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Utilitza 2 aplicacions alhora i canvia d\'aplicació amb la barra de tasques"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Següent"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Tanca"</string>
 </resources>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index b2d092e..c4e632c 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Program později najdete v aplikaci <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Zrušit"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Přeskočit"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Používejte 2 aplikace naráz a přepínejte mezi aplikacemi pomocí hlavního panelu"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Další"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Zavřít"</string>
 </resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index f2e2df0..ed63f40 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du kan finde dette senere i appen <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuller"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Spring over"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Brug to apps på samme tid, og skift mellem dem via proceslinjen"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Næste"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Luk"</string>
 </resources>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 4a023e3..0ff759e 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du findest es später auch in der <xliff:g id="NAME">%1$s</xliff:g> App"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Abbrechen"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Überspringen"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Du kannst 2 Apps auf einmal verwenden und über die Taskleiste zwischen ihnen wechseln"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Weiter"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Schließen"</string>
 </resources>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 7243e03..1c5e24a 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Βρείτε τον αργότερα στην εφαρμογή <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Ακύρωση"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Παράβλεψη"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Χρησιμοποιήστε 2 εφαρμογές ταυτόχρονα και κάντε εναλλαγή εφαρμογών με τη γραμμή εργασιών"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Επόμενο"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Κλείσιμο"</string>
 </resources>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index 7b42aac..c045bcd 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Use two apps at once and switch apps with the taskbar"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
 </resources>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 7b42aac..c045bcd 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Use two apps at once and switch apps with the taskbar"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
 </resources>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index 7b42aac..c045bcd 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Use two apps at once and switch apps with the taskbar"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
 </resources>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index 7b42aac..c045bcd 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Use two apps at once and switch apps with the taskbar"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Next"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Close"</string>
 </resources>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index 35ec6bb..1550285 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‏‏‏‎‎‎‏‏‎‎‏‏‏‎‎‏‏‎‏‎‏‏‎‏‏‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‎‎‎‎‏‏‏‏‏‎‏‎‎‏‏‏‎‎You can find this later in the ‎‏‎‎‏‏‎<xliff:g id="NAME">%1$s</xliff:g>‎‏‎‎‏‏‏‎ app‎‏‎‎‏‎"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‎‎‏‏‎‏‏‏‏‏‎‏‎‎‎‏‏‏‏‎‏‎‎‎‎‏‏‎‏‎‎‏‎‎‎‏‎‏‎‏‏‏‏‏‏‏‎‏‏‏‎‏‏‎‏‏‎‎‎Cancel‎‏‎‎‏‎"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‎‏‏‏‎‏‎‏‏‏‏‎‎‏‎‏‏‎‎‎‎‎‏‎‏‏‎‎‏‏‎‎‏‎‏‎‎‏‏‏‏‎‎‎‏‎‏‎‎‎‎‎‏‎‏‎‎‏‏‎‎‎‎Skip‎‏‎‎‏‎"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‏‏‎‎‏‎‎‏‏‏‎‏‏‏‏‏‏‏‎‏‏‏‏‎‎‎‏‎‏‎‏‏‏‎‎‏‎‏‎‎‎‏‎‎‏‏‎‏‎‏‎‏‏‏‎‏‎‎‎‏‏‎‎‏‎Use 2 apps at once and switch apps with the taskbar‎‏‎‎‏‎"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‏‎‏‏‎‏‏‏‏‎‎‏‏‏‎‏‏‏‏‎‏‎‏‏‏‎‎‏‎‏‏‎‎‏‎‏‏‎‏‎‏‎‎‏‎‎‏‎‎‏‏‎‏‎‎‏‎‎‏‎‎‎‎‏‎Next‎‏‎‎‏‎"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"‎‏‎‎‎‎‎‏‎‏‏‏‎‎‎‎‎‎‏‎‎‎‏‏‎‏‏‏‏‏‏‎‎‏‏‎‎‎‏‎‎‏‏‏‏‎‏‎‏‎‏‏‎‏‎‏‏‎‏‎‏‏‎‏‏‏‏‎‎‏‎‎‏‎‏‎‎‎‏‏‏‎‎‎‎‎‏‏‎‎‎‎‏‎Close‎‏‎‎‏‎"</string>
 </resources>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index e61fd91..02f6ea6 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Puedes encontrarlo en la app de <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omitir"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Usa 2 apps a la vez e intercámbialas con la barra de tareas"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Siguiente"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Cerrar"</string>
 </resources>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 8e8829e..b4fee8b 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Puedes consultarlo en otro momento en la aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Saltar"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Usa dos aplicaciones a la vez y cambia de aplicación con la barra de tareas"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Siguiente"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Cerrar"</string>
 </resources>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 74b7528..9f8737c 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Leiate selle hiljem rakendusest <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Tühista"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Jäta vahele"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Tegumiribal kahe rakenduse korraga kasutamine ja rakenduste vahel vahetamine"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Järgmine"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Sule"</string>
 </resources>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index bd016e9..e4186a4 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioan dago eskuragarri tutoriala"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Utzi"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Saltatu"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Erabili bi aplikazio aldi berean eta aldatu aplikazioz zereginen barra erabilita"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Hurrengoa"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Itxi"</string>
 </resources>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index ae260ed..0a27952 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"می‌توانید آن را بعداً در برنامه <xliff:g id="NAME">%1$s</xliff:g> پیدا کنید"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"لغو"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"رد شدن"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"هم‌زمان از ۲ برنامه استفاده کنید و ازطریق نوار وظیفه بین برنامه‌ها جابه‌جا شوید"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"بعدی"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"بستن"</string>
 </resources>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 8762feb..fc19646 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Löydät tämän myöhemmin sovelluksesta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Peru"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ohita"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Voit käyttää kahta sovellusta samaan aikaan ja vaihtaa sovelluksesta toiseen tehtäväpalkin kautta"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Seuraava"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Sulje"</string>
 </resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index a3c9393..cb1eff6 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -84,4 +84,10 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Vous trouverez le tutoriel dans l\'application <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuler"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ignorer"</string>
+    <!-- no translation found for taskbar_edu_header_1 (5323217563328273689) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_next (4007618274426775841) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_close (887022990168191073) -->
+    <skip />
 </resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 5164792..67106b8 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Vous le retrouverez dans l\'appli <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuler"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Passer"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Utilisez deux applis à la fois et changez d\'appli avec la barre des tâches"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Suivant"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Fermer"</string>
 </resources>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index baa87e7..8600412 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Podes atopar isto máis tarde na aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omitir"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Usa dúas aplicacións á vez e alterna unha coa outra mediante a barra de ferramentas"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Seguinte"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Pechar"</string>
 </resources>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 33e8617..cf5e464 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -84,4 +84,10 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"તમે આને પછીથી <xliff:g id="NAME">%1$s</xliff:g> ઍપમાં જોઈ શકો છો"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"રદ કરો"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"છોડો"</string>
+    <!-- no translation found for taskbar_edu_header_1 (5323217563328273689) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_next (4007618274426775841) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_close (887022990168191073) -->
+    <skip />
 </resources>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 50ebb27..2c7a5ac 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"आप बाद में <xliff:g id="NAME">%1$s</xliff:g> ऐप्लिकेशन पर इसे देख सकते हैं"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"अभी नहीं"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"अभी नहीं"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"एक साथ दो ऐप्लिकेशन इस्तेमाल करें और टास्कबार से एक से दूसरे ऐप्लिकेशन पर जाएं"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"आगे बढ़ें"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"बंद करें"</string>
 </resources>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index 50efb74..b8d4e4f 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Kasnije ga možete pronaći u aplikaciji <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Odustani"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Upotrebljavajte dvije aplikacije odjednom i prebacujte se između aplikacija i programske trake"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Dalje"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Zatvori"</string>
 </resources>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index e9bd2bf..429b364 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Ezt később megtalálhatja a(z) <xliff:g id="NAME">%1$s</xliff:g> alkalmazásban"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Mégse"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Kihagyás"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Két alkalmazást használhat egyszerre, és az eszköztárral válthat az alkalmazások között"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Tovább"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Bezárás"</string>
 </resources>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index e2c0af3..0a18ae9 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Հետագայում սա կարող եք գտնել «<xliff:g id="NAME">%1$s</xliff:g>» հավելվածում"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Չեղարկել"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Բաց թողնել"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Միաժամանակ օգտագործեք 2 հավելված և խնդրագոտու միջոցով անցեք մեկից մյուսը։"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Առաջ"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Փակել"</string>
 </resources>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 3e24fcb..8ef7355 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Anda dapat menemukan tutorial ini di lain waktu di aplikasi <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Batal"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Lewati"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Gunakan 2 aplikasi sekaligus dan beralihlah antar-aplikasi dengan taskbar"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Berikutnya"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Tutup"</string>
 </resources>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index eeebc71..5bcc545 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Þú getur fundið þetta síðar í forritinu <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Hætta við"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Sleppa"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Notaðu 2 forrit í einu og skiptu á milli forrita á verkefnastikunni"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Áfram"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Loka"</string>
 </resources>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 5a33a38..5633381 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Puoi trovarlo in un secondo momento nell\'app <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annulla"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Salta"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Usa 2 app contemporaneamente e passa dall\'una all\'altra tramite la barra delle applicazioni"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Avanti"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Chiudi"</string>
 </resources>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 2677690..e687d88 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -84,4 +84,10 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ניתן למצוא את המדריך מאוחר יותר באפליקציה <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ביטול"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"דילוג"</string>
+    <!-- no translation found for taskbar_edu_header_1 (5323217563328273689) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_next (4007618274426775841) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_close (887022990168191073) -->
+    <skip />
 </resources>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 9c2adef..a0b25a9 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"チュートリアルは後から <xliff:g id="NAME">%1$s</xliff:g> アプリで確認できます"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"キャンセル"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"スキップ"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"2 つのアプリを同時に使用し、タスクバーでアプリを切り替えます"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"次へ"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"閉じる"</string>
 </resources>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index ab3715a..fec33cf 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ამის მოგვიანებით პოვნა <xliff:g id="NAME">%1$s</xliff:g> აპში შეგიძლიათ"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"გაუქმება"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"გამოტოვება"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"გამოიყენეთ ერთდროულად 2 აპი და გადართეთ აპები ამოცანების ზოლის მეშვეობით"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"შემდეგი"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"დახურვა"</string>
 </resources>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index d762bd8..dd337fc 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Мұны кейін <xliff:g id="NAME">%1$s</xliff:g> қолданбасынан таба аласыз."</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Бас тарту"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Өткізіп жіберу"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"2 қолданбаны қатар қолданыңыз және оларды тапсырмалар тақтасы арқылы ауыстырыңыз."</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Келесі"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Жабу"</string>
 </resources>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 2700b83..9f90d06 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"អ្នកអាចស្វែងរកមេរៀននេះនៅពេលក្រោយក្នុងកម្មវិធី <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"បោះបង់"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"រំលង"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"ប្រើ​កម្មវិធី 2 ក្នុងពេលតែមួយ ហើយប្ដូរ​កម្មវិធី​ដោយប្រើ​របារ​កិច្ចការ"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"បន្ទាប់"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"បិទ"</string>
 </resources>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 9b981c2..1a83864 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -84,4 +84,10 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> ಆ್ಯಪ್‌ನಲ್ಲಿ ಇದನ್ನು ನಂತರ ಕಾಣಬಹುದು"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ರದ್ದುಮಾಡಿ"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ಸ್ಕಿಪ್ ಮಾಡಿ"</string>
+    <!-- no translation found for taskbar_edu_header_1 (5323217563328273689) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_next (4007618274426775841) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_close (887022990168191073) -->
+    <skip />
 </resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index ba564a7..e5341f4 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"이 튜토리얼은 <xliff:g id="NAME">%1$s</xliff:g> 앱에서 다시 볼 수 있습니다"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"취소"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"건너뛰기"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"작업 표시줄을 통해 앱 2개를 동시에 사용하고 앱 간에 전환"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"다음"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"닫기"</string>
 </resources>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 8be5c53..b2e2ec2 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Аны кийин <xliff:g id="NAME">%1$s</xliff:g> колдонмосунан табасыз"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Жокко чыгаруу"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Өткрп жиберүү"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Бир убакта 2 колдонмону пайдаланып, колдонмолорду тапшырмалар тактасы аркылуу которуштуруу"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Кийинки"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Жабуу"</string>
 </resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 915578b..699cafa 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ທ່ານສາມາດຊອກສ່ວນນີ້ພາຍຫຼັງໄດ້ໃນແອັບ <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ຍົກເລີກ"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ຂ້າມ"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"ໃຊ້ 2 ແອັບພ້ອມກັບ ແລະ ສະຫຼັບແອັບດ້ວຍແຖບໜ້າວຽກ"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"ຕໍ່ໄປ"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"ປິດ"</string>
 </resources>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index b0c679c..f8c7bc7 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Tai galėsite rasti vėliau programoje „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Atšaukti"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Praleisti"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Užduočių juostoje vienu metu naudokite dvi programas ir jas perjunkite"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Kitas"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Uždaryti"</string>
 </resources>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index df1c3e9..0e44d77 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Varēsiet to vēlāk atrast lietotnē <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Atcelt"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Izlaist"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Varat izmantot divas lietotnes reizē un pāriet no vienas uz otru, izmantojot rīkjoslu"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Tālāk"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Aizvērt"</string>
 </resources>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 98307da..b3e08f5 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Ова може да го најдете подоцна во апликацијата <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Откажи"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Прескокни"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Користете 2 апликации одеднаш и префрлувајте се меѓу нив со лентата за задачи"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Следна"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
 </resources>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 52be3ac..9291259 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> ആപ്പിൽ നിങ്ങൾക്ക് ഇത് പിന്നീട് കാണാനാകും"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"റദ്ദാക്കുക"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ഒഴിവാക്കുക"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"ടാസ്‌ക്‌ബാറിന്റെ സഹായത്തോടെ ഒരേ സമയം 2 ആപ്പുകൾ ഉപയോഗിക്കുകയും ആപ്പുകൾ പരസ്പരം മാറുകയും ചെയ്യൂ"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"അടുത്തത്"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"അടയ്ക്കുക"</string>
 </resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 79fbca6..65023d6 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Та үүнийг дараа нь <xliff:g id="NAME">%1$s</xliff:g> аппаас олох боломжтой"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Цуцлах"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Алгасах"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"2 аппыг нэг дор ашиглан талбарын тусламжтайгаар аппуудыг сэлгэнэ үү"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Дараах"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Хаах"</string>
 </resources>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 8618f85..40c88a4 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -84,4 +84,10 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"तुम्हाला हे नंतर <xliff:g id="NAME">%1$s</xliff:g> ॲपमध्ये मिळेल"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"रद्द करा"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"वगळा"</string>
+    <!-- no translation found for taskbar_edu_header_1 (5323217563328273689) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_next (4007618274426775841) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_close (887022990168191073) -->
+    <skip />
 </resources>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 1e2d43d..886f3b6 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Anda boleh mendapatkan tutorial ini kemudian dalam apl <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Batal"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Langkau"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Gunakan 2 apl pada satu masa dan tukar apl dengan bar tugas"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Seterusnya"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Tutup"</string>
 </resources>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index b07bbfa..0d38c84 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"၎င်းကို နောက်မှ <xliff:g id="NAME">%1$s</xliff:g> အက်ပ်တွင် ရှာနိုင်သည်"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"မလုပ်တော့"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ကျော်ရန်"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"အက်ပ် ၂ ခုကို တစ်ပြိုင်ထဲသုံးပြီး လုပ်ဆောင်စရာဘားဖြင့် အက်ပ်များပြောင်းလိုက်ပါ"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"ရှေ့သို့"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"ပိတ်ရန်"</string>
 </resources>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 16988c5..8ad72cd 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du kan finne dette i <xliff:g id="NAME">%1$s</xliff:g>-appen senere"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Avbryt"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Hopp over"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Bruk to apper samtidig og bytt app med oppgavelinjen"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Neste"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Lukk"</string>
 </resources>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 91cae47..89ef427 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -84,4 +84,10 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"तपाईं पछि <xliff:g id="NAME">%1$s</xliff:g> नामक एपमा गई यो ट्युटोरियल भेट्टाउन सक्नुहुन्छ"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"रद्द गर्नुहोस्"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"स्किप गर्नु…"</string>
+    <!-- no translation found for taskbar_edu_header_1 (5323217563328273689) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_next (4007618274426775841) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_close (887022990168191073) -->
+    <skip />
 </resources>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 96da966..faed85b 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Je vindt dit later terug in de app <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuleren"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Overslaan"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Gebruik 2 apps tegelijk en schakel tussen apps via de taakbalk"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Volgende"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Sluiten"</string>
 </resources>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 9488021..b6281c3 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -84,4 +84,10 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ଆପଣ ପରେ ଏହାକୁ <xliff:g id="NAME">%1$s</xliff:g> ଆପରେ ପାଇପାରିବେ"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ବାତିଲ୍ କରନ୍ତୁ"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ବାଦ୍ ଦିଅନ୍ତୁ"</string>
+    <!-- no translation found for taskbar_edu_header_1 (5323217563328273689) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_next (4007618274426775841) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_close (887022990168191073) -->
+    <skip />
 </resources>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 89b2119..bdfc867 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -84,4 +84,10 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ਤੁਸੀਂ ਇਸਨੂੰ ਬਾਅਦ ਵਿੱਚ <xliff:g id="NAME">%1$s</xliff:g> ਐਪ ਵਿੱਚ ਲੱਭ ਸਕਦੇ ਹੋ"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ਰੱਦ ਕਰੋ"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ਛੱਡੋ"</string>
+    <!-- no translation found for taskbar_edu_header_1 (5323217563328273689) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_next (4007618274426775841) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_close (887022990168191073) -->
+    <skip />
 </resources>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 893db91..57c9e4c 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Znajdziesz to później w aplikacji <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Anuluj"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Pomiń"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Używaj 2 aplikacji jednocześnie i przełączaj je za pomocą paska zadań"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Dalej"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Zamknij"</string>
 </resources>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index c1cd2bb..40bb8a1 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Pode encontrar isto mais tarde na app <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ignorar"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Utilize 2 apps em simultâneo e alterne entre as apps com a barra de tarefas"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Seguinte"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Fechar"</string>
 </resources>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 422d13a..144bbf6 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Veja o tutorial mais tarde no app <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Pular"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Use dois apps ao mesmo tempo e alterne entre eles usando a barra de tarefas"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Próxima"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Fechar"</string>
 </resources>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index a5e97e0..2231522 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Îl puteți găsi mai târziu în aplicația <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Anulați"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omiteți"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Folosiți două aplicații simultan și comutați între aplicații folosind bara de activități"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Înainte"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Închideți"</string>
 </resources>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 7c4d485..9087da9 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Его можно найти в приложении \"<xliff:g id="NAME">%1$s</xliff:g>\"."</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Отмена"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Пропустить"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Пользуйтесь двумя приложениями одновременно и переключайтесь между ними с помощью панели задач"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Далее"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Закрыть"</string>
 </resources>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 5f322e6..b3d88c0 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ඔබට මෙය පසුව <xliff:g id="NAME">%1$s</xliff:g> යෙදුම තුළ සොයා ගත හැකිය"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"අවලංගු කරන්න"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"මඟ හරින්න"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"එකවර යෙදුම් 2ක් භාවිත කර කාර්ය තීරුව සමඟින් යෙදුම් මාරු කරන්න"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"ඊළඟ"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"වසන්න"</string>
 </resources>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 799e941..0b0082c 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Tento návod nájdete v aplikácii <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Zrušiť"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskočiť"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Používajte dve aplikácie naraz a prepínajte ich pomocou panela úloh"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Ďalej"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Zavrieť"</string>
 </resources>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 7e40277..a2b1363 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"To lahko pozneje najdete v aplikaciji <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Prekliči"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Sočasno uporabite dve aplikaciji in preklopite med njima z orodno vrstico."</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Naprej"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Zapri"</string>
 </resources>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 86528d2..f259f3c 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -84,4 +84,10 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Këtë mund ta gjesh më vonë tek aplikacioni <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Anulo"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Kapërce"</string>
+    <!-- no translation found for taskbar_edu_header_1 (5323217563328273689) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_next (4007618274426775841) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_close (887022990168191073) -->
+    <skip />
 </resources>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index f2ffa0a..0d6d4d6 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Можете да пронађете ово касније у апликацији <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Откажи"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Прескочи"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Користите 2 апликације одједном и мењајте апликације помоћу траке задатака"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Даље"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Затвори"</string>
 </resources>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 931e458..acb8014 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du hittar det här igen i <xliff:g id="NAME">%1$s</xliff:g>-appen"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Avbryt"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Hoppa över"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Använd två appar samtidigt och byt mellan appar via aktivitetsfältet"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Nästa"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Stäng"</string>
 </resources>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 22aa3ef..f49ef9b 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Utapata mafunzo haya baadaye katika programu ya <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Ghairi"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ruka"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Tumia programu mbili kwa wakati mmoja na ubadilishe programu ukitumia upau wa shughuli"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Endelea"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Funga"</string>
 </resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index de7c26d..321555f 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> ஆப்ஸில் பிறகு இதைக் கண்டறியலாம்"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ரத்துசெய்"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"தவிர்"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"ஒரே நேரத்தில் 2 ஆப்ஸைப் பயன்படுத்தலாம், பணிப்பட்டி மூலம் ஆப்ஸுக்கிடையே மாறலாம்"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"அடுத்து"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"மூடுக"</string>
 </resources>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index ef8f3ba..b8f3b04 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -84,4 +84,10 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> యాప్‌లో మీరు తర్వాత కనుగొనవచ్చు"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"రద్దు చేయి"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"స్కిప్ చేయి"</string>
+    <!-- no translation found for taskbar_edu_header_1 (5323217563328273689) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_next (4007618274426775841) -->
+    <skip />
+    <!-- no translation found for taskbar_edu_close (887022990168191073) -->
+    <skip />
 </resources>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 52b2878..6839fef 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"คุณดูบทแนะนำนี้ได้ภายหลังในแอป \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ยกเลิก"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ข้าม"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"ใช้แอป 2 แอปพร้อมกันและสลับแอปด้วยแถบงาน"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"ถัดไป"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"ปิด"</string>
 </resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 412449b..a7a0d81 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Makikita mo ito sa <xliff:g id="NAME">%1$s</xliff:g> app sa ibang pagkakataon"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Kanselahin"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Laktawan"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Gumamit ng 2 app nang sabay at magpalipat-lipat ng app gamit ang taskbar"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Susunod"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Isara"</string>
 </resources>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 58d78e0..7ea58a0 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Bunu daha sonra <xliff:g id="NAME">%1$s</xliff:g> uygulamasında bulabilirsiniz"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"İptal"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Atla"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"2 uygulamayı aynı anda kullanıp görev çubuğuyla uygulamalar arasında geçiş yapın"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"İleri"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Kapat"</string>
 </resources>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 544cec7..4127b75 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Ви знайдете його пізніше в додатку <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Скасувати"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Пропустити"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Користуйтеся двома додатками одночасно й перемикайтеся між ними за допомогою панелі завдань"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Далі"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Закрити"</string>
 </resources>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 2e8bde9..0af4328 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"آپ اسے بعد میں <xliff:g id="NAME">%1$s</xliff:g> ایپ میں تلاش کر سکتے ہیں"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"منسوخ کریں"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"نظر انداز کریں"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"ایک وقت میں 2 ایپس استعمال کریں اور ٹاسک بار کے ساتھ ایپس پر سوئچ کریں"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"آگے"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"بند کریں"</string>
 </resources>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 8b194de..c77a6c7 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Bu darslar <xliff:g id="NAME">%1$s</xliff:g> ilovasida chiqadi"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Bekor qilish"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Tashlab ketish"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Vazifalar panelidan almashtirish uchun birdaniga 2 ta ilovadan foydalanish"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Keyingisi"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Yopish"</string>
 </resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 7bd0c70..0261368 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Bạn có thể tìm lại phần hướng dẫn này trong ứng dụng <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Hủy"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Bỏ qua"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Dùng 2 ứng dụng một lúc và chuyển đổi ứng dụng thông qua thanh tác vụ"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Tiếp theo"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Đóng"</string>
 </resources>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 9e641de..8d97e7a 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"您之后可以在“<xliff:g id="NAME">%1$s</xliff:g>”应用中找到此教程"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"取消"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"跳过"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"借助任务栏,您可以同时使用 2 个应用,并可以在应用之间切换"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"继续"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"关闭"</string>
 </resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index d1e8392..d3cc14c 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"您之後可以在「<xliff:g id="NAME">%1$s</xliff:g>」應用程式找到這些說明"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"取消"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"略過"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"同時使用 2 個應用程式,以及使用工作列切換應用程式"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"繼續"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string>
 </resources>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index db10354..382f725 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"你之後可以在「<xliff:g id="NAME">%1$s</xliff:g>」應用程式找到這些說明"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"取消"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"略過"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"你可以同時使用 2 個應用程式,只要透過工作列即可切換"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"繼續"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"關閉"</string>
 </resources>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index bbfb840..1232a82 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -84,4 +84,7 @@
     <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Lokhu ungakuthola kamuva ku-app ye-<xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Khansela"</string>
     <string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Yeqa"</string>
+    <string name="taskbar_edu_header_1" msgid="5323217563328273689">"Sebenzisa ama-app ama-2 ngesikhathi esisodwa bese ushintsha ama-app ngebha yomsebenzi"</string>
+    <string name="taskbar_edu_next" msgid="4007618274426775841">"Okulandelayo"</string>
+    <string name="taskbar_edu_close" msgid="887022990168191073">"Vala"</string>
 </resources>
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 2f24441..17980f0 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -28,4 +28,7 @@
     <!-- Taskbar -->
     <color name="taskbar_background">@color/overview_scrim_dark</color>
     <color name="taskbar_icon_selection_ripple">#E0E0E0</color>
+
+    <color name="taskbar_stashed_handle_light_color">#EBffffff</color>
+    <color name="taskbar_stashed_handle_dark_color">#99000000</color>
 </resources>
\ No newline at end of file
diff --git a/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java b/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java
deleted file mode 100644
index 82e8903..0000000
--- a/quickstep/robolectric_tests/src/com/android/quickstep/RecentsActivityTest.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import static com.android.launcher3.util.LauncherUIHelper.doLayout;
-
-import android.app.ActivityManager.RunningTaskInfo;
-import android.graphics.Bitmap;
-import android.graphics.Bitmap.Config;
-
-import com.android.quickstep.fallback.FallbackRecentsView;
-import com.android.systemui.shared.recents.model.ThumbnailData;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.android.controller.ActivityController;
-import org.robolectric.annotation.LooperMode;
-import org.robolectric.annotation.LooperMode.Mode;
-import org.robolectric.shadows.ShadowLooper;
-import org.robolectric.util.ReflectionHelpers;
-
-
-@RunWith(RobolectricTestRunner.class)
-@LooperMode(Mode.PAUSED)
-@org.junit.Ignore
-public class RecentsActivityTest {
-
-    @Test
-    public void testRecentsActivityCreates() {
-        ActivityController<RecentsActivity> controller =
-                Robolectric.buildActivity(RecentsActivity.class);
-
-        RecentsActivity launcher = controller.setup().get();
-        doLayout(launcher);
-
-        // TODO: Ensure that LauncherAppState is not created
-    }
-
-    @Test
-    public void testRecents_showCurrentTask() {
-        ActivityController<RecentsActivity> controller =
-                Robolectric.buildActivity(RecentsActivity.class);
-
-        RecentsActivity activity = controller.setup().get();
-        doLayout(activity);
-
-        FallbackRecentsView frv = activity.getOverviewPanel();
-
-        RunningTaskInfo placeholderTask = new RunningTaskInfo();
-        placeholderTask.taskId = 22;
-        frv.showCurrentTask(new RunningTaskInfo[]{placeholderTask});
-        doLayout(activity);
-
-        ThumbnailData thumbnailData = new ThumbnailData();
-        ReflectionHelpers.setField(thumbnailData, "thumbnail",
-                Bitmap.createBitmap(300, 500, Config.ARGB_8888));
-        frv.switchToScreenshot(thumbnailData, () -> { });
-        ShadowLooper.idleMainLooper();
-    }
-}
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 433ae3c..f06447b 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -32,7 +32,6 @@
 import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
 import static com.android.launcher3.anim.Interpolators.DEACCEL_1_7;
-import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
 import static com.android.launcher3.anim.Interpolators.LINEAR;
 import static com.android.launcher3.config.FeatureFlags.ENABLE_SCRIM_FOR_APP_LAUNCH;
 import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION;
@@ -71,6 +70,7 @@
 import android.view.View;
 import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
+import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
 
@@ -142,21 +142,11 @@
     private static final String CONTROL_REMOTE_APP_TRANSITION_PERMISSION =
             "android.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS";
 
-    private static final long APP_LAUNCH_DURATION = 450;
-    // Use a shorter duration for x or y translation to create a curve effect
-    private static final long APP_LAUNCH_CURVED_DURATION = 250;
+    private static final long APP_LAUNCH_DURATION = 500;
+
     private static final long APP_LAUNCH_ALPHA_DURATION = 50;
     private static final long APP_LAUNCH_ALPHA_START_DELAY = 25;
 
-    // We scale the durations for the downward app launch animations (minus the scale animation).
-    private static final float APP_LAUNCH_DOWN_DUR_SCALE_FACTOR = 0.8f;
-    private static final long APP_LAUNCH_DOWN_DURATION =
-            (long) (APP_LAUNCH_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
-    private static final long APP_LAUNCH_DOWN_CURVED_DURATION =
-            (long) (APP_LAUNCH_CURVED_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
-    private static final long APP_LAUNCH_ALPHA_DOWN_DURATION =
-            (long) (APP_LAUNCH_ALPHA_DURATION * APP_LAUNCH_DOWN_DUR_SCALE_FACTOR);
-
     public static final int ANIMATION_NAV_FADE_IN_DURATION = 266;
     public static final int ANIMATION_NAV_FADE_OUT_DURATION = 133;
     public static final long ANIMATION_DELAY_NAV_FADE_IN =
@@ -166,9 +156,6 @@
     public static final Interpolator NAV_FADE_OUT_INTERPOLATOR =
             new PathInterpolator(0.2f, 0f, 1f, 1f);
 
-    private static final long CROP_DURATION = 375;
-    private static final long RADIUS_DURATION = 375;
-
     public static final int RECENTS_LAUNCH_DURATION = 336;
     private static final int LAUNCHER_RESUME_START_DELAY = 100;
     private static final int CLOSING_TRANSITION_DURATION_MS = 250;
@@ -222,6 +209,9 @@
     // Will never be larger than MAX_NUM_TASKS
     private LinkedHashMap<Integer, Pair<Integer, Integer>> mTaskStartParams;
 
+    private final Interpolator mOpeningXInterpolator;
+    private final Interpolator mOpeningInterpolator;
+
     public QuickstepTransitionManager(Context context) {
         mLauncher = Launcher.cast(Launcher.getLauncher(context));
         mDragLayer = mLauncher.getDragLayer();
@@ -248,6 +238,10 @@
             SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(
                     mStartingWindowListener);
         }
+
+        mOpeningXInterpolator = AnimationUtils.loadInterpolator(context, R.interpolator.app_open_x);
+        mOpeningInterpolator = AnimationUtils.loadInterpolator(context,
+                R.interpolator.three_point_fast_out_extra_slow_in);
     }
 
     @Override
@@ -686,27 +680,29 @@
         final float finalShadowRadius = appTargetsAreTranslucent ? 0 : mMaxShadowRadius;
 
         MultiValueUpdateListener listener = new MultiValueUpdateListener() {
-            FloatProp mDx = new FloatProp(0, prop.dX, 0, prop.xDuration, AGGRESSIVE_EASE);
-            FloatProp mDy = new FloatProp(0, prop.dY, 0, prop.yDuration, AGGRESSIVE_EASE);
+            FloatProp mDx = new FloatProp(0, prop.dX, 0, APP_LAUNCH_DURATION,
+                    mOpeningXInterpolator);
+            FloatProp mDy = new FloatProp(0, prop.dY, 0, APP_LAUNCH_DURATION,
+                    mOpeningInterpolator);
 
             FloatProp mIconScaleToFitScreen = new FloatProp(prop.initialAppIconScale,
-                    prop.finalAppIconScale, 0, APP_LAUNCH_DURATION, EXAGGERATED_EASE);
+                    prop.finalAppIconScale, 0, APP_LAUNCH_DURATION, mOpeningInterpolator);
             FloatProp mIconAlpha = new FloatProp(prop.iconAlphaStart, 0f,
-                    APP_LAUNCH_ALPHA_START_DELAY, prop.alphaDuration, LINEAR);
+                    APP_LAUNCH_ALPHA_START_DELAY, APP_LAUNCH_ALPHA_DURATION, LINEAR);
 
             FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius, 0,
-                    RADIUS_DURATION, EXAGGERATED_EASE);
+                    APP_LAUNCH_DURATION, mOpeningInterpolator);
             FloatProp mShadowRadius = new FloatProp(0, finalShadowRadius, 0,
-                    APP_LAUNCH_DURATION, EXAGGERATED_EASE);
+                    APP_LAUNCH_DURATION, mOpeningInterpolator);
 
             FloatProp mCropRectCenterX = new FloatProp(prop.cropCenterXStart, prop.cropCenterXEnd,
-                    0, CROP_DURATION, EXAGGERATED_EASE);
+                    0, APP_LAUNCH_DURATION, mOpeningInterpolator);
             FloatProp mCropRectCenterY = new FloatProp(prop.cropCenterYStart, prop.cropCenterYEnd,
-                    0, CROP_DURATION, EXAGGERATED_EASE);
+                    0, APP_LAUNCH_DURATION, mOpeningInterpolator);
             FloatProp mCropRectWidth = new FloatProp(prop.cropWidthStart, prop.cropWidthEnd, 0,
-                    CROP_DURATION, EXAGGERATED_EASE);
+                    APP_LAUNCH_DURATION, mOpeningInterpolator);
             FloatProp mCropRectHeight = new FloatProp(prop.cropHeightStart, prop.cropHeightEnd, 0,
-                    CROP_DURATION, EXAGGERATED_EASE);
+                    APP_LAUNCH_DURATION, mOpeningInterpolator);
 
             FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
                     NAV_FADE_OUT_INTERPOLATOR);
@@ -908,22 +904,23 @@
                     WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* delay */,
                     WIDGET_CROSSFADE_DURATION_MILLIS / 2 /* duration */, LINEAR);
             final FloatProp mWindowRadius = new FloatProp(initialWindowRadius, finalWindowRadius,
-                    0 /* start */, RADIUS_DURATION, LINEAR);
-            final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, 0, RADIUS_DURATION, LINEAR);
+                    0 /* start */, APP_LAUNCH_DURATION, mOpeningInterpolator);
+            final FloatProp mCornerRadiusProgress = new FloatProp(0, 1, 0, APP_LAUNCH_DURATION,
+                    mOpeningInterpolator);
 
             // Window & widget background positioning bounds
             final FloatProp mDx = new FloatProp(widgetBackgroundBounds.centerX(),
-                    windowTargetBounds.centerX(), 0 /* delay */, APP_LAUNCH_CURVED_DURATION,
-                    EXAGGERATED_EASE);
+                    windowTargetBounds.centerX(), 0 /* delay */, APP_LAUNCH_DURATION,
+                    mOpeningXInterpolator);
             final FloatProp mDy = new FloatProp(widgetBackgroundBounds.centerY(),
                     windowTargetBounds.centerY(), 0 /* delay */, APP_LAUNCH_DURATION,
-                    EXAGGERATED_EASE);
+                    mOpeningInterpolator);
             final FloatProp mWidth = new FloatProp(widgetBackgroundBounds.width(),
                     windowTargetBounds.width(), 0 /* delay */, APP_LAUNCH_DURATION,
-                    EXAGGERATED_EASE);
+                    mOpeningInterpolator);
             final FloatProp mHeight = new FloatProp(widgetBackgroundBounds.height(),
                     windowTargetBounds.height(), 0 /* delay */, APP_LAUNCH_DURATION,
-                    EXAGGERATED_EASE);
+                    mOpeningInterpolator);
 
             final FloatProp mNavFadeOut = new FloatProp(1f, 0f, 0, ANIMATION_NAV_FADE_OUT_DURATION,
                     NAV_FADE_OUT_INTERPOLATOR);
@@ -1467,10 +1464,6 @@
         public final float dX;
         public final float dY;
 
-        public final long xDuration;
-        public final long yDuration;
-        public final long alphaDuration;
-
         public final float initialAppIconScale;
         public final float finalAppIconScale;
 
@@ -1502,14 +1495,6 @@
             dX = centerX - launcherIconBounds.centerX();
             dY = centerY - launcherIconBounds.centerY();
 
-            boolean useUpwardAnimation = launcherIconBounds.top > centerY
-                    || Math.abs(dY) < dp.cellHeightPx;
-            xDuration = useUpwardAnimation ? APP_LAUNCH_CURVED_DURATION
-                    : APP_LAUNCH_DOWN_DURATION;
-            yDuration = useUpwardAnimation ? APP_LAUNCH_DURATION
-                    : APP_LAUNCH_DOWN_CURVED_DURATION;
-            alphaDuration = useUpwardAnimation ? APP_LAUNCH_ALPHA_DURATION
-                    : APP_LAUNCH_ALPHA_DOWN_DURATION;
             iconAlphaStart = hasSplashScreen && !hasDifferentAppIcon ? 0 : 1f;
 
             final int windowIconSize = ResourceUtils.getDimenByName("starting_surface_icon_size",
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 08300e2..e871c25 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -25,8 +25,11 @@
 import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_KEYGUARD;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
 
 import android.animation.ObjectAnimator;
 import android.annotation.DrawableRes;
@@ -69,6 +72,9 @@
     private static final int FLAG_A11Y_VISIBLE = 1 << 3;
     private static final int FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE = 1 << 4;
     private static final int FLAG_KEYGUARD_VISIBLE = 1 << 5;
+    private static final int FLAG_DISABLE_HOME = 1 << 6;
+    private static final int FLAG_DISABLE_RECENTS = 1 << 7;
+    private static final int FLAG_DISABLE_BACK = 1 << 8;
 
     private static final int MASK_IME_SWITCHER_VISIBLE = FLAG_SWITCHER_SUPPORTED | FLAG_IME_VISIBLE;
 
@@ -169,7 +175,8 @@
         mBackButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
                 mNavButtonContainer, mControllers.navButtonController, R.id.back);
         mPropertyHolders.add(new StatePropertyHolder(mBackButton,
-                flags -> (flags & FLAG_IME_VISIBLE) == 0));
+                flags -> (flags & FLAG_IME_VISIBLE) == 0 &&
+                        (flags & FLAG_DISABLE_BACK) == 0));
         // Hide when keyguard is showing, show when bouncer is showing
         mPropertyHolders.add(new StatePropertyHolder(mBackButton,
                 flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 ||
@@ -180,12 +187,14 @@
                 navButtonController, R.id.home);
         mPropertyHolders.add(new StatePropertyHolder(homeButton,
                 flags -> (flags & FLAG_IME_VISIBLE) == 0 &&
-                        (flags & FLAG_KEYGUARD_VISIBLE) == 0));
+                        (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
+                        (flags & FLAG_DISABLE_HOME) == 0));
         View recentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
                 navContainer, navButtonController, R.id.recent_apps);
         mPropertyHolders.add(new StatePropertyHolder(recentsButton,
                 flags -> (flags & FLAG_IME_VISIBLE) == 0 &&
-                        (flags & FLAG_KEYGUARD_VISIBLE) == 0));
+                        (flags & FLAG_KEYGUARD_VISIBLE) == 0 &&
+                        (flags & FLAG_DISABLE_RECENTS) == 0));
 
         // A11y button
         mA11yButton = addButton(R.drawable.ic_sysbar_accessibility_button, BUTTON_A11Y,
@@ -202,6 +211,12 @@
         boolean a11yVisible = (systemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
         boolean a11yLongClickable =
                 (systemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
+        boolean isHomeDisabled =
+                (systemUiStateFlags & SYSUI_STATE_HOME_DISABLED) != 0;
+        boolean isRecentsDisabled =
+                (systemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0;
+        boolean isBackDisabled =
+                (systemUiStateFlags & SYSUI_STATE_BACK_DISABLED) != 0;
 
         if (!forceUpdate && systemUiStateFlags == mSysuiStateFlags) {
             return;
@@ -211,6 +226,10 @@
         updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible);
         updateStateForFlag(FLAG_SWITCHER_SUPPORTED, isImeSwitcherShowing);
         updateStateForFlag(FLAG_A11Y_VISIBLE, a11yVisible);
+        updateStateForFlag(FLAG_DISABLE_HOME, isHomeDisabled);
+        updateStateForFlag(FLAG_DISABLE_RECENTS, isRecentsDisabled);
+        updateStateForFlag(FLAG_DISABLE_BACK, isBackDisabled);
+
         if (mA11yButton != null) {
             // Only used in 3 button
             mA11yButton.setLongClickable(a11yLongClickable);
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
new file mode 100644
index 0000000..0224bc4
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
@@ -0,0 +1,70 @@
+/*
+ * 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.taskbar;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.View;
+
+import androidx.annotation.ColorInt;
+import androidx.core.content.ContextCompat;
+
+import com.android.launcher3.R;
+
+public class StashedHandleView extends View {
+
+    private final @ColorInt int mStashedHandleLightColor;
+    private final @ColorInt int mStashedHandleDarkColor;
+    private final Rect mSampledRegion = new Rect();
+    private final int[] mTmpArr = new int[2];
+
+    public StashedHandleView(Context context) {
+        this(context, null);
+    }
+
+    public StashedHandleView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public StashedHandleView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public StashedHandleView(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        mStashedHandleLightColor = ContextCompat.getColor(context,
+                R.color.taskbar_stashed_handle_light_color);
+        mStashedHandleDarkColor = ContextCompat.getColor(context,
+                R.color.taskbar_stashed_handle_dark_color);
+    }
+
+    public void updateSampledRegion() {
+        getLocationOnScreen(mTmpArr);
+        mSampledRegion.set(mTmpArr[0], mTmpArr[1], mTmpArr[0] + getWidth(),
+                mTmpArr[1] + getHeight());
+    }
+
+    public Rect getSampledRegion() {
+        return mSampledRegion;
+    }
+
+    public void updateHandleColor(boolean isRegionDark) {
+        setBackgroundColor(isRegionDark ? mStashedHandleLightColor : mStashedHandleDarkColor);
+    }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index df37261..2858d7c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -16,6 +16,7 @@
 package com.android.launcher3.taskbar;
 
 import android.animation.Animator;
+import android.content.SharedPreferences;
 import android.content.res.Resources;
 import android.graphics.Outline;
 import android.graphics.Rect;
@@ -25,19 +26,30 @@
 import androidx.annotation.Nullable;
 
 import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
 import com.android.launcher3.anim.RevealOutlineAnimation;
 import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
+import com.android.launcher3.util.Executors;
 import com.android.quickstep.AnimatedFloat;
+import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
 
 /**
  * Handles properties/data collection, then passes the results to our stashed handle View to render.
  */
 public class StashedHandleViewController {
 
+    /**
+     * The SharedPreferences key for whether the stashed handle region is dark.
+     */
+    private static final String SHARED_PREFS_STASHED_HANDLE_REGION_DARK_KEY =
+            "stashed_handle_region_is_dark";
+
     private final TaskbarActivityContext mActivity;
-    private final View mStashedHandleView;
+    private final SharedPreferences mPrefs;
+    private final StashedHandleView mStashedHandleView;
     private final int mStashedHandleWidth;
     private final int mStashedHandleHeight;
+    private final RegionSamplingHelper mRegionSamplingHelper;
     private final AnimatedFloat mTaskbarStashedHandleAlpha = new AnimatedFloat(
             this::updateStashedHandleAlpha);
     private final AnimatedFloat mTaskbarStashedHandleHintScale = new AnimatedFloat(
@@ -52,13 +64,31 @@
 
     private boolean mIsAtStashedRevealBounds = true;
 
-    public StashedHandleViewController(TaskbarActivityContext activity, View stashedHandleView) {
+    public StashedHandleViewController(TaskbarActivityContext activity,
+            StashedHandleView stashedHandleView) {
         mActivity = activity;
+        mPrefs = Utilities.getPrefs(mActivity);
         mStashedHandleView = stashedHandleView;
+        mStashedHandleView.updateHandleColor(
+                mPrefs.getBoolean(SHARED_PREFS_STASHED_HANDLE_REGION_DARK_KEY, false));
         final Resources resources = mActivity.getResources();
         mStashedHandleWidth = resources.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width);
         mStashedHandleHeight = resources.getDimensionPixelSize(
                 R.dimen.taskbar_stashed_handle_height);
+        mRegionSamplingHelper = new RegionSamplingHelper(mStashedHandleView,
+                new RegionSamplingHelper.SamplingCallback() {
+                    @Override
+                    public void onRegionDarknessChanged(boolean isRegionDark) {
+                        mStashedHandleView.updateHandleColor(isRegionDark);
+                        mPrefs.edit().putBoolean(SHARED_PREFS_STASHED_HANDLE_REGION_DARK_KEY,
+                                isRegionDark).apply();
+                    }
+
+                    @Override
+                    public Rect getSampledRegion(View sampledView) {
+                        return mStashedHandleView.getSampledRegion();
+                    }
+                }, Executors.UI_HELPER_EXECUTOR);
     }
 
     public void init(TaskbarControllers controllers) {
@@ -93,6 +123,10 @@
         });
     }
 
+    public void onDestroy() {
+        mRegionSamplingHelper.stopAndDestroy();
+    }
+
     public AnimatedFloat getStashedHandleAlpha() {
         return mTaskbarStashedHandleAlpha;
     }
@@ -117,6 +151,16 @@
         return handleRevealProvider.createRevealAnimator(mStashedHandleView, !isStashed);
     }
 
+    public void onIsStashed(boolean isStashed) {
+        mRegionSamplingHelper.setWindowVisible(isStashed);
+        if (isStashed) {
+            mStashedHandleView.updateSampledRegion();
+            mRegionSamplingHelper.start(mStashedHandleView.getSampledRegion());
+        } else {
+            mRegionSamplingHelper.stop();
+        }
+    }
+
     protected void updateStashedHandleAlpha() {
         mStashedHandleView.setAlpha(mTaskbarStashedHandleAlpha.value);
     }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index a90f17d..ca574e6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -36,7 +36,6 @@
 import android.view.Display;
 import android.view.Gravity;
 import android.view.LayoutInflater;
-import android.view.RoundedCorner;
 import android.view.View;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
@@ -84,7 +83,6 @@
     private final TaskbarControllers mControllers;
 
     private final WindowManager mWindowManager;
-    private final RoundedCorner mLeftCorner, mRightCorner;
     private WindowManager.LayoutParams mWindowLayoutParams;
     private boolean mIsFullscreen;
     // The size we should return to when we call setTaskbarWindowFullscreen(false)
@@ -117,7 +115,7 @@
                 R.layout.taskbar, null, false);
         TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
         FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
-        View stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
+        StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
 
         // Construct controllers.
         mControllers = new TaskbarControllers(this,
@@ -138,12 +136,10 @@
                 ? windowContext.getApplicationContext()
                 : windowContext.getApplicationContext().createDisplayContext(display);
         mWindowManager = c.getSystemService(WindowManager.class);
-        mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
-        mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
     }
 
     public void init() {
-        mLastRequestedNonFullscreenHeight = getDefaultTaskbarWindowHeight();
+        mLastRequestedNonFullscreenHeight = mDeviceProfile.taskbarSize;
         mWindowLayoutParams = new WindowManager.LayoutParams(
                 MATCH_PARENT,
                 mLastRequestedNonFullscreenHeight,
@@ -173,14 +169,6 @@
         return mNavMode == Mode.THREE_BUTTONS;
     }
 
-    public RoundedCorner getLeftCorner() {
-        return mLeftCorner;
-    }
-
-    public RoundedCorner getRightCorner() {
-        return mRightCorner;
-    }
-
     @Override
     public LayoutInflater getLayoutInflater() {
         return mLayoutInflater;
@@ -247,7 +235,6 @@
             return;
         }
         mControllers.rotationButtonController.onDisable2FlagChanged(state2);
-        mControllers.taskbarKeyguardController.disableNavbarElements(state1, state2);
     }
 
     public void onSystemBarAttributesChanged(int displayId, int behavior) {
@@ -262,12 +249,8 @@
         setTaskbarWindowHeight(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenHeight);
     }
 
-    public boolean isTaskbarWindowFullscreen() {
-        return mIsFullscreen;
-    }
-
     /**
-     * Updates the TaskbarContainer height (pass {@link #getDefaultTaskbarWindowHeight()} to reset).
+     * Updates the TaskbarContainer height (pass deviceProfile.taskbarSize to reset).
      */
     public void setTaskbarWindowHeight(int height) {
         if (mWindowLayoutParams.height == height || mIsDestroyed) {
@@ -287,14 +270,6 @@
         mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
     }
 
-    /**
-     * Returns the default height of the window, including the static corner radii above taskbar.
-     */
-    public int getDefaultTaskbarWindowHeight() {
-        return mDeviceProfile.taskbarSize
-                + Math.max(mLeftCorner.getRadius(), mRightCorner.getRadius());
-    }
-
     protected void onTaskbarIconClicked(View view) {
         Object tag = view.getTag();
         if (tag instanceof Task) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 2927a63..b32a41e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -89,5 +89,6 @@
         taskbarDragLayerController.onDestroy();
         taskbarKeyguardController.onDestroy();
         taskbarViewController.onDestroy();
+        stashedHandleViewController.onDestroy();
     }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 0848c35..cd1baf7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -18,7 +18,6 @@
 import android.content.Context;
 import android.graphics.Canvas;
 import android.graphics.Paint;
-import android.graphics.Path;
 import android.util.AttributeSet;
 import android.view.MotionEvent;
 import android.view.View;
@@ -41,12 +40,9 @@
 public class TaskbarDragLayer extends BaseDragLayer<TaskbarActivityContext> {
 
     private final Paint mTaskbarBackgroundPaint;
-    private final Path mInvertedLeftCornerPath, mInvertedRightCornerPath;
     private final OnComputeInsetsListener mTaskbarInsetsComputer = this::onComputeTaskbarInsets;
 
-    // Initialized in init.
     private TaskbarDragLayerController.TaskbarDragLayerCallbacks mControllerCallbacks;
-    private float mLeftCornerRadius, mRightCornerRadius;
 
     private float mTaskbarBackgroundOffset;
 
@@ -69,32 +65,10 @@
         mTaskbarBackgroundPaint = new Paint();
         mTaskbarBackgroundPaint.setColor(getResources().getColor(R.color.taskbar_background));
         mTaskbarBackgroundPaint.setAlpha(0);
-        mTaskbarBackgroundPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
-        mTaskbarBackgroundPaint.setStyle(Paint.Style.FILL);
-
-        // Will be set in init(), but this ensures they are always non-null.
-        mInvertedLeftCornerPath = new Path();
-        mInvertedRightCornerPath = new Path();
     }
 
     public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) {
         mControllerCallbacks = callbacks;
-
-        // Create the paths for the inverted rounded corners above the taskbar. Start with a filled
-        // square, and then subtracting out a circle from the appropriate corner.
-        mLeftCornerRadius = mActivity.getLeftCorner().getRadius();
-        mRightCornerRadius = mActivity.getRightCorner().getRadius();
-        Path square = new Path();
-        square.addRect(0, 0, mLeftCornerRadius, mLeftCornerRadius, Path.Direction.CW);
-        Path circle = new Path();
-        circle.addCircle(mLeftCornerRadius, 0, mLeftCornerRadius, Path.Direction.CW);
-        mInvertedLeftCornerPath.op(square, circle, Path.Op.DIFFERENCE);
-        square.reset();
-        square.addRect(0, 0, mRightCornerRadius, mRightCornerRadius, Path.Direction.CW);
-        circle.reset();
-        circle.addCircle(0, 0, mRightCornerRadius, Path.Direction.CW);
-        mInvertedRightCornerPath.op(square, circle, Path.Op.DIFFERENCE);
-
         recreateControllers();
     }
 
@@ -147,20 +121,8 @@
     protected void dispatchDraw(Canvas canvas) {
         float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight()
                 * (1f - mTaskbarBackgroundOffset);
-        canvas.save();
-        canvas.translate(0, canvas.getHeight() - backgroundHeight);
-
-        // Draw the background behind taskbar content.
-        canvas.drawRect(0, 0, canvas.getWidth(), backgroundHeight, mTaskbarBackgroundPaint);
-
-        // Draw the inverted rounded corners above the taskbar.
-        canvas.translate(0, -mLeftCornerRadius);
-        canvas.drawPath(mInvertedLeftCornerPath, mTaskbarBackgroundPaint);
-        canvas.translate(0, mLeftCornerRadius);
-        canvas.translate(canvas.getWidth() - mRightCornerRadius, -mRightCornerRadius);
-        canvas.drawPath(mInvertedRightCornerPath, mTaskbarBackgroundPaint);
-
-        canvas.restore();
+        canvas.drawRect(0, canvas.getHeight() - backgroundHeight, canvas.getWidth(),
+                canvas.getHeight(), mTaskbarBackgroundPaint);
         super.dispatchDraw(canvas);
     }
 
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 0afa480..14150b9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -16,7 +16,6 @@
 package com.android.launcher3.taskbar;
 
 import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
-import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_CONTENT;
 import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_FRAME;
 import static com.android.systemui.shared.system.ViewTreeObserverWrapper.InsetsInfo.TOUCHABLE_INSETS_REGION;
 
@@ -133,14 +132,13 @@
                 // Let touches pass through us.
                 insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
             } else if (mControllers.navbarButtonsViewController.isImeVisible()) {
-                insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_CONTENT);
+                insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
             } else if (!mControllers.uiController.isTaskbarTouchable()) {
                 // Let touches pass through us.
                 insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
             } else if (mControllers.taskbarViewController.areIconsVisible()) {
                 // Buttons are visible, take over the full taskbar area
-                insetsInfo.setTouchableInsets(mActivity.isTaskbarWindowFullscreen()
-                        ? TOUCHABLE_INSETS_FRAME : TOUCHABLE_INSETS_CONTENT);
+                insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME);
             } else {
                 insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
             }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
index a2039b6..834cd9c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
@@ -1,7 +1,10 @@
 package com.android.launcher3.taskbar;
 
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
 import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
 
 import android.app.KeyguardManager;
@@ -9,7 +12,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.view.View;
 
 /**
  * Controller for managing keyguard state for taskbar
@@ -17,10 +19,11 @@
 public class TaskbarKeyguardController {
 
     private static final int KEYGUARD_SYSUI_FLAGS = SYSUI_STATE_BOUNCER_SHOWING |
-            SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_DEVICE_DOZING;
+            SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_DEVICE_DOZING |
+            SYSUI_STATE_OVERVIEW_DISABLED | SYSUI_STATE_HOME_DISABLED |
+            SYSUI_STATE_BACK_DISABLED;
 
     private final TaskbarActivityContext mContext;
-    private int mDisabledNavIcons;
     private int mKeyguardSysuiFlags;
     private boolean mBouncerShowing;
     private NavbarButtonsViewController mNavbarButtonsViewController;
@@ -70,22 +73,13 @@
         mIsScreenOff = false;
     }
 
-    public void disableNavbarElements(int state1, int state2) {
-        if (mDisabledNavIcons == state1) {
-            // no change
-            return;
-        }
-        mDisabledNavIcons = state1;
-        updateIconsForBouncer();
-    }
-
     /**
      * Hides/shows taskbar when keyguard is up
      */
     private void updateIconsForBouncer() {
-        boolean disableBack = (mDisabledNavIcons & View.STATUS_BAR_DISABLE_BACK) != 0;
-        boolean disableRecent = (mDisabledNavIcons & View.STATUS_BAR_DISABLE_RECENT) != 0;
-        boolean disableHome = (mDisabledNavIcons & View.STATUS_BAR_DISABLE_HOME) != 0;
+        boolean disableBack = (mKeyguardSysuiFlags & SYSUI_STATE_BACK_DISABLED) != 0;
+        boolean disableRecent = (mKeyguardSysuiFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0;
+        boolean disableHome = (mKeyguardSysuiFlags & SYSUI_STATE_HOME_DISABLED) != 0;
         boolean onlyBackEnabled = !disableBack && disableRecent && disableHome;
 
         boolean showBackForBouncer = onlyBackEnabled &&
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 949df82..1f5ff02 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -285,6 +285,7 @@
             @Override
             public void onAnimationStart(Animator animation) {
                 mIsStashed = isStashed;
+                onIsStashed(mIsStashed);
             }
 
             @Override
@@ -326,4 +327,8 @@
                 animateForward ? UNSTASHED_TASKBAR_HANDLE_HINT_SCALE : 1)
                 .setDuration(TASKBAR_HINT_STASH_DURATION).start();
     }
+
+    private void onIsStashed(boolean isStashed) {
+        mControllers.stashedHandleViewController.onIsStashed(isStashed);
+    }
 }
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 1882762..6b95f08 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -165,9 +165,8 @@
         int offsetY = launcherDp.getTaskbarOffsetY();
         setter.setFloat(mTaskbarIconTranslationYForHome, VALUE, -offsetY, LINEAR);
 
-        int collapsedHeight = mActivity.getDefaultTaskbarWindowHeight();
-        int expandedHeight = Math.max(collapsedHeight,
-                mActivity.getDeviceProfile().taskbarSize + offsetY);
+        int collapsedHeight = mActivity.getDeviceProfile().taskbarSize;
+        int expandedHeight = collapsedHeight + offsetY;
         setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight(
                 anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight));
 
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 069af96..14bc380 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -84,9 +84,9 @@
 import com.android.quickstep.util.QuickstepOnboardingPrefs;
 import com.android.quickstep.views.RecentsView;
 import com.android.quickstep.views.TaskView;
-import com.android.unfold.UnfoldTransitionFactory;
-import com.android.unfold.UnfoldTransitionProgressProvider;
-import com.android.unfold.config.UnfoldTransitionConfig;
+import com.android.systemui.unfold.UnfoldTransitionFactory;
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
+import com.android.systemui.unfold.config.UnfoldTransitionConfig;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index e781160..e2ef3bc 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -290,19 +290,35 @@
     public static void getTaskDimension(Context context, DeviceProfile dp, PointF out) {
         if (dp.isMultiWindowMode) {
             WindowBounds bounds = SplitScreenBounds.INSTANCE.getSecondaryWindowBounds(context);
-            if (TaskView.clipStatusAndNavBars(dp)) {
-                out.x = bounds.availableSize.x;
-                out.y = bounds.availableSize.y;
-            } else {
-                out.x = bounds.availableSize.x + bounds.insets.left + bounds.insets.right;
-                out.y = bounds.availableSize.y + bounds.insets.top + bounds.insets.bottom;
+            out.x = bounds.availableSize.x;
+            out.y = bounds.availableSize.y;
+            if (!TaskView.clipLeft(dp)) {
+                out.x += bounds.insets.left;
             }
-        } else if (TaskView.clipStatusAndNavBars(dp)) {
-            out.x = dp.availableWidthPx;
-            out.y = dp.availableHeightPx;
+            if (!TaskView.clipRight(dp)) {
+                out.x += bounds.insets.right;
+            }
+            if (!TaskView.clipTop(dp)) {
+                out.y += bounds.insets.top;
+            }
+            if (!TaskView.clipBottom(dp)) {
+                out.y += bounds.insets.bottom;
+            }
         } else {
             out.x = dp.widthPx;
             out.y = dp.heightPx;
+            if (TaskView.clipLeft(dp)) {
+                out.x -= dp.getInsets().left;
+            }
+            if (TaskView.clipRight(dp)) {
+                out.x -= dp.getInsets().right;
+            }
+            if (TaskView.clipTop(dp)) {
+                out.y -= dp.getInsets().top;
+            }
+            if (TaskView.clipBottom(dp)) {
+                out.y -= Math.max(dp.getInsets().bottom, dp.taskbarSize);
+            }
         }
     }
 
diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
index d0fb9e5..c5ab84d 100644
--- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
+++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java
@@ -24,8 +24,8 @@
 import com.android.launcher3.Hotseat;
 import com.android.launcher3.Launcher;
 import com.android.launcher3.util.HorizontalInsettableView;
-import com.android.unfold.UnfoldTransitionProgressProvider;
-import com.android.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener;
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener;
 
 /**
  * Controls animations that are happening during unfolding foldable devices
diff --git a/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java b/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java
index 9eda8f4..3777c65 100644
--- a/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java
+++ b/quickstep/src/com/android/quickstep/util/ProxyScreenStatusProvider.java
@@ -17,7 +17,7 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.unfold.updates.screen.ScreenStatusProvider;
+import com.android.systemui.unfold.updates.screen.ScreenStatusProvider;
 
 import java.util.ArrayList;
 import java.util.List;
diff --git a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
index 21e0ae8..841e578 100644
--- a/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
+++ b/quickstep/src/com/android/quickstep/util/RecentsOrientedState.java
@@ -396,9 +396,17 @@
         Rect insets = dp.getInsets();
         float fullWidth = dp.widthPx;
         float fullHeight = dp.heightPx;
-        if (TaskView.clipStatusAndNavBars(dp)) {
-            fullWidth -= insets.left + insets.right;
-            fullHeight -= insets.top + insets.bottom;
+        if (TaskView.clipLeft(dp)) {
+            fullWidth -= insets.left;
+        }
+        if (TaskView.clipRight(dp)) {
+            fullWidth -= insets.right;
+        }
+        if (TaskView.clipTop(dp)) {
+            fullHeight -= insets.top;
+        }
+        if (TaskView.clipBottom(dp)) {
+            fullHeight -= insets.bottom;
         }
 
         getTaskDimension(mContext, dp, outPivot);
diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
index 126e044..482092d 100644
--- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java
@@ -29,7 +29,7 @@
 import com.android.launcher3.widget.NavigableAppWidgetHostView;
 import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator;
 import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.TranslationApplier;
-import com.android.unfold.UnfoldTransitionProgressProvider;
+import com.android.systemui.unfold.UnfoldTransitionProgressProvider;
 
 import java.util.HashMap;
 import java.util.Map;
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 4d8c5d0..abeadfd 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -2806,14 +2806,49 @@
                     resetTaskVisuals();
 
                     int pageToSnapTo = mCurrentPage;
-                    if ((dismissedIndex < pageToSnapTo && !showAsGrid)
-                            || pageToSnapTo == taskCount - 1) {
-                        pageToSnapTo -= 1;
-                    }
+                    int taskViewIdToSnapTo = -1;
                     if (showAsGrid) {
+                        // Get the id of the task view we will snap to based on the current
+                        // page's relative position as the order of indices change over time due
+                        // to dismissals.
+                        TaskView snappedTaskView = getTaskViewAtByAbsoluteIndex(mCurrentPage);
+                        if (snappedTaskView != null) {
+                            if (snappedTaskView.getTaskViewId() == mFocusedTaskViewId) {
+                                if (finalNextFocusedTaskView != null) {
+                                    taskViewIdToSnapTo = finalNextFocusedTaskView.getTaskViewId();
+                                } else {
+                                    taskViewIdToSnapTo = mFocusedTaskViewId;
+                                }
+                            } else {
+                                int snappedTaskViewId = snappedTaskView.getTaskViewId();
+                                boolean isSnappedTaskInTopRow = mTopRowIdSet.contains(
+                                        snappedTaskViewId);
+                                IntArray taskViewIdArray =
+                                        isSnappedTaskInTopRow ? getTopRowIdArray()
+                                                : getBottomRowIdArray();
+                                int snappedIndex = taskViewIdArray.indexOf(snappedTaskViewId);
+                                taskViewIdArray.removeValue(dismissedTaskViewId);
+                                if (snappedIndex < taskViewIdArray.size()) {
+                                    taskViewIdToSnapTo = taskViewIdArray.get(snappedIndex);
+                                } else if (snappedIndex == taskViewIdArray.size()) {
+                                    // If the snapped task is the last item from the dismissed row,
+                                    // snap to the same column in the other grid row
+                                    IntArray inverseRowTaskViewIdArray =
+                                            isSnappedTaskInTopRow ? getBottomRowIdArray()
+                                                    : getTopRowIdArray();
+                                    if (snappedIndex < inverseRowTaskViewIdArray.size()) {
+                                        taskViewIdToSnapTo = inverseRowTaskViewIdArray.get(
+                                                snappedIndex);
+                                    }
+                                }
+                            }
+                        }
+
                         int primaryScroll = mOrientationHandler.getPrimaryScroll(RecentsView.this);
                         int currentPageScroll = getScrollForPage(pageToSnapTo);
                         mCurrentPageScrollDiff = primaryScroll - currentPageScroll;
+                    } else if (dismissedIndex < pageToSnapTo || pageToSnapTo == taskCount - 1) {
+                        pageToSnapTo -= 1;
                     }
                     removeViewInLayout(dismissedTaskView);
                     mTopRowIdSet.remove(dismissedTaskViewId);
@@ -2833,40 +2868,50 @@
                         // Update scroll and snap to page.
                         updateScrollSynchronously();
 
-                        int highestVisibleTaskIndex = getHighestVisibleTaskIndex();
-                        if (highestVisibleTaskIndex < Integer.MAX_VALUE) {
-                            TaskView taskView = getTaskViewAt(highestVisibleTaskIndex);
+                        if (showAsGrid) {
+                            // Rebalance tasks in the grid
+                            int highestVisibleTaskIndex = getHighestVisibleTaskIndex();
+                            if (highestVisibleTaskIndex < Integer.MAX_VALUE) {
+                                TaskView taskView = getTaskViewAt(highestVisibleTaskIndex);
 
-                            boolean shouldRebalance = false;
-                            int screenStart = mOrientationHandler.getPrimaryScroll(
-                                    RecentsView.this);
-                            int taskStart = mOrientationHandler.getChildStart(taskView)
-                                    + (int) taskView.getOffsetAdjustment(
-                                    /*fullscreenEnabled=*/ false,
-                                    /*gridEnabled=*/ true);
-
-                            // Rebalance only if there is a maximum gap between the task and the
-                            // screen's edge; this ensures that rebalanced tasks are outside the
-                            // visible screen.
-                            if (mIsRtl) {
-                                shouldRebalance = taskStart <= screenStart + mPageSpacing;
-                            } else {
-                                int screenEnd = screenStart + mOrientationHandler.getMeasuredSize(
+                                boolean shouldRebalance = false;
+                                int screenStart = mOrientationHandler.getPrimaryScroll(
                                         RecentsView.this);
-                                int taskSize = (int) (mOrientationHandler.getMeasuredSize(taskView)
-                                        * taskView.getSizeAdjustment(/*fullscreenEnabled=*/ false));
-                                int taskEnd = taskStart + taskSize;
+                                int taskStart = mOrientationHandler.getChildStart(taskView)
+                                        + (int) taskView.getOffsetAdjustment(/*fullscreenEnabled=*/
+                                        false, /*gridEnabled=*/ true);
 
-                                shouldRebalance = taskEnd >= screenEnd - mPageSpacing;
+                                // Rebalance only if there is a maximum gap between the task and the
+                                // screen's edge; this ensures that rebalanced tasks are outside the
+                                // visible screen.
+                                if (mIsRtl) {
+                                    shouldRebalance = taskStart <= screenStart + mPageSpacing;
+                                } else {
+                                    int screenEnd =
+                                            screenStart + mOrientationHandler.getMeasuredSize(
+                                                    RecentsView.this);
+                                    int taskSize = (int) (mOrientationHandler.getMeasuredSize(
+                                            taskView) * taskView
+                                            .getSizeAdjustment(/*fullscreenEnabled=*/false));
+                                    int taskEnd = taskStart + taskSize;
+
+                                    shouldRebalance = taskEnd >= screenEnd - mPageSpacing;
+                                }
+
+                                if (shouldRebalance) {
+                                    updateGridProperties(/*isTaskDismissal=*/ true,
+                                            highestVisibleTaskIndex);
+                                    updateScrollSynchronously();
+                                }
                             }
 
-                            if (shouldRebalance) {
-                                updateGridProperties(/*isTaskDismissal=*/ true,
-                                        highestVisibleTaskIndex);
-                                updateScrollSynchronously();
+                            // If snapping to another page due to indices rearranging, find the new
+                            // index after dismissal & rearrange using the task view id.
+                            if (taskViewIdToSnapTo != -1) {
+                                pageToSnapTo = indexOfChild(
+                                        getTaskViewFromTaskViewId(taskViewIdToSnapTo));
                             }
                         }
-
                         setCurrentPage(pageToSnapTo);
                         dispatchScrollChanged();
                     }
@@ -2879,10 +2924,32 @@
     }
 
     /**
+     * Returns all the tasks in the top row, without the focused task
+     */
+    private IntArray getTopRowIdArray() {
+        if (mTopRowIdSet.isEmpty()) {
+            return new IntArray(0);
+        }
+        IntArray topArray = new IntArray(mTopRowIdSet.size());
+        int taskViewCount = getTaskViewCount();
+        for (int i = 0; i < taskViewCount; i++) {
+            int taskViewId = getTaskViewAt(i).getTaskViewId();
+            if (mTopRowIdSet.contains(taskViewId)) {
+                topArray.add(taskViewId);
+            }
+        }
+        return topArray;
+    }
+
+    /**
      * Returns all the tasks in the bottom row, without the focused task
      */
     private IntArray getBottomRowIdArray() {
-        IntArray bottomArray = new IntArray();
+        int bottomRowIdArraySize = getTaskViewCount() - mTopRowIdSet.size() - 1;
+        if (bottomRowIdArraySize <= 0) {
+            return new IntArray(0);
+        }
+        IntArray bottomArray = new IntArray(bottomRowIdArraySize);
         int taskViewCount = getTaskViewCount();
         for (int i = 0; i < taskViewCount; i++) {
             int taskViewId = getTaskViewAt(i).getTaskViewId();
@@ -2903,7 +2970,7 @@
         if (mTopRowIdSet.isEmpty()) return Integer.MAX_VALUE; // return earlier
 
         int lastVisibleIndex = Integer.MAX_VALUE;
-        IntArray topRowIdArray = mTopRowIdSet.getArray();
+        IntArray topRowIdArray = getTopRowIdArray();
         IntArray bottomRowIdArray = getBottomRowIdArray();
         int balancedColumns = Math.min(bottomRowIdArray.size(), topRowIdArray.size());
 
@@ -4064,6 +4131,7 @@
         setCurrentTask(-1);
         mRecentsAnimationController = null;
         executeSideTaskLaunchCallback();
+        mRemoteTargetHandles = null;
     }
 
     public void setDisallowScrollToClearAll(boolean disallowScrollToClearAll) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 0577cce..28044e4 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -211,10 +211,6 @@
             return Insets.NONE;
         }
 
-        if (!TaskView.clipStatusAndNavBars(mActivity.getDeviceProfile())) {
-            return Insets.NONE;
-        }
-
         RectF bitmapRect = new RectF(
                 0, 0,
                 mThumbnailData.thumbnail.getWidth(), mThumbnailData.thumbnail.getHeight());
@@ -228,11 +224,14 @@
         RectF boundsInBitmapSpace = new RectF();
         boundsToBitmapSpace.mapRect(boundsInBitmapSpace, viewRect);
 
-        return Insets.of(
-            Math.round(boundsInBitmapSpace.left),
-            Math.round(boundsInBitmapSpace.top),
-            Math.round(bitmapRect.right - boundsInBitmapSpace.right),
-            Math.round(bitmapRect.bottom - boundsInBitmapSpace.bottom));
+        DeviceProfile dp = mActivity.getDeviceProfile();
+        int leftInset = TaskView.clipLeft(dp) ? Math.round(boundsInBitmapSpace.left) : 0;
+        int topInset = TaskView.clipTop(dp) ? Math.round(boundsInBitmapSpace.top) : 0;
+        int rightInset = TaskView.clipRight(dp) ? Math.round(
+                bitmapRect.right - boundsInBitmapSpace.right) : 0;
+        int bottomInset = TaskView.clipBottom(dp)
+                ? Math.round(bitmapRect.bottom - boundsInBitmapSpace.bottom) : 0;
+        return Insets.of(leftInset, topInset, rightInset, bottomInset);
     }
 
 
@@ -440,8 +439,19 @@
 
             int thumbnailRotation = thumbnailData.rotation;
             int deltaRotate = getRotationDelta(currentRotation, thumbnailRotation);
-            RectF thumbnailClipHint = TaskView.clipStatusAndNavBars(dp)
-                    ? new RectF(thumbnailData.insets) : new RectF();
+            RectF thumbnailClipHint = new RectF();
+            if (TaskView.clipLeft(dp)) {
+                thumbnailClipHint.left = thumbnailData.insets.left;
+            }
+            if (TaskView.clipRight(dp)) {
+                thumbnailClipHint.right = thumbnailData.insets.right;
+            }
+            if (TaskView.clipTop(dp)) {
+                thumbnailClipHint.top = thumbnailData.insets.top;
+            }
+            if (TaskView.clipBottom(dp)) {
+                thumbnailClipHint.bottom = thumbnailData.insets.bottom;
+            }
 
             float scale = thumbnailData.scale;
             final float thumbnailScale;
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 174e1b3..f84a05c 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -146,19 +146,39 @@
     public static final float MAX_PAGE_SCRIM_ALPHA = 0.4f;
 
     /**
-     * Should the TaskView display clip off the status and navigation bars in recents. When this
-     * is false the overview shows the whole screen scaled down instead.
+     * Should the TaskView display clip off the left inset in RecentsView.
      */
-    public static boolean clipStatusAndNavBars(DeviceProfile deviceProfile) {
-        return deviceProfile.isTaskbarPresentInApps;
+    public static boolean clipLeft(DeviceProfile deviceProfile) {
+        return false;
+    }
+
+    /**
+     * Should the TaskView display clip off the top inset in RecentsView.
+     */
+    public static boolean clipTop(DeviceProfile deviceProfile) {
+        return false;
+    }
+
+    /**
+     * Should the TaskView display clip off the right inset in RecentsView.
+     */
+    public static boolean clipRight(DeviceProfile deviceProfile) {
+        return false;
+    }
+
+    /**
+     * Should the TaskView display clip off the bottom inset in RecentsView.
+     */
+    public static boolean clipBottom(DeviceProfile deviceProfile) {
+        return deviceProfile.isTablet;
     }
 
     /**
      * Should the TaskView scale down to fit whole thumbnail in fullscreen.
      */
     public static boolean useFullThumbnail(DeviceProfile deviceProfile) {
-        return deviceProfile.isTaskbarPresentInApps;
-    };
+        return deviceProfile.isTablet && !deviceProfile.isTaskbarPresentInApps;
+    }
 
     private static final float EDGE_SCALE_DOWN_FACTOR_CAROUSEL = 0.03f;
     private static final float EDGE_SCALE_DOWN_FACTOR_GRID = 0.00f;
@@ -654,6 +674,7 @@
             TestLogging.recordEvent(
                     TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
             ActivityOptionsWrapper opts =  mActivity.getActivityLaunchOptions(this, null);
+            opts.options.setLaunchDisplayId(getRootViewDisplayId());
             if (ActivityManagerWrapper.getInstance()
                     .startActivityFromRecents(mTask.key, opts.options)) {
                 RecentsView recentsView = getRecentsView();
@@ -694,6 +715,7 @@
             // Indicate success once the system has indicated that the transition has started
             ActivityOptions opts = ActivityOptionsCompat.makeCustomAnimation(
                     getContext(), 0, 0, () -> callback.accept(true), MAIN_EXECUTOR.getHandler());
+            opts.setLaunchDisplayId(getRootViewDisplayId());
             if (freezeTaskList) {
                 ActivityOptionsCompat.setFreezeRecentTasksList(opts);
             }
@@ -1506,6 +1528,10 @@
         mDigitalWellBeingToast.setBannerColorTint(tintColor, amount);
     }
 
+    private int getRootViewDisplayId() {
+        return getRootView().getDisplay().getDisplayId();
+    }
+
     /**
      * We update and subsequently draw these in {@link #setFullscreenProgress(float)}.
      */
diff --git a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
index f33abb0..0f5a1c8 100644
--- a/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
+++ b/quickstep/tests/src/com/android/quickstep/ViewInflationDuringSwipeUp.java
@@ -19,9 +19,9 @@
 import static androidx.test.InstrumentationRegistry.getInstrumentation;
 import static androidx.test.InstrumentationRegistry.getTargetContext;
 
-import static com.android.launcher3.common.WidgetUtils.createWidgetInfo;
 import static com.android.launcher3.testcomponent.TestCommandReceiver.EXTRA_VALUE;
 import static com.android.launcher3.testcomponent.TestCommandReceiver.SET_LIST_VIEW_SERVICE_BINDER;
+import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
 import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON;
 
 import static org.junit.Assert.assertEquals;
diff --git a/robolectric_tests/Android.bp b/robolectric_tests/Android.bp
index 9ed26ff..6473d00 100644
--- a/robolectric_tests/Android.bp
+++ b/robolectric_tests/Android.bp
@@ -40,7 +40,6 @@
     name: "LauncherRoboTests",
     srcs: [
         ":launcher3-robolectric-src",
-        ":launcher3-test-src-common",
     ],
     java_resources: [":launcher3-robolectric-resources"],
     static_libs: [
diff --git a/robolectric_tests/src/com/android/launcher3/ui/LauncherUIScrollTest.java b/robolectric_tests/src/com/android/launcher3/ui/LauncherUIScrollTest.java
deleted file mode 100644
index ea75548..0000000
--- a/robolectric_tests/src/com/android/launcher3/ui/LauncherUIScrollTest.java
+++ /dev/null
@@ -1,181 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */package com.android.launcher3.ui;
-
-import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
-import static com.android.launcher3.util.LauncherUIHelper.buildAndBindLauncher;
-import static com.android.launcher3.util.LauncherUIHelper.doLayout;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-
-import android.content.Context;
-import android.os.SystemClock;
-import android.provider.Settings;
-import android.view.InputDevice;
-import android.view.MotionEvent;
-import android.view.MotionEvent.PointerProperties;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.folder.Folder;
-import com.android.launcher3.folder.FolderIcon;
-import com.android.launcher3.folder.FolderPagedView;
-import com.android.launcher3.util.LauncherLayoutBuilder;
-import com.android.launcher3.util.LauncherLayoutBuilder.FolderBuilder;
-import com.android.launcher3.util.LauncherModelHelper;
-import com.android.launcher3.widget.picker.WidgetsFullSheet;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.LooperMode;
-import org.robolectric.annotation.LooperMode.Mode;
-import org.robolectric.shadows.ShadowLooper;
-
-/**
- * Tests scroll behavior at various Launcher UI components
- */
-@RunWith(RobolectricTestRunner.class)
-@LooperMode(Mode.PAUSED)
-@org.junit.Ignore
-public class LauncherUIScrollTest {
-
-    private Context mTargetContext;
-    private InvariantDeviceProfile mIdp;
-    private LauncherModelHelper mModelHelper;
-
-    private LauncherLayoutBuilder mLayoutBuilder;
-
-    @Before
-    public void setup() throws Exception {
-        mModelHelper = new LauncherModelHelper();
-        mTargetContext = RuntimeEnvironment.application;
-        mIdp = InvariantDeviceProfile.INSTANCE.get(mTargetContext);
-
-        Settings.Global.putFloat(mTargetContext.getContentResolver(),
-                Settings.Global.WINDOW_ANIMATION_SCALE, 0);
-
-        mModelHelper.installApp(TEST_PACKAGE);
-        // LayoutBuilder with 3 workspace pages
-        mLayoutBuilder = new LauncherLayoutBuilder()
-                .atWorkspace(0,  mIdp.numRows - 1, 0).putApp(TEST_PACKAGE, TEST_PACKAGE)
-                .atWorkspace(0,  mIdp.numRows - 1, 1).putApp(TEST_PACKAGE, TEST_PACKAGE)
-                .atWorkspace(0,  mIdp.numRows - 1, 2).putApp(TEST_PACKAGE, TEST_PACKAGE);
-    }
-
-    @Test
-    public void testWorkspacePagesBound() throws Exception {
-        // Verify that the workspace if bound synchronously
-        Launcher launcher = loadLauncher();
-        assertEquals(3, launcher.getWorkspace().getPageCount());
-        assertEquals(0, launcher.getWorkspace().getCurrentPage());
-
-        launcher.dispatchGenericMotionEvent(createScrollEvent(-1));
-        assertNotEquals("Workspace was not scrolled",
-                0, launcher.getWorkspace().getNextPage());
-    }
-
-    @Test
-    public void testAllAppsScroll() throws Exception {
-        // Install 100 apps
-        for (int i = 0; i < 100; i++) {
-            mModelHelper.installApp(TEST_PACKAGE + i);
-        }
-
-        // Bind and open all-apps
-        Launcher launcher = loadLauncher();
-        launcher.getStateManager().goToState(LauncherState.ALL_APPS, false);
-        doLayout(launcher);
-
-        int currentScroll = launcher.getAppsView().getActiveRecyclerView().getCurrentScrollY();
-        launcher.dispatchGenericMotionEvent(createScrollEvent(-1));
-        int newScroll = launcher.getAppsView().getActiveRecyclerView().getCurrentScrollY();
-
-        assertNotEquals("All Apps was not scrolled", currentScroll, newScroll);
-        assertEquals("Workspace was scrolled", 0, launcher.getWorkspace().getNextPage());
-    }
-
-    @Test
-    public void testWidgetsListScroll() throws Exception {
-        // Install 100 widgets
-        for (int i = 0; i < 100; i++) {
-            mModelHelper.installCustomShortcut(TEST_PACKAGE + i, "shortcutProvider");
-        }
-
-        // Bind and open widgets
-        Launcher launcher = loadLauncher();
-        WidgetsFullSheet widgets = WidgetsFullSheet.show(launcher, false);
-        doLayout(launcher);
-
-        int currentScroll = widgets.getRecyclerView().getCurrentScrollY();
-        launcher.dispatchGenericMotionEvent(createScrollEvent(-1));
-        int newScroll = widgets.getRecyclerView().getCurrentScrollY();
-        assertNotEquals("Widgets was not scrolled", currentScroll, newScroll);
-        assertEquals("Workspace was scrolled", 0, launcher.getWorkspace().getNextPage());
-    }
-
-    @Test
-    public void testFolderPageScroll() throws Exception {
-        // Add a folder with multiple icons
-        FolderBuilder fb = mLayoutBuilder.atWorkspace(mIdp.numColumns / 2, mIdp.numRows / 2, 0)
-                .putFolder(0);
-        for (int i = 0; i < 100; i++) {
-            fb.addApp(TEST_PACKAGE, TEST_PACKAGE);
-        }
-
-        // Bind and open folder
-        Launcher launcher = loadLauncher();
-        doLayout(launcher);
-        launcher.getWorkspace().getFirstMatch((i, v) -> v instanceof FolderIcon).performClick();
-        ShadowLooper.idleMainLooper();
-        doLayout(launcher);
-        FolderPagedView folderPages = Folder.getOpen(launcher).getContent();
-
-        assertEquals(0, folderPages.getNextPage());
-        launcher.dispatchGenericMotionEvent(createScrollEvent(-1));
-        assertNotEquals("Folder page was not scrolled", 0, folderPages.getNextPage());
-        assertEquals("Workspace was scrolled", 0, launcher.getWorkspace().getNextPage());
-    }
-
-    private Launcher loadLauncher() throws Exception {
-        mModelHelper.setupDefaultLayoutProvider(mLayoutBuilder).loadModelSync();
-        return buildAndBindLauncher();
-    }
-
-    private static MotionEvent createScrollEvent(int scroll) {
-        DeviceProfile dp = InvariantDeviceProfile.INSTANCE
-                .get(RuntimeEnvironment.application).supportedProfiles.get(0);
-
-        final PointerProperties[] pointerProperties = new PointerProperties[1];
-        pointerProperties[0] = new PointerProperties();
-        pointerProperties[0].id = 0;
-        final MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[1];
-        coords[0] = new MotionEvent.PointerCoords();
-        coords[0].setAxisValue(MotionEvent.AXIS_VSCROLL, scroll);
-        coords[0].x = dp.widthPx / 2;
-        coords[0].y = dp.heightPx / 2;
-
-        final long time = SystemClock.uptimeMillis();
-        return MotionEvent.obtain(time, time, MotionEvent.ACTION_SCROLL, 1,
-                pointerProperties, coords, 0, 0, 1.0f, 1.0f, 0, 0,
-                InputDevice.SOURCE_CLASS_POINTER, 0);
-    }
-
-}
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 9778b61..ec96c6d 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -145,6 +145,7 @@
     /**
      * Returns {@link StatsLogManager} for user event logging.
      */
+    @Override
     public StatsLogManager getStatsLogManager() {
         if (mStatsLogManager == null) {
             mStatsLogManager = StatsLogManager.newInstance(this);
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index d162abd..38beeea 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -683,8 +683,9 @@
         CellLayout finalScreen = mWorkspaceScreens.get(finalScreenId);
 
         // If the final screen is empty, convert it to the extra empty screen
-        if (finalScreen.getShortcutsAndWidgets().getChildCount() == 0 &&
-                !finalScreen.isDropPending()) {
+        if (finalScreen != null
+                && finalScreen.getShortcutsAndWidgets().getChildCount() == 0
+                && !finalScreen.isDropPending()) {
             mWorkspaceScreens.remove(finalScreenId);
             mScreenOrder.removeValue(finalScreenId);
 
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index b95904e..c822213 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -27,6 +27,7 @@
 import com.android.launcher3.dot.DotInfo;
 import com.android.launcher3.dragndrop.DragController;
 import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.logging.StatsLogManager;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.util.ViewCache;
 
@@ -109,6 +110,10 @@
         return null;
     }
 
+    default StatsLogManager getStatsLogManager() {
+        return StatsLogManager.newInstance((Context) this);
+    }
+
     /**
      * Returns the ActivityContext associated with the given Context.
      */
diff --git a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
index 95c3e1e..aacb9c5 100644
--- a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
+++ b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
@@ -17,6 +17,7 @@
 
 import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
 
+import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
@@ -34,7 +35,6 @@
 
 import androidx.annotation.NonNull;
 
-import com.android.launcher3.BaseActivity;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.R;
@@ -46,6 +46,7 @@
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.pm.ShortcutConfigActivityInfo;
 import com.android.launcher3.util.Executors;
+import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.widget.util.WidgetSizes;
 
 import java.util.concurrent.ExecutionException;
@@ -56,10 +57,10 @@
 
     private static final String TAG = "WidgetPreviewLoader";
 
-    private final BaseActivity mContext;
+    private final Context mContext;
     private final float mPreviewBoxCornerRadius;
 
-    public DatabaseWidgetPreviewLoader(BaseActivity context) {
+    public DatabaseWidgetPreviewLoader(Context context) {
         mContext = context;
         float previewCornerRadius = RoundedCornerEnforcement.computeEnforcedRadius(context);
         mPreviewBoxCornerRadius = previewCornerRadius > 0
@@ -139,12 +140,13 @@
         int previewWidth;
         int previewHeight;
 
+        DeviceProfile dp = ActivityContext.lookupContext(mContext).getDeviceProfile();
+
         if (widgetPreviewExists && drawable.getIntrinsicWidth() > 0
                 && drawable.getIntrinsicHeight() > 0) {
             previewWidth = drawable.getIntrinsicWidth();
             previewHeight = drawable.getIntrinsicHeight();
         } else {
-            DeviceProfile dp = mContext.getDeviceProfile();
             Size widgetSize = WidgetSizes.getWidgetPaddedSizePx(mContext, info.provider, dp, spanX,
                     spanY);
             previewWidth = widgetSize.getWidth();
@@ -215,7 +217,7 @@
                     Drawable icon = LauncherAppState.getInstance(mContext).getIconCache()
                             .getFullResIcon(info.provider.getPackageName(), info.icon);
                     if (icon != null) {
-                        int appIconSize = mContext.getDeviceProfile().iconSizePx;
+                        int appIconSize = dp.iconSizePx;
                         int iconSize = (int) Math.min(appIconSize * scale,
                                 Math.min(boxRect.width(), boxRect.height()));
 
@@ -248,7 +250,7 @@
 
     private Bitmap generateShortcutPreview(
             ShortcutConfigActivityInfo info, int maxWidth, int maxHeight) {
-        int iconSize = mContext.getDeviceProfile().allAppsIconSizePx;
+        int iconSize = ActivityContext.lookupContext(mContext).getDeviceProfile().allAppsIconSizePx;
         int padding = mContext.getResources()
                 .getDimensionPixelSize(R.dimen.widget_preview_shortcut_padding);
 
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 423c66a..f1ac656 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -43,7 +43,6 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
-import com.android.launcher3.BaseActivity;
 import com.android.launcher3.CheckLongPressHelper;
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.Launcher;
@@ -123,7 +122,7 @@
     protected HandlerRunnable mActiveRequest;
     private boolean mAnimatePreview = true;
 
-    protected final BaseActivity mActivity;
+    protected final ActivityContext mActivity;
     private final CheckLongPressHelper mLongPressHelper;
     private final float mEnforcedCornerRadius;
 
@@ -143,8 +142,8 @@
     public WidgetCell(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        mActivity = BaseActivity.fromContext(context);
-        mWidgetPreviewLoader = new DatabaseWidgetPreviewLoader(mActivity);
+        mActivity = ActivityContext.lookupContext(context);
+        mWidgetPreviewLoader = new DatabaseWidgetPreviewLoader(context);
         mLongPressHelper = new CheckLongPressHelper(this);
         mLongPressHelper.setLongPressTimeoutFactor(1);
 
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index de0d8b8..d52134c 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -39,13 +39,13 @@
 import androidx.recyclerview.widget.RecyclerView.LayoutParams;
 import androidx.recyclerview.widget.RecyclerView.ViewHolder;
 
-import com.android.launcher3.Launcher;
 import com.android.launcher3.R;
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.data.PackageItemInfo;
 import com.android.launcher3.recyclerview.ViewHolderBinder;
 import com.android.launcher3.util.LabelComparator;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.views.ActivityContext;
 import com.android.launcher3.widget.model.WidgetListSpaceEntry;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
@@ -85,7 +85,7 @@
     private static final int VIEW_TYPE_WIDGETS_HEADER = R.id.view_type_widgets_header;
     private static final int VIEW_TYPE_WIDGETS_SEARCH_HEADER = R.id.view_type_widgets_search_header;
 
-    private final Launcher mLauncher;
+    private final Context mContext;
     private final WidgetsDiffReporter mDiffReporter;
     private final SparseArray<ViewHolderBinder> mViewHolderBinders = new SparseArray<>();
     private final WidgetListBaseRowEntryComparator mRowComparator =
@@ -109,7 +109,7 @@
     public WidgetsListAdapter(Context context, LayoutInflater layoutInflater,
             IconCache iconCache, IntSupplier emptySpaceHeightProvider,
             OnClickListener iconClickListener, OnLongClickListener iconLongClickListener) {
-        mLauncher = Launcher.getLauncher(context);
+        mContext = context;
         mDiffReporter = new WidgetsDiffReporter(iconCache, this);
         WidgetsListDrawableFactory listDrawableFactory = new WidgetsListDrawableFactory(context);
 
@@ -340,7 +340,8 @@
 
         if (showWidgets) {
             mWidgetsContentVisiblePackageUserKey = packageUserKey;
-            mLauncher.getStatsLogManager().logger().log(LAUNCHER_WIDGETSTRAY_APP_EXPANDED);
+            ActivityContext.lookupContext(mContext)
+                    .getStatsLogManager().logger().log(LAUNCHER_WIDGETSTRAY_APP_EXPANDED);
         } else {
             mWidgetsContentVisiblePackageUserKey = null;
         }
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index feeb0fe..8c9ff09 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -110,10 +110,13 @@
 
                 // When preview loads, notify adapter to rebind the item and possibly animate
                 widget.applyFromCellItem(widgetItem, 1f,
-                        bitmap -> holder.getBindingAdapter().notifyItemChanged(
-                                holder.getBindingAdapterPosition(),
-                                Pair.create(widgetItem, bitmap)),
-                        holder.previewCache.get(widgetItem));
+                        bitmap -> {
+                        if (holder.getBindingAdapter() != null) {
+                            holder.getBindingAdapter().notifyItemChanged(
+                                    holder.getBindingAdapterPosition(),
+                                    Pair.create(widgetItem, bitmap));
+                            }
+                        }, holder.previewCache.get(widgetItem));
             }
         }
     }
diff --git a/tests/Android.bp b/tests/Android.bp
index da55c28..aeddc4c 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -20,7 +20,78 @@
     default_applicable_licenses: ["packages_apps_Launcher3_license"],
 }
 
+// Source code used for test
 filegroup {
-    name: "launcher3-test-src-common",
-    srcs: ["src_common/**/*.java"],
+    name: "launcher-tests-src",
+    srcs: ["src/**/*.java"],
+}
+
+// Source code used for oop test helpers
+filegroup {
+    name: "launcher-oop-tests-src",
+    srcs: [
+      "src/com/android/launcher3/ui/AbstractLauncherUiTest.java",
+      "src/com/android/launcher3/ui/ActivityLeakTracker.java",
+      "src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
+      "src/com/android/launcher3/util/Wait.java",
+      "src/com/android/launcher3/util/WidgetUtils.java",
+      "src/com/android/launcher3/util/rule/FailureWatcher.java",
+      "src/com/android/launcher3/util/rule/LauncherActivityRule.java",
+      "src/com/android/launcher3/util/rule/ScreenRecordRule.java",
+      "src/com/android/launcher3/util/rule/ShellCommandRule.java",
+      "src/com/android/launcher3/util/rule/SimpleActivityRule.java",
+      "src/com/android/launcher3/util/rule/TestStabilityRule.java",
+      "src/com/android/launcher3/ui/TaplTestsLauncher3.java",
+      "src/com/android/launcher3/testcomponent/BaseTestingActivity.java",
+      "src/com/android/launcher3/testcomponent/CustomShortcutConfigActivity.java",
+      "src/com/android/launcher3/testcomponent/TestCommandReceiver.java",
+      "src/com/android/launcher3/testcomponent/TestLauncherActivity.java",
+    ],
+}
+
+// Library with all the dependencies for building quickstep
+android_library {
+    name: "Launcher3TestLib",
+    srcs: [ ],
+    resource_dirs: ["res"],
+    static_libs: [
+        "launcher-aosp-tapl",
+        "androidx.test.core",
+        "androidx.test.runner",
+        "androidx.test.rules",
+        "androidx.test.ext.junit",
+        "androidx.test.espresso.core",
+        "androidx.test.espresso.contrib",
+        "androidx.test.espresso.intents",
+        "androidx.test.uiautomator_uiautomator",
+        "mockito-target-inline-minus-junit4",
+        "launcher_log_protos_lite",
+        "truth-prebuilt"
+    ],
+    manifest: "AndroidManifest-common.xml",
+    platform_apis: true,
+}
+
+android_test {
+    name: "Launcher3Tests",
+    srcs: [
+        ":launcher-tests-src",
+    ],
+    static_libs: ["Launcher3TestLib"],
+    libs: [
+        "android.test.base",
+        "android.test.runner",
+        "android.test.mock",
+    ],
+    jni_libs: [
+        "libdexmakerjvmtiagent",
+        "libstaticjvmtiagent",
+    ],
+    use_embedded_native_libs: false,
+    compile_multilib: "both",
+    instrumentation_for: "Launcher3",
+    manifest: "AndroidManifest.xml",
+    platform_apis: true,
+    test_config: "Launcher3Tests.xml",
+    data: [":Launcher3"]
 }
diff --git a/tests/Android.mk b/tests/Android.mk
deleted file mode 100644
index 6adc685..0000000
--- a/tests/Android.mk
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright (C) 2015 The Android Open Source Project
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#      http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-#
-# Build rule for Launcher3Tests
-#
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := tests
-LOCAL_STATIC_JAVA_LIBRARIES := \
-    androidx.test.runner \
-    androidx.test.rules \
-    androidx.test.uiautomator_uiautomator \
-    mockito-target-minus-junit4 \
-    launcher_log_protos_lite
-
-LOCAL_PRIVATE_PLATFORM_APIS := true
-LOCAL_STATIC_JAVA_LIBRARIES += launcher-aosp-tapl
-
-LOCAL_SRC_FILES := \
-	$(call all-java-files-under, src) \
-	$(call all-java-files-under, src_common)
-
-
-LOCAL_FULL_LIBS_MANIFEST_FILES := $(LOCAL_PATH)/AndroidManifest-common.xml
-
-LOCAL_PACKAGE_NAME := Launcher3Tests
-
-LOCAL_INSTRUMENTATION_FOR := Launcher3
-
-LOCAL_TEST_CONFIG := Launcher3Tests.xml
-
-LOCAL_COMPATIBILITY_SUPPORT_FILES := $(call intermediates-dir-for,APPS,Launcher3)/package.apk:Launcher3.apk
-
-LOCAL_LICENSE_KINDS := SPDX-license-identifier-Apache-2.0
-LOCAL_LICENSE_CONDITIONS := notice
-LOCAL_NOTICE_FILE := $(LOCAL_PATH)/../NOTICE
-include $(BUILD_PACKAGE)
-
-include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 918ec4a..8222f75 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -24,7 +24,7 @@
     <uses-permission android:name="android.permission.READ_LOGS"/>
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
 
-    <application android:debuggable="true">
+    <application android:debuggable="true" android:extractNativeLibs="true">
         <uses-library android:name="android.test.runner"/>
 
         <receiver
diff --git a/robolectric_tests/src/com/android/launcher3/folder/FolderNameProviderTest.java b/tests/src/com/android/launcher3/folder/FolderNameProviderTest.java
similarity index 90%
rename from robolectric_tests/src/com/android/launcher3/folder/FolderNameProviderTest.java
rename to tests/src/com/android/launcher3/folder/FolderNameProviderTest.java
index 2a94d9b..23e6235 100644
--- a/robolectric_tests/src/com/android/launcher3/folder/FolderNameProviderTest.java
+++ b/tests/src/com/android/launcher3/folder/FolderNameProviderTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.folder;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
 
@@ -23,6 +25,9 @@
 import android.content.Intent;
 import android.os.UserHandle;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import com.android.launcher3.model.data.AppInfo;
 import com.android.launcher3.model.data.WorkspaceItemInfo;
 import com.android.launcher3.util.Executors;
@@ -30,15 +35,11 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.LooperMode;
-import org.robolectric.annotation.LooperMode.Mode;
 
 import java.util.ArrayList;
 
-@RunWith(RobolectricTestRunner.class)
-@LooperMode(Mode.PAUSED)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public final class FolderNameProviderTest {
     private Context mContext;
     private WorkspaceItemInfo mItem1;
@@ -46,7 +47,7 @@
 
     @Before
     public void setUp() {
-        mContext = RuntimeEnvironment.application;
+        mContext = getApplicationContext();
         mItem1 = new WorkspaceItemInfo(new AppInfo(
                 new ComponentName("a.b.c", "a.b.c/a.b.c.d"),
                 "title1",
diff --git a/robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java b/tests/src/com/android/launcher3/logging/FileLogTest.java
similarity index 89%
rename from robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java
rename to tests/src/com/android/launcher3/logging/FileLogTest.java
index 01b23ba..e5f8cec 100644
--- a/robolectric_tests/src/com/android/launcher3/logging/FileLogTest.java
+++ b/tests/src/com/android/launcher3/logging/FileLogTest.java
@@ -1,16 +1,17 @@
 package com.android.launcher3.logging;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.annotation.LooperMode;
-import org.robolectric.annotation.LooperMode.Mode;
 
 import java.io.File;
 import java.io.PrintWriter;
@@ -20,8 +21,8 @@
 /**
  * Tests for {@link FileLog}
  */
-@RunWith(RobolectricTestRunner.class)
-@LooperMode(Mode.PAUSED)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class FileLogTest {
 
     private File mTempDir;
@@ -29,7 +30,7 @@
     public void setUp() {
         int count = 0;
         do {
-            mTempDir = new File(RuntimeEnvironment.application.getCacheDir(),
+            mTempDir = new File(getApplicationContext().getCacheDir(),
                     "log-test-" + (count++));
         } while (!mTempDir.mkdir());
 
diff --git a/robolectric_tests/src/com/android/launcher3/popup/PopupPopulatorTest.java b/tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
similarity index 95%
rename from robolectric_tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
rename to tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
index 83bf7da..6764e09 100644
--- a/robolectric_tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
+++ b/tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
@@ -16,6 +16,8 @@
 
 package com.android.launcher3.popup;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
 import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
 import static com.android.launcher3.popup.PopupPopulator.NUM_DYNAMIC;
 
@@ -27,10 +29,11 @@
 
 import android.content.pm.ShortcutInfo;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -39,7 +42,8 @@
 /**
  * Tests the sorting and filtering of shortcuts in {@link PopupPopulator}.
  */
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class PopupPopulatorTest {
 
     @Test
@@ -137,7 +141,7 @@
 
     private ShortcutInfo createInfo(boolean isStatic, int rank) {
         ShortcutInfo info = spy(new ShortcutInfo.Builder(
-                RuntimeEnvironment.application, generateId(isStatic, rank))
+                getApplicationContext(), generateId(isStatic, rank))
                 .setRank(rank)
                 .build());
         doReturn(isStatic).when(info).isDeclaredInManifest();
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 0d5b9ad..1a6ce8c 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -52,7 +52,6 @@
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.LauncherState;
 import com.android.launcher3.Utilities;
-import com.android.launcher3.common.WidgetUtils;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.statemanager.StateManager;
 import com.android.launcher3.tapl.LauncherInstrumentation;
@@ -63,6 +62,7 @@
 import com.android.launcher3.util.LooperExecutor;
 import com.android.launcher3.util.PackageManagerHelper;
 import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.WidgetUtils;
 import com.android.launcher3.util.rule.FailureWatcher;
 import com.android.launcher3.util.rule.LauncherActivityRule;
 import com.android.launcher3.util.rule.ScreenRecordRule;
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 9c6c317..fa39ce0 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -17,7 +17,7 @@
 
 import static androidx.test.InstrumentationRegistry.getTargetContext;
 
-import static com.android.launcher3.common.WidgetUtils.createWidgetInfo;
+import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
diff --git a/tests/src/com/android/launcher3/util/ActivityContextWrapper.java b/tests/src/com/android/launcher3/util/ActivityContextWrapper.java
new file mode 100644
index 0000000..2618a2e
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/ActivityContextWrapper.java
@@ -0,0 +1,62 @@
+/*
+ * 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.util;
+
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.view.ContextThemeWrapper;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.InvariantDeviceProfile;
+import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.BaseDragLayer;
+
+/**
+ * {@link ContextWrapper} with internal Launcher interface for testing
+ */
+public class ActivityContextWrapper extends ContextThemeWrapper implements ActivityContext {
+
+    private final DeviceProfile mProfile;
+    private final MyDragLayer mMyDragLayer;
+
+    public ActivityContextWrapper(Context base) {
+        super(base, android.R.style.Theme_DeviceDefault);
+        mProfile = InvariantDeviceProfile.INSTANCE.get(base).getDeviceProfile(base).copy(base);
+        mMyDragLayer = new MyDragLayer(this);
+    }
+
+    @Override
+    public BaseDragLayer getDragLayer() {
+        return mMyDragLayer;
+    }
+
+    @Override
+    public DeviceProfile getDeviceProfile() {
+        return mProfile;
+    }
+
+    private static class MyDragLayer extends BaseDragLayer<ActivityContextWrapper> {
+
+        MyDragLayer(Context context) {
+            super(context, null, 1);
+        }
+
+        @Override
+        public void recreateControllers() {
+            mControllers = new TouchController[0];
+        }
+    }
+}
diff --git a/robolectric_tests/src/com/android/launcher3/util/GridOccupancyTest.java b/tests/src/com/android/launcher3/util/GridOccupancyTest.java
similarity index 92%
rename from robolectric_tests/src/com/android/launcher3/util/GridOccupancyTest.java
rename to tests/src/com/android/launcher3/util/GridOccupancyTest.java
index 2f3fc37..b498077 100644
--- a/robolectric_tests/src/com/android/launcher3/util/GridOccupancyTest.java
+++ b/tests/src/com/android/launcher3/util/GridOccupancyTest.java
@@ -4,14 +4,17 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
 
 /**
  * Unit tests for {@link GridOccupancy}
  */
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class GridOccupancyTest {
 
     @Test
diff --git a/robolectric_tests/src/com/android/launcher3/util/IntArrayTest.java b/tests/src/com/android/launcher3/util/IntArrayTest.java
similarity index 86%
rename from robolectric_tests/src/com/android/launcher3/util/IntArrayTest.java
rename to tests/src/com/android/launcher3/util/IntArrayTest.java
index c08e198..a3c7007 100644
--- a/robolectric_tests/src/com/android/launcher3/util/IntArrayTest.java
+++ b/tests/src/com/android/launcher3/util/IntArrayTest.java
@@ -17,14 +17,17 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
 
 /**
- * Robolectric unit tests for {@link IntArray}
+ * Unit tests for {@link IntArray}
  */
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class IntArrayTest {
 
     @Test
diff --git a/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java b/tests/src/com/android/launcher3/util/IntSetTest.java
similarity index 91%
rename from robolectric_tests/src/com/android/launcher3/util/IntSetTest.java
rename to tests/src/com/android/launcher3/util/IntSetTest.java
index 7a8c00b..cdb2891 100644
--- a/robolectric_tests/src/com/android/launcher3/util/IntSetTest.java
+++ b/tests/src/com/android/launcher3/util/IntSetTest.java
@@ -21,14 +21,17 @@
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import org.junit.Test;
 import org.junit.runner.RunWith;
-import org.robolectric.RobolectricTestRunner;
 
 /**
- * Robolectric unit tests for {@link IntSet}
+ * Unit tests for {@link IntSet}
  */
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class IntSetTest {
 
     @Test
diff --git a/tests/src_common/com/android/launcher3/common/WidgetUtils.java b/tests/src/com/android/launcher3/util/WidgetUtils.java
similarity index 82%
rename from tests/src_common/com/android/launcher3/common/WidgetUtils.java
rename to tests/src/com/android/launcher3/util/WidgetUtils.java
index 97500e3..6fc8491 100644
--- a/tests/src_common/com/android/launcher3/common/WidgetUtils.java
+++ b/tests/src/com/android/launcher3/util/WidgetUtils.java
@@ -13,19 +13,25 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.launcher3.common;
+package com.android.launcher3.util;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
 
 import android.appwidget.AppWidgetHost;
+import android.appwidget.AppWidgetManager;
+import android.appwidget.AppWidgetProviderInfo;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
 import android.os.Bundle;
+import android.os.Process;
 
 import com.android.launcher3.LauncherSettings;
 import com.android.launcher3.model.data.ItemInfo;
 import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.util.ContentWriter;
 import com.android.launcher3.widget.LauncherAppWidgetHost;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.PendingAddWidgetInfo;
@@ -102,4 +108,17 @@
         resolver.insert(LauncherSettings.Favorites.CONTENT_URI,
                 writer.getValues(targetContext));
     }
+
+
+    /**
+     * Creates a {@link AppWidgetProviderInfo} for the provided component name
+     */
+    public static AppWidgetProviderInfo createAppWidgetProviderInfo(ComponentName cn) {
+        AppWidgetProviderInfo info = AppWidgetManager.getInstance(getApplicationContext())
+                .getInstalledProvidersForPackage(
+                        getInstrumentation().getContext().getPackageName(), Process.myUserHandle())
+                .get(0);
+        info.provider = cn;
+        return info;
+    }
 }
diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
index 0b60ffc..fae55cc 100644
--- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
+++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java
@@ -30,6 +30,7 @@
     public FailureWatcher(UiDevice device, LauncherInstrumentation launcher) {
         mDevice = device;
         mLauncher = launcher;
+        Log.d("b/196820244", "FailureWatcher.ctor", new Exception());
     }
 
     @Override
@@ -44,7 +45,9 @@
             @Override
             public void evaluate() throws Throwable {
                 try {
+                    Log.d("b/196820244", "Before evaluate");
                     FailureWatcher.super.apply(base, description).evaluate();
+                    Log.d("b/196820244", "After evaluate");
                 } finally {
                     if (mLauncher.hadNontestEvents()) {
                         throw new AssertionError(
@@ -64,7 +67,9 @@
     }
 
     public static void onError(UiDevice device, Description description, Throwable e) {
+        Log.d("b/196820244", "onError 1");
         if (device == null) return;
+        Log.d("b/196820244", "onError 2");
         final File parentFile = getInstrumentation().getTargetContext().getFilesDir();
         final File sceenshot = new File(parentFile,
                 "TestScreenshot-" + description.getMethodName() + ".png");
diff --git a/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java b/tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
similarity index 96%
rename from robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
rename to tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
index a6f892c..24ae583 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
+++ b/tests/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfoTest.java
@@ -15,6 +15,8 @@
  */
 package com.android.launcher3.widget;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
@@ -25,6 +27,9 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import com.android.launcher3.DeviceProfile;
 import com.android.launcher3.InvariantDeviceProfile;
 
@@ -32,15 +37,13 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mockito;
-import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public final class LauncherAppWidgetProviderInfoTest {
 
     private static final int CELL_SIZE = 50;
@@ -51,8 +54,7 @@
 
     @Before
     public void setUp() {
-        MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = getApplicationContext();
     }
 
     @Test
@@ -260,6 +262,7 @@
             return null;
         }).when(profile).getCellSize(any(Point.class));
         Mockito.when(profile.getCellSize()).thenReturn(new Point(CELL_SIZE, CELL_SIZE));
+        Mockito.when(profile.shouldInsetWidgets()).thenReturn(true);
 
         InvariantDeviceProfile idp = new InvariantDeviceProfile();
         List<DeviceProfile> supportedProfiles = new ArrayList<>(idp.supportedProfiles);
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
similarity index 95%
rename from robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
rename to tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
index b9f183c..6232938 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsDiffReporterTest.java
@@ -15,13 +15,16 @@
  */
 package com.android.launcher3.widget.picker;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
-import static org.robolectric.Shadows.shadowOf;
 
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
@@ -30,6 +33,8 @@
 import android.os.UserHandle;
 
 import androidx.recyclerview.widget.RecyclerView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
 
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.icons.BitmapInfo;
@@ -48,15 +53,12 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowPackageManager;
-import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
 import java.util.List;
 
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public final class WidgetsDiffReporterTest {
     private static final String TEST_PACKAGE_PREFIX = "com.android.test";
     private static final WidgetListBaseRowEntryComparator COMPARATOR =
@@ -87,7 +89,7 @@
                 .getComponent().getPackageName())
                 .when(mIconCache).getTitleNoCache(any());
 
-        mContext = RuntimeEnvironment.application;
+        mContext = getApplicationContext();
         mWidgetsDiffReporter = new WidgetsDiffReporter(mIconCache, mAdapter);
         mHeaderA = createWidgetsHeaderEntry(TEST_PACKAGE_PREFIX + "A",
                 /* appName= */ "A", /* numOfWidgets= */ 3);
@@ -294,14 +296,10 @@
     }
 
     private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
-        ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
         ArrayList<WidgetItem> widgetItems = new ArrayList<>();
         for (int i = 0; i < numOfWidgets; i++) {
             ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
-            AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
-            widgetInfo.provider = cn;
-            ReflectionHelpers.setField(widgetInfo, "providerInfo",
-                    packageManager.addReceiverIfNotPresent(cn));
+            AppWidgetProviderInfo widgetInfo = createAppWidgetProviderInfo(cn);
 
             WidgetItem widgetItem = new WidgetItem(
                     LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
similarity index 92%
rename from robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
rename to tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
index 12aac8b..44d6964 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListAdapterTest.java
@@ -15,12 +15,13 @@
  */
 package com.android.launcher3.widget.picker;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Matchers.eq;
 import static org.mockito.Matchers.isNull;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
-import static org.robolectric.Shadows.shadowOf;
 
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
@@ -31,6 +32,8 @@
 import android.view.LayoutInflater;
 
 import androidx.recyclerview.widget.RecyclerView;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
 
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.icons.BitmapInfo;
@@ -38,7 +41,9 @@
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.data.PackageItemInfo;
+import com.android.launcher3.util.ActivityContextWrapper;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.WidgetUtils;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
@@ -50,15 +55,16 @@
 import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowPackageManager;
-import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
 import java.util.List;
 
-@RunWith(RobolectricTestRunner.class)
+/**
+ * Unit tests for WidgetsListAdapter
+ * Note that all indices matching are shifted by 1 to account for the empty space at the start.
+ */
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public final class WidgetsListAdapterTest {
     private static final String TEST_PACKAGE_PLACEHOLDER = "com.google.test";
 
@@ -74,7 +80,7 @@
     @Before
     public void setup() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = new ActivityContextWrapper(getApplicationContext());
         mTestProfile = new InvariantDeviceProfile();
         mTestProfile.numRows = 5;
         mTestProfile.numColumns = 5;
@@ -100,7 +106,7 @@
         mAdapter.setWidgets(generateSampleMap(1));
         mAdapter.setWidgets(generateSampleMap(2));
 
-        verify(mListener).onItemRangeInserted(eq(1), eq(1));
+        verify(mListener).onItemRangeInserted(eq(2), eq(1));
     }
 
     @Test
@@ -108,7 +114,7 @@
         mAdapter.setWidgets(generateSampleMap(2));
         mAdapter.setWidgets(generateSampleMap(1));
 
-        verify(mListener).onItemRangeRemoved(eq(1), eq(1));
+        verify(mListener).onItemRangeRemoved(eq(2), eq(1));
     }
 
     @Test
@@ -116,7 +122,7 @@
         mAdapter.setWidgets(generateSampleMap(1));
         mAdapter.setWidgets(generateSampleMap(1));
 
-        verify(mListener).onItemRangeChanged(eq(0), eq(1), isNull());
+        verify(mListener).onItemRangeChanged(eq(1), eq(1), isNull());
     }
 
     @Test
@@ -135,7 +141,7 @@
         // THEN the visible entries list becomes:
         // [com.google.test0, com.google.test1, com.google.test1 content, com.google.test2]
         // com.google.test.1 content is inserted into position 2.
-        verify(mListener).onItemRangeInserted(eq(2), eq(1));
+        verify(mListener).onItemRangeInserted(eq(3), eq(1));
     }
 
     @Test
@@ -163,7 +169,7 @@
         mAdapter.setWidgets(allEntries);
 
         // THEN the onItemRangeChanged is invoked for "com.google.test1 content" at index 2.
-        verify(mListener).onItemRangeChanged(eq(2), eq(1), isNull());
+        verify(mListener).onItemRangeChanged(eq(3), eq(1), isNull());
     }
 
     @Test
@@ -194,15 +200,16 @@
                 allAppsWithWidgets.get(6), allAppsWithWidgets.get(7));
         mAdapter.setWidgets(newList);
 
+        // Account for 1st items as empty space
         // Computation logic                           | [Intermediate list during computation]
         // THEN B <> C < 0, removed B from index 1     | [A, E]
-        verify(mListener).onItemRangeRemoved(/* positionStart= */ 1, /* itemCount= */ 1);
+        verify(mListener).onItemRangeRemoved(/* positionStart= */ 2, /* itemCount= */ 1);
         // THEN E <> C > 0, C inserted to index 1      | [A, C, E]
-        verify(mListener).onItemRangeInserted(/* positionStart= */ 1, /* itemCount= */ 1);
-        // THEN E <> D > 0, D inserted to index 2      | [A, C, D, E]
         verify(mListener).onItemRangeInserted(/* positionStart= */ 2, /* itemCount= */ 1);
+        // THEN E <> D > 0, D inserted to index 2      | [A, C, D, E]
+        verify(mListener).onItemRangeInserted(/* positionStart= */ 3, /* itemCount= */ 1);
         // THEN E <> null = -1, E deleted from index 3 | [A, C, D]
-        verify(mListener).onItemRangeRemoved(/* positionStart= */ 3, /* itemCount= */ 1);
+        verify(mListener).onItemRangeRemoved(/* positionStart= */ 4, /* itemCount= */ 1);
     }
 
     @Test
@@ -225,8 +232,8 @@
 
         // THEN expanded app is reset and the visible entries list becomes:
         // [com.google.test0, com.google.test1, com.google.test2]
-        verify(mListener).onItemRangeChanged(eq(1), eq(1), isNull());
-        verify(mListener).onItemRangeRemoved(/* positionStart= */ 2, /* itemCount= */ 1);
+        verify(mListener).onItemRangeChanged(eq(2), eq(1), isNull());
+        verify(mListener).onItemRangeRemoved(/* positionStart= */ 3, /* itemCount= */ 1);
     }
 
     /**
@@ -263,14 +270,10 @@
     }
 
     private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
-        ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
         ArrayList<WidgetItem> widgetItems = new ArrayList<>();
         for (int i = 0; i < numOfWidgets; i++) {
             ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
-            AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
-            widgetInfo.provider = cn;
-            ReflectionHelpers.setField(widgetInfo, "providerInfo",
-                    packageManager.addReceiverIfNotPresent(cn));
+            AppWidgetProviderInfo widgetInfo = WidgetUtils.createAppWidgetProviderInfo(cn);
 
             widgetItems.add(new WidgetItem(
                     LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
similarity index 76%
rename from robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
rename to tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
index fa000c0..969c12a 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListHeaderViewHolderBinderTest.java
@@ -15,13 +15,14 @@
  */
 package com.android.launcher3.widget.picker;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
-import static org.robolectric.Shadows.shadowOf;
 
 import static java.util.Collections.EMPTY_LIST;
 
@@ -33,7 +34,9 @@
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
-import com.android.launcher3.DeviceProfile;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.icons.BitmapInfo;
@@ -41,28 +44,23 @@
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.testing.TestActivity;
+import com.android.launcher3.util.ActivityContextWrapper;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.WidgetUtils;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.model.WidgetsListHeaderEntry;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.android.controller.ActivityController;
-import org.robolectric.shadows.ShadowPackageManager;
-import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
 import java.util.List;
 
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public final class WidgetsListHeaderViewHolderBinderTest {
     private static final String TEST_PACKAGE = "com.google.test";
     private static final String APP_NAME = "Test app";
@@ -70,49 +68,35 @@
     private Context mContext;
     private WidgetsListHeaderViewHolderBinder mViewHolderBinder;
     private InvariantDeviceProfile mTestProfile;
-    // Replace ActivityController with ActivityScenario, which is the recommended way for activity
-    // testing.
-    private ActivityController<TestActivity> mActivityController;
-    private TestActivity mTestActivity;
 
     @Mock
     private IconCache mIconCache;
     @Mock
-    private DeviceProfile mDeviceProfile;
-    @Mock
     private OnHeaderClickListener mOnHeaderClickListener;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+
+        mContext = new ActivityContextWrapper(getApplicationContext());
         mTestProfile = new InvariantDeviceProfile();
         mTestProfile.numRows = 5;
         mTestProfile.numColumns = 5;
 
-        mActivityController = Robolectric.buildActivity(TestActivity.class);
-        mTestActivity = mActivityController.setup().get();
-        mTestActivity.setDeviceProfile(mDeviceProfile);
-
         doAnswer(invocation -> {
             ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
             return componentWithLabel.getComponent().getShortClassName();
         }).when(mIconCache).getTitleNoCache(any());
         mViewHolderBinder = new WidgetsListHeaderViewHolderBinder(
-                LayoutInflater.from(mTestActivity),
+                LayoutInflater.from(mContext),
                 mOnHeaderClickListener,
-                new WidgetsListDrawableFactory(mTestActivity));
-    }
-
-    @After
-    public void tearDown() {
-        mActivityController.destroy();
+                new WidgetsListDrawableFactory(mContext));
     }
 
     @Test
     public void bindViewHolder_appWith3Widgets_shouldShowTheCorrectAppNameAndSubtitle() {
         WidgetsListHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
-                new FrameLayout(mTestActivity));
+                new FrameLayout(mContext));
         WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
         WidgetsListHeaderEntry entry = generateSampleAppHeader(
                 APP_NAME,
@@ -129,7 +113,7 @@
     @Test
     public void bindViewHolder_shouldAttachOnHeaderClickListener() {
         WidgetsListHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
-                new FrameLayout(mTestActivity));
+                new FrameLayout(mContext));
         WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
         WidgetsListHeaderEntry entry = generateSampleAppHeader(
                 APP_NAME,
@@ -155,14 +139,10 @@
     }
 
     private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
-        ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
         ArrayList<WidgetItem> widgetItems = new ArrayList<>();
         for (int i = 0; i < numOfWidgets; i++) {
             ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
-            AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
-            widgetInfo.provider = cn;
-            ReflectionHelpers.setField(widgetInfo, "providerInfo",
-                    packageManager.addReceiverIfNotPresent(cn));
+            AppWidgetProviderInfo widgetInfo = WidgetUtils.createAppWidgetProviderInfo(cn);
 
             widgetItems.add(new WidgetItem(
                     LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
similarity index 77%
rename from robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
rename to tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
index b18c8b7..453f4fb 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListSearchHeaderViewHolderBinderTest.java
@@ -15,13 +15,14 @@
  */
 package com.android.launcher3.widget.picker;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.verify;
-import static org.robolectric.Shadows.shadowOf;
 
 import static java.util.Collections.EMPTY_LIST;
 
@@ -33,7 +34,9 @@
 import android.widget.FrameLayout;
 import android.widget.TextView;
 
-import com.android.launcher3.DeviceProfile;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.icons.BitmapInfo;
@@ -41,28 +44,23 @@
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.testing.TestActivity;
+import com.android.launcher3.util.ActivityContextWrapper;
 import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.WidgetUtils;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.model.WidgetsListSearchHeaderEntry;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.android.controller.ActivityController;
-import org.robolectric.shadows.ShadowPackageManager;
-import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
 import java.util.List;
 
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public final class WidgetsListSearchHeaderViewHolderBinderTest {
     private static final String TEST_PACKAGE = "com.google.test";
     private static final String APP_NAME = "Test app";
@@ -70,49 +68,34 @@
     private Context mContext;
     private WidgetsListSearchHeaderViewHolderBinder mViewHolderBinder;
     private InvariantDeviceProfile mTestProfile;
-    // Replace ActivityController with ActivityScenario, which is the recommended way for activity
-    // testing.
-    private ActivityController<TestActivity> mActivityController;
-    private TestActivity mTestActivity;
 
     @Mock
     private IconCache mIconCache;
     @Mock
-    private DeviceProfile mDeviceProfile;
-    @Mock
     private OnHeaderClickListener mOnHeaderClickListener;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = new ActivityContextWrapper(getApplicationContext());
         mTestProfile = new InvariantDeviceProfile();
         mTestProfile.numRows = 5;
         mTestProfile.numColumns = 5;
 
-        mActivityController = Robolectric.buildActivity(TestActivity.class);
-        mTestActivity = mActivityController.setup().get();
-        mTestActivity.setDeviceProfile(mDeviceProfile);
-
         doAnswer(invocation -> {
             ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
             return componentWithLabel.getComponent().getShortClassName();
         }).when(mIconCache).getTitleNoCache(any());
         mViewHolderBinder = new WidgetsListSearchHeaderViewHolderBinder(
-                LayoutInflater.from(mTestActivity),
+                LayoutInflater.from(mContext),
                 mOnHeaderClickListener,
-                new WidgetsListDrawableFactory(mTestActivity));
-    }
-
-    @After
-    public void tearDown() {
-        mActivityController.destroy();
+                new WidgetsListDrawableFactory(mContext));
     }
 
     @Test
     public void bindViewHolder_appWith3Widgets_shouldShowTheCorrectAppNameAndSubtitle() {
         WidgetsListSearchHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
-                new FrameLayout(mTestActivity));
+                new FrameLayout(mContext));
         WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
         WidgetsListSearchHeaderEntry entry = generateSampleSearchHeader(
                 APP_NAME,
@@ -130,7 +113,7 @@
     @Test
     public void bindViewHolder_shouldAttachOnHeaderClickListener() {
         WidgetsListSearchHeaderHolder viewHolder = mViewHolderBinder.newViewHolder(
-                new FrameLayout(mTestActivity));
+                new FrameLayout(mContext));
         WidgetsListHeader widgetsListHeader = viewHolder.mWidgetsListHeader;
         WidgetsListSearchHeaderEntry entry = generateSampleSearchHeader(
                 APP_NAME,
@@ -156,14 +139,10 @@
     }
 
     private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
-        ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
         ArrayList<WidgetItem> widgetItems = new ArrayList<>();
         for (int i = 0; i < numOfWidgets; i++) {
             ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
-            AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
-            widgetInfo.provider = cn;
-            ReflectionHelpers.setField(widgetInfo, "providerInfo",
-                    packageManager.addReceiverIfNotPresent(cn));
+            AppWidgetProviderInfo widgetInfo = WidgetUtils.createAppWidgetProviderInfo(cn);
 
             widgetItems.add(new WidgetItem(
                     LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
similarity index 74%
rename from robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
rename to tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
index cb38c6f..5816b77 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
@@ -15,13 +15,12 @@
  */
 package com.android.launcher3.widget.picker;
 
-import static android.os.Looper.getMainLooper;
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
 
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
-import static org.robolectric.Shadows.shadowOf;
 
 import static java.util.Collections.EMPTY_LIST;
 
@@ -37,7 +36,9 @@
 import android.widget.TableRow;
 import android.widget.TextView;
 
-import com.android.launcher3.DeviceProfile;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.R;
 import com.android.launcher3.icons.BitmapInfo;
@@ -45,29 +46,24 @@
 import com.android.launcher3.icons.IconCache;
 import com.android.launcher3.model.WidgetItem;
 import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.testing.TestActivity;
-import com.android.launcher3.widget.DatabaseWidgetPreviewLoader;
+import com.android.launcher3.util.ActivityContextWrapper;
+import com.android.launcher3.util.Executors;
+import com.android.launcher3.util.WidgetUtils;
 import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
 import com.android.launcher3.widget.WidgetCell;
 import com.android.launcher3.widget.model.WidgetsListContentEntry;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.android.controller.ActivityController;
-import org.robolectric.shadows.ShadowPackageManager;
-import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
 import java.util.List;
 
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public final class WidgetsListTableViewHolderBinderTest {
     private static final String TEST_PACKAGE = "com.google.test";
     private static final String APP_NAME = "Test app";
@@ -75,10 +71,6 @@
     private Context mContext;
     private WidgetsListTableViewHolderBinder mViewHolderBinder;
     private InvariantDeviceProfile mTestProfile;
-    // Replace ActivityController with ActivityScenario, which is the recommended way for activity
-    // testing.
-    private ActivityController<TestActivity> mActivityController;
-    private TestActivity mTestActivity;
 
     @Mock
     private OnLongClickListener mOnLongClickListener;
@@ -86,50 +78,37 @@
     private OnClickListener mOnIconClickListener;
     @Mock
     private IconCache mIconCache;
-    @Mock
-    private DatabaseWidgetPreviewLoader mWidgetPreviewLoader;
-    @Mock
-    private DeviceProfile mDeviceProfile;
 
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mContext = RuntimeEnvironment.application;
+        mContext = new ActivityContextWrapper(getApplicationContext());
         mTestProfile = new InvariantDeviceProfile();
         mTestProfile.numRows = 5;
         mTestProfile.numColumns = 5;
 
-        mActivityController = Robolectric.buildActivity(TestActivity.class);
-        mTestActivity = mActivityController.setup().get();
-        mTestActivity.setDeviceProfile(mDeviceProfile);
-
         doAnswer(invocation -> {
             ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
             return componentWithLabel.getComponent().getShortClassName();
         }).when(mIconCache).getTitleNoCache(any());
 
         mViewHolderBinder = new WidgetsListTableViewHolderBinder(
-                LayoutInflater.from(mTestActivity),
+                LayoutInflater.from(mContext),
                 mOnIconClickListener,
                 mOnLongClickListener,
-                new WidgetsListDrawableFactory(mTestActivity));
-    }
-
-    @After
-    public void tearDown() {
-        mActivityController.destroy();
+                new WidgetsListDrawableFactory(mContext));
     }
 
     @Test
-    public void bindViewHolder_appWith3Widgets_shouldHave3Widgets() {
+    public void bindViewHolder_appWith3Widgets_shouldHave3Widgets() throws Exception {
         WidgetsRowViewHolder viewHolder = mViewHolderBinder.newViewHolder(
-                new FrameLayout(mTestActivity));
+                new FrameLayout(mContext));
         WidgetsListContentEntry entry = generateSampleAppWithWidgets(
                 APP_NAME,
                 TEST_PACKAGE,
                 /* numOfWidgets= */ 3);
         mViewHolderBinder.bindViewHolder(viewHolder, entry, /* position= */ 0, EMPTY_LIST);
-        shadowOf(getMainLooper()).idle();
+        Executors.MAIN_EXECUTOR.submit(() -> { }).get();
 
         // THEN the table container has one row, which contains 3 widgets.
         // View:  .SampleWidget0 | .SampleWidget1 | .SampleWidget2
@@ -152,18 +131,15 @@
 
         return new WidgetsListContentEntry(appInfo,
                 /* titleSectionName= */ "",
-                generateWidgetItems(packageName, numOfWidgets));
+                generateWidgetItems(packageName, numOfWidgets),
+                Integer.MAX_VALUE);
     }
 
     private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
-        ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
         ArrayList<WidgetItem> widgetItems = new ArrayList<>();
         for (int i = 0; i < numOfWidgets; i++) {
             ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
-            AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
-            widgetInfo.provider = cn;
-            ReflectionHelpers.setField(widgetInfo, "providerInfo",
-                    packageManager.addReceiverIfNotPresent(cn));
+            AppWidgetProviderInfo widgetInfo = WidgetUtils.createAppWidgetProviderInfo(cn);
 
             widgetItems.add(new WidgetItem(
                     LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/model/WidgetsListContentEntryTest.java b/tests/src/com/android/launcher3/widget/picker/model/WidgetsListContentEntryTest.java
similarity index 92%
rename from robolectric_tests/src/com/android/launcher3/widget/picker/model/WidgetsListContentEntryTest.java
rename to tests/src/com/android/launcher3/widget/picker/model/WidgetsListContentEntryTest.java
index 106cac0..4b61b2c 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/model/WidgetsListContentEntryTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/model/WidgetsListContentEntryTest.java
@@ -15,15 +15,20 @@
  */
 package com.android.launcher3.widget.picker.model;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
-import static org.robolectric.Shadows.shadowOf;
 
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
-import android.content.Context;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
 
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.icons.ComponentWithLabel;
@@ -38,16 +43,13 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowPackageManager;
-import org.robolectric.util.ReflectionHelpers;
 
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public final class WidgetsListContentEntryTest {
     private static final String PACKAGE_NAME = "com.android.test";
     private static final String PACKAGE_NAME_2 = "com.android.test2";
@@ -60,7 +62,6 @@
 
     @Mock private IconCache mIconCache;
 
-    private Context mContext;
     private InvariantDeviceProfile mTestProfile;
 
     @Before
@@ -71,7 +72,6 @@
         mWidgetsToLabels.put(mWidget2, "Dog");
         mWidgetsToLabels.put(mWidget3, "Bird");
 
-        mContext = RuntimeEnvironment.application;
         mTestProfile = new InvariantDeviceProfile();
         mTestProfile.numRows = 5;
         mTestProfile.numColumns = 5;
@@ -242,17 +242,12 @@
         assertThat(widgetsListRowEntry1.equals(widgetsListRowEntry2)).isTrue();
     }
 
-
     private WidgetItem createWidgetItem(ComponentName componentName, int spanX, int spanY) {
         String label = mWidgetsToLabels.get(componentName);
-        ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
-        AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
-        widgetInfo.provider = componentName;
-        ReflectionHelpers.setField(widgetInfo, "providerInfo",
-                packageManager.addReceiverIfNotPresent(componentName));
+        AppWidgetProviderInfo widgetInfo = createAppWidgetProviderInfo(componentName);
 
         LauncherAppWidgetProviderInfo launcherAppWidgetProviderInfo =
-                LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo);
+                LauncherAppWidgetProviderInfo.fromProviderInfo(getApplicationContext(), widgetInfo);
         launcherAppWidgetProviderInfo.spanX = spanX;
         launcherAppWidgetProviderInfo.spanY = spanY;
         launcherAppWidgetProviderInfo.label = label;
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java b/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
similarity index 90%
rename from robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
rename to tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
index 36b6f01..c862d6b 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/search/SimpleWidgetsSearchAlgorithmTest.java
@@ -16,7 +16,10 @@
 
 package com.android.launcher3.widget.picker.search;
 
-import static android.os.Looper.getMainLooper;
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo;
 
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
@@ -25,7 +28,6 @@
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
-import static org.robolectric.Shadows.shadowOf;
 
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
@@ -33,6 +35,9 @@
 import android.graphics.Bitmap;
 import android.os.UserHandle;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.icons.BitmapInfo;
 import com.android.launcher3.icons.ComponentWithLabel;
@@ -52,16 +57,13 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowPackageManager;
-import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class SimpleWidgetsSearchAlgorithmTest {
 
     @Mock private IconCache mIconCache;
@@ -82,7 +84,7 @@
     private SearchCallback<WidgetsListBaseEntry> mSearchCallback;
 
     @Before
-    public void setUp() {
+    public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
         doAnswer(invocation -> {
             ComponentWithLabel componentWithLabel = (ComponentWithLabel) invocation.getArgument(0);
@@ -91,7 +93,7 @@
         mTestProfile = new InvariantDeviceProfile();
         mTestProfile.numRows = 5;
         mTestProfile.numColumns = 5;
-        mContext = RuntimeEnvironment.application;
+        mContext = getApplicationContext();
 
         mCalendarHeaderEntry =
                 createWidgetsHeaderEntry("com.example.android.Calendar", "Calendar", 2);
@@ -102,8 +104,8 @@
         mClockHeaderEntry = createWidgetsHeaderEntry("com.example.android.Clock", "Clock", 3);
         mClockContentEntry = createWidgetsContentEntry("com.example.android.Clock", "Clock", 3);
 
-
-        mSimpleWidgetsSearchAlgorithm = new SimpleWidgetsSearchAlgorithm(mDataProvider);
+        mSimpleWidgetsSearchAlgorithm = MAIN_EXECUTOR.submit(
+                () -> new SimpleWidgetsSearchAlgorithm(mDataProvider)).get();
         doReturn(Collections.EMPTY_LIST).when(mDataProvider).getAllWidgets();
     }
 
@@ -156,13 +158,13 @@
     }
 
     @Test
-    public void doSearch_shouldInformCallback() {
+    public void doSearch_shouldInformCallback() throws Exception {
         doReturn(List.of(mCalendarHeaderEntry, mCalendarContentEntry, mCameraHeaderEntry,
                 mCameraContentEntry, mClockHeaderEntry, mClockContentEntry))
                 .when(mDataProvider)
                 .getAllWidgets();
         mSimpleWidgetsSearchAlgorithm.doSearch("Ca", mSearchCallback);
-        shadowOf(getMainLooper()).idle();
+        MAIN_EXECUTOR.submit(() -> { }).get();
         verify(mSearchCallback).onSearchResult(
                 matches("Ca"), argThat(a -> a != null && !a.isEmpty()));
     }
@@ -195,14 +197,10 @@
     }
 
     private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
-        ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
         ArrayList<WidgetItem> widgetItems = new ArrayList<>();
         for (int i = 0; i < numOfWidgets; i++) {
             ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
-            AppWidgetProviderInfo widgetInfo = new AppWidgetProviderInfo();
-            widgetInfo.provider = cn;
-            ReflectionHelpers.setField(widgetInfo, "providerInfo",
-                    packageManager.addReceiverIfNotPresent(cn));
+            AppWidgetProviderInfo widgetInfo = createAppWidgetProviderInfo(cn);
 
             WidgetItem widgetItem = new WidgetItem(
                     LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java b/tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
similarity index 83%
rename from robolectric_tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
rename to tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
index 7ac879a..583d37f 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
@@ -16,39 +16,38 @@
 
 package com.android.launcher3.widget.picker.search;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
 import static org.junit.Assert.assertEquals;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 
+import android.content.Context;
 import android.view.View;
 import android.widget.ImageButton;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import com.android.launcher3.ExtendedEditText;
 import com.android.launcher3.search.SearchAlgorithm;
-import com.android.launcher3.testing.TestActivity;
 import com.android.launcher3.widget.model.WidgetsListBaseEntry;
 
-import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.robolectric.Robolectric;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.android.controller.ActivityController;
 
 import java.util.ArrayList;
 
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public class WidgetsSearchBarControllerTest {
 
     private WidgetsSearchBarController mController;
-    // TODO: Replace ActivityController with ActivityScenario, which is the recommended way for
-    // activity testing.
-    private ActivityController<TestActivity> mActivityController;
     private ExtendedEditText mEditText;
     private ImageButton mCancelButton;
     @Mock
@@ -59,20 +58,14 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
-        mActivityController = Robolectric.buildActivity(TestActivity.class);
-        TestActivity testActivity = mActivityController.setup().get();
+        Context context = getApplicationContext();
 
-        mEditText = new ExtendedEditText(testActivity);
-        mCancelButton = new ImageButton(testActivity);
+        mEditText = new ExtendedEditText(context);
+        mCancelButton = new ImageButton(context);
         mController = new WidgetsSearchBarController(
                 mSearchAlgorithm, mEditText, mCancelButton, mSearchModeListener);
     }
 
-    @After
-    public void tearDown() {
-        mActivityController.destroy();
-    }
-
     @Test
     public void onSearchResult_shouldInformSearchModeListener() {
         ArrayList<WidgetsListBaseEntry> entries = new ArrayList<>();
diff --git a/robolectric_tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java b/tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
similarity index 89%
rename from robolectric_tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
rename to tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
index 56d7d68..d6da776 100644
--- a/robolectric_tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
@@ -15,11 +15,14 @@
  */
 package com.android.launcher3.widget.picker.util;
 
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo;
+
 import static com.google.common.truth.Truth.assertThat;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.Mockito.doAnswer;
-import static org.robolectric.Shadows.shadowOf;
 
 import android.appwidget.AppWidgetProviderInfo;
 import android.content.ComponentName;
@@ -29,6 +32,9 @@
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
 import com.android.launcher3.InvariantDeviceProfile;
 import com.android.launcher3.icons.ComponentWithLabel;
 import com.android.launcher3.icons.IconCache;
@@ -42,15 +48,12 @@
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
-import org.robolectric.RobolectricTestRunner;
-import org.robolectric.RuntimeEnvironment;
-import org.robolectric.shadows.ShadowPackageManager;
-import org.robolectric.util.ReflectionHelpers;
 
 import java.util.ArrayList;
 import java.util.List;
 
-@RunWith(RobolectricTestRunner.class)
+@SmallTest
+@RunWith(AndroidJUnit4.class)
 public final class WidgetsTableUtilsTest {
     private static final String TEST_PACKAGE = "com.google.test";
 
@@ -73,7 +76,7 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
 
-        mContext = RuntimeEnvironment.application;
+        mContext = getApplicationContext();
 
         mTestProfile = new InvariantDeviceProfile();
         mTestProfile.numRows = 5;
@@ -152,16 +155,14 @@
         ArrayList<WidgetItem> widgetItems = new ArrayList<>();
         widgetSizes.stream().forEach(
                 widgetSize -> {
-                    ShadowPackageManager packageManager = shadowOf(mContext.getPackageManager());
-                    AppWidgetProviderInfo info = new AppWidgetProviderInfo();
-                    info.provider = ComponentName.createRelative(TEST_PACKAGE,
-                            ".WidgetProvider_" + widgetSize.x + "x" + widgetSize.y);
+                    AppWidgetProviderInfo info = createAppWidgetProviderInfo(
+                            ComponentName.createRelative(
+                                    TEST_PACKAGE,
+                                    ".WidgetProvider_" + widgetSize.x + "x" + widgetSize.y));
                     LauncherAppWidgetProviderInfo widgetInfo =
                             LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info);
                     widgetInfo.spanX = widgetSize.x;
                     widgetInfo.spanY = widgetSize.y;
-                    ReflectionHelpers.setField(widgetInfo, "providerInfo",
-                            packageManager.addReceiverIfNotPresent(widgetInfo.provider));
                     widgetItems.add(new WidgetItem(widgetInfo, mTestProfile, mIconCache));
                 }
         );
diff --git a/tests/src_common/README.md b/tests/src_common/README.md
deleted file mode 100644
index 2bc9e73..0000000
--- a/tests/src_common/README.md
+++ /dev/null
@@ -1 +0,0 @@
-Common source code used by both android tests and robolectric tests
\ No newline at end of file
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 2ca40d8..23aaa25 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -251,8 +251,19 @@
             } else {
                 try {
                     final int userId = ContextUtils.getUserId(getContext());
+                    final String launcherPidCommand = "pidof " + pi.packageName;
+                    final String initialPid = mDevice.executeShellCommand(launcherPidCommand)
+                            .replaceAll("\\s", "");
                     mDevice.executeShellCommand(
                             "pm enable --user " + userId + " " + cn.flattenToString());
+                    // Wait for Launcher restart after enabling test provider.
+                    for (int i = 0; i < 100; ++i) {
+                        final String currentPid = mDevice.executeShellCommand(launcherPidCommand)
+                                .replaceAll("\\s", "");
+                        if (!currentPid.isEmpty() && !currentPid.equals(initialPid)) break;
+                        if (i == 99) fail("Launcher didn't restart after enabling test provider");
+                        SystemClock.sleep(100);
+                    }
                 } catch (IOException e) {
                     fail(e.toString());
                 }
@@ -305,7 +316,7 @@
 
     public boolean isTwoPanels() {
         return getTestInfo(TestProtocol.REQUEST_IS_TWO_PANELS)
-            .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+                .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
     }
 
     private void setForcePauseTimeout(long timeout) {