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) {