Merge "Fix for bug where we don't use default grid on comet, and migrate normally if not in a B&R case" into main
diff --git a/Android.bp b/Android.bp
index bcbd362..9d7aa73 100644
--- a/Android.bp
+++ b/Android.bp
@@ -17,7 +17,7 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-min_launcher3_sdk_version = "30"
+min_launcher3_sdk_version = "31"
// Targets that don't inherit framework aconfig libs (i.e., those that don't set
// `platform_apis: true`) must manually link them.
@@ -64,11 +64,74 @@
filegroup {
name: "launcher-quickstep-src",
srcs: [
- "quickstep/src/**/*.java",
"quickstep/src/**/*.kt",
+ "quickstep/src/**/*.java",
+ ":launcher-quickstep-processed-protolog-src",
],
}
+// Launcher ProtoLog support
+filegroup {
+ name: "launcher-quickstep-unprocessed-protolog-src",
+ srcs: [
+ "quickstep/src_protolog/**/*.java",
+ ],
+}
+
+java_library {
+ name: "launcher-quickstep_protolog-groups",
+ srcs: [
+ "quickstep/src_protolog/**/*.java",
+ ],
+ static_libs: [
+ "protolog-group",
+ "androidx.annotation_annotation",
+ "com_android_launcher3_flags_lib",
+ ],
+}
+
+genrule {
+ name: "launcher-quickstep-processed-protolog-src",
+ srcs: [
+ ":protolog-impl",
+ ":launcher-quickstep-unprocessed-protolog-src",
+ ":launcher-quickstep_protolog-groups",
+ ],
+ tools: ["protologtool"],
+ cmd: "$(location protologtool) transform-protolog-calls " +
+ "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--loggroups-class com.android.quickstep.util.QuickstepProtoLogGroup " +
+ "--loggroups-jar $(location :launcher-quickstep_protolog-groups) " +
+ "--viewer-config-file-path /system_ext/etc/launcher.quickstep.protolog.pb " +
+ "--output-srcjar $(out) " +
+ "$(locations :launcher-quickstep-unprocessed-protolog-src)",
+ out: ["launcher.quickstep.protolog.srcjar"],
+}
+
+genrule {
+ name: "gen-launcher.quickstep.protolog.pb",
+ srcs: [
+ ":launcher-quickstep-unprocessed-protolog-src",
+ ":launcher-quickstep_protolog-groups",
+ ],
+ tools: ["protologtool"],
+ cmd: "$(location protologtool) generate-viewer-config " +
+ "--protolog-class com.android.internal.protolog.common.ProtoLog " +
+ "--loggroups-class com.android.quickstep.util.QuickstepProtoLogGroup " +
+ "--loggroups-jar $(location :launcher-quickstep_protolog-groups) " +
+ "--viewer-config-type proto " +
+ "--viewer-config $(out) " +
+ "$(locations :launcher-quickstep-unprocessed-protolog-src)",
+ out: ["launcher.quickstep.protolog.pb"],
+}
+
+prebuilt_etc {
+ name: "launcher.quickstep.protolog.pb",
+ system_ext_specific: true,
+ src: ":gen-launcher.quickstep.protolog.pb",
+ filename_from_src: true,
+}
+
// Source code for quickstep dagger
filegroup {
name: "launcher-quickstep-dagger",
@@ -405,6 +468,7 @@
"SystemUISharedLib",
"SettingsLibSettingsTheme",
"dagger2",
+ "protolog-group",
],
manifest: "quickstep/AndroidManifest.xml",
min_sdk_version: "current",
@@ -503,7 +567,10 @@
"Launcher2",
"Launcher3",
],
- required: ["privapp_whitelist_com.android.launcher3"],
+ required: [
+ "privapp_whitelist_com.android.launcher3",
+ "launcher.quickstep.protolog.pb",
+ ],
resource_dirs: ["quickstep/res"],
diff --git a/proguard.flags b/proguard.flags
index 31edd8d..da00c00 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -57,3 +57,7 @@
-keep class com.android.quickstep.** {
*;
}
+
+-keep class com.android.internal.protolog.** {
+ *;
+}
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index bf198b6..57bfb4a 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -54,6 +54,7 @@
android:protectionLevel="signature|privileged" />
<application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
+ android:enableOnBackInvokedCallback="true"
android:fullBackupOnly="true"
android:fullBackupContent="@xml/backupscheme"
android:hardwareAccelerated="true"
diff --git a/quickstep/dagger/LauncherAppComponent.java b/quickstep/dagger/LauncherAppComponent.java
index bd6008e..068f01c 100644
--- a/quickstep/dagger/LauncherAppComponent.java
+++ b/quickstep/dagger/LauncherAppComponent.java
@@ -18,6 +18,7 @@
import com.android.quickstep.dagger.QuickStepModule;
+import com.android.quickstep.dagger.QuickstepBaseAppComponent;
import dagger.Component;
@@ -26,7 +27,7 @@
*/
@LauncherAppSingleton
@Component(modules = QuickStepModule.class)
-public interface LauncherAppComponent extends LauncherBaseAppComponent {
+public interface LauncherAppComponent extends QuickstepBaseAppComponent {
/** Builder for quickstep LauncherAppComponent. */
@Component.Builder
interface Builder extends LauncherBaseAppComponent.Builder {
diff --git a/quickstep/res/drawable/taskbar_overflow_icon.xml b/quickstep/res/drawable/taskbar_overflow_icon.xml
new file mode 100644
index 0000000..b93a70e
--- /dev/null
+++ b/quickstep/res/drawable/taskbar_overflow_icon.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:viewportHeight="960"
+ android:viewportWidth="960">
+ <path
+ android:fillColor="@color/taskbar_divider_background"
+ android:pathData="M80,605v-250q0,-28.88 20.59,-49.44t49.5,-20.56q28.91,0 49.41,20.56Q220,326.12 220,355v250q0,28.87 -20.59,49.44Q178.82,675 149.91,675t-49.41,-20.56Q80,633.87 80,605ZM340,760q-24,0 -42,-18t-18,-42v-440q0,-24 18,-42t42,-18h280q24,0 42,18t18,42v440q0,24 -18,42t-42,18L340,760ZM740,605v-250q0,-28.88 20.59,-49.44t49.5,-20.56q28.91,0 49.41,20.56Q880,326.12 880,355v250q0,28.87 -20.59,49.44Q838.82,675 809.91,675t-49.41,-20.56Q740,633.87 740,605ZM340,700h280v-440L340,260v440ZM480,480Z"/>
+</vector>
diff --git a/quickstep/res/layout/bubblebar_flyout.xml b/quickstep/res/layout/bubblebar_flyout.xml
index ff5047f..fc1e914 100644
--- a/quickstep/res/layout/bubblebar_flyout.xml
+++ b/quickstep/res/layout/bubblebar_flyout.xml
@@ -20,11 +20,12 @@
<ImageView
android:id="@+id/bubble_flyout_avatar"
- android:layout_width="36dp"
+ android:layout_width="50dp"
android:layout_height="36dp"
- android:padding="@dimen/bubblebar_flyout_avatar_message_space"
+ android:paddingEnd="@dimen/bubblebar_flyout_avatar_message_space"
android:scaleType="centerInside"
app:layout_constraintTop_toTopOf="parent"
+ app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
tools:src="#ff0000"/>
diff --git a/quickstep/res/layout/task_thumbnail.xml b/quickstep/res/layout/task_thumbnail.xml
index d90d916..afbcdb5 100644
--- a/quickstep/res/layout/task_thumbnail.xml
+++ b/quickstep/res/layout/task_thumbnail.xml
@@ -16,6 +16,7 @@
<com.android.quickstep.task.thumbnail.TaskThumbnailView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
+ android:id="@+id/snapshot"
android:layout_width="match_parent"
android:layout_height="match_parent" >
diff --git a/quickstep/res/layout/taskbar_overflow_button.xml b/quickstep/res/layout/taskbar_overflow_button.xml
new file mode 100644
index 0000000..20104f2
--- /dev/null
+++ b/quickstep/res/layout/taskbar_overflow_button.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2024 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.
+-->
+
+<!-- Note: The actual size will match the taskbar icon sizes in TaskbarView#onLayout(). -->
+<com.android.launcher3.views.IconButtonView xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/BaseIcon.Workspace.Taskbar"
+ android:layout_width="@dimen/taskbar_icon_min_touch_size"
+ android:layout_height="@dimen/taskbar_icon_min_touch_size"
+ android:backgroundTint="@android:color/transparent"
+ android:contentDescription="@string/taskbar_overflow_a11y_title" />
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 4122637..7d65403 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Wys altyd Taakbalk"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Verander navigasiemodus"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taakbalkverdeler"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Skuif na links bo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Skuif na regs onder"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{meer app}other{meer apps}}"</string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 956767ee..28bd69a 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"ሁልጊዜ የተግባር አሞሌ ያሳዩ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"የአሰሳ ሁነታን ይለውጡ"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"የተግባር አሞሌ አካፋይ"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ወደ ላይ/ግራ ይውሰዱ"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ወደ ታች/ቀኝ ይውሰዱ"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ተጨማሪ መተግበሪያ}one{ተጨማሪ መተግበሪያ}other{ተጨማሪ መተግበሪያዎች}}"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index e691663..6ba2e5d 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"إظهار شريط التطبيقات دائمًا"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"تغيير وضع التنقل"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"مقسِّم شريط التطبيقات"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"الانتقال إلى يمين الشاشة أو أعلاها"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"الانتقال إلى يسار الشاشة أو أسفلها"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{تطبيق واحد آخر}zero{تطبيق آخر}two{تطبيقان آخران}few{تطبيقات أخرى}many{تطبيقًا آخر}other{تطبيق آخر}}"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 912003b..486dc09 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"টাস্কবাৰ সদায় দেখুৱাওক"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"নেভিগেশ্বন ম’ড সলনি কৰক"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"টাস্কবাৰ বিভাজক"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ওপৰৰ বাঁওফাললৈ নিয়ক"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"তলৰ সোঁফাললৈ নিয়ক"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{অধিক এপ্}one{অধিক এপ্}other{অধিক এপ্}}"</string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index b89b707..c483db3 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"İşləmə paneli həmişə görünsün"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Naviqasiya rejimini dəyişin"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"İşləmə paneli ayırıcısı"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuxarı/sola köçürün"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Aşağı/sağa köçürün"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{əlavə tətbiq}other{əlavə tətbiq}}"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 4ef487e..f08cf83 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Uvek prikazuj traku zadataka"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Promeni režim navigacije"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdelnik trake zadataka"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premesti gore levo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premesti dole desno"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index c506acb..fb5b556 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Заўсёды паказваць панэль задач"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Змяніць рэжым навігацыі"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Раздзяляльнік панэлі задач"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перамясціць уверх/улева"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перамясціць уніз/управа"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{даступная праграма}one{даступная праграма}few{даступныя праграмы}many{даступных праграм}other{даступнай праграмы}}"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index d03e4f7..3c0d840 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Лентата на задачите винаги да се показва"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Промяна на режима на навигация"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделител на лентата на задачите"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Преместване горе/вляво"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Преместване долу/вдясно"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{допълнително приложение}other{допълнителни приложения}}"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 0c568d9..a224dac 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"সবসময় টাস্কবার দেখুন"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"\'নেভিগেশন\' মোড পরিবর্তন করুন"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"টাস্কবার ডিভাইডার"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"উপরে/বাঁদিকে সরান"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"নিচে/ডানদিকে সরান"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{আরও অ্যাপ}one{আরও অ্যাপ}other{আরও অ্যাপ}}"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 922883e..6588dd0 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Uvijek prikaži traku zadataka"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Promijeni način navigacije"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdjelnik trake zadataka"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore lijevo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje desno"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index fe7933b..abb2984 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Barra de tasques sempre visible"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Canvia el mode de navegació"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separador de la Barra de tasques"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mou a la part superior o a l\'esquerra"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mou a la part inferior o a la dreta"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicació més}other{aplicacions més}}"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 3047d05..324b02a 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Vždy zobrazovat panel aplikací"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Změnit režim navigace"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Rozdělovač panelu aplikací"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Přesunout doleva nahoru"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Přesunout doprava dolů"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{další aplikace}few{další aplikace}many{další aplikace}other{dalších aplikací}}"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 6e2130c..ca30dda 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Vis altid proceslinjen"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Skift navigationstilstand"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Opdeling af proceslinjen"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flyt til toppen eller venstre side"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flyt til bunden eller højre side"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{yderligere app}one{yderligere app}other{yderligere apps}}"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 54961fe..f14eddf 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Taskleiste immer anzeigen"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Navigationsmodus ändern"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskleisten-Teiler"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Nach oben / Nach links verschieben"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Nach unten / Nach rechts verschieben"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{weitere App}other{weitere Apps}}"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 6cbb833..e767c74 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Εμφάνιση Γραμμής εργαλείων"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Αλλαγή τρόπου πλοήγησης"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Διαχωριστικό Γραμμής εργαλείων"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Μετακίνηση επάνω/αριστερά"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Μετακίνηση κάτω/δεξιά"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ακόμη εφαρμογή}other{ακόμη εφαρμογές}}"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index dcbaa7a..a74a17b 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Always show Taskbar"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Change navigation mode"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar divider"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index c00e6cd..e0787ca 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -139,6 +139,7 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Always show Taskbar"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Change navigation mode"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar Divider"</string>
+ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taskbar Overflow"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index dcbaa7a..a74a17b 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Always show Taskbar"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Change navigation mode"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar divider"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index dcbaa7a..a74a17b 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Always show Taskbar"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Change navigation mode"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar divider"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index 2abef91..8fcbe2b 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -139,6 +139,7 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Always show Taskbar"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Change navigation mode"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar Divider"</string>
+ <string name="taskbar_overflow_a11y_title" msgid="7960342079198820179">"Taskbar Overflow"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Move to top/left"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Move to bottom/right"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index f09fae6..e6efd43 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Barra de tareas visible"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Cambiar el modo de navegación"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor de la Barra de tareas"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover a la parte superior o izquierda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover a la parte inferior o derecha"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app más}other{apps más}}"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 356a38b..527bdc3 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Barra de tareas visible"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Cambiar el modo de navegación"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor de Barra de Tareas"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover arriba/a la izquierda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover abajo/a la derecha"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicación más}other{aplicaciones más}}"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index fccbeda..0e222bc 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Kuva tegumiriba alati"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Navigeerimisrežiimi muutmine"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Tegumiriba jagaja"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Teisalda üles/vasakule"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Teisalda alla/paremale"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{rakendus veel}other{rakendust veel}}"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index a1d8cc3..7764cb8 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Erakutsi beti zereginen barra"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Aldatu nabigazio modua"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Zereginen barraren zatitzailea"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Eraman gora, ezkerretara"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Eraman behera, eskuinetara"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikazio gehiago}other{aplikazio gehiago}}"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 8f37686..05cf83e 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"نوار وظیفه همیشه نشان داده شود"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"تغییر حالت پیمایش"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"جداکننده نوار وظیفه"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"انتقال به بالا/ چپ"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"انتقال به پایین/ راست"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{برنامه دیگر}one{برنامه دیگر}other{برنامه دیگر}}"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 175a896..73b1ba4 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Näytä tehtäväpalkki aina"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Vaihda navigointitilaa"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Tehtäväpalkin jakaja"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Siirrä ylös tai vasemmalle"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Siirrä alas tai oikealle"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{muu sovellus}other{muuta sovellusta}}"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 6d6c67c..a554881 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Tjrs afficher barre des tâches"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Changer de mode de navigation"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Séparateur de la barre des tâches"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer vers le coin supérieur gauche de l\'écran"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer vers le coin inférieur droit de l\'écran"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{autre appli}one{autre appli}other{autres applis}}"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index a395266..3711dcd 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Barre des tâches tjs visible"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Modifier le mode de navigation"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Séparateur de barre des tâches"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer en haut ou à gauche"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer en bas ou à droite"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{autre application}one{autre application}other{autres applications}}"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 5b04960..a2c4b73 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Ver sempre a barra de tarefas"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Cambiar modo de navegación"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor da Barra de tarefas"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover á parte superior ou á esquerda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover á parte inferior ou á dereita"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicación máis}other{aplicacións máis}}"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index fc253bd..dea52c3 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"હંમેશાં ટાસ્કબાર બતાવો"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"નૅવિગેશન મોડ બદલો"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ટાસ્કબાર વિભાજક"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"સૌથી ઉપર ડાબી બાજુએ ખસેડો"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"સૌથી નીચે જમણી બાજુએ ખસેડો"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{વધુ ઍપ}one{વધુ ઍપ}other{વધુ ઍપ}}"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 30a17db..e81e942 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"टास्कबार हमेशा दिखाएं"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"नेविगेशन का मोड बदलें"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार डिवाइडर"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ऊपर/बाईं तरफ़ ले जाएं"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"नीचे/दाईं तरफ़ ले जाएं"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ज़्यादा ऐप्लिकेशन}one{ज़्यादा ऐप्लिकेशन}other{ज़्यादा ऐप्लिकेशन}}"</string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index 06511e9..a2bf691 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Uvijek prikaži traku zadataka"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Promijeni način navigacije"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdjelnik trake sa zadacima"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore/lijevo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje/desno"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 9bd9478..4dc9974 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Mindig megjelenő Feladatsáv"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Navigációs mód módosítása"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Feladatsáv-elválasztó"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mozgatás felülre vagy a bal oldalra"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mozgatás alulra vagy a jobb oldalra"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{további alkalmazás}other{további alkalmazás}}"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index e1481ec..f4fcacf 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Միշտ ցույց տալ վահանակը"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Փոխել նավիգացիայի ռեժիմը"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Հավելվածների վահանակի բաժանիչ"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Տեղափոխել վերևի ձախ անկյուն"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Տեղափոխել ներքևի աջ անկյուն"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{լրացուցիչ հավելված}one{լրացուցիչ հավելված}other{լրացուցիչ հավելված}}"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index f8345b5..519dced 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Selalu tampilkan Taskbar"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Ubah mode navigasi"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Pemisah Taskbar"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pindahkan ke atas/kiri"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pindahkan ke bawah/kanan"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikasi lainnya}other{aplikasi lainnya}}"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index 017d108..274e1da 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Alltaf sýna forritastiku"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Breyta leiðsagnarstillingu"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Skipting forritastiku"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Færa efst/til vinstri"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Færa neðst/til hægri"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{forrit til viðbótar}one{forrit til viðbótar}other{forrit til viðbótar}}"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 1983ee3..445474e 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Mostra sempre barra app"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Cambia modalità di navigazione"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisore barra delle app"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sposta in alto/a sinistra"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sposta in basso/a destra"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{altra app}other{altre app}}"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index a7115e3..5bb51ce 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"סרגל האפליקציות מוצג תמיד"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"שינוי מצב הניווט"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"המחיצה בסרגל האפליקציות"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"העברה לפינה השמאלית/העליונה"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"העברה לפינה הימנית/התחתונה"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{אפליקציה נוספת}one{אפליקציות נוספות}two{אפליקציות נוספות}other{אפליקציות נוספות}}"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index fa3c01d..0cff4c1 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"常にタスクバーを表示する"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ナビゲーション モードを変更"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"タスクバーの区切り"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"上 / 左に移動"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"下 / 右に移動"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個のその他のアプリ}other{個のその他のアプリ}}"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index a032731..efff980 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"ამოცანათა ზოლის მუდამ ჩვენება"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"შეცვალეთ ნავიგაციის რეჟიმი"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ამოცანათა ზოლის გამყოფი"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ზემოთ/მარცხნივ გადატანა"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ქვემოთ/მარჯვნივ გადატანა"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{სხვა აპი}other{სხვა აპი}}"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index e1a9e8e..193b606 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Тапсырма жолағын үнемі көрсету"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Навигация режимін өзгерту"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Тапсырмалар жолағын бөлгіш"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жоғары/солға жылжыту"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмен/оңға жылжыту"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{қосымша қолданба}other{қосымша қолданба}}"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 2eb3114..aadfd67 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"បង្ហាញរបារកិច្ចការជានិច្ច"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ប្ដូរមុខងាររុករក"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"បន្ទាត់ខណ្ឌចែករបារកិច្ចការ"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ផ្លាស់ទីទៅខាងលើ/ឆ្វេង"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ផ្លាស់ទីទៅខាងក្រោម/ស្ដាំ"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{កម្មវិធីច្រើនទៀត}other{កម្មវិធីច្រើនទៀត}}"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index bb60620..9a04ffd 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"ಯಾವಾಗಲೂ ಟಾಸ್ಕ್ಬಾರ್ ತೋರಿಸಿ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ನ್ಯಾವಿಗೇಶನ್ ಮೋಡ್ ಬದಲಾಯಿಸಿ"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ಟಾಸ್ಕ್ಬಾರ್ ಡಿವೈಡರ್"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ಮೇಲಿನ/ಎಡಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ಕೆಳಗಿನ/ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ಹೆಚ್ಚಿನ ಆ್ಯಪ್}one{ಹೆಚ್ಚಿನ ಆ್ಯಪ್ಗಳು}other{ಹೆಚ್ಚಿನ ಆ್ಯಪ್ಗಳು}}"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index e6a80c3..38d5bbb 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"태스크 바 항상 표시"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"탐색 모드 변경"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"태스크 바 분할"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"상단/왼쪽으로 이동"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"하단/오른쪽으로 이동"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{추가 앱}other{추가 앱}}"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 04e7f6e..8eba2a5 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Такта ар дайым көрүнсүн"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Өтүү режимин өзгөртүү"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Тапшырмалар панелин бөлгүч"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Жогорку/сол бурчка жылдыруу"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Төмөнкү/оң бурчка жылдыруу"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{колдонмо бар}other{колдонмо бар}}"</string>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index b3ca116..284cdc7 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"ສະແດງແຖບໜ້າວຽກສະເໝີ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ປ່ຽນໂໝດການນຳທາງ"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ເສັ້ນແບ່ງແຖບໜ້າວຽກ"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ຍ້າຍໄປຊ້າຍ/ເທິງ"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ຍ້າຍໄປຂວາ/ລຸ່ມ"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ແອັບເພີ່ມເຕີມ}other{ແອັບເພີ່ມເຕີມ}}"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index 4f3f36e..1c20015 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Visada rodyti užduočių juostą"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Keisti naršymo režimą"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Užduočių juostos daliklis"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Perkelti aukštyn, kairėn"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Perkelti žemyn, dešinėn"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{papildoma programa}one{papildoma programa}few{papildomos programos}many{papildomos programos}other{papildomų programų}}"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index fd75fc4..408f3c3 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Vienmēr rādīt uzdevumu joslu"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Mainīt navigācijas režīmu"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Uzdevumu joslas atdalītājs"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pārvietot uz augšējo/kreiso stūri"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pārvietot uz apakšējo/labo stūri"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{papildu lietotne}zero{papildu lietotņu}one{papildu lietotne}other{papildu lietotnes}}"</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index b50277b..588578e 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Секогаш прикажувај „Лента“"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Променете режим на навигација"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделник на „Лента со задачи“"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести долу десно"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{дополнителна апликација}one{дополнителна апликација}other{дополнителни апликации}}"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index ef72da1..bb5c014 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"ടാസ്ക്ബാർ എപ്പോഴും കാണിക്കൂ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"നാവിഗേഷൻ മോഡ് മാറ്റുക"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ടാസ്ക്ബാർ ഡിവൈഡർ"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"മുകളിലേക്കോ ഇടത്തേക്കോ നീക്കുക"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"താഴേക്കോ വലത്തേക്കോ നീക്കുക"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{കൂടുതൽ ആപ്പ്}other{കൂടുതൽ ആപ്പുകൾ}}"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 2ca2e26..9223139 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Ажлын хэсгийг үргэлж харуулах"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Навигацын горимыг өөрчлөх"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Ажлын хэсгийг хуваагч"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Зүүн дээд хэсэг рүү зөөх"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Баруун доод хэсэг рүү зөөх"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{бусад апп}other{бусад апп}}"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 159368d..3eef060 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"नेहमी टास्कबार दाखवा"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"नेव्हिगेशन मोड बदला"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार विभाजक"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सर्वात वरती/डावीकडे हलवा"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"तळाशी/उजवीकडे हलवा"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{आणखी अॅप}other{आणखी अॅप्स}}"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 9a27e51..9bdc973 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Papar Bar Tugas selalu"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Tukar mod navigasi"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Pembahagi Bar Tugas"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Alihkan ke atas/kiri"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Alihkan ke bawah/kanan"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{apl lagi}other{apl lagi}}"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 7e298fb..6ea946a 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Taskbar အမြဲပြရန်"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ရွှေ့ကြည့်သည့်မုဒ် ပြောင်းရန်"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"လုပ်ဆောင်စရာဘား ပိုင်းခြားစနစ်"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"အပေါ်/ဘယ်ဘက်သို့ ရွှေ့ရန်"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"အောက်ခြေ/ညာဘက်သို့ ရွှေ့ရန်"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{နောက်ထပ်အက်ပ်}other{နောက်ထပ်အက်ပ်များ}}"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 21b5fd4..33cde5a 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Vis alltid oppgavelinjen"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Endre navigasjonsmodus"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Skille for oppgavelinjen"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytt til øverst/venstre"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytt til nederst/høyre"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app til}other{apper til}}"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 326222b..4c9747f 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"टास्कबार सधैँ देखाउनुहोस्"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"नेभिगेसन मोड बदल्नुहोस्"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार डिभाइडर"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"सिरान/बायाँतिर सार्नुहोस्"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"फेद/दायाँतिर सार्नुहोस्"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{थप एप}other{थप एपहरू}}"</string>
diff --git a/quickstep/res/values-night/colors.xml b/quickstep/res/values-night/colors.xml
index 2052446..98e4871 100644
--- a/quickstep/res/values-night/colors.xml
+++ b/quickstep/res/values-night/colors.xml
@@ -25,7 +25,7 @@
<color name="all_set_page_background">@android:color/system_neutral1_900</color>
<!-- Turn on work apps button -->
- <color name="work_turn_on_stroke">?androidprv:attr/colorAccentSecondaryVariant</color>
+ <color name="work_turn_on_stroke">?attr/materialColorPrimary</color>
<color name="work_fab_bg_color">?attr/materialColorPrimaryFixedDim</color>
<color name="work_fab_icon_color">?attr/materialColorOnPrimaryFixed</color>
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 8a923b5..a4949ac 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Taakbalk altijd tonen"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Navigatiemodus wijzigen"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Scheiding voor Taakbalk"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Naar boven/links verplaatsen"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Naar beneden/rechts verplaatsen"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{extra app}other{extra apps}}"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 3150ded..7753153 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"ସର୍ବଦା ଟାସ୍କବାର ଦେଖାନ୍ତୁ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ନାଭିଗେସନ ମୋଡ ପରିବର୍ତ୍ତନ କରନ୍ତୁ"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ଟାସ୍କବାର ଡିଭାଇଡର"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ଶୀର୍ଷ/ବାମକୁ ମୁଭ କରନ୍ତୁ"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ନିମ୍ନ/ଡାହାଣକୁ ମୁଭ କରନ୍ତୁ"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ଅଧିକ ଆପ}other{ଅଧିକ ଆପ୍ସ}}"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 7da7555..011fa6e 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"ਹਮੇਸ਼ਾਂ ਟਾਸਕਬਾਰ ਦਿਖਾਓ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"ਨੈਵੀਗੇਸ਼ਨ ਮੋਡ ਬਦਲੋ"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ਟਾਸਕਬਾਰ ਵਿਭਾਜਕ"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ਸਿਖਰਲੇ/ਖੱਬੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ਹੇਠਾਂ/ਸੱਜੇ ਪਾਸੇ ਲੈ ਕੇ ਜਾਓ"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ਹੋਰ ਐਪ}one{ਹੋਰ ਐਪ}other{ਹੋਰ ਐਪਾਂ}}"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 0cc49e2..df0f74c 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Zawsze pokazuj pasek aplikacji"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Zmień tryb nawigacji"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Linia dzielenia paska aplikacji"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Przesuń w górny lewy róg"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Przesuń w dolny prawy róg"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{inna aplikacja}few{inne aplikacje}many{innych aplikacji}other{innej aplikacji}}"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 33b87df..5ad32af 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Ver sempre Barra de tarefas"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Alterar modo de navegação"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor da Barra de tarefas"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para a parte superior esquerda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para a part superior direita"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{outra app}other{outras apps}}"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 0aa6295..28b3414 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Sempre mostrar a Barra de tarefas"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Mudar o modo de navegação"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separador da Barra de tarefas"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover para cima/para a esquerda"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover para baixo/para a direita"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{outro app}one{outro app}other{outros apps}}"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 2f9d287..6bd3e0f 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Afișează mereu bara"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Schimbă modul de navigare"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separator pentru bara de activități"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mută în stânga sus"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mută în dreapta jos"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicație suplimentară}few{mai multe aplicații}other{mai multe aplicații}}"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 2722ca9..20f579d 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Всегда показывать панель задач"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Изменить режим навигации"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделитель панели задач"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Переместить вверх или влево"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Переместить вниз или вправо"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{дополнительное приложение}one{дополнительное приложение}few{дополнительных приложения}many{дополнительных приложений}other{дополнительного приложения}}"</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 19b61f7..dd9739c 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"සෑම විටම කාර්ය තීරුව පෙන්වන්න"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"සංචාලන ප්රකාරය වෙනස් කරන්න"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"කාර්ය තීරු බෙදනය"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ඉහළ/වම වෙත ගෙන යන්න"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"පහළ/දකුණ වෙත ගෙන යන්න"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{තව යෙදුම}one{තවත් යෙදුම්}other{තවත් යෙදුම්}}"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 0f0ec27..6241ad2 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Zobrazovať panel aplikácií"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Zmeniť režim navigácie"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Rozdeľovač panela aplikácií"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Presunúť hore alebo doľava"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Presunúť dole alebo doprava"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ďalšia aplikácia}few{ďalšie aplikácie}many{ďalšie aplikácie}other{ďalšie aplikácie}}"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 972ced5..9394a5a 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Stalen prikaz oprav. vrstice"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Spreminjanje načina navigacije"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdelilnik opravilne vrstice"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premakni na vrh/levo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premakni na dno/desno"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}two{dodatni aplikaciji}few{dodatne aplikacije}other{dodatnih aplikacij}}"</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index d2a7281..12635c6 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Shfaq gjithmonë shiritin e detyrave"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Ndrysho modalitetin e navigimit"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Ndarësi i shiritit të detyrave"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Lëviz në krye/majtas"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Lëviz në fund/djathtas"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikacion tjetër}other{aplikacione të tjera}}"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 81204af..a7760b9 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Увек приказуј траку задатака"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Промени режим навигације"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделник траке задатака"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Премести горе лево"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Премести доле десно"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{додатна апликација}one{додатна апликација}few{додатне апликације}other{додатних апликација}}"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 5d0c7a3..d4c3a69 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Visa alltid aktivitetsfältet"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Ändra navigeringsläge"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Avdelare för aktivitetsfältet"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytta högst upp/till vänster"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytta längst ned/till höger"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app till}other{appar till}}"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index e133ba3..5b74600 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Onyesha Zana kila wakati"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Badilisha hali ya usogezaji"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Kitenganishi cha Upauzana"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sogeza juu/kushoto"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sogeza chini/kulia"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{programu nyingine}other{programu zingine}}"</string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 95d0fa9..39dc6bd 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"செயல் பட்டியை எப்போதும் காட்டு"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"வழிசெலுத்தல் பயன்முறையை மாற்று"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"செயல் பட்டிப் பிரிப்பான்"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"மேலே/இடதுபுறம் நகர்த்தும்"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"கீழே/வலதுபுறம் நகர்த்தும்"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{கூடுதல் ஆப்ஸ்}other{கூடுதல் ஆப்ஸ்}}"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 116d388..86161b4 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"టాస్క్బార్ను నిరంతరం చూపండి"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"నావిగేషన్ మోడ్ను మార్చండి"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"టాస్క్బార్ డివైడర్"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ఎగువ/ఎడమ వైపునకు తరలించండి"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"దిగువ/కుడి వైపునకు తరలించండి"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{మరో యాప్}other{మరిన్ని యాప్లు}}"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index ecdb3b5..c6fddfb 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"แสดงแถบงานเสมอ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"เปลี่ยนโหมดการนําทาง"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ตัวแบ่งแถบงาน"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"ย้ายไปที่ด้านบนหรือด้านซ้าย"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"ย้ายไปที่ด้านล่างหรือด้านขวา"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{แอปเพิ่มเติม}other{แอปเพิ่มเติม}}"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index da646a4..91f9675 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Ipakita lagi ang Taskbar"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Magpalit ng navigation mode"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divider ng Taskbar"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Ilipat sa itaas/kaliwa"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Ilipat sa ibaba/kanan"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{pang app}one{pang app}other{pang app}}"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 7be5464..f5f98bb 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Görev çubuğunu daima göster"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Gezinme modunu değiştir"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Görev Çubuğu Ayırıcısı"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sol üste taşı"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sağ alta taşı"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{uygulama daha}other{uygulama daha}}"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 216ae0b..93d974f 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Завжди показув. панель завдань"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Змінити режим навігації"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Розділювач панелі завдань"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Перемістити вгору або вліво"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Перемістити вниз або вправо"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{інший додаток}one{інший додаток}few{інші додатки}many{інших додатків}other{іншого додатка}}"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 2307cb1..76a2c81 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"ہمیشہ ٹاسک بار دکھائیں"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"نیویگیشن موڈ تبدیل کریں"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ٹاسک بار ڈیوائیڈر"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"اوپر/بائیں طرف منتقل کریں"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"نیچے/دائیں طرف منتقل کریں"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{مزید ایپ}other{مزید ایپس}}"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 9f98b55..0d6c09d 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Vazifalar paneli doim chiqarilsin"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Navigatsiya rejimini oʻzgartirish"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Vazifalar panelini ajratkich"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuqoriga yoki chapga oʻtkazish"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pastga yoki oʻngga oʻtkazish"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{boshqa ilova}other{boshqa ilovalar}}"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 50acbbc..cf38392 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Luôn hiện Thanh tác vụ"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Thay đổi chế độ điều hướng"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Đường phân chia Taskbar"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Chuyển lên trên cùng/sang bên trái"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Chuyển xuống dưới cùng/sang bên phải"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ứng dụng khác}other{ứng dụng khác}}"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 1b6c4e4..9017482 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"始终显示任务栏"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"更改导航模式"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"任务栏分隔线"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到顶部/左侧"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右侧"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{多个应用}other{多个应用}}"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 38608e5..672a61c 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"一律顯示工作列"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"變更導覽模式"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"工作列分隔線"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移至上方/左側"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移至底部/右側"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個其他應用程式}other{個其他應用程式}}"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 3e46779..257c996 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"一律顯示工作列"</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"變更操作模式"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"工作列分隔線"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到上方/左側"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右側"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個其他應用程式}other{個其他應用程式}}"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 120b387..9d7ecd7 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -139,6 +139,8 @@
<string name="always_show_taskbar" msgid="3608801276107751229">"Bonisa i-Taskbar njalo."</string>
<string name="change_navigation_mode" msgid="9088393078736808968">"Shintsha imodi yokufuna"</string>
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Isihlukanisi se-Taskbar"</string>
+ <!-- no translation found for taskbar_overflow_a11y_title (7960342079198820179) -->
+ <skip />
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Hamba phezulu/kwesokunxele"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Hamba phansi/kwesokudla"</string>
<string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{i-app eyengeziwe}one{ama-app engeziwe}other{ama-app engeziwe}}"</string>
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index 0bb971e..4c48bd3 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -94,7 +94,7 @@
<color name="lottie_yellow600">#f9ab00</color>
<!-- Turn on work apps button -->
- <color name="work_turn_on_stroke">?androidprv:attr/colorAccentPrimaryVariant</color>
+ <color name="work_turn_on_stroke">?attr/materialColorPrimary</color>
<color name="work_fab_bg_color">?attr/materialColorPrimaryFixedDim</color>
<color name="work_fab_icon_color">?attr/materialColorOnPrimaryFixed</color>
</resources>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index e99e9b5..8957e0d 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -480,11 +480,15 @@
<dimen name="bubble_expanded_view_drop_target_margin">16dp</dimen>
<!-- Bubble bar flyout view -->
- <dimen name="bubblebar_flyout_padding_horizontal">14dp</dimen>
- <dimen name="bubblebar_flyout_padding_vertical">10dp</dimen>
+ <dimen name="bubblebar_flyout_padding">16dp</dimen>
<dimen name="bubblebar_flyout_elevation">4dp</dimen>
- <dimen name="bubblebar_flyout_avatar_message_space">6dp</dimen>
- <dimen name="bubblebar_flyout_max_width">96dp</dimen>
+ <dimen name="bubblebar_flyout_avatar_message_space">14dp</dimen>
+ <dimen name="bubblebar_flyout_min_width">238dp</dimen>
+ <dimen name="bubblebar_flyout_max_width">276dp</dimen>
+ <dimen name="bubblebar_flyout_triangle_width">12dp</dimen>
+ <dimen name="bubblebar_flyout_triangle_height">10dp</dimen>
+ <dimen name="bubblebar_flyout_triangle_overlap_amount">1dp</dimen>
+ <dimen name="bubblebar_flyout_triangle_radius">2dp</dimen>
<!-- Launcher splash screen -->
<!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index f72f3c5..008766b 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -320,6 +320,8 @@
<string name="change_navigation_mode">Change navigation mode</string>
<!-- Accessibility title for the Taskbar vertical divider icon. [CHAR_LIMIT=NONE] -->
<string name="taskbar_divider_a11y_title">Taskbar Divider</string>
+ <!-- Accessibility title for the Taskbar Overflow icon. [CHAR_LIMIT=NONE] -->
+ <string name="taskbar_overflow_a11y_title">Taskbar Overflow</string>
<!-- Label for moving drop target to the top or left side of the screen, depending on orientation (from the Taskbar only). -->
diff --git a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
index 7a8b58e..32fda48 100644
--- a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -31,6 +31,7 @@
import android.view.accessibility.AccessibilityManager;
import androidx.annotation.ColorInt;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -253,4 +254,9 @@
public View getFocusedChild() {
return null;
}
+
+ @VisibleForTesting
+ public DividerType getDividerType() {
+ return mDividerType;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index f29980b..3dcb2ac 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -16,9 +16,9 @@
package com.android.launcher3.statehandlers;
import static android.view.View.VISIBLE;
+import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import android.content.Context;
import android.os.Debug;
@@ -167,7 +167,8 @@
notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
}
- if (!WALLPAPER_ACTIVITY.isEnabled(mContext) && wasVisible != isVisible) {
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && wasVisible != isVisible) {
// TODO: b/333533253 - Remove after flag rollout
if (mVisibleDesktopTasksCount > 0) {
setLauncherViewsVisibility(View.INVISIBLE);
@@ -225,7 +226,7 @@
notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
}
- if (WALLPAPER_ACTIVITY.isEnabled(mContext)) {
+ if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
return;
}
// TODO: b/333533253 - Clean up after flag rollout
@@ -252,7 +253,7 @@
for (DesktopVisibilityListener listener : mDesktopVisibilityListeners) {
listener.onDesktopVisibilityChanged(areDesktopTasksVisible);
}
- DisplayController.handleInfoChangeForDesktopMode(mContext);
+ DisplayController.INSTANCE.get(mContext).notifyConfigChange();
}
private void notifyTaskbarDesktopModeListeners(boolean doesAnyTaskRequireTaskbarRounding) {
@@ -341,7 +342,7 @@
if (mContext == null) {
return;
}
- if (WALLPAPER_ACTIVITY.isEnabled(mContext)) {
+ if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
return;
}
if (DEBUG) {
@@ -376,7 +377,7 @@
if (mContext == null) {
return;
}
- if (WALLPAPER_ACTIVITY.isEnabled(mContext)) {
+ if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
return;
}
if (DEBUG) {
@@ -396,7 +397,7 @@
if (mContext == null) {
return;
}
- if (WALLPAPER_ACTIVITY.isEnabled(mContext)) {
+ if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) {
return;
}
if (DEBUG) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index b4102a9..fc8204a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -58,8 +58,12 @@
import java.util.Locale;
/**
- * View that allows quick switching between recent tasks through keyboard alt-tab and alt-shift-tab
- * commands.
+ * View that allows quick switching between recent tasks.
+ *
+ * Can be access via:
+ * - keyboard alt-tab
+ * - alt-shift-tab
+ * - taskbar overflow button
*/
public class KeyboardQuickSwitchView extends ConstraintLayout {
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index aa8cea5..477f90c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -15,15 +15,15 @@
*/
package com.android.launcher3.taskbar;
+import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY;
+
import static com.android.launcher3.QuickstepTransitionManager.TRANSIENT_TASKBAR_TRANSITION_DURATION;
import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
import static com.android.launcher3.taskbar.TaskbarEduTooltipControllerKt.TOOLTIP_STEP_FEATURES;
import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
-import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import android.animation.Animator;
import android.animation.AnimatorSet;
-import android.graphics.Rect;
import android.window.RemoteTransition;
import androidx.annotation.NonNull;
@@ -127,7 +127,7 @@
@Override
protected void onDestroy() {
- onLauncherVisibilityChanged(false);
+ onLauncherVisibilityChanged(false /* isVisible */, true /* fromInitOrDestroy */);
super.onDestroy();
mTaskbarLauncherStateController.onDestroy();
@@ -189,38 +189,20 @@
}
/**
- * Returns the bounds of launcher's hotseat.
- */
- public void getHotseatBounds(Rect hotseatBoundsOut) {
- DeviceProfile launcherDP = mLauncher.getDeviceProfile();
- if (launcherDP.isQsbInline) {
- // Not currently supported.
- hotseatBoundsOut.setEmpty();
- return;
- }
- int left = (launcherDP.widthPx - launcherDP.getHotseatWidthPx()
- - mLauncher.getHotseat().getUnusedHorizontalSpace()) / 2;
- int right = left + launcherDP.getHotseatWidthPx();
- int bottom = launcherDP.getHotseatLayoutPadding(mLauncher).bottom;
- int top = bottom - launcherDP.hotseatCellHeightPx;
- hotseatBoundsOut.set(left, top, right, bottom);
- }
-
- /**
* Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
*/
@Override
public void onLauncherVisibilityChanged(boolean isVisible) {
if (DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(mLauncher)) {
- DisplayController.handleInfoChangeForLauncherVisibilityChanged(mLauncher);
+ DisplayController.INSTANCE.get(mLauncher).notifyConfigChange();
}
onLauncherVisibilityChanged(isVisible, false /* fromInit */);
}
- private void onLauncherVisibilityChanged(boolean isVisible, boolean fromInit) {
+ private void onLauncherVisibilityChanged(boolean isVisible, boolean fromInitOrDestroy) {
onLauncherVisibilityChanged(
isVisible,
- fromInit,
+ fromInitOrDestroy,
/* startAnimation= */ true,
DisplayController.isTransientTaskbar(mLauncher)
? TRANSIENT_TASKBAR_TRANSITION_DURATION
@@ -231,7 +213,7 @@
@Nullable
private Animator onLauncherVisibilityChanged(
- boolean isVisible, boolean fromInit, boolean startAnimation, int duration) {
+ boolean isVisible, boolean fromInitOrDestroy, boolean startAnimation, int duration) {
// Launcher is resumed during the swipe-to-overview gesture under shell-transitions, so
// avoid updating taskbar state in that situation (when it's non-interactive -- or
// "background") to avoid premature animations.
@@ -242,14 +224,14 @@
return null;
}
- if (!WALLPAPER_ACTIVITY.isEnabled(mLauncher)
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
&& mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
// TODO: b/333533253 - Remove after flag rollout
isVisible = false;
}
mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, isVisible);
- if (fromInit || mControllers == null) {
+ if (fromInitOrDestroy) {
duration = 0;
}
return mTaskbarLauncherStateController.applyState(duration, startAnimation);
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index e9bd30a..2ac5793 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -400,12 +400,6 @@
}
};
mSeparateWindowParent.recreateControllers();
- if (com.android.wm.shell.Flags.enableBubbleBarInPersistentTaskBar()
- && mControllers.bubbleControllers.isPresent()) {
- BubbleBarLocation bubblesLocation = mControllers.bubbleControllers.get()
- .bubbleBarViewController.getBubbleBarLocation();
- onBubbleBarLocationUpdated(bubblesLocation);
- }
}
private void initButtons(ViewGroup navContainer, ViewGroup endContainer,
@@ -1223,6 +1217,16 @@
return (int) navBarTargetStartX - mNavButtonContainer.getLeft();
}
+ /** Adjusts the navigation buttons layout position according to the bubble bar location. */
+ public void onTaskbarLayoutChange() {
+ if (com.android.wm.shell.Flags.enableBubbleBarInPersistentTaskBar()
+ && mControllers.bubbleControllers.isPresent()) {
+ BubbleBarLocation bubblesLocation = mControllers.bubbleControllers.get()
+ .bubbleBarViewController.getBubbleBarLocation();
+ onBubbleBarLocationUpdated(bubblesLocation);
+ }
+ }
+
private class RotationButtonListener implements RotationButton.RotationButtonUpdatesCallback {
@Override
public void onVisibilityChanged(boolean isVisible) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/NewWindowTaskbarShortcut.kt b/quickstep/src/com/android/launcher3/taskbar/NewWindowTaskbarShortcut.kt
new file mode 100644
index 0000000..dc66e0b
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/NewWindowTaskbarShortcut.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2024 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.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK
+import android.view.View
+import com.android.launcher3.AbstractFloatingView
+import com.android.launcher3.R
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.popup.SystemShortcut
+import com.android.launcher3.views.ActivityContext
+
+/**
+ * A single menu item shortcut to execute creating a new instance of an app. Default interaction for
+ * [onClick] is to launch the app in full screen or as a floating window in Desktop Mode.
+ */
+class NewWindowTaskbarShortcut<T>(target: T, itemInfo: ItemInfo?, originalView: View?) :
+ SystemShortcut<T>(
+ R.drawable.desktop_mode_ic_taskbar_menu_new_window,
+ R.string.new_window_option_taskbar,
+ target,
+ itemInfo,
+ originalView
+ ) where T : Context?, T : ActivityContext? {
+
+ override fun onClick(v: View?) {
+ val intent = mItemInfo.intent ?: return
+ intent.addFlags(FLAG_ACTIVITY_MULTIPLE_TASK)
+ mTarget?.startActivitySafely(v, intent, mItemInfo)
+ AbstractFloatingView.closeAllOpenViews(mTarget)
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index fabf3a5..7273fac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -208,11 +208,8 @@
* Creates and returns a {@link RevealOutlineAnimation} Animator that updates the stashed handle
* shape and size. When stashed, the shape is a thin rounded pill. When unstashed, the shape
* morphs into the size of where the taskbar icons will be.
- *
- * @param taskbarToHotseatOffsets A Rect of offsets used to transform the bounds of the
- * stashed handle to wrap around the hotseat items.
*/
- public Animator createRevealAnimToIsStashed(boolean isStashed, Rect taskbarToHotseatOffsets) {
+ public Animator createRevealAnimToIsStashed(boolean isStashed) {
Rect visualBounds = mControllers.taskbarViewController.getIconLayoutVisualBounds();
float startRadius = mStashedHandleRadius;
@@ -223,13 +220,6 @@
visualBounds.bottom += heightDiff;
startRadius = visualBounds.height() / 2f;
-
- // We use these offsets to create a larger stashed handle to wrap around the items
- // of the hotseat. This is only used for certain animations.
- visualBounds.top += taskbarToHotseatOffsets.top;
- visualBounds.bottom += taskbarToHotseatOffsets.bottom;
- visualBounds.left += taskbarToHotseatOffsets.left;
- visualBounds.right += taskbarToHotseatOffsets.right;
}
final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index b95c406..a59445b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -29,6 +29,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY;
import static com.android.launcher3.Flags.enableCursorHoverStates;
+import static com.android.launcher3.Flags.taskbarOverflow;
import static com.android.launcher3.Utilities.calculateTextHeight;
import static com.android.launcher3.Utilities.isRunningInTestHarness;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
@@ -107,6 +108,7 @@
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
import com.android.launcher3.taskbar.bubbles.BubbleBarController;
import com.android.launcher3.taskbar.bubbles.BubbleBarPinController;
+import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController;
import com.android.launcher3.taskbar.bubbles.BubbleBarView;
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
@@ -130,11 +132,11 @@
import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.ApiWrapper;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.NavigationMode;
-import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
@@ -278,9 +280,11 @@
BubbleBarController.onTaskbarRecreated();
if (BubbleBarController.isBubbleBarEnabled() && bubbleBarView != null) {
Optional<BubbleStashedHandleViewController> bubbleHandleController = Optional.empty();
+ Optional<BubbleBarSwipeController> bubbleBarSwipeController = Optional.empty();
if (isTransientTaskbar) {
bubbleHandleController = Optional.of(
new BubbleStashedHandleViewController(this, bubbleHandleView));
+ bubbleBarSwipeController = Optional.of(new BubbleBarSwipeController(this));
}
TaskbarHotseatDimensionsProvider dimensionsProvider =
new DeviceProfileDimensionsProviderAdapter(this);
@@ -298,6 +302,7 @@
() -> DisplayController.INSTANCE.get(this).getInfo().currentSize),
new BubblePinController(this, mDragLayer,
() -> DisplayController.INSTANCE.get(this).getInfo().currentSize),
+ bubbleBarSwipeController,
new BubbleCreator(this)
));
}
@@ -361,38 +366,6 @@
}
/**
- * Calculate the offsets needed to transform the transient taskbar bounds to the hotseat bounds.
- * @return The offsets will be stored in a Rect
- */
- public Rect calculateTaskbarToHotseatOffsets(Rect hotseatBounds) {
- Rect taskbar = getTransientTaskbarBounds();
- Rect offsets = new Rect();
-
- offsets.left = hotseatBounds.left - taskbar.left;
- offsets.right = hotseatBounds.right - taskbar.right;
-
- int heightDiff = hotseatBounds.height() - taskbar.height();
- offsets.top = (taskbar.height() - heightDiff) / 2;
-
- int gleanedTaskbarPadding = (mDeviceProfile.taskbarHeight
- - getTransientTaskbarBounds().height()) / 2;
- offsets.left -= gleanedTaskbarPadding;
- offsets.top -= gleanedTaskbarPadding;
- offsets.right += gleanedTaskbarPadding;
-
- // Bottom is relative to the bottom of layout, so we can calculate it with padding included.
- offsets.bottom = (hotseatBounds.height() - taskbar.height()) / 2;
-
- // Update bounds in taskbar background
- if (hotseatBounds.isEmpty()) {
- mDragLayer.getTaskbarToHotseatOffsetRect().setEmpty();
- } else {
- mDragLayer.getTaskbarToHotseatOffsetRect().set(offsets);
- }
- return offsets;
- }
-
- /**
* Copy the original DeviceProfile, match the number of hotseat icons and qsb width and update
* the icon size
*/
@@ -1221,6 +1194,11 @@
RecentsView recents = taskbarUIController.getRecentsView();
boolean shouldCloseAllOpenViews = true;
Object tag = view.getTag();
+
+ if (taskbarOverflow()) {
+ mControllers.keyboardQuickSwitchController.closeQuickSwitchView(false);
+ }
+
if (tag instanceof GroupTask groupTask) {
handleGroupTaskLaunch(
groupTask,
@@ -1259,7 +1237,8 @@
Intent intent = new Intent(info.getIntent())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
- if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) {
+ if (mIsSafeModeEnabled
+ && !new ApplicationInfoWrapper(this, intent).isSystem()) {
Toast.makeText(this, R.string.safemode_shortcut_error,
Toast.LENGTH_SHORT).show();
} else if (info.isPromise()) {
@@ -1711,18 +1690,6 @@
}
/**
- * Returns the bounds of launcher's hotseat (if exists).
- */
- public void getHotseatBounds(Rect hotseatBoundsOut) {
- TaskbarUIController uiController = mControllers.uiController;
- if (uiController instanceof LauncherTaskbarUIController launcherController) {
- launcherController.getHotseatBounds(hotseatBoundsOut);
- } else {
- hotseatBoundsOut.setEmpty();
- }
- }
-
- /**
* Called when we determine the touchable region.
*
* @param exclude {@code true} then the magnification region computation will omit the window.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index d6ce3a4..c0e921e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -21,7 +21,6 @@
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
-import android.graphics.Rect
import android.graphics.RectF
import com.android.app.animation.Interpolators
import com.android.internal.policy.ScreenDecorationsUtils
@@ -60,9 +59,6 @@
var translationYForSwipe = 0f
var translationYForStash = 0f
- // When not empty, we can use this to transform transient taskbar background to hotseat bounds.
- val taskbarToHotseatOffsetRect = Rect()
-
private val transientBackgroundBounds = context.transientTaskbarBounds
private val shadowAlpha: Float
@@ -230,12 +226,6 @@
val radius = newBackgroundHeight / 2f
val bottomMarginProgress = bottomMargin * ((1f - progress) / 2f)
- // Used to transform the background so that it wraps around the items on the hotseat.
- val hotseatOffsetLeft = taskbarToHotseatOffsetRect.left * progress
- val hotseatOffsetTop = taskbarToHotseatOffsetRect.top * progress
- val hotseatOffsetRight = taskbarToHotseatOffsetRect.right * progress
- val hotseatOffsetBottom = taskbarToHotseatOffsetRect.bottom * progress
-
// Aligns the bottom with the bottom of the stashed handle.
val bottom =
canvas.height - bottomMargin +
@@ -260,10 +250,10 @@
strokePaint.alpha = (paint.alpha * strokeAlpha) / 255
lastDrawnTransientRect.set(
- transientBackgroundBounds.left + halfWidthDelta + hotseatOffsetLeft,
- bottom - newBackgroundHeight + hotseatOffsetTop,
- transientBackgroundBounds.right - halfWidthDelta + hotseatOffsetRight,
- bottom + hotseatOffsetBottom,
+ transientBackgroundBounds.left + halfWidthDelta,
+ bottom - newBackgroundHeight,
+ transientBackgroundBounds.right - halfWidthDelta,
+ bottom
)
val horizontalInset = fullWidth * widthInsetPercentage
lastDrawnTransientRect.inset(horizontalInset, 0f)
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index a090956..e16c76d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -22,7 +22,6 @@
import android.content.Context;
import android.graphics.Canvas;
-import android.graphics.Rect;
import android.graphics.RectF;
import android.media.permission.SafeCloseable;
import android.util.AttributeSet;
@@ -100,7 +99,7 @@
public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, 1 /* alphaChannelCount */);
- mBackgroundRenderer = new TaskbarBackgroundRenderer(mActivity);
+ mBackgroundRenderer = new TaskbarBackgroundRenderer(mContainer);
mTaskbarBackgroundAlpha = new MultiPropertyFactory<>(this, BG_ALPHA, INDEX_COUNT,
(a, b) -> a * b, 1f);
@@ -109,7 +108,7 @@
public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) {
mControllerCallbacks = callbacks;
- mBackgroundRenderer.updateStashedHandleWidth(mActivity, getResources());
+ mBackgroundRenderer.updateStashedHandleWidth(mContainer, getResources());
recreateControllers();
}
@@ -260,11 +259,6 @@
return mBackgroundRenderer.getLastDrawnTransientRect();
}
- /** Returns the rect used to transform transient taskbar to the hotseat */
- public Rect getTaskbarToHotseatOffsetRect() {
- return mBackgroundRenderer.getTaskbarToHotseatOffsetRect();
- }
-
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
@@ -275,7 +269,7 @@
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) {
- AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
+ AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mContainer);
if (topView != null && topView.canHandleBack()) {
topView.onBackInvoked();
// Handled by the floating view.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index e301dc4..876221b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -300,6 +300,7 @@
stashController.updateStateForFlag(FLAG_IN_APP, false);
updateStateForFlag(FLAG_TRANSITION_TO_VISIBLE, true);
+ mLauncherState = toState;
animatorSet.play(stashController.createApplyStateAnimator(duration));
animatorSet.play(applyState(duration, false));
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 1b4db7a..78e7b47 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -60,6 +60,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
@@ -247,6 +248,7 @@
context,
navCallbacks,
SystemUiProxy.INSTANCE.get(mContext),
+ ContextualEduStatsManager.INSTANCE.get(mContext),
new Handler(),
AssistUtils.newInstance(mContext));
mComponentCallbacks = new ComponentCallbacks() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 5024cd8..bdefea6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -250,6 +250,7 @@
Map<PackageUserKey, Integer> packageUserKeytoUidMap) {
Preconditions.assertUIThread();
mControllers.taskbarAllAppsController.setApps(apps, flags, packageUserKeytoUidMap);
+ mControllers.taskbarPopupController.setApps(apps);
}
protected void dumpLogs(String prefix, PrintWriter pw) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 872a4d0..15c35b6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -45,12 +45,14 @@
import androidx.annotation.StringRes;
import com.android.launcher3.R;
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskUtils;
import com.android.quickstep.util.AssistUtils;
+import com.android.systemui.contextualeducation.GestureType;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import java.io.PrintWriter;
@@ -109,6 +111,7 @@
private final Context mContext;
private final TaskbarNavButtonCallbacks mCallbacks;
private final SystemUiProxy mSystemUiProxy;
+ private final ContextualEduStatsManager mContextualEduStatsManager;
private final Handler mHandler;
private final AssistUtils mAssistUtils;
@Nullable private StatsLogManager mStatsLogManager;
@@ -119,11 +122,13 @@
Context context,
TaskbarNavButtonCallbacks callbacks,
SystemUiProxy systemUiProxy,
+ ContextualEduStatsManager contextualEduStatsManager,
Handler handler,
AssistUtils assistUtils) {
mContext = context;
mCallbacks = callbacks;
mSystemUiProxy = systemUiProxy;
+ mContextualEduStatsManager = contextualEduStatsManager;
mHandler = handler;
mAssistUtils = assistUtils;
}
@@ -137,14 +142,20 @@
switch (buttonType) {
case BUTTON_BACK:
logEvent(LAUNCHER_TASKBAR_BACK_BUTTON_TAP);
+ mContextualEduStatsManager.updateEduStats(/* isTrackpadGesture= */ false,
+ GestureType.BACK);
executeBack();
break;
case BUTTON_HOME:
logEvent(LAUNCHER_TASKBAR_HOME_BUTTON_TAP);
+ mContextualEduStatsManager.updateEduStats(/* isTrackpadGesture= */ false,
+ GestureType.HOME);
navigateHome();
break;
case BUTTON_RECENTS:
logEvent(LAUNCHER_TASKBAR_OVERVIEW_BUTTON_TAP);
+ mContextualEduStatsManager.updateEduStats(/* isTrackpadGesture= */ false,
+ GestureType.OVERVIEW);
navigateToOverview();
break;
case BUTTON_IME_SWITCH:
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index 2cee77d..70d4bb1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR;
import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
import android.content.Intent;
@@ -29,11 +30,13 @@
import com.android.internal.logging.InstanceId;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.dot.FolderDotInfo;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -51,9 +54,11 @@
import com.android.launcher3.views.ActivityContext;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.LogUtils;
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
@@ -79,6 +84,7 @@
// Initialized in init.
private TaskbarControllers mControllers;
private boolean mAllowInitialSplitSelection;
+ private AppInfo[] mAppInfosList;
public TaskbarPopupController(TaskbarActivityContext context) {
mContext = context;
@@ -195,6 +201,10 @@
if (com.android.wm.shell.Flags.enableBubbleAnything()) {
shortcuts.add(BUBBLE);
}
+ if (Flags.enableMultiInstanceMenuTaskbar()
+ && DesktopModeStatus.canEnterDesktopMode(mContext)) {
+ shortcuts.addAll(getMultiInstanceMenuOptions().toList());
+ }
return shortcuts.stream();
}
@@ -258,7 +268,55 @@
originalView, position, mAllowInitialSplitSelection);
}
- /**
+ /**
+ * Set the list of AppInfos to be able to pull from later
+ */
+ public void setApps(AppInfo[] apps) {
+ mAppInfosList = apps;
+ }
+
+ /**
+ * Finds and returns an AppInfo object from a list, using its ComponentKey for identification.
+ * Based off of {@link com.android.launcher3.allapps.AllAppsStore#getApp(ComponentKey)}
+ * since we cannot access AllAppsStore from here.
+ */
+ public AppInfo getApp(ComponentKey key) {
+ if (key == null) {
+ return null;
+ }
+ AppInfo tempInfo = new AppInfo();
+ tempInfo.componentName = key.componentName;
+ tempInfo.user = key.user;
+ int index = Arrays.binarySearch(mAppInfosList, tempInfo, COMPONENT_KEY_COMPARATOR);
+ return index < 0 ? null : mAppInfosList[index];
+ }
+
+ /**
+ * Returns a stream of Multi Instance menu options if an app supports it.
+ */
+ Stream<SystemShortcut.Factory<BaseTaskbarContext>> getMultiInstanceMenuOptions() {
+ SystemShortcut.Factory<BaseTaskbarContext> factory = createNewWindowShortcutFactory();
+ return factory != null ? Stream.of(factory) : Stream.empty();
+
+ }
+
+ /**
+ * Creates a factory function representing a "New Window" menu item only if the calling app
+ * supports multi-instance.
+ * @return A factory function to be used in populating the long-press menu.
+ */
+ SystemShortcut.Factory<BaseTaskbarContext> createNewWindowShortcutFactory() {
+ return (context, itemInfo, originalView) -> {
+ ComponentKey key = itemInfo.getComponentKey();
+ AppInfo app = getApp(key);
+ if (app != null && app.supportsMultiInstance()) {
+ return new NewWindowTaskbarShortcut<>(context, itemInfo, originalView);
+ }
+ return null;
+ };
+ }
+
+ /**
* A single menu item ("Split left," "Split right," or "Split top") that executes a split
* from the taskbar, as if the user performed a drag and drop split.
* Includes an onClick method that initiates the actual split.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
index 72bdafe..57d4dbb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar
import android.content.Context
+import android.window.flags.DesktopModeFlags
import androidx.annotation.VisibleForTesting
import com.android.launcher3.Flags.enableRecentsInTaskbar
import com.android.launcher3.model.data.ItemInfo
@@ -26,7 +27,6 @@
import com.android.quickstep.RecentsModel
import com.android.quickstep.util.DesktopTask
import com.android.quickstep.util.GroupTask
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import java.io.PrintWriter
@@ -40,7 +40,7 @@
var canShowRunningApps =
DesktopModeStatus.canEnterDesktopMode(context) &&
- DesktopModeFlags.TASKBAR_RUNNING_APPS.isEnabled(context)
+ DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS.isTrue
@VisibleForTesting
set(isEnabledFromTest) {
field = isEnabledFromTest
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 751a42a..bf086b4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -27,6 +27,8 @@
import android.view.animation.Interpolator;
import android.view.animation.PathInterpolator;
+import androidx.annotation.VisibleForTesting;
+
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
import com.android.launcher3.util.DisplayController;
@@ -77,7 +79,7 @@
public void onTaskbarVisibilityChanged(int visibility) {
mTaskbarVisible = visibility == VISIBLE;
if (shouldShowScrim()) {
- showScrim(true, getScrimAlpha(), false /* skipAnim */);
+ showScrim(true, computeScrimAlpha(), false /* skipAnim */);
} else if (mScrimView.getScrimAlpha() > 0f) {
showScrim(false, 0, false /* skipAnim */);
}
@@ -96,7 +98,7 @@
return;
}
mSysUiStateFlags = stateFlags;
- showScrim(shouldShowScrim(), getScrimAlpha(), skipAnim);
+ showScrim(shouldShowScrim(), computeScrimAlpha(), skipAnim);
}
private boolean shouldShowScrim() {
@@ -119,7 +121,7 @@
&& !mControllers.taskbarStashController.isHiddenForBubbles();
}
- private float getScrimAlpha() {
+ private float computeScrimAlpha() {
final boolean isPersistentTaskBarVisible =
mTaskbarVisible && !DisplayController.isTransientTaskbar(mScrimView.getContext());
final boolean manageMenuExpanded =
@@ -140,7 +142,7 @@
mScrimView.setOnClickListener(showScrim ? (view) -> onClick() : null);
mScrimView.setClickable(showScrim);
if (skipAnim) {
- mScrimView.setScrimAlpha(alpha);
+ mScrimAlpha.updateValue(alpha);
} else {
ObjectAnimator anim = mScrimAlpha.animateToValue(showScrim ? alpha : 0);
anim.setInterpolator(showScrim ? SCRIM_ALPHA_IN : SCRIM_ALPHA_OUT);
@@ -167,4 +169,14 @@
pw.println(prefix + "\tmScrimAlpha.value=" + mScrimAlpha.value);
}
+
+ @VisibleForTesting
+ TaskbarScrimView getScrimView() {
+ return mScrimView;
+ }
+
+ @VisibleForTesting
+ float getScrimAlpha() {
+ return mScrimAlpha.value;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 7624afb..5b168e0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -42,7 +42,6 @@
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.app.RemoteAction;
-import android.graphics.Rect;
import android.graphics.drawable.Icon;
import android.os.SystemClock;
import android.util.Log;
@@ -82,6 +81,8 @@
private static final String TAG = "TaskbarStashController";
private static final boolean DEBUG = false;
+ private static boolean sEnableSoftwareImeForTests = false;
+
/**
* Def. value for @param shouldBubblesFollow in
* {@link #updateAndAnimateTransientTaskbar(boolean)} */
@@ -131,19 +132,22 @@
*
* Use {@link #getStashDuration()} to query duration
*/
- private static final long TASKBAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE;
+ @VisibleForTesting
+ static final long TASKBAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE;
/**
* How long to stash/unstash transient taskbar.
*
* Use {@link #getStashDuration()} to query duration.
*/
- private static final long TRANSIENT_TASKBAR_STASH_DURATION = 417;
+ @VisibleForTesting
+ static final long TRANSIENT_TASKBAR_STASH_DURATION = 417;
/**
* How long to stash/unstash when keyboard is appearing/disappearing.
*/
- private static final long TASKBAR_STASH_DURATION_FOR_IME = 80;
+ @VisibleForTesting
+ static final long TASKBAR_STASH_DURATION_FOR_IME = 80;
/**
* The scale TaskbarView animates to when being stashed.
@@ -164,7 +168,7 @@
/**
* How long the icon/stash handle alpha animation plays.
*/
- public static final long TASKBAR_STASH_ALPHA_DURATION = 50;
+ public static final long TRANSIENT_TASKBAR_STASH_ALPHA_DURATION = 50;
/**
* How long to delay the icon/stash handle alpha for the home to app taskbar animation.
@@ -209,7 +213,6 @@
* by not scaling the height of the taskbar background.
*/
private static final int TRANSITION_UNSTASH_SUW_MANUAL = 3;
- private static final Rect EMPTY_RECT = new Rect();
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
@@ -254,7 +257,7 @@
private boolean mEnableBlockingTimeoutDuringTests = false;
private Animator mTaskbarBackgroundAlphaAnimator;
- private long mTaskbarBackgroundDuration;
+ private final long mTaskbarBackgroundDuration;
private boolean mUserIsNotGoingHome = false;
// Evaluate whether the handle should be stashed
@@ -771,7 +774,7 @@
}
fullLengthAnimatorSet.play(mControllers.stashedHandleViewController
- .createRevealAnimToIsStashed(isStashed, EMPTY_RECT));
+ .createRevealAnimToIsStashed(isStashed));
// Return the stashed handle to its default scale in case it was changed as part of the
// feedforward hint. Note that the reveal animation above also visually scales it.
fullLengthAnimatorSet.play(mTaskbarStashedHandleHintScale.animateToValue(1f));
@@ -801,14 +804,14 @@
if (animationType == TRANSITION_HANDLE_FADE) {
// When fading, the handle fades in/out at the beginning of the transition with
// TASKBAR_STASH_ALPHA_DURATION.
- backgroundAndHandleAlphaDuration = TASKBAR_STASH_ALPHA_DURATION;
+ backgroundAndHandleAlphaDuration = TRANSIENT_TASKBAR_STASH_ALPHA_DURATION;
// The iconAlphaDuration must be set to duration for the skippable interpolators
// below to work.
iconAlphaDuration = duration;
} else {
iconAlphaStartDelay = TASKBAR_STASH_ALPHA_START_DELAY;
- iconAlphaDuration = TASKBAR_STASH_ALPHA_DURATION;
- backgroundAndHandleAlphaDuration = TASKBAR_STASH_ALPHA_DURATION;
+ iconAlphaDuration = TRANSIENT_TASKBAR_STASH_ALPHA_DURATION;
+ backgroundAndHandleAlphaDuration = TRANSIENT_TASKBAR_STASH_ALPHA_DURATION;
if (isStashed) {
if (animationType == TRANSITION_HOME_TO_APP) {
@@ -821,19 +824,6 @@
}
}
-
- Rect taskbarToHotseatOffsets = new Rect();
- if (enableScalingRevealHomeAnimation() && animationType == TRANSITION_HOME_TO_APP) {
- Rect hotseatRect = new Rect();
- mActivity.getHotseatBounds(hotseatRect);
-
- // Calculate and store offsets so that we can sync with the taskbar stashed handle
- taskbarToHotseatOffsets.set(
- mActivity.calculateTaskbarToHotseatOffsets(hotseatRect));
- as.addListener(AnimatorListeners.forEndCallback(
- () -> mActivity.calculateTaskbarToHotseatOffsets(EMPTY_RECT)));
- }
-
play(as, mTaskbarStashedHandleAlpha.animateToValue(stashedHandleAlphaTarget),
backgroundAndHandleAlphaStartDelay,
backgroundAndHandleAlphaDuration, LINEAR);
@@ -882,12 +872,10 @@
}
mControllers.taskbarViewController.addRevealAnimToIsStashed(skippable, isStashed, duration,
- EMPHASIZED, animationType == TRANSITION_UNSTASH_SUW_MANUAL,
- animationType == TRANSITION_HOME_TO_APP);
+ EMPHASIZED, animationType == TRANSITION_UNSTASH_SUW_MANUAL);
play(skippable, mControllers.stashedHandleViewController
- .createRevealAnimToIsStashed(isStashed, taskbarToHotseatOffsets), 0, duration,
- EMPHASIZED);
+ .createRevealAnimToIsStashed(isStashed), 0, duration, EMPHASIZED);
// Return the stashed handle to its default scale in case it was changed as part of the
// feedforward hint. Note that the reveal animation above also visually scales it.
@@ -1087,7 +1075,8 @@
/**
* When hiding the IME, delay the unstash animation to align with the end of the transition.
*/
- private long getTaskbarStashStartDelayForIme() {
+ @VisibleForTesting
+ long getTaskbarStashStartDelayForIme() {
if (mIsImeShowing) {
// Only delay when IME is exiting, not entering.
return 0;
@@ -1143,13 +1132,13 @@
}
// Do not stash if pinned taskbar, hardware keyboard is attached and no IME is docked
- if (mActivity.isHardwareKeyboard() && DisplayController.isPinnedTaskbar(mActivity)
+ if (isHardwareKeyboard() && DisplayController.isPinnedTaskbar(mActivity)
&& !mActivity.isImeDocked()) {
return false;
}
// Do not stash if hardware keyboard is attached, in 3 button nav and desktop windowing mode
- if (mActivity.isHardwareKeyboard()
+ if (isHardwareKeyboard()
&& mActivity.isThreeButtonNav()
&& mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) {
return false;
@@ -1163,6 +1152,21 @@
return mIsImeShowing || mIsImeSwitcherShowing;
}
+ private boolean isHardwareKeyboard() {
+ return mActivity.isHardwareKeyboard() && !sEnableSoftwareImeForTests;
+ }
+
+ /**
+ * Overrides {@link #isHardwareKeyboard()} to {@code false} for testing, if enabled.
+ * <p>
+ * Virtual devices are sometimes in hardware keyboard mode, leading to an inconsistent
+ * testing environment.
+ */
+ @VisibleForTesting
+ static void enableSoftwareImeForTests(boolean enable) {
+ sEnableSoftwareImeForTests = enable;
+ }
+
/**
* Updates the proper flag to indicate whether the task bar should be stashed.
*
@@ -1288,7 +1292,7 @@
/**
* Attempts to start timer to auto hide the taskbar based on time.
*/
- public void tryStartTaskbarTimeout() {
+ private void tryStartTaskbarTimeout() {
if (!DisplayController.isTransientTaskbar(mActivity)
|| mIsStashed
|| mEnableBlockingTimeoutDuringTests) {
@@ -1316,6 +1320,11 @@
updateAndAnimateTransientTaskbarForTimeout();
}
+ @VisibleForTesting
+ Alarm getTimeoutAlarm() {
+ return mTimeoutAlarm;
+ }
+
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "TaskbarStashController:");
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 0389a11..2734137 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -46,6 +46,7 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -63,6 +64,7 @@
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.IconButtonView;
import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
@@ -100,9 +102,12 @@
// Only non-null when device supports having an All Apps button.
@Nullable private final TaskbarAllAppsButtonContainer mAllAppsButtonContainer;
- // Only non-null when device supports having an All Apps button.
+ // Only non-null when device supports having a Divider button.
@Nullable private TaskbarDividerContainer mTaskbarDividerContainer;
+ // Only non-null when device supports having a Taskbar Overflow button.
+ @Nullable private IconButtonView mTaskbarOverflowView;
+
/**
* Whether the divider is between Hotseat icons and Recents,
* instead of between All Apps button and Hotseat.
@@ -171,6 +176,13 @@
mTaskbarDividerContainer = new TaskbarDividerContainer(context);
}
+ if (Flags.taskbarOverflow()) {
+ mTaskbarOverflowView = (IconButtonView) LayoutInflater.from(context)
+ .inflate(R.layout.taskbar_overflow_button, this, false);
+ mTaskbarOverflowView.setIconDrawable(
+ resources.getDrawable(R.drawable.taskbar_overflow_icon));
+ mTaskbarOverflowView.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+ }
// TODO: Disable touch events on QSB otherwise it can crash.
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
}
@@ -263,6 +275,12 @@
if (mTaskbarDividerContainer != null && callbacks.supportsDividerLongPress()) {
mTaskbarDividerContainer.setUpCallbacks(callbacks);
}
+ if (mTaskbarOverflowView != null) {
+ mTaskbarOverflowView.setOnClickListener(
+ mControllerCallbacks.getOverflowOnClickListener());
+ mTaskbarOverflowView.setOnLongClickListener(
+ mControllerCallbacks.getOverflowOnLongClickListener());
+ }
}
private void removeAndRecycle(View view) {
@@ -290,6 +308,9 @@
removeView(mTaskbarDividerContainer);
}
}
+ if (mTaskbarOverflowView != null) {
+ removeView(mTaskbarOverflowView);
+ }
removeView(mQsb);
// Add Hotseat icons.
@@ -377,6 +398,9 @@
if (mTaskbarDividerContainer != null && !recentTasks.isEmpty()) {
addView(mTaskbarDividerContainer, nextViewIndex++);
mAddedDividerForRecents = true;
+ if (mTaskbarOverflowView != null) {
+ addView(mTaskbarOverflowView, nextViewIndex++);
+ }
}
// Add Recent/Running icons.
@@ -699,6 +723,14 @@
}
/**
+ * Returns the taskbar overflow view in the taskbar.
+ */
+ @Nullable
+ public IconButtonView getTaskbarOverflowView() {
+ return mTaskbarOverflowView;
+ }
+
+ /**
* Returns whether the divider is between Hotseat icons and Recents,
* instead of between All Apps button and Hotseat.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
index 5c8d439..d108d8c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -134,4 +134,25 @@
return Flags.enableBubbleBarInPersistentTaskBar()
&& mControllers.bubbleControllers.isPresent();
}
+
+ /** Returns on click listener for the taskbar overflow view. */
+ public View.OnClickListener getOverflowOnClickListener() {
+ return new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ mControllers.keyboardQuickSwitchController.openQuickSwitchView();
+ }
+ };
+ }
+
+ /** Returns on long click listener for the taskbar overflow view. */
+ public View.OnLongClickListener getOverflowOnLongClickListener() {
+ return new View.OnLongClickListener() {
+ @Override
+ public boolean onLongClick(View v) {
+ mControllers.keyboardQuickSwitchController.openQuickSwitchView();
+ return true;
+ }
+ };
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index b663ccb..b207b37 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -36,7 +36,6 @@
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_ALIGNMENT_ANIM;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_PINNING_ANIM;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_REVEAL_ANIM;
-import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -140,10 +139,6 @@
private final AnimatedFloat mTaskbarIconTranslationYForPinning = new AnimatedFloat(
this::updateTranslationY);
- private final View.OnLayoutChangeListener mTaskbarViewLayoutChangeListener =
- (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
- -> updateTaskbarIconTranslationXForPinning();
-
private AnimatedFloat mTaskbarNavButtonTranslationY;
private AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay;
@@ -158,6 +153,12 @@
// Initialized in init.
private TaskbarControllers mControllers;
+ private final View.OnLayoutChangeListener mTaskbarViewLayoutChangeListener =
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ updateTaskbarIconTranslationXForPinning();
+ mControllers.navbarButtonsViewController.onTaskbarLayoutChange();
+ };
+
// Animation to align icons with Launcher, created lazily. This allows the controller to be
// active only during the animation and does not need to worry about layout changes.
private AnimatorPlaybackController mIconAlignControllerLazy = null;
@@ -669,8 +670,7 @@
* @param interpolator The interpolator to use for all animations.
*/
public void addRevealAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration,
- Interpolator interpolator, boolean dispatchOnAnimationStart,
- boolean isHomeToAppAnimation) {
+ Interpolator interpolator, boolean dispatchOnAnimationStart) {
AnimatorSet reveal = new AnimatorSet();
Rect stashedBounds = new Rect();
@@ -719,21 +719,8 @@
reveal.play(ObjectAnimator.ofFloat(mtd.getTranslationX(INDEX_TASKBAR_REVEAL_ANIM),
MULTI_PROPERTY_VALUE, transX)
.setDuration(duration));
-
- if (enableScalingRevealHomeAnimation()) {
- // Delay y-translation by 1 frame to keep icons within the bounds of the bg.
- int delay = isHomeToAppAnimation ? getSingleFrameMs(mActivity) : 0;
- ObjectAnimator yAnimator =
- ObjectAnimator.ofFloat(mtd.getTranslationY(INDEX_TASKBAR_REVEAL_ANIM),
- MULTI_PROPERTY_VALUE, transY)
- .setDuration(Math.max(0, duration - delay));
- yAnimator.setStartDelay(delay);
- reveal.play(yAnimator);
- } else {
- reveal.play(
- ObjectAnimator.ofFloat(mtd.getTranslationY(INDEX_TASKBAR_REVEAL_ANIM),
- MULTI_PROPERTY_VALUE, transY));
- }
+ reveal.play(ObjectAnimator.ofFloat(mtd.getTranslationY(INDEX_TASKBAR_REVEAL_ANIM),
+ MULTI_PROPERTY_VALUE, transY));
as.addListener(forEndCallback(() ->
mtd.setTranslation(INDEX_TASKBAR_REVEAL_ANIM, 0, 0)));
} else {
@@ -829,6 +816,7 @@
View child = mTaskbarView.getChildAt(i);
boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonContainer();
boolean isTaskbarDividerView = child == mTaskbarView.getTaskbarDividerViewContainer();
+ boolean isTaskbarOverflowView = child == mTaskbarView.getTaskbarOverflowView();
boolean isRecentTask = child.getTag() instanceof GroupTask;
// TODO(b/343522351): show recents on the home screen.
final boolean isRecentsInHotseat = false;
@@ -839,7 +827,8 @@
setter.setViewAlpha(child, 0, Interpolators.clampToProgress(LINEAR, 0.8f, 1f));
} else if ((isAllAppsButton && !FeatureFlags.enableAllAppsButtonInHotseat())
|| (isTaskbarDividerView && enableTaskbarPinning())
- || (isRecentTask && !isRecentsInHotseat)) {
+ || (isRecentTask && !isRecentsInHotseat)
+ || isTaskbarOverflowView) {
if (!isToHome
&& mIsHotseatIconOnTopWhenAligned
&& mIsStashed) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeController.kt
new file mode 100644
index 0000000..a831fd7
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeController.kt
@@ -0,0 +1,203 @@
+/*
+ * Copyright (C) 2024 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.bubbles
+
+import android.animation.ValueAnimator
+import android.content.Context
+import androidx.annotation.VisibleForTesting
+import androidx.core.animation.doOnEnd
+import androidx.dynamicanimation.animation.SpringForce
+import com.android.launcher3.anim.AnimatedFloat
+import com.android.launcher3.anim.SpringAnimationBuilder
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.TaskbarThresholdUtils
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
+import com.android.launcher3.touch.OverScroll
+
+/** Handle swipe events on the bubble bar and handle */
+class BubbleBarSwipeController {
+
+ private val context: Context
+
+ private var bubbleStashedHandleViewController: BubbleStashedHandleViewController? = null
+ private var bubbleBarViewController: BubbleBarViewController? = null
+ private var bubbleStashController: BubbleStashController? = null
+
+ private var springAnimation: ValueAnimator? = null
+ private val animatedSwipeTranslation = AnimatedFloat(this::onSwipeUpdate)
+
+ private val unstashThreshold: Int
+ private val expandThreshold: Int
+ private val maxOverscroll: Int
+
+ private var swipeState: SwipeState = SwipeState()
+
+ constructor(tac: TaskbarActivityContext) : this(tac, DefaultDimensionProvider(tac))
+
+ @VisibleForTesting
+ constructor(context: Context, dimensionProvider: DimensionProvider) {
+ this.context = context
+ unstashThreshold = dimensionProvider.unstashThreshold
+ expandThreshold = dimensionProvider.expandThreshold
+ maxOverscroll = dimensionProvider.maxOverscroll
+ }
+
+ fun init(bubbleControllers: BubbleControllers) {
+ bubbleStashedHandleViewController =
+ bubbleControllers.bubbleStashedHandleViewController.orElse(null)
+ bubbleBarViewController = bubbleControllers.bubbleBarViewController
+ bubbleStashController = bubbleControllers.bubbleStashController
+ }
+
+ /** Start tracking a new swipe gesture */
+ fun start() {
+ if (springAnimation != null) reset()
+ val stashed = bubbleStashController?.isStashed ?: false
+ val barVisible = bubbleStashController?.isBubbleBarVisible() ?: false
+ val expanded = bubbleBarViewController?.isExpanded ?: false
+
+ swipeState =
+ SwipeState(
+ stashedOnStart = stashed,
+ collapsedOnStart = !stashed && barVisible && !expanded,
+ expandedOnStart = expanded,
+ )
+ }
+
+ /** Update swipe distance to [dy] */
+ fun swipeTo(dy: Float) {
+ // Only handle swipe up and stashed or collapsed bar
+ if (dy > 0 || swipeState.expandedOnStart) return
+
+ animatedSwipeTranslation.updateValue(dy)
+
+ val prevState = swipeState
+ // We can pass unstash threshold once per gesture, keep it true if it happened once
+ val passedUnstashThreshold = isUnstash(dy) || prevState.passedUnstashThreshold
+ // Expand happens at the end of the gesture, always keep the current value
+ val passedExpandThreshold = isExpand(dy)
+
+ if (
+ passedUnstashThreshold != prevState.passedUnstashThreshold ||
+ passedExpandThreshold != prevState.passedExpandThreshold
+ ) {
+ swipeState =
+ swipeState.copy(
+ passedUnstashThreshold = passedUnstashThreshold,
+ passedExpandThreshold = passedExpandThreshold,
+ )
+ }
+
+ if (
+ swipeState.stashedOnStart &&
+ swipeState.passedUnstashThreshold &&
+ !prevState.passedUnstashThreshold
+ ) {
+ bubbleStashController?.showBubbleBar(expandBubbles = false)
+ }
+ }
+
+ /** Finish tracking swipe gesture. Animate views back to resting state */
+ fun finish() {
+ if (swipeState.passedExpandThreshold) {
+ bubbleStashController?.showBubbleBar(expandBubbles = true)
+ }
+ springToRest()
+ }
+
+ /** Returns `true` if we are tracking a swipe gesture */
+ fun isSwipeGesture(): Boolean {
+ return swipeState.passedUnstashThreshold || swipeState.passedExpandThreshold
+ }
+
+ private fun isUnstash(dy: Float): Boolean {
+ return dy < -unstashThreshold
+ }
+
+ private fun isExpand(dy: Float): Boolean {
+ return dy < -expandThreshold
+ }
+
+ private fun reset() {
+ springAnimation?.let {
+ if (it.isRunning) {
+ it.removeAllListeners()
+ it.cancel()
+ animatedSwipeTranslation.updateValue(0f)
+ }
+ }
+ springAnimation = null
+ swipeState = SwipeState()
+ }
+
+ private fun onSwipeUpdate(value: Float) {
+ val dampedSwipe = -OverScroll.dampedScroll(-value, maxOverscroll).toFloat()
+ bubbleStashedHandleViewController?.setTranslationYForSwipe(dampedSwipe)
+ bubbleBarViewController?.setTranslationYForSwipe(dampedSwipe)
+ }
+
+ private fun springToRest() {
+ springAnimation =
+ SpringAnimationBuilder(context)
+ .setStartValue(animatedSwipeTranslation.value)
+ .setEndValue(0f)
+ .setDampingRatio(SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY)
+ .setStiffness(SpringForce.STIFFNESS_LOW)
+ .build(animatedSwipeTranslation, AnimatedFloat.VALUE)
+ .also { it.doOnEnd { reset() } }
+ springAnimation?.start()
+ }
+
+ internal data class SwipeState(
+ val stashedOnStart: Boolean = false,
+ val collapsedOnStart: Boolean = false,
+ val expandedOnStart: Boolean = false,
+ val passedUnstashThreshold: Boolean = false,
+ val passedExpandThreshold: Boolean = false,
+ )
+
+ /** Allows overriding the dimension provider for testing */
+ @VisibleForTesting
+ interface DimensionProvider {
+ val unstashThreshold: Int
+ val expandThreshold: Int
+ val maxOverscroll: Int
+ }
+
+ private class DefaultDimensionProvider(taskbarActivityContext: TaskbarActivityContext) :
+ DimensionProvider {
+ override val unstashThreshold: Int
+ override val expandThreshold: Int
+ override val maxOverscroll: Int
+
+ init {
+ val resources = taskbarActivityContext.resources
+ unstashThreshold =
+ TaskbarThresholdUtils.getFromNavThreshold(
+ resources,
+ taskbarActivityContext.deviceProfile,
+ )
+ // TODO(325673340): review threshold with ux
+ expandThreshold =
+ TaskbarThresholdUtils.getAppWindowThreshold(
+ resources,
+ taskbarActivityContext.deviceProfile,
+ )
+ maxOverscroll = taskbarActivityContext.deviceProfile.heightPx - unstashThreshold
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
index a66df4c..8230f42 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
@@ -40,6 +40,7 @@
public final BubbleDismissController bubbleDismissController;
public final BubbleBarPinController bubbleBarPinController;
public final BubblePinController bubblePinController;
+ public final Optional<BubbleBarSwipeController> bubbleBarSwipeController;
public final BubbleCreator bubbleCreator;
private final RunnableList mPostInitRunnables = new RunnableList();
@@ -58,6 +59,7 @@
BubbleDismissController bubbleDismissController,
BubbleBarPinController bubbleBarPinController,
BubblePinController bubblePinController,
+ Optional<BubbleBarSwipeController> bubbleBarSwipeController,
BubbleCreator bubbleCreator) {
this.bubbleBarController = bubbleBarController;
this.bubbleBarViewController = bubbleBarViewController;
@@ -67,6 +69,7 @@
this.bubbleDismissController = bubbleDismissController;
this.bubbleBarPinController = bubbleBarPinController;
this.bubblePinController = bubblePinController;
+ this.bubbleBarSwipeController = bubbleBarSwipeController;
this.bubbleCreator = bubbleCreator;
}
@@ -111,6 +114,7 @@
bubbleDismissController.init(/* bubbleControllers = */ this);
bubbleBarPinController.init(this, bubbleBarLocationListeners);
bubblePinController.init(this);
+ bubbleBarSwipeController.ifPresent(c -> c.init(this));
mPostInitRunnables.executeAllAndDestroy();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
index 12b1487..340a120 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleCreator.java
@@ -44,8 +44,6 @@
import android.view.LayoutInflater;
import android.view.ViewGroup;
-import androidx.appcompat.content.res.AppCompatResources;
-
import com.android.internal.graphics.ColorUtils;
import com.android.launcher3.R;
import com.android.launcher3.icons.BitmapInfo;
@@ -196,8 +194,7 @@
}
private Bitmap createOverflowBitmap() {
- Drawable iconDrawable = AppCompatResources.getDrawable(mContext,
- R.drawable.bubble_ic_overflow_button);
+ Drawable iconDrawable = mContext.getDrawable(R.drawable.bubble_ic_overflow_button);
final TypedArray ta = mContext.obtainStyledAttributes(
new int[]{
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
index 152dcf7..4939c99 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
@@ -28,12 +28,12 @@
) {
private var flyout: BubbleBarFlyoutView? = null
- val horizontalMargin =
+ private val horizontalMargin =
container.context.resources.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin)
fun setUpFlyout(message: BubbleBarFlyoutMessage) {
flyout?.let(container::removeView)
- val flyout = BubbleBarFlyoutView(container.context)
+ val flyout = BubbleBarFlyoutView(container.context, onLeft = positioner.isOnLeft)
flyout.translationY = positioner.targetTy
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
index d3dc3f8..4b91f46 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
@@ -21,14 +21,17 @@
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
+import android.graphics.Path
import android.view.LayoutInflater
import android.widget.ImageView
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import com.android.launcher3.R
+import com.android.launcher3.popup.RoundedArrowDrawable
/** The flyout view used to notify the user of a new bubble notification. */
-class BubbleBarFlyoutView(context: Context) : ConstraintLayout(context) {
+class BubbleBarFlyoutView(context: Context, private val onLeft: Boolean) :
+ ConstraintLayout(context) {
private val sender: TextView by
lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_name) }
@@ -39,9 +42,36 @@
private val message: TextView by
lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_text) }
- private val flyoutHorizontalPadding by
+ private val flyoutPadding by
lazy(LazyThreadSafetyMode.NONE) {
- context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding_horizontal)
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding)
+ }
+
+ private val triangleHeight by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_triangle_height)
+ }
+
+ private val triangleOverlap by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(
+ R.dimen.bubblebar_flyout_triangle_overlap_amount
+ )
+ }
+
+ private val triangleWidth by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_triangle_width)
+ }
+
+ private val triangleRadius by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_triangle_radius)
+ }
+
+ private val minFlyoutWidth by
+ lazy(LazyThreadSafetyMode.NONE) {
+ context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_min_width)
}
private val maxFlyoutWidth by
@@ -50,6 +80,7 @@
}
private val cornerRadius: Float
+ private val triangle: Path = Path()
private var backgroundColor = Color.BLACK
/**
@@ -69,13 +100,19 @@
clipChildren = false
clipToPadding = false
- val horizontalPadding =
- context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding_horizontal)
- val verticalPadding =
- context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding_vertical)
- setPadding(horizontalPadding, verticalPadding, horizontalPadding, verticalPadding)
+ val padding = context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_padding)
+ // add extra padding to the bottom of the view to include the triangle
+ setPadding(padding, padding, padding, padding + triangleHeight - triangleOverlap)
translationZ =
context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_elevation).toFloat()
+
+ RoundedArrowDrawable.addDownPointingRoundedTriangleToPath(
+ triangleWidth.toFloat(),
+ triangleHeight.toFloat(),
+ triangleRadius.toFloat(),
+ triangle,
+ )
+
applyConfigurationColors(resources.configuration)
}
@@ -88,15 +125,28 @@
avatar.visibility = GONE
}
- val maxTextViewWidth = maxFlyoutWidth - flyoutHorizontalPadding * 2
+ val minTextViewWidth: Int
+ val maxTextViewWidth: Int
+ if (avatar.visibility == VISIBLE) {
+ minTextViewWidth = minFlyoutWidth - avatar.width - flyoutPadding * 2
+ maxTextViewWidth = maxFlyoutWidth - avatar.width - flyoutPadding * 2
+ } else {
+ // when there's no avatar, the width of the text view is constant, so we're setting the
+ // min and max to the same value
+ minTextViewWidth = minFlyoutWidth - flyoutPadding * 2
+ maxTextViewWidth = minTextViewWidth
+ }
+
if (flyoutMessage.senderName.isEmpty()) {
sender.visibility = GONE
} else {
+ sender.minWidth = minTextViewWidth
sender.maxWidth = maxTextViewWidth
sender.text = flyoutMessage.senderName
sender.visibility = VISIBLE
}
+ message.minWidth = minTextViewWidth
message.maxWidth = maxTextViewWidth
message.text = flyoutMessage.message
}
@@ -106,14 +156,23 @@
0f,
0f,
width.toFloat(),
- height.toFloat(),
+ height.toFloat() - triangleHeight + triangleOverlap,
cornerRadius,
cornerRadius,
backgroundPaint,
)
+ drawTriangle(canvas)
super.onDraw(canvas)
}
+ private fun drawTriangle(canvas: Canvas) {
+ canvas.save()
+ val triangleX = if (onLeft) cornerRadius else width - cornerRadius - triangleWidth
+ canvas.translate(triangleX, (height - triangleHeight).toFloat())
+ canvas.drawPath(triangle, backgroundPaint)
+ canvas.restore()
+ }
+
private fun applyConfigurationColors(configuration: Configuration) {
val nightModeFlags = configuration.uiMode and Configuration.UI_MODE_NIGHT_MASK
val isNightModeOn = nightModeFlags == Configuration.UI_MODE_NIGHT_YES
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 4f0337d..74e3c00 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -32,8 +32,8 @@
import com.android.launcher3.anim.AnimatedFloat
import com.android.launcher3.anim.SpringAnimationBuilder
import com.android.launcher3.taskbar.TaskbarInsetsController
-import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_DURATION
import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_ALPHA_START_DELAY
+import com.android.launcher3.taskbar.TaskbarStashController.TRANSIENT_TASKBAR_STASH_ALPHA_DURATION
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_DURATION
@@ -305,7 +305,8 @@
animatorSet.play(
createBackgroundAlphaAnimator(isStashed).apply {
- val alphaDuration = if (isStashed) duration else TASKBAR_STASH_ALPHA_DURATION
+ val alphaDuration =
+ if (isStashed) duration else TRANSIENT_TASKBAR_STASH_ALPHA_DURATION
val alphaDelay = if (isStashed) TASKBAR_STASH_ALPHA_START_DELAY else 0L
this.duration = max(0L, alphaDuration - alphaDelay)
this.startDelay = alphaDelay
@@ -317,7 +318,7 @@
bubbleBarBubbleAlpha
.animateToValue(getBarAlphaStart(isStashed), getBarAlphaEnd(isStashed))
.apply {
- this.duration = TASKBAR_STASH_ALPHA_DURATION
+ this.duration = TRANSIENT_TASKBAR_STASH_ALPHA_DURATION
this.startDelay = TASKBAR_STASH_ALPHA_START_DELAY
this.interpolator = LINEAR
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
index 773b0b9..669850c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
@@ -73,7 +73,7 @@
@Override
public void recreateControllers() {
List<TouchController> controllers = new ArrayList<>();
- controllers.add(mActivity.getDragController());
+ controllers.add(mContainer.getDragController());
controllers.addAll(mTouchControllers);
mControllers = controllers.toArray(new TouchController[0]);
}
@@ -87,7 +87,7 @@
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) {
- AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
+ AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mContainer);
if (topView != null && topView.canHandleBack()) {
topView.onBackInvoked();
return true;
@@ -96,7 +96,7 @@
&& event.getKeyCode() == KeyEvent.KEYCODE_ESCAPE && event.hasNoModifiers()) {
// Ignore escape if pressed in conjunction with any modifier keys. Close each
// floating view one at a time for each key press.
- AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
+ AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mContainer);
if (topView != null) {
topView.close(/* animate= */ true);
return true;
@@ -107,7 +107,7 @@
@Override
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
- if (mActivity.isAnySystemDragInProgress()) {
+ if (mContainer.isAnySystemDragInProgress()) {
inoutInfo.touchableRegion.setEmpty();
inoutInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
}
@@ -123,7 +123,7 @@
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);
- mActivity.getOverlayController().maybeCloseWindow();
+ mContainer.getOverlayController().maybeCloseWindow();
}
/** Adds a {@link TouchController} to this drag layer. */
@@ -147,14 +147,14 @@
* 2) Sets tappableInsets bottom inset to 0.
*/
private WindowInsets updateInsetsDueToStashing(WindowInsets oldInsets) {
- if (!DisplayController.isTransientTaskbar(mActivity)) {
+ if (!DisplayController.isTransientTaskbar(mContainer)) {
return oldInsets;
}
WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets);
Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars());
Insets newNavInsets = Insets.of(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right,
- mActivity.getStashedTaskbarHeight());
+ mContainer.getStashedTaskbarHeight());
updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), newNavInsets);
Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement());
diff --git a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index 14d391b..bcad478 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -86,7 +86,7 @@
}
setStateWithAnimationInternal(toState, config, builder);
builder.addEndListener(success -> {
- if (!success) {
+ if (!success && !toState.isRecentsViewVisible) {
mRecentsView.reset();
}
});
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
index 93cbdc7..26a1322 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java
@@ -29,7 +29,6 @@
import android.widget.RemoteViews;
import android.window.SplashScreen;
-import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.ActivityOptionsWrapper;
@@ -66,7 +65,7 @@
Pair<Intent, ActivityOptions> options = remoteResponse.getLaunchOptions(view);
ActivityOptionsWrapper activityOptions = mLauncher.getAppTransitionManager()
.getActivityLaunchOptions(hostView, (ItemInfo) hostView.getTag());
- if (Utilities.ATLEAST_S && !pendingIntent.isActivity()) {
+ if (!pendingIntent.isActivity()) {
// In the event this pending intent eventually launches an activity, i.e. a trampoline,
// use the Quickstep transition animation.
try {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 1f5cd3a..5082c11 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -19,6 +19,7 @@
import static android.os.Trace.TRACE_TAG_APP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_OPTIMIZE_MEASURE;
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
+import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY;
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_WORKSPACE;
@@ -64,7 +65,6 @@
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
-import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50;
import android.animation.Animator;
@@ -200,8 +200,6 @@
import com.android.systemui.unfold.updates.RotationChangeProvider;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
-import kotlin.Unit;
-
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -214,6 +212,8 @@
import java.util.function.Predicate;
import java.util.stream.Stream;
+import kotlin.Unit;
+
public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
SystemShortcut.BubbleActivityStarter {
private static final boolean TRACE_LAYOUTS =
@@ -271,7 +271,7 @@
RecentsView<?,?> overviewPanel = getOverviewPanel();
SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(this);
mSplitSelectStateController =
- new SplitSelectStateController(this, mHandler, getStateManager(),
+ new SplitSelectStateController(this, getStateManager(),
getDepthController(), getStatsLogManager(),
systemUiProxy, RecentsModel.INSTANCE.get(this),
() -> onStateBack());
@@ -681,10 +681,6 @@
@Override
protected void onCreate(Bundle savedInstanceState) {
- // Back dispatcher is registered in {@link BaseActivity#onCreate}. For predictive back to
- // work, we must opt-in BEFORE registering back dispatcher. So we need to call
- // setEnableOnBackInvokedCallback() before super.onCreate()
- getApplicationInfo().setEnableOnBackInvokedCallback(true);
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mPendingSplitSelectInfo = ObjectWrapper.unwrap(
@@ -1003,7 +999,7 @@
@Override
public void setResumed() {
DesktopVisibilityController desktopVisibilityController = getDesktopVisibilityController();
- if (!WALLPAPER_ACTIVITY.isEnabled(this)
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
&& desktopVisibilityController != null
&& desktopVisibilityController.areDesktopTasksVisible()
&& !desktopVisibilityController.isRecentsGestureInProgress()) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index 11e0ed5..1d9e492 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -45,6 +45,7 @@
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.touch.SingleAxisSwipeDetector;
import com.android.launcher3.util.DisplayController;
@@ -53,6 +54,7 @@
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.OverviewToHomeAnim;
import com.android.quickstep.views.RecentsView;
+import com.android.systemui.contextualeducation.GestureType;
import java.util.function.BiConsumer;
@@ -219,6 +221,8 @@
}
if (mStartState != mEndState) {
logHomeGesture();
+ ContextualEduStatsManager.INSTANCE.get(mLauncher).updateEduStats(
+ mSwipeDetector.isTrackpadGesture(), GestureType.HOME);
}
AbstractFloatingView topOpenView = AbstractFloatingView.getTopOpenView(mLauncher);
if (topOpenView != null) {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 240d6ad..fe1d015 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -45,6 +45,7 @@
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC;
import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
+import static com.android.quickstep.BaseContainerInterface.AnimationFactory;
import static com.android.quickstep.GestureState.GestureEndTarget.HOME;
import static com.android.quickstep.GestureState.GestureEndTarget.LAST_TASK;
import static com.android.quickstep.GestureState.GestureEndTarget.NEW_TASK;
@@ -92,6 +93,7 @@
import android.view.animation.Interpolator;
import android.widget.Toast;
import android.window.PictureInPictureSurfaceTransaction;
+import android.window.flags.DesktopModeFlags;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -102,6 +104,7 @@
import com.android.internal.util.LatencyTracker;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
@@ -111,6 +114,7 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.taskbar.TaskbarThresholdUtils;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
@@ -119,9 +123,9 @@
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.WindowBounds;
-import com.android.quickstep.BaseActivityInterface.AnimationFactory;
import com.android.quickstep.GestureState.GestureEndTarget;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
+import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.util.ActiveGestureErrorDetector;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.ActivityInitListener;
@@ -152,12 +156,9 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.wm.shell.shared.TransactionPool;
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.startingsurface.SplashScreenExitAnimationUtils;
-import kotlin.Unit;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -167,15 +168,16 @@
import java.util.OptionalInt;
import java.util.function.Consumer;
+import kotlin.Unit;
+
/**
* Handles the navigation gestures when Launcher is the default home activity.
*/
public abstract class AbsSwipeUpHandler<
- RECENTS_CONTAINER extends Context & RecentsViewContainer,
- RECENTS_VIEW extends RecentsView<RECENTS_CONTAINER, STATE>,
- STATE extends BaseState<STATE>>
- extends SwipeUpAnimationLogic
- implements OnApplyWindowInsetsListener, RecentsAnimationCallbacks.RecentsAnimationListener {
+ RECENTS_CONTAINER extends Context & RecentsViewContainer & StatefulContainer<STATE>,
+ RECENTS_VIEW extends RecentsView<RECENTS_CONTAINER, STATE>, STATE extends BaseState<STATE>>
+ extends SwipeUpAnimationLogic implements OnApplyWindowInsetsListener,
+ RecentsAnimationCallbacks.RecentsAnimationListener {
private static final String TAG = "AbsSwipeUpHandler";
private static final ArrayList<String> STATE_NAMES = new ArrayList<>();
@@ -292,7 +294,7 @@
private static final int LOG_NO_OP_PAGE_INDEX = -1;
protected final TaskAnimationManager mTaskAnimationManager;
-
+ protected final RecentsWindowManager mRecentsWindowManager;
// Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise
private RunningWindowAnim[] mRunningWindowAnim;
// Possible second animation running at the same time as mRunningWindowAnim
@@ -353,9 +355,12 @@
public AbsSwipeUpHandler(Context context, RecentsAnimationDeviceState deviceState,
TaskAnimationManager taskAnimationManager, GestureState gestureState,
long touchTimeMs, boolean continuingLastGesture,
- InputConsumerController inputConsumer) {
+ InputConsumerController inputConsumer, RecentsWindowManager recentsWindowManager) {
super(context, deviceState, gestureState);
mContainerInterface = gestureState.getContainerInterface();
+ if (recentsWindowManager != null && Flags.enableFallbackOverviewInWindow()) {
+ recentsWindowManager.registerInitListener(this::onActivityInit);
+ }
mActivityInitListener =
mContainerInterface.createActivityInitListener(this::onActivityInit);
mInputConsumerProxy =
@@ -369,6 +374,7 @@
endLauncherTransitionController();
}, new InputProxyHandlerFactory(mContainerInterface, mGestureState));
mTaskAnimationManager = taskAnimationManager;
+ mRecentsWindowManager = recentsWindowManager;
mTouchTimeMs = touchTimeMs;
mContinuingLastGesture = continuingLastGesture;
@@ -819,7 +825,7 @@
return;
}
initTransitionEndpoints(mContainer.getDeviceProfile());
- mAnimationFactory.createActivityInterface(mTransitionDragLength);
+ mAnimationFactory.createContainerInterface(mTransitionDragLength);
}
/**
@@ -863,10 +869,13 @@
}
}
+ public Intent getHomeIntent() {
+ return mGestureState.getHomeIntent();
+ }
+
public Intent getLaunchIntent() {
return mGestureState.getOverviewIntent();
}
-
/**
* Called when the value of {@link #mCurrentShift} changes
*/
@@ -1256,8 +1265,8 @@
? mRecentsView.getCurrentPageTaskView() : null;
if (DesktopModeStatus.canEnterDesktopMode(mContext)
- && !(DesktopModeFlags.WALLPAPER_ACTIVITY.isEnabled(mContext)
- && DesktopModeFlags.QUICK_SWITCH.isEnabled(mContext))) {
+ && !(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_QUICK_SWITCH.isTrue())) {
if ((nextPageTaskView instanceof DesktopTaskView
|| currentPageTaskView instanceof DesktopTaskView)
&& endTarget == NEW_TASK) {
@@ -1423,8 +1432,8 @@
};
if (DesktopModeStatus.canEnterDesktopMode(mContext)
- && !(DesktopModeFlags.WALLPAPER_ACTIVITY.isEnabled(mContext)
- && DesktopModeFlags.QUICK_SWITCH.isEnabled(mContext))) {
+ && !(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_QUICK_SWITCH.isTrue())) {
if (mRecentsView != null && (mRecentsView.getCurrentPageTaskView() != null
&& !(mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView))) {
ActiveGestureLog.INSTANCE.trackEvent(ActiveGestureErrorDetector.GestureEvent
@@ -2249,8 +2258,8 @@
});
if (DesktopModeStatus.canEnterDesktopMode(mContext)
- && !(DesktopModeFlags.WALLPAPER_ACTIVITY.isEnabled(mContext)
- && DesktopModeFlags.QUICK_SWITCH.isEnabled(mContext))) {
+ && !(DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_QUICK_SWITCH.isTrue())) {
if (mRecentsView.getNextPageTaskView() instanceof DesktopTaskView
|| mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView) {
mRecentsViewScrollLinked = false;
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 8703843..1e755eb 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -36,7 +36,6 @@
import android.view.MotionEvent;
import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
@@ -62,17 +61,14 @@
public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_TYPE>,
ACTIVITY_TYPE extends StatefulActivity<STATE_TYPE> & RecentsViewContainer> extends
BaseContainerInterface<STATE_TYPE, ACTIVITY_TYPE> {
- private final STATE_TYPE mBackgroundState;
private STATE_TYPE mTargetState;
- @Nullable private Runnable mOnInitBackgroundStateUICallback = null;
-
protected BaseActivityInterface(boolean rotationSupportedByActivity,
STATE_TYPE overviewState, STATE_TYPE backgroundState) {
+ super(backgroundState);
this.rotationSupportedByActivity = rotationSupportedByActivity;
mTargetState = overviewState;
- mBackgroundState = backgroundState;
}
/**
@@ -124,13 +120,6 @@
return activity != null && activity.isStarted();
}
- @UiThread
- @Nullable
- public abstract <T extends RecentsView> T getVisibleRecentsView();
-
- @UiThread
- public abstract boolean switchToRecentsIfVisible(Animator.AnimatorListener animatorListener);
-
public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
TaskbarUIController controller = getTaskbarController();
boolean isEventOverBubbleBarStashHandle =
@@ -163,49 +152,6 @@
recentsView.switchToScreenshot(thumbnailDatas, runnable);
}
-
- protected void runOnInitBackgroundStateUI(Runnable callback) {
- ACTIVITY_TYPE activity = getCreatedContainer();
- if (activity != null && activity.getStateManager().getState() == mBackgroundState) {
- callback.run();
- onInitBackgroundStateUI();
- return;
- }
- mOnInitBackgroundStateUICallback = callback;
- }
-
- private void onInitBackgroundStateUI() {
- if (mOnInitBackgroundStateUICallback != null) {
- mOnInitBackgroundStateUICallback.run();
- mOnInitBackgroundStateUICallback = null;
- }
- }
-
- public interface AnimationFactory {
-
- void createActivityInterface(long transitionLength);
-
- /**
- * @param attached Whether to show RecentsView alongside the app window. If false, recents
- * will be hidden by some property we can animate, e.g. alpha.
- * @param animate Whether to animate recents to/from its new attached state.
- * @param updateRunningTaskAlpha Whether to update the running task's attached alpha
- */
- default void setRecentsAttachedToAppWindow(
- boolean attached, boolean animate, boolean updateRunningTaskAlpha) { }
-
- default boolean isRecentsAttachedToAppWindow() {
- return false;
- }
-
- default boolean hasRecentsEverAttachedToAppWindow() {
- return false;
- }
-
- /** Called when the gesture ends and we know what state it is going towards */
- default void setEndTarget(GestureState.GestureEndTarget endTarget) { }
- }
-
class DefaultAnimationFactory implements AnimationFactory {
protected final ACTIVITY_TYPE mActivity;
@@ -234,7 +180,7 @@
}
@Override
- public void createActivityInterface(long transitionLength) {
+ public void createContainerInterface(long transitionLength) {
PendingAnimation pa = new PendingAnimation(transitionLength * 2);
createBackgroundToOverviewAnim(mActivity, pa);
AnimatorPlaybackController controller = pa.createPlaybackController();
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index bf3a662..14c2cc4 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -34,16 +34,19 @@
import android.view.View;
import androidx.annotation.Nullable;
+import androidx.annotation.UiThread;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.views.ScrimView;
+import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.AnimatorControllerWithResistance;
@@ -57,13 +60,28 @@
import java.util.function.Predicate;
public abstract class BaseContainerInterface<STATE_TYPE extends BaseState<STATE_TYPE>,
- CONTAINER_TYPE extends RecentsViewContainer> {
+ CONTAINER_TYPE extends RecentsViewContainer & StatefulContainer<STATE_TYPE>> {
public boolean rotationSupportedByActivity = false;
+ protected final STATE_TYPE mBackgroundState;
+
+ protected BaseContainerInterface(STATE_TYPE backgroundState) {
+ mBackgroundState = backgroundState;
+ }
+
+ @UiThread
+ @Nullable
+ public abstract <T extends RecentsView<?,?>> T getVisibleRecentsView();
+
+ @UiThread
+ public abstract boolean switchToRecentsIfVisible(Animator.AnimatorListener animatorListener);
@Nullable
public abstract CONTAINER_TYPE getCreatedContainer();
+ @Nullable
+ protected Runnable mOnInitBackgroundStateUICallback = null;
+
public abstract boolean isInLiveTileMode();
public abstract void onAssistantVisibilityChanged(float assistantVisibility);
@@ -88,7 +106,32 @@
@Nullable
public abstract TaskbarUIController getTaskbarController();
- public abstract BaseActivityInterface.AnimationFactory prepareRecentsUI(
+ public interface AnimationFactory {
+
+ void createContainerInterface(long transitionLength);
+
+ /**
+ * @param attached Whether to show RecentsView alongside the app window. If false, recents
+ * will be hidden by some property we can animate, e.g. alpha.
+ * @param animate Whether to animate recents to/from its new attached state.
+ * @param updateRunningTaskAlpha Whether to update the running task's attached alpha
+ */
+ default void setRecentsAttachedToAppWindow(
+ boolean attached, boolean animate, boolean updateRunningTaskAlpha) { }
+
+ default boolean isRecentsAttachedToAppWindow() {
+ return false;
+ }
+
+ default boolean hasRecentsEverAttachedToAppWindow() {
+ return false;
+ }
+
+ /** Called when the gesture ends and we know what state it is going towards */
+ default void setEndTarget(GestureState.GestureEndTarget endTarget) { }
+ }
+
+ public abstract BaseContainerInterface.AnimationFactory prepareRecentsUI(
RecentsAnimationDeviceState deviceState, boolean activityVisible,
Consumer<AnimatorControllerWithResistance> callback);
@@ -126,6 +169,17 @@
return false;
}
+ public void runOnInitBackgroundStateUI(Runnable callback) {
+ StatefulContainer container = getCreatedContainer();
+ if (container != null
+ && container.getStateManager().getState() == mBackgroundState) {
+ callback.run();
+ onInitBackgroundStateUI();
+ return;
+ }
+ mOnInitBackgroundStateUICallback = callback;
+ }
+
@Nullable
public DesktopVisibilityController getDesktopVisibilityController() {
CONTAINER_TYPE container = getCreatedContainer();
@@ -403,4 +457,11 @@
outRect,
orientationHandler);
}
+
+ protected void onInitBackgroundStateUI() {
+ if (mOnInitBackgroundStateUICallback != null) {
+ mOnInitBackgroundStateUICallback.run();
+ mOnInitBackgroundStateUICallback = null;
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/BaseWindowInterface.java b/quickstep/src/com/android/quickstep/BaseWindowInterface.java
new file mode 100644
index 0000000..9d6e61d
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/BaseWindowInterface.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2024 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.app.animation.Interpolators.ACCELERATE_2;
+import static com.android.app.animation.Interpolators.INSTANT;
+import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
+import static com.android.quickstep.AbsSwipeUpHandler.RECENTS_ATTACH_DURATION;
+import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_FADE_ANIM;
+import static com.android.quickstep.util.RecentsAtomicAnimationFactory.INDEX_RECENTS_TRANSLATE_X_ANIM;
+import static com.android.quickstep.views.RecentsView.ADJACENT_PAGE_HORIZONTAL_OFFSET;
+import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
+import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
+import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.util.Log;
+import android.view.MotionEvent;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.statehandlers.DepthController;
+import com.android.launcher3.taskbar.TaskbarUIController;
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.NavigationMode;
+import com.android.quickstep.fallback.RecentsState;
+import com.android.quickstep.fallback.window.RecentsWindowManager;
+import com.android.quickstep.util.AnimatorControllerWithResistance;
+import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import java.util.HashMap;
+import java.util.Optional;
+import java.util.function.Consumer;
+
+/**
+ * Temporary utility class in place for differences needed between
+ * Recents in Window in Launcher vs Fallback
+ */
+public abstract class BaseWindowInterface extends
+ BaseContainerInterface<RecentsState, RecentsWindowManager> {
+
+ final String TAG = "BaseWindowInterface";
+ private RecentsState mTargetState;
+
+
+ protected BaseWindowInterface(RecentsState overviewState, RecentsState backgroundState) {
+ super(backgroundState);
+ mTargetState = overviewState;
+ }
+
+ @Nullable
+ public abstract RecentsWindowManager getCreatedContainer();
+
+ @Nullable
+ public DepthController getDepthController() {
+ return null;
+ }
+
+ public final boolean isResumed() {
+ return isStarted();
+ }
+
+ public final boolean isStarted() {
+ RecentsWindowManager windowManager = getCreatedContainer();
+ return windowManager != null && windowManager.isStarted();
+ }
+
+ public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
+ TaskbarUIController controller = getTaskbarController();
+ boolean isEventOverBubbleBarStashHandle =
+ controller != null && controller.isEventOverBubbleBarViews(ev);
+ return deviceState.isInDeferredGestureRegion(ev) || deviceState.isImeRenderingNavButtons()
+ || isTrackpadMultiFingerSwipe(ev) || isEventOverBubbleBarStashHandle;
+ }
+
+ /**
+ * Closes any overlays.
+ */
+ public void closeOverlay() {
+ Optional.ofNullable(getTaskbarController()).ifPresent(
+ TaskbarUIController::hideOverlayWindow);
+ }
+
+ public void switchRunningTaskViewToScreenshot(HashMap<Integer, ThumbnailData> thumbnailDatas,
+ Runnable runnable) {
+ RecentsWindowManager windowManager = getCreatedContainer();
+ if (windowManager == null) {
+ return;
+ }
+ RecentsView recentsView = windowManager.getOverviewPanel();
+ if (recentsView == null) {
+ if (runnable != null) {
+ runnable.run();
+ }
+ return;
+ }
+ recentsView.switchToScreenshot(thumbnailDatas, runnable);
+ }
+
+ /**
+ * todo: Create an abstract animation factory to handle both activity and window implementations
+ * todo: move new factory into BaseContainerInterface and cleanup.
+ */
+
+ class DefaultAnimationFactory implements AnimationFactory {
+
+ protected final RecentsWindowManager mRecentsWindowManager;
+ private final RecentsState mStartState;
+ private final Consumer<AnimatorControllerWithResistance> mCallback;
+
+ private boolean mIsAttachedToWindow;
+ private boolean mHasEverAttachedToWindow;
+
+ DefaultAnimationFactory(Consumer<AnimatorControllerWithResistance> callback) {
+ mCallback = callback;
+
+ mRecentsWindowManager = getCreatedContainer();
+ mStartState = mRecentsWindowManager.getStateManager().getState();
+ }
+
+ protected RecentsWindowManager initBackgroundStateUI() {
+ RecentsState resetState = mStartState;
+ if (mStartState.shouldDisableRestore()) {
+ resetState = mRecentsWindowManager.getStateManager().getRestState();
+ }
+ mRecentsWindowManager.getStateManager().setRestState(resetState);
+ mRecentsWindowManager.getStateManager().goToState(mBackgroundState, false);
+ onInitBackgroundStateUI();
+ return mRecentsWindowManager;
+ }
+
+ @Override
+ public void createContainerInterface(long transitionLength) {
+ PendingAnimation pa = new PendingAnimation(transitionLength * 2);
+ createBackgroundToOverviewAnim(mRecentsWindowManager, pa);
+ AnimatorPlaybackController controller = pa.createPlaybackController();
+ mRecentsWindowManager.getStateManager().setCurrentUserControlledAnimation(controller);
+
+ // Since we are changing the start position of the UI, reapply the state, at the end
+ controller.setEndAction(() -> {
+ mRecentsWindowManager.getStateManager().goToState(
+ controller.getInterpolatedProgress() > 0.5 ? mTargetState
+ : mBackgroundState,
+ /* animated= */ false);
+ });
+
+ RecentsView recentsView = mRecentsWindowManager.getOverviewPanel();
+ AnimatorControllerWithResistance controllerWithResistance =
+ AnimatorControllerWithResistance.createForRecents(controller,
+ mRecentsWindowManager, recentsView.getPagedViewOrientedState(),
+ mRecentsWindowManager.getDeviceProfile(), recentsView,
+ RECENTS_SCALE_PROPERTY, recentsView, TASK_SECONDARY_TRANSLATION);
+ mCallback.accept(controllerWithResistance);
+
+ // Creating the activity controller animation sometimes reapplies the launcher state
+ // (because we set the animation as the current state animation), so we reapply the
+ // attached state here as well to ensure recents is shown/hidden appropriately.
+ if (DisplayController.getNavigationMode(mRecentsWindowManager)
+ == NavigationMode.NO_BUTTON) {
+ setRecentsAttachedToAppWindow(mIsAttachedToWindow, false, false);
+ }
+ }
+
+ @Override
+ public void setRecentsAttachedToAppWindow(boolean attached, boolean animate,
+ boolean updateRunningTaskAlpha) {
+
+ if (mIsAttachedToWindow == attached && animate) {
+ return;
+ }
+ mRecentsWindowManager.getStateManager()
+ .cancelStateElementAnimation(INDEX_RECENTS_FADE_ANIM);
+ mRecentsWindowManager.getStateManager()
+ .cancelStateElementAnimation(INDEX_RECENTS_TRANSLATE_X_ANIM);
+
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ super.onAnimationStart(animation);
+ mIsAttachedToWindow = attached;
+ if (attached) {
+ mHasEverAttachedToWindow = true;
+ }
+ }});
+
+ long animationDuration = animate ? RECENTS_ATTACH_DURATION : 0;
+ Animator fadeAnim = mRecentsWindowManager.getStateManager()
+ .createStateElementAnimation(INDEX_RECENTS_FADE_ANIM, attached ? 1 : 0);
+ fadeAnim.setInterpolator(attached ? INSTANT : ACCELERATE_2);
+ fadeAnim.setDuration(animationDuration);
+ animatorSet.play(fadeAnim);
+
+ float fromTranslation = ADJACENT_PAGE_HORIZONTAL_OFFSET.get(
+ mRecentsWindowManager.getOverviewPanel());
+ float toTranslation = attached ? 0 : 1;
+
+ Animator translationAnimator =
+ mRecentsWindowManager.getStateManager().createStateElementAnimation(
+ INDEX_RECENTS_TRANSLATE_X_ANIM, fromTranslation, toTranslation);
+ translationAnimator.setDuration(animationDuration);
+ animatorSet.play(translationAnimator);
+ animatorSet.start();
+ }
+
+ @Override
+ public boolean isRecentsAttachedToAppWindow() {
+ return mIsAttachedToWindow;
+ }
+
+ @Override
+ public boolean hasRecentsEverAttachedToAppWindow() {
+ return mHasEverAttachedToWindow;
+ }
+
+ @Override
+ public void setEndTarget(GestureState.GestureEndTarget endTarget) {
+ mTargetState = stateFromGestureEndTarget(endTarget);
+ }
+
+ protected void createBackgroundToOverviewAnim(RecentsWindowManager container,
+ PendingAnimation pa) {
+ // Scale down recents from being full screen to being in overview.
+ RecentsView recentsView = container.getOverviewPanel();
+ pa.addFloat(recentsView, RECENTS_SCALE_PROPERTY,
+ recentsView.getMaxScaleForFullScreen(), 1, LINEAR);
+ pa.addFloat(recentsView, FULLSCREEN_PROGRESS, 1, 0, LINEAR);
+
+ pa.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ TaskbarUIController taskbarUIController = getTaskbarController();
+ if (taskbarUIController != null) {
+ taskbarUIController.setSystemGestureInProgress(true);
+ }
+ }
+ });
+ }
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index 9b66154..7abcfb8 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -64,6 +64,7 @@
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
+import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
@@ -82,7 +83,7 @@
* Handles the navigation gestures when a 3rd party launcher is the default home activity.
*/
public class FallbackSwipeHandler extends
- AbsSwipeUpHandler<RecentsActivity, FallbackRecentsView, RecentsState> {
+ AbsSwipeUpHandler<RecentsActivity, FallbackRecentsView<RecentsActivity>, RecentsState> {
private static final String TAG = "FallbackSwipeHandler";
@@ -105,7 +106,7 @@
TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
boolean continuingLastGesture, InputConsumerController inputConsumer) {
super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
- continuingLastGesture, inputConsumer);
+ continuingLastGesture, inputConsumer, null);
mRunningOverHome = mGestureState.getRunningTask() != null
&& mGestureState.getRunningTask().isHomeTask();
diff --git a/quickstep/src/com/android/quickstep/FallbackWindowInterface.java b/quickstep/src/com/android/quickstep/FallbackWindowInterface.java
new file mode 100644
index 0000000..ea478dd
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/FallbackWindowInterface.java
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2024 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.NavigationMode.NO_BUTTON;
+import static com.android.quickstep.fallback.RecentsState.BACKGROUND_APP;
+import static com.android.quickstep.fallback.RecentsState.DEFAULT;
+import static com.android.quickstep.fallback.RecentsState.HOME;
+
+import android.animation.Animator;
+import android.animation.AnimatorSet;
+import android.content.Context;
+import android.graphics.Rect;
+import android.view.MotionEvent;
+import android.view.RemoteAnimationTarget;
+
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.taskbar.FallbackTaskbarUIController;
+import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.GestureState.GestureEndTarget;
+import com.android.quickstep.fallback.RecentsState;
+import com.android.quickstep.fallback.window.RecentsWindowManager;
+import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.util.ActivityInitListener;
+import com.android.quickstep.util.AnimatorControllerWithResistance;
+import com.android.quickstep.views.RecentsView;
+
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+/**
+ * {@link BaseWindowInterface} for recents when the default launcher is different than the
+ * currently running one and apps should interact with the {@link RecentsWindowManager} as opposed
+ * to the in-launcher one.
+ */
+public final class FallbackWindowInterface extends BaseWindowInterface{
+
+ private static FallbackWindowInterface INSTANCE;
+
+ private final RecentsWindowManager mRecentsWindowManager;
+
+ /**
+ * This is only null before init() or after destroy()
+ */
+ @Nullable
+ public static FallbackWindowInterface getInstance(){
+ return INSTANCE;
+ }
+
+ public static void init(RecentsWindowManager recentsWindowManager) {
+ if (INSTANCE == null) {
+ INSTANCE = new FallbackWindowInterface(recentsWindowManager);
+ }
+ }
+
+ private FallbackWindowInterface(RecentsWindowManager recentsWindowManager) {
+ super(DEFAULT, BACKGROUND_APP);
+ mRecentsWindowManager = recentsWindowManager;
+ }
+
+ public void destroy() {
+ INSTANCE = null;
+ }
+
+ /** 2 */
+ @Override
+ public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect,
+ RecentsPagedOrientationHandler orientationHandler) {
+ calculateTaskSize(context, dp, outRect, orientationHandler);
+ if (dp.isVerticalBarLayout() && DisplayController.getNavigationMode(context) != NO_BUTTON) {
+ return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right);
+ } else {
+ return dp.heightPx - outRect.bottom;
+ }
+ }
+
+ /** 5 */
+ @Override
+ public void onAssistantVisibilityChanged(float visibility) {
+ // This class becomes active when the screen is locked.
+ // Rather than having it handle assistant visibility changes, the assistant visibility is
+ // set to zero prior to this class becoming active.
+ }
+
+ /** 6 */
+ @Override
+ public BaseWindowInterface.AnimationFactory prepareRecentsUI(RecentsAnimationDeviceState
+ deviceState, boolean activityVisible,
+ Consumer<AnimatorControllerWithResistance> callback) {
+ notifyRecentsOfOrientation(deviceState.getRotationTouchHelper());
+ BaseWindowInterface.DefaultAnimationFactory factory =
+ new BaseWindowInterface.DefaultAnimationFactory(callback);
+ factory.initBackgroundStateUI();
+ return factory;
+ }
+
+ @Override
+ public ActivityInitListener createActivityInitListener(
+ Predicate<Boolean> onInitListener) {
+ //todo figure out how to properly replace this
+ return new ActivityInitListener<>((activity, alreadyOnHome) ->
+ onInitListener.test(alreadyOnHome), RecentsActivity.ACTIVITY_TRACKER);
+ }
+
+ @Nullable
+ @Override
+ public RecentsWindowManager getCreatedContainer() {
+ return mRecentsWindowManager;
+ }
+
+ @Override
+ public FallbackTaskbarUIController getTaskbarController() {
+ RecentsWindowManager manager = getCreatedContainer();
+ if (manager == null) {
+ return null;
+ }
+ return null;
+ // todo b/365775636: pass a taskbar implementation
+ // return manager.getTaskbarUIController();
+ }
+
+ @Override
+ public Rect getOverviewWindowBounds(Rect homeBounds, RemoteAnimationTarget target) {
+ // TODO: Remove this once b/77875376 is fixed
+ return target.screenSpaceBounds;
+ }
+
+ @Nullable
+ @Override
+ public <T extends RecentsView<?, ?>> T getVisibleRecentsView() {
+ RecentsWindowManager manager = getCreatedContainer();
+ if(manager.isStarted() || isInLiveTileMode()){
+ return getCreatedContainer().getOverviewPanel();
+ }
+ return null;
+ }
+
+ @Override
+ public boolean switchToRecentsIfVisible(Animator.AnimatorListener animatorListener) {
+ return false;
+ }
+
+ @Override
+ protected int getOverviewScrimColorForState(RecentsWindowManager container,
+ RecentsState state) {
+ return state.getScrimColor(container.asContext());
+ }
+
+ @Override
+ public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
+ // In non-gesture mode, user might be clicking on the home button which would directly
+ // start the home activity instead of going through recents. In that case, defer starting
+ // recents until we are sure it is a gesture.
+ return false;
+// return !deviceState.isFullyGesturalNavMode();
+// || super.deferStartingActivity(deviceState, ev);
+ }
+
+ @Override
+ public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) {
+ final StateManager<RecentsState, RecentsWindowManager> stateManager =
+ getCreatedContainer().getStateManager();
+ if (stateManager.getState() == HOME) {
+ exitRunnable.run();
+ notifyRecentsOfOrientation(deviceState);
+ return;
+ }
+
+ stateManager.addStateListener(
+ new StateManager.StateListener<RecentsState>() {
+ @Override
+ public void onStateTransitionComplete(RecentsState toState) {
+ // Are we going from Recents to Workspace?
+ if (toState == HOME) {
+ exitRunnable.run();
+ notifyRecentsOfOrientation(deviceState);
+ stateManager.removeStateListener(this);
+ }
+ }
+ });
+ }
+
+ @Override
+ public boolean isInLiveTileMode() {
+ RecentsWindowManager windowManager = getCreatedContainer();
+ return windowManager != null && windowManager.getStateManager().getState() == DEFAULT &&
+ windowManager.isStarted();
+ }
+
+ @Override
+ public void onLaunchTaskFailed() {
+ // TODO: probably go back to overview instead.
+ RecentsWindowManager manager = getCreatedContainer();
+ if (manager == null) {
+ return;
+ }
+ manager.<RecentsView>getOverviewPanel().startHome();
+ }
+
+ @Override
+ public RecentsState stateFromGestureEndTarget(GestureEndTarget endTarget) {
+ switch (endTarget) {
+ case RECENTS:
+ return DEFAULT;
+ case NEW_TASK:
+ case LAST_TASK:
+ return BACKGROUND_APP;
+ case HOME:
+ case ALL_APPS:
+ default:
+ return HOME;
+ }
+ }
+
+ private void notifyRecentsOfOrientation(RotationTouchHelper rotationTouchHelper) {
+ // reset layout on swipe to home
+ RecentsView recentsView = getCreatedContainer().getOverviewPanel();
+ recentsView.setLayoutRotation(rotationTouchHelper.getCurrentActiveRotation(),
+ rotationTouchHelper.getDisplayRotation());
+ }
+
+ @Override
+ public @Nullable Animator getParallelAnimationToLauncher(GestureEndTarget endTarget,
+ long duration, RecentsAnimationCallbacks callbacks) {
+ FallbackTaskbarUIController uiController = getTaskbarController();
+ Animator superAnimator = super.getParallelAnimationToLauncher(
+ endTarget, duration, callbacks);
+ if (uiController == null) {
+ return superAnimator;
+ }
+ RecentsState toState = stateFromGestureEndTarget(endTarget);
+ Animator taskbarAnimator = uiController.createAnimToRecentsState(toState, duration);
+ if (taskbarAnimator == null) {
+ return superAnimator;
+ }
+ if (superAnimator == null) {
+ return taskbarAnimator;
+ }
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.playTogether(superAnimator, taskbarAnimator);
+ return animatorSet;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 9cc463a..22967cb 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -38,6 +38,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.statemanager.StatefulContainer;
import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
import com.android.quickstep.util.ActiveGestureErrorDetector;
import com.android.quickstep.util.ActiveGestureLog;
@@ -190,7 +191,7 @@
public GestureState(OverviewComponentObserver componentObserver, int gestureId) {
mHomeIntent = componentObserver.getHomeIntent();
mOverviewIntent = componentObserver.getOverviewIntent();
- mContainerInterface = componentObserver.getActivityInterface();
+ mContainerInterface = componentObserver.getContainerInterface();
mStateCallback = new MultiStateCallback(
STATE_NAMES.toArray(new String[0]), GestureState::getTrackedEventForState);
mGestureId = gestureId;
@@ -269,8 +270,8 @@
/**
* @return the interface to the activity handing the UI updates for this gesture.
*/
- public <S extends BaseState<S>, T extends RecentsViewContainer>
- BaseContainerInterface<S, T> getContainerInterface() {
+ public <S extends BaseState<S>, T extends RecentsViewContainer & StatefulContainer<S>>
+ BaseContainerInterface getContainerInterface() {
return mContainerInterface;
}
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index d2dcd7b..dacafd4 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -46,6 +46,7 @@
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.views.FloatingView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
+import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.ScalingWorkspaceRevealAnim;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
@@ -68,7 +69,7 @@
TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
boolean continuingLastGesture, InputConsumerController inputConsumer) {
super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
- continuingLastGesture, inputConsumer);
+ continuingLastGesture, inputConsumer, null);
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
index f92c557..66224ae 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt
@@ -46,7 +46,6 @@
import com.android.quickstep.OverviewCommandHelper.CommandType.TOGGLE
import com.android.quickstep.util.ActiveGestureLog
import com.android.quickstep.views.RecentsView
-import com.android.quickstep.views.RecentsViewContainer
import com.android.quickstep.views.TaskView
import com.android.systemui.shared.recents.model.ThumbnailData
import com.android.systemui.shared.system.InteractionJankMonitorWrapper
@@ -80,19 +79,11 @@
*/
private var keyboardTaskFocusIndex = -1
- /**
- * Whether we should incoming toggle commands while a previous toggle command is still ongoing.
- * This serves as a rate-limiter to prevent overlapping animations that can clobber each other
- * and prevent clean-up callbacks from running. This thus prevents a recurring set of bugs with
- * janky recents animations and unresponsive home and overview buttons.
- */
- private var waitForToggleCommandComplete = false
-
- private val activityInterface: BaseActivityInterface<*, *>
- get() = overviewComponentObserver.activityInterface
+ private val containerInterface: BaseContainerInterface<*, *>
+ get() = overviewComponentObserver.containerInterface
private val visibleRecentsView: RecentsView<*, *>?
- get() = activityInterface.getVisibleRecentsView<RecentsView<*, *>>()
+ get() = containerInterface.getVisibleRecentsView<RecentsView<*, *>>()
/**
* Adds a command to be executed next, after all pending tasks are completed. Max commands that
@@ -174,12 +165,6 @@
*/
@VisibleForTesting
fun executeCommand(command: CommandInfo, onCallbackResult: () -> Unit): Boolean {
- // This shouldn't happen if we execute 1 command per time.
- if (waitForToggleCommandComplete && command.type == TOGGLE) {
- Log.d(TAG, "executeCommand: $command - waiting for toggle command complete")
- return true
- }
-
val recentsView = visibleRecentsView
Log.d(TAG, "executeCommand: $command - visibleRecentsView: $recentsView")
return if (recentsView != null) {
@@ -251,7 +236,6 @@
): Boolean {
var callbackList: RunnableList? = null
if (taskView != null) {
- waitForToggleCommandComplete = true
taskView.isEndQuickSwitchCuj = true
callbackList = taskView.launchWithAnimation()
}
@@ -260,13 +244,11 @@
callbackList.add {
Log.d(TAG, "launching task callback: $command")
onCallbackResult()
- waitForToggleCommandComplete = false
}
Log.d(TAG, "launching task - waiting for callback: $command")
return false
} else {
recents.startHome()
- waitForToggleCommandComplete = false
return true
}
}
@@ -275,10 +257,10 @@
command: CommandInfo,
onCallbackResult: () -> Unit,
): Boolean {
- val recentsViewContainer = activityInterface.getCreatedContainer() as? RecentsViewContainer
+ val recentsViewContainer = containerInterface.getCreatedContainer()
val recentsView: RecentsView<*, *>? = recentsViewContainer?.getOverviewPanel()
val deviceProfile = recentsViewContainer?.getDeviceProfile()
- val uiController = activityInterface.getTaskbarController()
+ val uiController = containerInterface.getTaskbarController()
val allowQuickSwitch =
uiController != null &&
deviceProfile != null &&
@@ -333,13 +315,13 @@
onCallbackResult()
}
}
- if (activityInterface.switchToRecentsIfVisible(animatorListener)) {
+ if (containerInterface.switchToRecentsIfVisible(animatorListener)) {
Log.d(TAG, "switching to Overview state - waiting: $command")
// If successfully switched, wait until animation finishes
return false
}
- val activity = activityInterface.getCreatedContainer()
+ val activity = containerInterface.getCreatedContainer()
if (activity != null) {
InteractionJankMonitorWrapper.begin(activity.rootView, Cuj.CUJ_LAUNCHER_QUICK_SWITCH)
}
@@ -369,7 +351,7 @@
Log.d(TAG, "recents animation started: $command")
updateRecentsViewFocus(command)
logShowOverviewFrom(command.type)
- activityInterface.runOnInitBackgroundStateUI {
+ containerInterface.runOnInitBackgroundStateUI {
Log.d(TAG, "recents animation started - onInitBackgroundStateUI: $command")
interactionHandler.onGestureEnded(0f, PointF())
}
@@ -383,7 +365,7 @@
interactionHandler.onGestureCancelled()
command.removeListener(this)
- activityInterface.getCreatedContainer() ?: return
+ containerInterface.getCreatedContainer() ?: return
recentsView?.onRecentsAnimationComplete()
}
}
@@ -490,7 +472,7 @@
}
private fun logShowOverviewFrom(commandType: CommandType) {
- val container = activityInterface.getCreatedContainer() as? RecentsViewContainer ?: return
+ val container = containerInterface.getCreatedContainer() ?: return
val event =
when (commandType) {
SHOW -> LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT
@@ -517,7 +499,6 @@
pw.println(" pendingCommandType=${commandQueue.first().type}")
}
pw.println(" keyboardTaskFocusIndex=$keyboardTaskFocusIndex")
- pw.println(" waitForToggleCommandComplete=$waitForToggleCommandComplete")
}
@VisibleForTesting
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index ca19480..a69b831 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -39,6 +39,7 @@
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
+import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.quickstep.util.ActiveGestureLog;
@@ -73,7 +74,7 @@
private Consumer<Boolean> mOverviewChangeListener = b -> { };
private String mUpdateRegisteredPackage;
- private BaseActivityInterface mActivityInterface;
+ private BaseContainerInterface mContainerInterface;
private Intent mOverviewIntent;
private boolean mIsHomeAndOverviewSame;
private boolean mIsDefaultHome;
@@ -150,8 +151,8 @@
// Set assistant visibility to 0 from launcher's perspective, ensures any elements that
// launcher made invisible become visible again before the new activity control helper
// becomes active.
- if (mActivityInterface != null) {
- mActivityInterface.onAssistantVisibilityChanged(0.f);
+ if (mContainerInterface != null) {
+ mContainerInterface.onAssistantVisibilityChanged(0.f);
}
if (SEPARATE_RECENTS_ACTIVITY.get()) {
@@ -168,7 +169,7 @@
if (!mIsHomeDisabled && (defaultHome == null || mIsDefaultHome)) {
// User default home is same as out home app. Use Overview integrated in Launcher.
- mActivityInterface = LauncherActivityInterface.INSTANCE;
+ mContainerInterface = LauncherActivityInterface.INSTANCE;
mIsHomeAndOverviewSame = true;
mOverviewIntent = mMyHomeIntent;
mCurrentHomeIntent.setComponent(mMyHomeIntent.getComponent());
@@ -178,7 +179,11 @@
} else {
// The default home app is a different launcher. Use the fallback Overview instead.
- mActivityInterface = FallbackActivityInterface.INSTANCE;
+ if (Flags.enableFallbackOverviewInWindow()) {
+ mContainerInterface = FallbackWindowInterface.getInstance();
+ } else {
+ mContainerInterface = FallbackActivityInterface.INSTANCE;
+ }
mIsHomeAndOverviewSame = false;
mOverviewIntent = mFallbackIntent;
mCurrentHomeIntent.setComponent(defaultHome);
@@ -266,21 +271,12 @@
}
/**
- * Get the current activity control helper for managing interactions to the overview activity.
+ * Get the current control helper for managing interactions to the overview container.
*
- * @return the current activity control helper
+ * @return the current control helper
*/
- public BaseActivityInterface getActivityInterface() {
- return mActivityInterface;
- }
-
- /**
- * Get the current container control helper for managing interactions to the overview activity.
- *
- * @return the current container control helper
- */
- public BaseContainerInterface<?, ?> getContainerInterface() {
- return mActivityInterface;
+ public BaseContainerInterface<?,?> getContainerInterface() {
+ return mContainerInterface;
}
public void dump(PrintWriter pw) {
diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
index f4e68dc..334bead 100644
--- a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
+++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
@@ -25,6 +25,7 @@
import com.android.launcher3.BuildConfig;
import com.android.launcher3.MainProcessInitializer;
+import com.android.quickstep.util.QuickstepProtoLogGroup;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
@SuppressWarnings("unused")
@@ -69,5 +70,7 @@
call.descriptor + " called on main thread under " + call.activeTrace
+ " stackTrace: " + call.stackTrace));
}
+
+ QuickstepProtoLogGroup.initProtoLog();
}
}
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index 49b6f57..c3b9736 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -7,6 +7,7 @@
import android.content.Context;
import android.content.res.Resources;
import android.os.Bundle;
+import android.view.WindowInsets;
import androidx.annotation.Nullable;
@@ -203,11 +204,12 @@
}
@Override
- protected Activity getCurrentActivity() {
+ protected WindowInsets getWindowInsets() {
RecentsAnimationDeviceState rads = new RecentsAnimationDeviceState(mContext);
OverviewComponentObserver observer = new OverviewComponentObserver(mContext, rads);
try {
- return observer.getActivityInterface().getCreatedContainer();
+ return observer.getContainerInterface()
+ .getCreatedContainer().getRootView().getRootWindowInsets();
} finally {
observer.onDestroy();
rads.destroy();
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 9c60693..9ac4141 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -122,9 +122,6 @@
// Strong refs to runners which are cleared when the activity is destroyed
private RemoteAnimationFactory mActivityLaunchAnimationRunner;
- // For handling degenerate cases where starting an activity doesn't actually trigger the remote
- // animation callback
- private final Handler mHandler = new Handler();
private final Runnable mAnimationStartTimeoutRunnable = this::onAnimationStartTimeout;
private SplitSelectStateController mSplitSelectStateController;
@Nullable
@@ -137,7 +134,7 @@
SystemUiProxy systemUiProxy = SystemUiProxy.INSTANCE.get(this);
// SplitSelectStateController needs to be created before setContentView()
mSplitSelectStateController =
- new SplitSelectStateController(this, mHandler, getStateManager(),
+ new SplitSelectStateController(this, getStateManager(),
null /* depthController */, getStatsLogManager(),
systemUiProxy, RecentsModel.INSTANCE.get(this),
null /*activityBackCallback*/);
@@ -198,7 +195,7 @@
}
@Override
- protected void onHandleConfigurationChanged() {
+ public void onHandleConfigurationChanged() {
initDeviceProfile();
AbstractFloatingView.closeOpenViews(this, true,
@@ -352,7 +349,6 @@
@Override
protected void onStop() {
super.onStop();
-
// Workaround for b/78520668, explicitly trim memory once UI is hidden
onTrimMemory(TRIM_MEMORY_UI_HIDDEN);
mFallbackRecentsView.updateLocusId();
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index b4bd3e3..6482f34 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -51,9 +51,11 @@
import android.window.RemoteTransition;
import android.window.TaskSnapshot;
import android.window.TransitionFilter;
+import android.window.flags.DesktopModeFlags;
import androidx.annotation.MainThread;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import com.android.internal.logging.InstanceId;
@@ -85,14 +87,13 @@
import com.android.wm.shell.desktopmode.IDesktopTaskListener;
import com.android.wm.shell.draganddrop.IDragAndDrop;
import com.android.wm.shell.onehanded.IOneHanded;
-import com.android.wm.shell.recents.IRecentsAnimationController;
-import com.android.wm.shell.recents.IRecentsAnimationRunner;
import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.recents.IRecentsAnimationController;
+import com.android.wm.shell.recents.IRecentsAnimationRunner;
import com.android.wm.shell.shared.GroupedRecentTaskInfo;
import com.android.wm.shell.shared.IShellTransitions;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
-import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.shared.split.SplitBounds;
@@ -187,7 +188,8 @@
@Nullable
private final ProxyUnfoldTransitionProvider mUnfoldTransitionProvider;
- private SystemUiProxy(Context context) {
+ @VisibleForTesting
+ protected SystemUiProxy(Context context) {
mContext = context;
mAsyncHandler = new Handler(UI_HELPER_EXECUTOR.getLooper(), this::handleMessageAsync);
final Intent baseIntent = new Intent().setPackage(mContext.getPackageName());
@@ -1395,7 +1397,7 @@
private boolean shouldEnableRunningTasksForDesktopMode() {
return DesktopModeStatus.canEnterDesktopMode(mContext)
- && DesktopModeFlags.TASKBAR_RUNNING_APPS.isEnabled(mContext);
+ && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS.isTrue();
}
private boolean handleMessageAsync(Message msg) {
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 289a2c1..4beb99a 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -43,10 +43,12 @@
import androidx.annotation.UiThread;
import com.android.internal.util.ArrayUtils;
+import com.android.launcher3.Flags;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.SystemUiFlagUtils;
import com.android.quickstep.views.RecentsView;
@@ -64,6 +66,7 @@
SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
private final Context mCtx;
+ private RecentsWindowManager mRecentsWindowsManager;
private RecentsAnimationController mController;
private RecentsAnimationCallbacks mCallbacks;
private RecentsAnimationTargets mTargets;
@@ -98,10 +101,10 @@
}
};
- TaskAnimationManager(Context ctx) {
+ TaskAnimationManager(Context ctx, RecentsWindowManager manager) {
mCtx = ctx;
+ mRecentsWindowsManager = manager;
}
-
SystemUiProxy getSystemUiProxy() {
return SystemUiProxy.INSTANCE.get(mCtx);
}
@@ -299,34 +302,43 @@
mCallbacks.addListener(listener);
final ActivityOptions options = ActivityOptions.makeBasic();
- options.setPendingIntentBackgroundActivityStartMode(
- ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
- options.setTransientLaunch();
- options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
- // Notify taskbar that we should skip reacting to launcher visibility change to
- // avoid a jumping taskbar.
- TaskbarUIController taskbarUIController = containerInterface.getTaskbarController();
- if (enableScalingRevealHomeAnimation() && taskbarUIController != null) {
- taskbarUIController.setSkipLauncherVisibilityChange(true);
+ // TODO:(b/365777482) if flag is enabled, but on launcher it will crash.
+ if(containerInterface.getCreatedContainer() instanceof RecentsWindowManager
+ && Flags.enableFallbackOverviewInWindow()){
+ mRecentsAnimationStartPending =
+ getSystemUiProxy().startRecentsActivity(intent, options, mCallbacks);
+ mRecentsWindowsManager.startRecentsWindow();
+ } else {
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS);
+ options.setTransientLaunch();
+ options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
- mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
- @Override
- public void onRecentsAnimationCanceled(
- @NonNull HashMap<Integer, ThumbnailData> thumbnailDatas) {
- taskbarUIController.setSkipLauncherVisibilityChange(false);
- }
+ // Notify taskbar that we should skip reacting to launcher visibility change to
+ // avoid a jumping taskbar.
+ TaskbarUIController taskbarUIController = containerInterface.getTaskbarController();
+ if (enableScalingRevealHomeAnimation() && taskbarUIController != null) {
+ taskbarUIController.setSkipLauncherVisibilityChange(true);
- @Override
- public void onRecentsAnimationFinished(
- @NonNull RecentsAnimationController controller) {
- taskbarUIController.setSkipLauncherVisibilityChange(false);
- }
- });
+ mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() {
+ @Override
+ public void onRecentsAnimationCanceled(
+ @NonNull HashMap<Integer, ThumbnailData> thumbnailDatas) {
+ taskbarUIController.setSkipLauncherVisibilityChange(false);
+ }
+
+ @Override
+ public void onRecentsAnimationFinished(
+ @NonNull RecentsAnimationController controller) {
+ taskbarUIController.setSkipLauncherVisibilityChange(false);
+ }
+ });
+ }
+
+ mRecentsAnimationStartPending = getSystemUiProxy()
+ .startRecentsActivity(intent, options, mCallbacks);
}
-
- mRecentsAnimationStartPending = getSystemUiProxy()
- .startRecentsActivity(intent, options, mCallbacks);
if (enableHandleDelayedGestureCallbacks()) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
"TaskAnimationManager.startRecentsAnimation: ")
@@ -487,6 +499,10 @@
mTargets = null;
mLastGestureState = null;
mLastAppearedTaskTargets = null;
+
+ if(Flags.enableFallbackOverviewInWindow()) {
+ mRecentsWindowsManager.cleanup();
+ }
}
@Nullable
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index f4ff4b2..8e45767 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -173,9 +173,8 @@
protected T getActionsView() {
if (mActionsView == null) {
- mActionsView = BaseActivity.fromContext(
- mTaskContainer.getTaskView().getContext()).findViewById(
- R.id.overview_actions_view);
+ mActionsView = (T) RecentsViewContainer.containerFromContext(
+ mTaskContainer.getTaskView().getContext()).getActionsView();
}
return mActionsView;
}
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index 63e536a..49f7daf 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -31,8 +31,8 @@
import androidx.annotation.Nullable;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.TraceHelper;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -70,8 +70,8 @@
return "";
}
UserHandle user = UserHandle.of(userId);
- ApplicationInfo applicationInfo = PackageManagerHelper.INSTANCE.get(context)
- .getApplicationInfo(packageName, user, 0);
+ ApplicationInfo applicationInfo =
+ new ApplicationInfoWrapper(context, packageName, user).getInfo();
if (applicationInfo == null) {
Log.e(TAG, "Failed to get title for userId=" + userId + ", packageName=" + packageName);
return "";
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index d8063ba..07ee479 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -59,7 +59,6 @@
import com.android.app.animation.Interpolators;
import com.android.internal.jank.Cuj;
-import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimationSuccessListener;
@@ -68,6 +67,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
@@ -80,6 +80,7 @@
import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.GroupedTaskView;
import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskView;
import com.android.systemui.animation.RemoteAnimationTargetCompat;
import com.android.systemui.shared.recents.model.Task;
@@ -155,8 +156,9 @@
return taskView;
}
- public static void createRecentsWindowAnimator(
- @NonNull RecentsView recentsView,
+ public static <T extends Context & RecentsViewContainer & StatefulContainer<?>>
+ void createRecentsWindowAnimator(
+ @NonNull RecentsView<T, ?> recentsView,
@NonNull TaskView v,
boolean skipViewChanges,
@NonNull RemoteAnimationTarget[] appTargets,
@@ -204,8 +206,9 @@
int taskIndex = recentsView.indexOfChild(v);
Context context = v.getContext();
- BaseActivity baseActivity = BaseActivity.fromContext(context);
- DeviceProfile dp = baseActivity.getDeviceProfile();
+
+ T container = RecentsViewContainer.containerFromContext(context);
+ DeviceProfile dp = container.getDeviceProfile();
boolean showAsGrid = dp.isTablet;
boolean parallaxCenterAndAdjacentTask =
!showAsGrid && taskIndex != recentsView.getCurrentPage();
@@ -417,7 +420,8 @@
if (depthController != null) {
out.setFloat(depthController.stateDepth, MULTI_PROPERTY_VALUE,
- BACKGROUND_APP.getDepth(baseActivity), TOUCH_RESPONSE);
+ BACKGROUND_APP.getDepth(container),
+ TOUCH_RESPONSE);
}
}
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index 3cf0542..23a1ec7 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -206,12 +206,17 @@
Collections.addAll(mOrderedTaskList, tasks);
}
- // Strip the pinned task
ArrayList<RunningTaskInfo> tasks = new ArrayList<>(mOrderedTaskList);
- tasks.removeIf(t -> t.taskId == mPinnedTaskId);
+ // Strip the pinned task and recents task
+ tasks.removeIf(t -> t.taskId == mPinnedTaskId || isRecentsTask(t));
return new CachedTaskInfo(tasks);
}
+ private static boolean isRecentsTask(RunningTaskInfo task) {
+ return task != null && task.configuration.windowConfiguration
+ .getActivityType() == ACTIVITY_TYPE_RECENTS;
+ }
+
/**
* Class to provide information about a task which can be safely cached and do not change
* during the lifecycle of the task.
@@ -267,8 +272,7 @@
}
public boolean isRecentsTask() {
- return mTopTask != null && mTopTask.configuration.windowConfiguration
- .getActivityType() == ACTIVITY_TYPE_RECENTS;
+ return TopTaskTracker.isRecentsTask(mTopTask);
}
/**
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 178636e..c5791fa 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -76,6 +76,7 @@
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.MotionEvent;
+import android.view.View;
import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
@@ -83,7 +84,6 @@
import androidx.annotation.UiThread;
import androidx.annotation.VisibleForTesting;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ConstantItem;
import com.android.launcher3.EncryptionType;
import com.android.launcher3.Flags;
@@ -107,6 +107,8 @@
import com.android.launcher3.util.ScreenOnTracker;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.OverviewCommandHelper.CommandType;
+import com.android.quickstep.fallback.window.RecentsWindowManager;
+import com.android.quickstep.fallback.window.RecentsWindowSwipeHandler;
import com.android.quickstep.inputconsumers.AccessibilityInputConsumer;
import com.android.quickstep.inputconsumers.AssistantInputConsumer;
import com.android.quickstep.inputconsumers.BubbleBarInputConsumer;
@@ -324,10 +326,10 @@
@Override
public void enterStageSplitFromRunningApp(boolean leftOrTop) {
executeForTouchInteractionService(tis -> {
- StatefulActivity activity =
- tis.mOverviewComponentObserver.getActivityInterface().getCreatedContainer();
- if (activity != null) {
- activity.enterStageSplitFromRunningApp(leftOrTop);
+ RecentsViewContainer container = tis.mOverviewComponentObserver
+ .getContainerInterface().getCreatedContainer();
+ if (container != null) {
+ container.enterStageSplitFromRunningApp(leftOrTop);
}
});
}
@@ -606,6 +608,8 @@
this::createLauncherSwipeHandler;
private final AbsSwipeUpHandler.Factory mFallbackSwipeHandlerFactory =
this::createFallbackSwipeHandler;
+ private final AbsSwipeUpHandler.Factory mRecentsWindowSwipeHandlerFactory =
+ this::createRecentsWindowSwipeHandler;
private final ScreenOnTracker.ScreenOnListener mScreenOnListener = this::onScreenOnChanged;
@@ -638,6 +642,7 @@
private InputEventReceiver mInputEventReceiver;
private TaskbarManager mTaskbarManager;
+ private RecentsWindowManager mRecentsWindowManager;
private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null;
private AllAppsActionManager mAllAppsActionManager;
private InputManager mInputManager;
@@ -668,6 +673,9 @@
mDesktopVisibilityController = new DesktopVisibilityController(this);
mTaskbarManager = new TaskbarManager(
this, mAllAppsActionManager, mNavCallbacks, mDesktopVisibilityController);
+ if(Flags.enableFallbackOverviewInWindow()) {
+ mRecentsWindowManager = new RecentsWindowManager(this);
+ }
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
// Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
@@ -718,7 +726,7 @@
@UiThread
public void onUserUnlocked() {
Log.d(TAG, "onUserUnlocked: userId=" + getUserId());
- mTaskAnimationManager = new TaskAnimationManager(this);
+ mTaskAnimationManager = new TaskAnimationManager(this, mRecentsWindowManager);
mOverviewComponentObserver = new OverviewComponentObserver(this, mDeviceState);
mOverviewCommandHelper = new OverviewCommandHelper(this,
mOverviewComponentObserver, mTaskAnimationManager);
@@ -761,11 +769,12 @@
private void onOverviewTargetChange(boolean isHomeAndOverviewSame) {
mAllAppsActionManager.setHomeAndOverviewSame(isHomeAndOverviewSame);
-
- StatefulActivity<?> newOverviewActivity =
- mOverviewComponentObserver.getActivityInterface().getCreatedContainer();
- if (newOverviewActivity != null) {
- mTaskbarManager.setActivity(newOverviewActivity);
+ RecentsViewContainer newOverviewContainer =
+ mOverviewComponentObserver.getContainerInterface().getCreatedContainer();
+ if (newOverviewContainer != null
+ && newOverviewContainer instanceof StatefulActivity activity) {
+ //TODO(b/368030750) refactor taskbarManager to accept RecentsViewContainer
+ mTaskbarManager.setActivity(activity);
}
mTISBinder.onOverviewTargetChange();
}
@@ -795,7 +804,7 @@
@UiThread
private void onAssistantVisibilityChanged() {
if (LockedUserState.get(this).isUserUnlocked()) {
- mOverviewComponentObserver.getActivityInterface().onAssistantVisibilityChanged(
+ mOverviewComponentObserver.getContainerInterface().onAssistantVisibilityChanged(
mDeviceState.getAssistantVisibility());
}
}
@@ -818,6 +827,10 @@
mTrackpadsConnected.clear();
mTaskbarManager.destroy();
+
+ if (mRecentsWindowManager != null) {
+ mRecentsWindowManager.destroy();
+ }
mDesktopVisibilityController.onDestroy();
sConnected = false;
@@ -1430,8 +1443,9 @@
}
public AbsSwipeUpHandler.Factory getSwipeUpHandlerFactory() {
- return !mOverviewComponentObserver.isHomeAndOverviewSame()
- ? mFallbackSwipeHandlerFactory : mLauncherSwipeHandlerFactory;
+ return mOverviewComponentObserver.isHomeAndOverviewSame()
+ ? mLauncherSwipeHandlerFactory : (Flags.enableFallbackOverviewInWindow()
+ ? mRecentsWindowSwipeHandlerFactory : mFallbackSwipeHandlerFactory);
}
private InputConsumer createOtherActivityInputConsumer(GestureState gestureState,
@@ -1480,7 +1494,8 @@
.append("activity == null, trying to use default input consumer"));
}
- boolean hasWindowFocus = container.getRootView().hasWindowFocus();
+ View rootview = container.getRootView();
+ boolean hasWindowFocus = rootview != null && rootview.hasWindowFocus();
boolean isPreviousGestureAnimatingToLauncher =
previousGestureState.isRunningAnimationToLauncher()
|| mDeviceState.isPredictiveBackToHomeInProgress();
@@ -1575,11 +1590,11 @@
return;
}
- final BaseActivityInterface activityInterface =
- mOverviewComponentObserver.getActivityInterface();
+ final BaseContainerInterface containerInterface =
+ mOverviewComponentObserver.getContainerInterface();
final Intent overviewIntent = new Intent(
mOverviewComponentObserver.getOverviewIntentIgnoreSysUiState());
- if (activityInterface.getCreatedContainer() != null && fromInit) {
+ if (containerInterface.getCreatedContainer() != null && fromInit) {
// The activity has been created before the initialization of overview service. It is
// usually happens when booting or launcher is the top activity, so we should already
// have the latest state.
@@ -1599,18 +1614,18 @@
if (!LockedUserState.get(this).isUserUnlocked()) {
return;
}
- final BaseActivityInterface activityInterface =
- mOverviewComponentObserver.getActivityInterface();
- final BaseDraggingActivity activity = activityInterface.getCreatedContainer();
- if (activity == null || activity.isStarted()) {
+ final BaseContainerInterface containerInterface =
+ mOverviewComponentObserver.getContainerInterface();
+ final RecentsViewContainer container = containerInterface.getCreatedContainer();
+ if (container == null || container.isStarted()) {
// We only care about the existing background activity.
return;
}
- Configuration oldConfig = activity.getResources().getConfiguration();
+ Configuration oldConfig = container.asContext().getResources().getConfiguration();
boolean isFoldUnfold = isTablet(oldConfig) != isTablet(newConfig);
if (!isFoldUnfold && mOverviewComponentObserver.canHandleConfigChanges(
- activity.getComponentName(),
- activity.getResources().getConfiguration().diff(newConfig))) {
+ container.getComponentName(),
+ container.asContext().getResources().getConfiguration().diff(newConfig))) {
// Since navBar gestural height are different between portrait and landscape,
// can handle orientation changes and refresh navigation gestural region through
// onOneHandedModeChanged()
@@ -1649,11 +1664,11 @@
pw.println("\tmInputEventReceiver=" + mInputEventReceiver);
DisplayController.INSTANCE.get(this).dump(pw);
pw.println("TouchState:");
- BaseDraggingActivity createdOverviewActivity = mOverviewComponentObserver == null ? null
- : mOverviewComponentObserver.getActivityInterface().getCreatedContainer();
+ RecentsViewContainer createdOverviewContainer = mOverviewComponentObserver == null ? null
+ : mOverviewComponentObserver.getContainerInterface().getCreatedContainer();
boolean resumed = mOverviewComponentObserver != null
- && mOverviewComponentObserver.getActivityInterface().isResumed();
- pw.println("\tcreatedOverviewActivity=" + createdOverviewActivity);
+ && mOverviewComponentObserver.getContainerInterface().isResumed();
+ pw.println("\tcreatedOverviewActivity=" + createdOverviewContainer);
pw.println("\tresumed=" + resumed);
pw.println("\tmConsumer=" + mConsumer.getName());
ActiveGestureLog.INSTANCE.dump("", pw);
@@ -1661,8 +1676,8 @@
if (mTaskAnimationManager != null) {
mTaskAnimationManager.dump("", pw);
}
- if (createdOverviewActivity != null) {
- createdOverviewActivity.getDeviceProfile().dump(this, "", pw);
+ if (createdOverviewContainer != null) {
+ createdOverviewContainer.getDeviceProfile().dump(this, "", pw);
}
mTaskbarManager.dumpLogs("", pw);
mDesktopVisibilityController.dumpLogs("", pw);
@@ -1685,4 +1700,11 @@
gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(),
mInputConsumer);
}
+
+ private AbsSwipeUpHandler createRecentsWindowSwipeHandler(
+ GestureState gestureState, long touchTimeMs) {
+ return new RecentsWindowSwipeHandler(this, mDeviceState, mTaskAnimationManager,
+ gestureState, touchTimeMs, mTaskAnimationManager.isRecentsAnimationRunning(),
+ mInputConsumer, mRecentsWindowManager);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
index db29636..08345b8 100644
--- a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
+++ b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
@@ -15,10 +15,8 @@
*/
package com.android.quickstep.dagger;
-import com.android.quickstep.logging.LoggingModule;
-
import dagger.Module;
-@Module(includes = {LoggingModule.class})
+@Module
public class QuickStepModule {
}
diff --git a/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
new file mode 100644
index 0000000..f2d5715
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2024 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.dagger;
+
+import com.android.launcher3.dagger.LauncherAppComponent;
+import com.android.launcher3.dagger.LauncherBaseAppComponent;
+import com.android.quickstep.logging.SettingsChangeLogger;
+
+/**
+ * Launcher Quickstep base component for Dagger injection.
+ *
+ * This class is not actually annotated as a Dagger component, since it is not used directly as one.
+ * Doing so generates unnecessary code bloat.
+ *
+ * See {@link LauncherAppComponent} for the one actually used.
+ */
+public interface QuickstepBaseAppComponent extends LauncherBaseAppComponent {
+ SettingsChangeLogger getSettingsChangeLogger();
+}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 94764a5..83794fb 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -47,9 +47,9 @@
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.quickstep.RecentsActivity;
import com.android.quickstep.views.ClearAllButton;
import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
/**
* State controller for fallback recents activity
@@ -57,12 +57,12 @@
public class FallbackRecentsStateController implements StateHandler<RecentsState> {
private final StateAnimationConfig mNoConfig = new StateAnimationConfig();
- private final RecentsActivity mActivity;
+ private final RecentsViewContainer mRecentsViewContainer;
private final FallbackRecentsView mRecentsView;
- public FallbackRecentsStateController(RecentsActivity activity) {
- mActivity = activity;
- mRecentsView = activity.getOverviewPanel();
+ public FallbackRecentsStateController(RecentsViewContainer container) {
+ mRecentsViewContainer = container;
+ mRecentsView = container.getOverviewPanel();
}
@Override
@@ -81,7 +81,7 @@
// While animating into recents, update the visible task data as needed
setter.addOnFrameCallback(() -> mRecentsView.loadVisibleTaskData(FLAG_UPDATE_ALL));
setter.addEndListener(success -> {
- if (!success) {
+ if (!success && !toState.isRecentsViewVisible()) {
mRecentsView.reset();
}
});
@@ -96,10 +96,10 @@
setter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
clearAllButtonAlpha, LINEAR);
float overviewButtonAlpha = state.hasOverviewActions() ? 1 : 0;
- setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(),
+ setter.setFloat(mRecentsViewContainer.getActionsView().getVisibilityAlpha(),
AnimatedFloat.VALUE, overviewButtonAlpha, LINEAR);
- float[] scaleAndOffset = state.getOverviewScaleAndOffset(mActivity);
+ float[] scaleAndOffset = state.getOverviewScaleAndOffset(mRecentsViewContainer);
setter.setFloat(mRecentsView, RECENTS_SCALE_PROPERTY, scaleAndOffset[0],
config.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR));
setter.setFloat(mRecentsView, ADJACENT_PAGE_HORIZONTAL_OFFSET, scaleAndOffset[1],
@@ -110,16 +110,19 @@
setter.setFloat(mRecentsView, TASK_MODALNESS, state.getOverviewModalness(),
config.getInterpolator(ANIM_OVERVIEW_MODAL, LINEAR));
setter.setFloat(mRecentsView, FULLSCREEN_PROGRESS, state.isFullScreen() ? 1 : 0, LINEAR);
- boolean showAsGrid = state.displayOverviewTasksAsGrid(mActivity.getDeviceProfile());
+ boolean showAsGrid =
+ state.displayOverviewTasksAsGrid(mRecentsViewContainer.getDeviceProfile());
setter.setFloat(mRecentsView, RECENTS_GRID_PROGRESS, showAsGrid ? 1f : 0f,
getOverviewInterpolator(state));
setter.setFloat(mRecentsView, TASK_THUMBNAIL_SPLASH_ALPHA,
state.showTaskThumbnailSplash() ? 1f : 0f, getOverviewInterpolator(state));
- setter.setViewBackgroundColor(mActivity.getScrimView(), state.getScrimColor(mActivity),
+ setter.setViewBackgroundColor(mRecentsViewContainer.getScrimView(),
+ state.getScrimColor(mRecentsViewContainer.asContext()),
config.getInterpolator(ANIM_SCRIM_FADE, LINEAR));
if (isSplitSelectionState(state)) {
- int duration = state.getTransitionDuration(mActivity, true /* isToState */);
+ int duration =
+ state.getTransitionDuration(mRecentsViewContainer.asContext(), true);
// TODO (b/246851887): Pass in setter as a NO_ANIM PendingAnimation instead
PendingAnimation pa = new PendingAnimation(duration);
mRecentsView.createSplitSelectInitAnimation(pa, duration);
@@ -129,7 +132,7 @@
Pair<FloatProperty<RecentsView>, FloatProperty<RecentsView>> taskViewsFloat =
mRecentsView.getPagedOrientationHandler().getSplitSelectTaskOffset(
TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
- mActivity.getDeviceProfile());
+ mRecentsViewContainer.getDeviceProfile());
setter.setFloat(mRecentsView, taskViewsFloat.first, isSplitSelectionState(state)
? mRecentsView.getSplitSelectTranslation() : 0, LINEAR);
setter.setFloat(mRecentsView, taskViewsFloat.second, 0, LINEAR);
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index e67a9bc..7f88090 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -19,7 +19,6 @@
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
-import static com.android.quickstep.fallback.RecentsState.HOME;
import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
import static com.android.quickstep.fallback.RecentsState.OVERVIEW_SPLIT_SELECT;
@@ -31,6 +30,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Flags;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
@@ -38,17 +38,20 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateListener;
+import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
+import com.android.quickstep.BaseContainerInterface;
import com.android.quickstep.FallbackActivityInterface;
+import com.android.quickstep.FallbackWindowInterface;
import com.android.quickstep.GestureState;
-import com.android.quickstep.RecentsActivity;
import com.android.quickstep.RotationTouchHelper;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
@@ -56,7 +59,8 @@
import java.util.Arrays;
import java.util.List;
-public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsState>
+public class FallbackRecentsView<CONTAINER_TYPE extends Context & RecentsViewContainer
+ & StatefulContainer<RecentsState>> extends RecentsView<CONTAINER_TYPE, RecentsState>
implements StateListener<RecentsState> {
private static final int TASK_DISMISS_DURATION = 150;
@@ -69,10 +73,16 @@
}
public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr, FallbackActivityInterface.INSTANCE);
+ super(context, attrs, defStyleAttr, getContainerInterface());
mContainer.getStateManager().addStateListener(this);
}
+ private static BaseContainerInterface<RecentsState, ?> getContainerInterface() {
+ return Flags.enableFallbackOverviewInWindow()
+ ? FallbackWindowInterface.getInstance()
+ : FallbackActivityInterface.INSTANCE;
+ }
+
@Override
public void init(OverviewActionsView actionsView, SplitSelectStateController splitController,
@Nullable DesktopRecentsTransitionController desktopRecentsTransitionController) {
@@ -93,7 +103,7 @@
}
@Override
- public StateManager<RecentsState, RecentsActivity> getStateManager() {
+ public StateManager<RecentsState, ?> getStateManager() {
return mContainer.getStateManager();
}
@@ -260,7 +270,7 @@
@Override
public void onStateTransitionComplete(RecentsState finalState) {
- if (finalState == HOME) {
+ if (!finalState.isRecentsViewVisible()) {
// Clean-up logic that occurs when recents is no longer in use/visible.
reset();
}
@@ -283,7 +293,8 @@
}
}
- if (isOverlayEnabled) {
+ // disabling this so app icons aren't drawn on top of recent tasks.
+ if (isOverlayEnabled && !Flags.enableFallbackOverviewInWindow()) {
runActionOnRemoteHandles(remoteTargetHandle ->
remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true));
}
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsDragLayer.java b/quickstep/src/com/android/quickstep/fallback/RecentsDragLayer.java
index 29c3dc8..a2884b6 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsDragLayer.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsDragLayer.java
@@ -20,13 +20,12 @@
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.RecentsActivity;
+import com.android.quickstep.views.RecentsViewContainer;
/**
* Drag layer for fallback recents activity
*/
-public class RecentsDragLayer extends BaseDragLayer<RecentsActivity> {
-
+public class RecentsDragLayer<T extends Context & RecentsViewContainer> extends BaseDragLayer<T> {
public RecentsDragLayer(Context context, AttributeSet attrs) {
super(context, attrs, 1 /* alphaChannelCount */);
}
@@ -34,8 +33,8 @@
@Override
public void recreateControllers() {
mControllers = new TouchController[] {
- new RecentsTaskController(mActivity),
- new FallbackNavBarTouchController(mActivity),
+ new RecentsTaskController(mContainer),
+ new FallbackNavBarTouchController(mContainer),
};
}
}
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
index 2cb398c..07da379 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
@@ -15,18 +15,22 @@
*/
package com.android.quickstep.fallback;
+import android.content.Context;
+
+import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.uioverrides.touchcontrollers.TaskViewTouchController;
-import com.android.quickstep.RecentsActivity;
+import com.android.quickstep.views.RecentsViewContainer;
-public class RecentsTaskController extends TaskViewTouchController<RecentsActivity> {
-
- public RecentsTaskController(RecentsActivity activity) {
- super(activity);
+public class RecentsTaskController<T extends Context & RecentsViewContainer &
+ StatefulContainer<RecentsState>> extends TaskViewTouchController<T> {
+ public RecentsTaskController(T container) {
+ super(container);
}
@Override
protected boolean isRecentsInteractive() {
- return mContainer.hasWindowFocus() || mContainer.getStateManager().getState().hasLiveTile();
+ return mContainer.getRootView().hasWindowFocus()
+ || mContainer.getStateManager().getState().hasLiveTile();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowContext.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowContext.kt
new file mode 100644
index 0000000..52a7682
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowContext.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 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.fallback.window
+
+import android.content.Context
+import android.graphics.PixelFormat
+import android.view.ContextThemeWrapper
+import android.view.ViewGroup
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+import android.view.WindowManager.LayoutParams.PRIVATE_FLAG_CONSUME_IME_INSETS
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.util.Themes
+import com.android.launcher3.views.ActivityContext
+import com.android.launcher3.views.BaseDragLayer
+import com.android.quickstep.fallback.RecentsDragLayer
+
+/**
+ * Window context for the Overview overlays.
+ * <p>
+ * Overlays have their own window and need a window context.
+ */
+open class RecentsWindowContext(windowContext: Context) :
+ ContextThemeWrapper(windowContext, Themes.getActivityThemeRes(windowContext)), ActivityContext {
+
+ private var deviceProfile: DeviceProfile? = null
+ private var dragLayer: RecentsDragLayer<RecentsWindowManager> = RecentsDragLayer(this, null)
+ private val deviceProfileChangeListeners:
+ MutableList<DeviceProfile.OnDeviceProfileChangeListener> =
+ ArrayList()
+
+ private val windowTitle: String = "RecentsWindow"
+
+ protected var windowLayoutParams: WindowManager.LayoutParams? =
+ createDefaultWindowLayoutParams(
+ WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, windowTitle)
+
+ override fun getDragLayer(): BaseDragLayer<RecentsWindowManager> {
+ return dragLayer
+ }
+
+ override fun getDeviceProfile(): DeviceProfile {
+ if (deviceProfile == null) {
+ deviceProfile = InvariantDeviceProfile.INSTANCE[this].getDeviceProfile(this)
+ .copy(this)
+ }
+ return deviceProfile!!
+ }
+
+ override fun getOnDeviceProfileChangeListeners():
+ List<DeviceProfile.OnDeviceProfileChangeListener> {
+ return deviceProfileChangeListeners
+ }
+
+ /**
+ * Creates LayoutParams for adding a view directly to WindowManager as a new window.
+ *
+ * @param type The window type to pass to the created WindowManager.LayoutParams.
+ * @param title The window title to pass to the created WindowManager.LayoutParams.
+ */
+ fun createDefaultWindowLayoutParams(type: Int, title: String): WindowManager.LayoutParams {
+ var windowFlags =
+ (WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS or
+ WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS or
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED)
+
+ val windowLayoutParams =
+ WindowManager.LayoutParams(
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ ViewGroup.LayoutParams.MATCH_PARENT,
+ type,
+ windowFlags,
+ PixelFormat.TRANSLUCENT,
+ )
+
+ windowLayoutParams.title = title
+ windowLayoutParams.fitInsetsTypes = 0
+ windowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS
+ windowLayoutParams.isSystemApplicationOverlay = true
+ windowLayoutParams.privateFlags = PRIVATE_FLAG_CONSUME_IME_INSETS
+
+ return windowLayoutParams
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
new file mode 100644
index 0000000..8ce61f5
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowManager.kt
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2024 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.fallback.window
+
+import android.animation.AnimatorSet
+import android.app.ActivityOptions
+import android.content.ComponentName
+import android.content.Context
+import android.content.LocusId
+import android.os.Bundle
+import android.util.Log
+import android.view.KeyEvent
+import android.view.LayoutInflater
+import android.view.MotionEvent
+import android.view.RemoteAnimationAdapter
+import android.view.RemoteAnimationTarget
+import android.view.SurfaceControl
+import android.view.View
+import android.view.Window
+import android.view.WindowManager
+import android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
+import android.window.RemoteTransition
+import com.android.launcher3.BaseActivity
+import com.android.launcher3.LauncherAnimationRunner
+import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory
+import com.android.launcher3.R
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.launcher3.statemanager.StateManager
+import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory
+import com.android.launcher3.statemanager.StatefulContainer
+import com.android.launcher3.util.DisplayController
+import com.android.launcher3.util.RunnableList
+import com.android.launcher3.util.SystemUiController
+import com.android.launcher3.views.BaseDragLayer
+import com.android.launcher3.views.ScrimView
+import com.android.quickstep.FallbackWindowInterface
+import com.android.quickstep.OverviewComponentObserver
+import com.android.quickstep.RecentsModel
+import com.android.quickstep.RemoteAnimationTargets
+import com.android.quickstep.SystemUiProxy
+import com.android.quickstep.fallback.FallbackRecentsStateController
+import com.android.quickstep.fallback.FallbackRecentsView
+import com.android.quickstep.fallback.RecentsDragLayer
+import com.android.quickstep.fallback.RecentsState
+import com.android.quickstep.fallback.RecentsState.BACKGROUND_APP
+import com.android.quickstep.fallback.RecentsState.BG_LAUNCHER
+import com.android.quickstep.fallback.RecentsState.DEFAULT
+import com.android.quickstep.fallback.RecentsState.HOME
+import com.android.quickstep.fallback.RecentsState.MODAL_TASK
+import com.android.quickstep.fallback.RecentsState.OVERVIEW_SPLIT_SELECT
+import com.android.quickstep.util.RecentsAtomicAnimationFactory
+import com.android.quickstep.util.SplitSelectStateController
+import com.android.quickstep.util.TISBindHelper
+import com.android.quickstep.views.OverviewActionsView
+import com.android.quickstep.views.RecentsView
+import com.android.quickstep.views.RecentsViewContainer
+import java.util.function.Predicate
+
+/**
+ * Class that will manage RecentsView lifecycle within a window and interface correctly
+ * where needed. This allows us to run RecentsView in a window where needed.
+ * todo: b/365776320, b/365777482
+ */
+class RecentsWindowManager(context: Context) :
+ RecentsWindowContext(context), RecentsViewContainer, StatefulContainer<RecentsState> {
+
+ companion object {
+ private const val HOME_APPEAR_DURATION: Long = 250
+ private const val TAG = "RecentsWindowManager"
+ private const val DEBUG = false
+ }
+
+ protected var recentsView: FallbackRecentsView<RecentsWindowManager>? = null
+ private val windowContext: Context = createWindowContext(TYPE_APPLICATION_OVERLAY, null)
+ private val windowManager: WindowManager = windowContext.getSystemService(WindowManager::class.java)!!
+ private var layoutInflater: LayoutInflater = LayoutInflater.from(this).cloneInContext(this)
+ private var stateManager: StateManager<RecentsState, RecentsWindowManager> =
+ StateManager<RecentsState, RecentsWindowManager>(this, RecentsState.BG_LAUNCHER)
+ private var mSystemUiController: SystemUiController? = null
+
+ private var dragLayer: RecentsDragLayer<RecentsWindowManager>? = null
+ private var windowView: View? = null
+ private var actionsView: OverviewActionsView<*>? = null
+ private var scrimView: ScrimView? = null
+
+ private var isShown = false
+
+ private var tisBindHelper: TISBindHelper = TISBindHelper(this) {}
+
+ // Callback array that corresponds to events defined in @ActivityEvent
+ private val mEventCallbacks =
+ arrayOf(RunnableList(), RunnableList(), RunnableList(), RunnableList())
+ private var onInitListener: Predicate<Boolean>? = null
+
+ init {
+ FallbackWindowInterface.init(this)
+ }
+
+ override fun destroy() {
+ super.destroy()
+ FallbackWindowInterface.getInstance()?.destroy()
+ }
+
+ override fun startHome() {
+ val recentsView: RecentsView<*, *> = getOverviewPanel()
+ recentsView.switchToScreenshot {
+ recentsView.finishRecentsAnimation(true) { startHomeInternal() }
+ }
+ }
+
+ private fun startHomeInternal() {
+ val runner = LauncherAnimationRunner(mainThreadHandler, mAnimationToHomeFactory, true)
+ val options =
+ ActivityOptions.makeRemoteAnimation(
+ RemoteAnimationAdapter(runner, HOME_APPEAR_DURATION, 0),
+ RemoteTransition(
+ runner.toRemoteTransition(),
+ iApplicationThread,
+ "StartHomeFromRecents",
+ ),
+ )
+ OverviewComponentObserver.startHomeIntentSafely(this, options.toBundle(), TAG)
+ }
+
+ private val mAnimationToHomeFactory =
+ RemoteAnimationFactory {
+ _: Int,
+ appTargets: Array<RemoteAnimationTarget>?,
+ wallpaperTargets: Array<RemoteAnimationTarget>?,
+ nonAppTargets: Array<RemoteAnimationTarget>?,
+ result: LauncherAnimationRunner.AnimationResult? ->
+ val controller =
+ getStateManager().createAnimationToNewWorkspace(BG_LAUNCHER, HOME_APPEAR_DURATION)
+ controller.dispatchOnStart()
+ val targets =
+ RemoteAnimationTargets(
+ appTargets,
+ wallpaperTargets,
+ nonAppTargets,
+ RemoteAnimationTarget.MODE_OPENING,
+ )
+ for (app in targets.apps) {
+ SurfaceControl.Transaction().setAlpha(app.leash, 1f).apply()
+ }
+ val anim = AnimatorSet()
+ anim.play(controller.animationPlayer)
+ anim.setDuration(HOME_APPEAR_DURATION)
+ result!!.setAnimation(
+ anim,
+ this@RecentsWindowManager,
+ {
+ getStateManager().goToState(HOME, false)
+ cleanup()
+ },
+ true, /* skipFirstFrame */
+ )
+ }
+
+ fun cleanup() {
+ if (isShown) {
+ windowManager.removeViewImmediate(windowView)
+ isShown = false
+ }
+ }
+
+ fun startRecentsWindow() {
+ if (isShown) return
+ if (windowView == null) {
+ windowView = layoutInflater.inflate(R.layout.fallback_recents_activity, null)
+ }
+ windowManager.addView(windowView, windowLayoutParams)
+ isShown = true
+
+ windowView?.systemUiVisibility =
+ (View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
+ View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
+ View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION)
+
+ recentsView = windowView?.findViewById(R.id.overview_panel)
+ actionsView = windowView?.findViewById(R.id.overview_actions_view)
+ scrimView = windowView?.findViewById(R.id.scrim_view)
+ val systemUiProxy = SystemUiProxy.INSTANCE[this]
+ val splitSelectStateController =
+ SplitSelectStateController(
+ this,
+ getStateManager(),
+ null, /* depthController */
+ statsLogManager,
+ systemUiProxy,
+ RecentsModel.INSTANCE[this],
+ null, /*activityBackCallback*/
+ )
+ recentsView?.init(actionsView, splitSelectStateController, null)
+ dragLayer = windowView?.findViewById(R.id.drag_layer)
+
+ actionsView?.updateDimension(getDeviceProfile(), recentsView?.lastComputedTaskSize)
+ actionsView?.updateVerticalMargin(DisplayController.getNavigationMode(this))
+
+ mSystemUiController = SystemUiController(windowView)
+ onInitListener?.test(true)
+ }
+
+ override fun canStartHomeSafely(): Boolean {
+ val overviewCommandHelper = tisBindHelper.overviewCommandHelper
+ return overviewCommandHelper == null || overviewCommandHelper.canStartHomeSafely()
+ }
+
+ override fun getDesktopVisibilityController(): DesktopVisibilityController? {
+ return tisBindHelper.desktopVisibilityController
+ }
+
+ fun registerInitListener(onInitListener: Predicate<Boolean>) {
+ this.onInitListener = onInitListener
+ }
+
+ override fun collectStateHandlers(out: MutableList<StateManager.StateHandler<RecentsState?>>?) {
+ out!!.add(FallbackRecentsStateController(this))
+ }
+
+ override fun getStateManager(): StateManager<RecentsState, RecentsWindowManager> {
+ return this.stateManager
+ }
+
+ override fun shouldAnimateStateChange(): Boolean {
+ return true
+ }
+
+ override fun isInState(state: RecentsState?): Boolean {
+ return stateManager.state == state
+ }
+
+ override fun onStateSetStart(state: RecentsState?) {
+ super.onStateSetStart(state)
+ logState(state, "state started:")
+ }
+
+ override fun onStateSetEnd(state: RecentsState?) {
+ super.onStateSetEnd(state)
+ logState(state, "state ended:")
+ }
+
+ private fun logState(state: RecentsState?, prefix: String) {
+ if (!DEBUG) {
+ return
+ }
+ if (state != null) {
+ when (state) {
+ DEFAULT -> Log.d(TAG, prefix + "default")
+ MODAL_TASK -> {
+ Log.d(TAG, prefix + "MODAL_TASK")
+ }
+ BACKGROUND_APP -> {
+ Log.d(TAG, prefix + "BACKGROUND_APP")
+ }
+ HOME -> {
+ Log.d(TAG, prefix + "HOME")
+ }
+ BG_LAUNCHER -> {
+ Log.d(TAG, prefix + "BG_LAUNCHER")
+ }
+ OVERVIEW_SPLIT_SELECT -> {
+ Log.d(TAG, prefix + "OVERVIEW_SPLIT_SELECT")
+ }
+ }
+ }
+ }
+
+ override fun getSystemUiController(): SystemUiController? {
+ if (mSystemUiController == null) {
+ mSystemUiController = SystemUiController(rootView)
+ }
+ return mSystemUiController
+ }
+
+ override fun getContext(): Context {
+ return this
+ }
+
+ override fun getScrimView(): ScrimView? {
+ return scrimView
+ }
+
+ override fun <T : View?> getOverviewPanel(): T {
+ return recentsView as T
+ }
+
+ override fun getRootView(): View? {
+ return windowView
+ }
+
+ override fun getDragLayer(): BaseDragLayer<RecentsWindowManager> {
+ return dragLayer!!
+ }
+
+ override fun dispatchGenericMotionEvent(ev: MotionEvent?): Boolean {
+ // TODO(b/368610710)
+ return false
+ }
+
+ override fun dispatchKeyEvent(ev: KeyEvent?): Boolean {
+ // TODO(b/368610710)
+ return false
+ }
+
+ override fun getActionsView(): OverviewActionsView<*>? {
+ return actionsView
+ }
+
+ override fun addForceInvisibleFlag(flag: Int) {}
+
+ override fun clearForceInvisibleFlag(flag: Int) {}
+
+ override fun setLocusContext(id: LocusId?, bundle: Bundle?) {
+ // no op
+ }
+
+ override fun isStarted(): Boolean {
+ return isShown
+ }
+
+ /** Adds a callback for the provided activity event */
+ override fun addEventCallback(@BaseActivity.ActivityEvent event: Int, callback: Runnable?) {
+ mEventCallbacks[event].add(callback)
+ }
+
+ /** Removes a previously added callback */
+ override fun removeEventCallback(@BaseActivity.ActivityEvent event: Int, callback: Runnable?) {
+ mEventCallbacks[event].remove(callback)
+ }
+
+ override fun runOnBindToTouchInteractionService(r: Runnable?) {
+ tisBindHelper.runOnBindToTouchInteractionService(r)
+ }
+
+ override fun addMultiWindowModeChangedListener(
+ listener: BaseActivity.MultiWindowModeChangedListener?
+ ) {
+ // TODO(b/368408838)
+ }
+
+ override fun removeMultiWindowModeChangedListener(
+ listener: BaseActivity.MultiWindowModeChangedListener?
+ ) {}
+
+ override fun returnToHomescreen() {
+ startHome()
+ }
+
+ override fun isRecentsViewVisible(): Boolean {
+ return getStateManager().state!!.isRecentsViewVisible
+ }
+
+ override fun createAtomicAnimationFactory(): AtomicAnimationFactory<RecentsState?>? {
+ return RecentsAtomicAnimationFactory<RecentsWindowManager, RecentsState>(this)
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
new file mode 100644
index 0000000..34b3d74
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/fallback/window/RecentsWindowSwipeHandler.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2024 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.fallback.window;
+
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.content.Intent.EXTRA_COMPONENT_NAME;
+import static android.content.Intent.EXTRA_USER;
+
+import static com.android.app.animation.Interpolators.ACCELERATE;
+import static com.android.launcher3.GestureNavContract.EXTRA_GESTURE_CONTRACT;
+import static com.android.launcher3.GestureNavContract.EXTRA_ICON_POSITION;
+import static com.android.launcher3.GestureNavContract.EXTRA_ICON_SURFACE;
+import static com.android.launcher3.GestureNavContract.EXTRA_ON_FINISH_CALLBACK;
+import static com.android.launcher3.GestureNavContract.EXTRA_REMOTE_CALLBACK;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
+
+import android.animation.ObjectAnimator;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Matrix;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Messenger;
+import android.os.ParcelUuid;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.view.RemoteAnimationTarget;
+import android.view.Surface;
+import android.view.SurfaceControl;
+import android.view.SurfaceControl.Transaction;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.anim.SpringAnimationBuilder;
+import com.android.launcher3.states.StateAnimationConfig;
+import com.android.launcher3.util.DisplayController;
+import com.android.quickstep.AbsSwipeUpHandler;
+import com.android.quickstep.GestureState;
+import com.android.quickstep.RecentsAnimationDeviceState;
+import com.android.quickstep.RemoteAnimationTargets;
+import com.android.quickstep.TaskAnimationManager;
+import com.android.quickstep.fallback.FallbackRecentsView;
+import com.android.quickstep.fallback.RecentsState;
+import com.android.quickstep.util.ActiveGestureLog;
+import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
+import com.android.quickstep.util.TransformParams;
+import com.android.quickstep.util.TransformParams.BuilderProxy;
+import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.recents.model.Task.TaskKey;
+import com.android.systemui.shared.system.InputConsumerController;
+
+import java.lang.ref.WeakReference;
+import java.util.List;
+import java.util.UUID;
+import java.util.function.Consumer;
+
+/**
+ * Handles the navigation gestures when a 3rd party launcher is the default home activity.
+ *
+ * Bugs: b/365775417
+ */
+public class RecentsWindowSwipeHandler extends AbsSwipeUpHandler<RecentsWindowManager,
+ FallbackRecentsView<RecentsWindowManager>, RecentsState> {
+
+ private static final String TAG = "RecentsWindowSwipeHandler";
+
+ /**
+ * Message used for receiving gesture nav contract information. We use a static messenger to
+ * avoid leaking too make binders in case the receiving launcher does not handle the contract
+ * properly.
+ */
+ private static StaticMessageReceiver sMessageReceiver = null;
+
+ private FallbackHomeAnimationFactory mActiveAnimationFactory;
+ private final boolean mRunningOverHome;
+
+ private final Matrix mTmpMatrix = new Matrix();
+ private float mMaxLauncherScale = 1;
+
+ private boolean mAppCanEnterPip;
+
+ public RecentsWindowSwipeHandler(Context context, RecentsAnimationDeviceState deviceState,
+ TaskAnimationManager taskAnimationManager, GestureState gestureState, long touchTimeMs,
+ boolean continuingLastGesture, InputConsumerController inputConsumer,
+ RecentsWindowManager recentsWindowManager) {
+ super(context, deviceState, taskAnimationManager, gestureState, touchTimeMs,
+ continuingLastGesture, inputConsumer, recentsWindowManager);
+
+ mRunningOverHome = mGestureState.getRunningTask() != null
+ && mGestureState.getRunningTask().isHomeTask();
+ if (mRunningOverHome) {
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTransformParams().setHomeBuilderProxy(
+ RecentsWindowSwipeHandler.
+ this::updateHomeActivityTransformDuringSwipeUp));
+ }
+ }
+
+ @Override
+ protected void initTransitionEndpoints(DeviceProfile dp) {
+ super.initTransitionEndpoints(dp);
+ if (mRunningOverHome) {
+ // Full screen scale should be independent of remote target handle
+ mMaxLauncherScale = 1 / mRemoteTargetHandles[0].getTaskViewSimulator()
+ .getFullScreenScale();
+ }
+ }
+
+ private void updateHomeActivityTransformDuringSwipeUp(SurfaceProperties builder,
+ RemoteAnimationTarget app, TransformParams params) {
+ setHomeScaleAndAlpha(builder, app, mCurrentShift.value,
+ Utilities.boundToRange(1 - mCurrentShift.value, 0, 1));
+ }
+
+ private void setHomeScaleAndAlpha(SurfaceProperties builder,
+ RemoteAnimationTarget app, float verticalShift, float alpha) {
+ float scale = Utilities.mapRange(verticalShift, 1, mMaxLauncherScale);
+ mTmpMatrix.setScale(scale, scale,
+ app.localBounds.exactCenterX(), app.localBounds.exactCenterY());
+ builder.setMatrix(mTmpMatrix).setAlpha(alpha);
+ builder.setShow();
+ }
+
+ @Override
+ protected HomeAnimationFactory createHomeAnimationFactory(
+ List<IBinder> launchCookies,
+ long duration,
+ boolean isTargetTranslucent,
+ boolean appCanEnterPip,
+ RemoteAnimationTarget runningTaskTarget,
+ @Nullable TaskView targetTaskView) {
+ mAppCanEnterPip = appCanEnterPip;
+ if (appCanEnterPip) {
+ return new FallbackPipToHomeAnimationFactory();
+ }
+ mActiveAnimationFactory = new FallbackHomeAnimationFactory(duration);
+ //todo: b/368410893 follow up on this as its intent focused and seems to cut immediately
+ Intent intent = new Intent(mGestureState.getHomeIntent());
+ if (mActiveAnimationFactory != null && runningTaskTarget != null) {
+ mActiveAnimationFactory.addGestureContract(intent, runningTaskTarget.taskInfo);
+ }
+ return mActiveAnimationFactory;
+ }
+
+ @Override
+ protected boolean handleTaskAppeared(@NonNull RemoteAnimationTarget[] appearedTaskTargets,
+ @NonNull ActiveGestureLog.CompoundString failureReason) {
+ if (mActiveAnimationFactory != null
+ && mActiveAnimationFactory.handleHomeTaskAppeared(appearedTaskTargets)) {
+ mActiveAnimationFactory = null;
+ return false;
+ }
+
+ return super.handleTaskAppeared(appearedTaskTargets, failureReason);
+ }
+
+ @Override
+ protected void finishRecentsControllerToHome(Runnable callback) {
+ final Runnable recentsCallback;
+ if (mAppCanEnterPip) {
+ // Make sure Launcher is resumed after auto-enter-pip transition to actually trigger
+ // the PiP task appearing.
+ recentsCallback = () -> {
+ callback.run();
+ mRecentsWindowManager.startHome();
+ };
+ } else {
+ recentsCallback = callback;
+ }
+ mRecentsView.cleanupRemoteTargets();
+ mRecentsAnimationController.finish(
+ mAppCanEnterPip /* toRecents */, recentsCallback, true /* sendUserLeaveHint */);
+ }
+
+ @Override
+ protected void switchToScreenshot() {
+ if (mRunningOverHome) {
+ // When the current task is home, then we don't need to capture anything
+ mStateCallback.setStateOnUiThread(STATE_SCREENSHOT_CAPTURED);
+ } else {
+ super.switchToScreenshot();
+ }
+ }
+
+ @Override
+ protected void notifyGestureAnimationStartToRecents() {
+ if (mRunningOverHome) {
+ if (DisplayController.getNavigationMode(mContext).hasGestures) {
+ mRecentsView.onGestureAnimationStartOnHome(
+ mGestureState.getRunningTask().getPlaceholderTasks(),
+ mDeviceState.getRotationTouchHelper());
+ }
+ } else {
+ super.notifyGestureAnimationStartToRecents();
+ }
+ }
+
+ private class FallbackPipToHomeAnimationFactory extends HomeAnimationFactory {
+ @NonNull
+ @Override
+ public AnimatorPlaybackController createActivityAnimationToHome() {
+ // copied from {@link LauncherSwipeHandlerV2.LauncherHomeAnimationFactory}
+ long accuracy = 2 * Math.max(mDp.widthPx, mDp.heightPx);
+ return mContainer.getStateManager().createAnimationToNewWorkspace(
+ RecentsState.HOME, accuracy, StateAnimationConfig.SKIP_ALL_ANIMATIONS);
+ }
+ }
+
+ private class FallbackHomeAnimationFactory extends HomeAnimationFactory
+ implements Consumer<Message> {
+ private final Rect mTempRect = new Rect();
+ private final TransformParams mHomeAlphaParams = new TransformParams();
+ private final AnimatedFloat mHomeAlpha;
+
+ private final AnimatedFloat mVerticalShiftForScale = new AnimatedFloat();
+ private final AnimatedFloat mRecentsAlpha = new AnimatedFloat();
+
+ private final RectF mTargetRect = new RectF();
+ private SurfaceControl mSurfaceControl;
+
+ private boolean mAnimationFinished;
+ private Message mOnFinishCallback;
+
+ private final long mDuration;
+
+ private RectFSpringAnim mSpringAnim;
+ FallbackHomeAnimationFactory(long duration) {
+ mDuration = duration;
+
+ if (mRunningOverHome) {
+ mHomeAlpha = new AnimatedFloat();
+ mHomeAlpha.value = Utilities.boundToRange(1 - mCurrentShift.value, 0, 1);
+ mVerticalShiftForScale.value = mCurrentShift.value;
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTransformParams().setHomeBuilderProxy(
+ FallbackHomeAnimationFactory.this
+ ::updateHomeActivityTransformDuringHomeAnim));
+ } else {
+ mHomeAlpha = new AnimatedFloat(this::updateHomeAlpha);
+ mHomeAlpha.value = 0;
+ mHomeAlphaParams.setHomeBuilderProxy(
+ this::updateHomeActivityTransformDuringHomeAnim);
+ }
+
+ mRecentsAlpha.value = 1;
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTransformParams().setBaseBuilderProxy(
+ FallbackHomeAnimationFactory.this
+ ::updateRecentsActivityTransformDuringHomeAnim));
+ }
+
+ @NonNull
+ @Override
+ public RectF getWindowTargetRect() {
+ if (mTargetRect.isEmpty()) {
+ mTargetRect.set(super.getWindowTargetRect());
+ }
+ return mTargetRect;
+ }
+
+ private void updateRecentsActivityTransformDuringHomeAnim(SurfaceProperties builder,
+ RemoteAnimationTarget app, TransformParams params) {
+ builder.setAlpha(mRecentsAlpha.value);
+ }
+
+ private void updateHomeActivityTransformDuringHomeAnim(SurfaceProperties builder,
+ RemoteAnimationTarget app, TransformParams params) {
+ setHomeScaleAndAlpha(builder, app, mVerticalShiftForScale.value, mHomeAlpha.value);
+ }
+
+ @NonNull
+ @Override
+ public AnimatorPlaybackController createActivityAnimationToHome() {
+ PendingAnimation pa = new PendingAnimation(mDuration);
+ pa.setFloat(mRecentsAlpha, AnimatedFloat.VALUE, 0, ACCELERATE);
+ return pa.createPlaybackController();
+ }
+
+ private void updateHomeAlpha() {
+ if (mHomeAlphaParams.getTargetSet() != null) {
+ mHomeAlphaParams.applySurfaceParams(
+ mHomeAlphaParams.createSurfaceParams(BuilderProxy.NO_OP));
+ }
+ }
+
+ public boolean handleHomeTaskAppeared(RemoteAnimationTarget[] appearedTaskTargets) {
+ RemoteAnimationTarget appearedTaskTarget = appearedTaskTargets[0];
+ if (appearedTaskTarget.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME) {
+ RemoteAnimationTargets targets = new RemoteAnimationTargets(
+ new RemoteAnimationTarget[] {appearedTaskTarget},
+ new RemoteAnimationTarget[0], new RemoteAnimationTarget[0],
+ appearedTaskTarget.mode);
+ mHomeAlphaParams.setTargetSet(targets);
+ updateHomeAlpha();
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void playAtomicAnimation(float velocity) {
+ ObjectAnimator alphaAnim = mHomeAlpha.animateToValue(mHomeAlpha.value, 1);
+ alphaAnim.setDuration(mDuration).setInterpolator(ACCELERATE);
+ alphaAnim.start();
+
+ if (mRunningOverHome) {
+ // Spring back launcher scale
+ new SpringAnimationBuilder(mContext)
+ .setStartValue(mVerticalShiftForScale.value)
+ .setEndValue(0)
+ .setStartVelocity(-velocity / mTransitionDragLength)
+ .setMinimumVisibleChange(1f / mDp.heightPx)
+ .setDampingRatio(0.6f)
+ .setStiffness(800)
+ .build(mVerticalShiftForScale, AnimatedFloat.VALUE)
+ .start();
+ }
+ }
+
+ @Override
+ public void setAnimation(RectFSpringAnim anim) {
+ mSpringAnim = anim;
+ mSpringAnim.addAnimatorListener(forEndCallback(this::onRectAnimationEnd));
+ }
+
+ private void onRectAnimationEnd() {
+ mAnimationFinished = true;
+ maybeSendEndMessage();
+ }
+
+ private void maybeSendEndMessage() {
+ if (mAnimationFinished && mOnFinishCallback != null) {
+ try {
+ mOnFinishCallback.replyTo.send(mOnFinishCallback);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error sending icon position", e);
+ }
+ }
+ }
+
+ @Override
+ public void accept(Message msg) {
+ try {
+ Bundle data = msg.getData();
+ RectF position = data.getParcelable(EXTRA_ICON_POSITION);
+ if (!position.isEmpty()) {
+ mSurfaceControl = data.getParcelable(EXTRA_ICON_SURFACE);
+ mTargetRect.set(position);
+ if (mSpringAnim != null) {
+ mSpringAnim.onTargetPositionChanged();
+ }
+ }
+ mOnFinishCallback = data.getParcelable(EXTRA_ON_FINISH_CALLBACK);
+ maybeSendEndMessage();
+ } catch (Exception e) {
+ // Ignore
+ }
+ }
+
+ @Override
+ public void update(RectF currentRect, float progress, float radius, int overlayAlpha) {
+ if (mSurfaceControl != null) {
+ currentRect.roundOut(mTempRect);
+ Transaction t = new Transaction();
+ try {
+ t.setGeometry(mSurfaceControl, null, mTempRect, Surface.ROTATION_0);
+ t.apply();
+ } catch (RuntimeException e) {
+ // Ignore
+ }
+ }
+ }
+
+ private void addGestureContract(Intent intent, RunningTaskInfo runningTaskInfo) {
+ if (mRunningOverHome || runningTaskInfo == null) {
+ return;
+ }
+
+ TaskKey key = new TaskKey(runningTaskInfo);
+ if (key.getComponent() != null) {
+ if (sMessageReceiver == null) {
+ sMessageReceiver = new StaticMessageReceiver();
+ }
+
+ Bundle gestureNavContract = new Bundle();
+ gestureNavContract.putParcelable(EXTRA_COMPONENT_NAME, key.getComponent());
+ gestureNavContract.putParcelable(EXTRA_USER, UserHandle.of(key.userId));
+ gestureNavContract.putParcelable(
+ EXTRA_REMOTE_CALLBACK, sMessageReceiver.newCallback(this));
+ intent.putExtra(EXTRA_GESTURE_CONTRACT, gestureNavContract);
+ }
+ }
+ }
+
+ private static class StaticMessageReceiver implements Handler.Callback {
+
+ private final Messenger mMessenger =
+ new Messenger(new Handler(Looper.getMainLooper(), this));
+
+ private ParcelUuid mCurrentUID = new ParcelUuid(UUID.randomUUID());
+ private WeakReference<Consumer<Message>> mCurrentCallback = new WeakReference<>(null);
+
+ public Message newCallback(Consumer<Message> callback) {
+ mCurrentUID = new ParcelUuid(UUID.randomUUID());
+ mCurrentCallback = new WeakReference<>(callback);
+
+ Message msg = Message.obtain();
+ msg.replyTo = mMessenger;
+ msg.obj = mCurrentUID;
+ return msg;
+ }
+
+ @Override
+ public boolean handleMessage(@NonNull Message message) {
+ if (mCurrentUID.equals(message.obj)) {
+ Consumer<Message> consumer = mCurrentCallback.get();
+ if (consumer != null) {
+ consumer.accept(message);
+ return true;
+ }
+ }
+ return false;
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
index 92031c5..778c231 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/BubbleBarInputConsumer.java
@@ -23,10 +23,12 @@
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.taskbar.TaskbarActivityContext;
+import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController;
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
-import com.android.launcher3.taskbar.bubbles.BubbleDragController;
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -40,10 +42,11 @@
private final BubbleStashController mBubbleStashController;
private final BubbleBarViewController mBubbleBarViewController;
- private final BubbleDragController mBubbleDragController;
+ @Nullable
+ private final BubbleBarSwipeController mBubbleBarSwipeController;
private final InputMonitorCompat mInputMonitorCompat;
- private boolean mSwipeUpOnBubbleHandle;
+ private boolean mPilfered;
private boolean mPassedTouchSlop;
private boolean mStashedOrCollapsedOnDown;
@@ -57,7 +60,8 @@
InputMonitorCompat inputMonitorCompat) {
mBubbleStashController = bubbleControllers.bubbleStashController;
mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
- mBubbleDragController = bubbleControllers.bubbleDragController;
+ mBubbleBarSwipeController = bubbleControllers.bubbleBarSwipeController.orElse(null);
+
mInputMonitorCompat = inputMonitorCompat;
mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
mTimeForTap = ViewConfiguration.getTapTimeout();
@@ -77,6 +81,9 @@
mDownPos.set(ev.getX(), ev.getY());
mLastPos.set(mDownPos);
mStashedOrCollapsedOnDown = mBubbleStashController.isStashed() || isCollapsed();
+ if (mBubbleBarSwipeController != null) {
+ mBubbleBarSwipeController.start();
+ }
break;
case MotionEvent.ACTION_MOVE:
int pointerIndex = ev.findPointerIndex(mActivePointerId);
@@ -90,11 +97,10 @@
if (!mPassedTouchSlop) {
mPassedTouchSlop = Math.abs(dY) > mTouchSlop || Math.abs(dX) > mTouchSlop;
}
- if (mStashedOrCollapsedOnDown && !mSwipeUpOnBubbleHandle && mPassedTouchSlop) {
- boolean verticalGesture = Math.abs(dY) > Math.abs(dX);
- if (verticalGesture && !mBubbleDragController.isDragging()) {
- mSwipeUpOnBubbleHandle = true;
- mBubbleStashController.showBubbleBar(/* expandBubbles= */ true);
+ if (mBubbleBarSwipeController != null) {
+ mBubbleBarSwipeController.swipeTo(dY);
+ if (!mPilfered && mBubbleBarSwipeController.isSwipeGesture()) {
+ mPilfered = true;
// Bubbles is handling the swipe so make sure no one else gets it.
TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
mInputMonitorCompat.pilferPointers();
@@ -102,8 +108,10 @@
}
break;
case MotionEvent.ACTION_UP:
+ boolean swipeUpOnBubbleHandle = mBubbleBarSwipeController != null
+ && mBubbleBarSwipeController.isSwipeGesture();
boolean isWithinTapTime = ev.getEventTime() - ev.getDownTime() <= mTimeForTap;
- if (isWithinTapTime && !mSwipeUpOnBubbleHandle && !mPassedTouchSlop
+ if (isWithinTapTime && !swipeUpOnBubbleHandle && !mPassedTouchSlop
&& mStashedOrCollapsedOnDown) {
// Taps on the handle / collapsed state should open the bar
mBubbleStashController.showBubbleBar(/* expandBubbles= */ true);
@@ -116,8 +124,11 @@
}
private void cleanupAfterMotionEvent() {
+ if (mBubbleBarSwipeController != null) {
+ mBubbleBarSwipeController.finish();
+ }
mPassedTouchSlop = false;
- mSwipeUpOnBubbleHandle = false;
+ mPilfered = false;
}
private boolean isCollapsed() {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 69d3bc9..e19b338 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -41,6 +41,7 @@
import androidx.annotation.UiThread;
+import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.testing.TestLogging;
@@ -424,7 +425,10 @@
mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler);
notifyGestureStarted(true /*isLikelyToStartNewTask*/);
} else {
- Intent intent = new Intent(mInteractionHandler.getLaunchIntent());
+ // todo differentiate intent based on if we are on home or in app for overview in window
+ Intent intent = new Intent(Flags.enableFallbackOverviewInWindow()
+ ? mInteractionHandler.getHomeIntent()
+ : mInteractionHandler.getLaunchIntent());
intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId());
mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent,
mInteractionHandler);
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
index c61f71d..a236eca 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewInputConsumer.java
@@ -28,6 +28,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.views.BaseDragLayer;
@@ -41,7 +42,8 @@
/**
* Input consumer for handling touch on the recents/Launcher activity.
*/
-public class OverviewInputConsumer<S extends BaseState<S>, T extends RecentsViewContainer>
+public class OverviewInputConsumer<S extends BaseState<S>,
+ T extends RecentsViewContainer & StatefulContainer<S>>
implements InputConsumer {
private final T mContainer;
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index b56958a..f7f3157 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -219,7 +219,7 @@
}
private void startBackgroundAnimation(boolean forTablet) {
- if (!Utilities.ATLEAST_S || mVibrator == null) {
+ if (mVibrator == null) {
return;
}
boolean supportsThud = mVibrator.areAllPrimitivesSupported(
diff --git a/quickstep/src/com/android/quickstep/logging/LoggingModule.java b/quickstep/src/com/android/quickstep/logging/LoggingModule.java
deleted file mode 100644
index 8fdf3c7..0000000
--- a/quickstep/src/com/android/quickstep/logging/LoggingModule.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2024 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.logging;
-
-import android.content.Context;
-
-import com.android.launcher3.dagger.ApplicationContext;
-import com.android.launcher3.dagger.LauncherAppSingleton;
-
-import dagger.Module;
-import dagger.Provides;
-
-@Module
-public class LoggingModule {
- @Provides
- @LauncherAppSingleton
- SettingsChangeLogger provideSettingsChangeLogger(@ApplicationContext Context context) {
- return SettingsChangeLogger.INSTANCE.get(context);
- }
-}
diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
index 717f6c8..995635f 100644
--- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
+++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
@@ -43,16 +43,21 @@
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.DeviceGridState;
+import com.android.launcher3.util.DaggerSingletonObject;
+import com.android.launcher3.util.DaggerSingletonTracker;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
-import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.ExecutorUtil;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.SettingsCache;
+import com.android.quickstep.dagger.QuickstepBaseAppComponent;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -60,9 +65,12 @@
import java.io.IOException;
import java.util.Optional;
+import javax.inject.Inject;
+
/**
* Utility class to log launcher settings changes
*/
+@LauncherAppSingleton
public class SettingsChangeLogger implements
DisplayController.DisplayInfoChangeListener, OnSharedPreferenceChangeListener,
SafeCloseable {
@@ -70,8 +78,8 @@
/**
* Singleton instance
*/
- public static MainThreadInitializedObject<SettingsChangeLogger> INSTANCE =
- new MainThreadInitializedObject<>(SettingsChangeLogger::new);
+ public static DaggerSingletonObject<SettingsChangeLogger> INSTANCE =
+ new DaggerSingletonObject<>(QuickstepBaseAppComponent::getSettingsChangeLogger);
private static final String TAG = "SettingsChangeLogger";
private static final String BOOLEAN_PREF = "SwitchPreference";
@@ -84,25 +92,31 @@
private StatsLogManager.LauncherEvent mNotificationDotsEvent;
private StatsLogManager.LauncherEvent mHomeScreenSuggestionEvent;
- private SettingsChangeLogger(Context context) {
- this(context, StatsLogManager.newInstance(context));
+ @Inject
+ SettingsChangeLogger(@ApplicationContext Context context, DaggerSingletonTracker tracker) {
+ this(context, StatsLogManager.newInstance(context), tracker);
}
@VisibleForTesting
- SettingsChangeLogger(Context context, StatsLogManager statsLogManager) {
+ SettingsChangeLogger(Context context, StatsLogManager statsLogManager,
+ DaggerSingletonTracker tracker) {
mContext = context;
mStatsLogManager = statsLogManager;
mLoggablePrefs = loadPrefKeys(context);
- DisplayController.INSTANCE.get(context).addChangeListener(this);
- mNavMode = DisplayController.getNavigationMode(context);
- getPrefs(context).registerOnSharedPreferenceChangeListener(this);
- getDevicePrefs(context).registerOnSharedPreferenceChangeListener(this);
+ ExecutorUtil.executeSyncOnMainOrFail(() -> {
+ DisplayController.INSTANCE.get(context).addChangeListener(this);
+ mNavMode = DisplayController.getNavigationMode(context);
- SettingsCache mSettingsCache = SettingsCache.INSTANCE.get(context);
- mSettingsCache.register(NOTIFICATION_BADGING_URI,
- this::onNotificationDotsChanged);
- onNotificationDotsChanged(mSettingsCache.getValue(NOTIFICATION_BADGING_URI));
+ getPrefs(context).registerOnSharedPreferenceChangeListener(this);
+ getDevicePrefs(context).registerOnSharedPreferenceChangeListener(this);
+
+ SettingsCache settingsCache = SettingsCache.INSTANCE.get(context);
+ settingsCache.register(NOTIFICATION_BADGING_URI,
+ this::onNotificationDotsChanged);
+ onNotificationDotsChanged(settingsCache.getValue(NOTIFICATION_BADGING_URI));
+ tracker.addCloseable(this);
+ });
}
private static ArrayMap<String, LoggablePref> loadPrefKeys(Context context) {
@@ -209,6 +223,8 @@
public void close() {
getPrefs(mContext).unregisterOnSharedPreferenceChangeListener(this);
getDevicePrefs(mContext).unregisterOnSharedPreferenceChangeListener(this);
+ SettingsCache settingsCache = SettingsCache.INSTANCE.get(mContext);
+ settingsCache.unregister(NOTIFICATION_BADGING_URI, this::onNotificationDotsChanged);
}
@VisibleForTesting
diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
index 658975c..88ef0a8 100644
--- a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
@@ -453,6 +453,10 @@
}
}
+ /**
+ * @param inSplitSelection Whether user currently has a task from this task group staged for
+ * split screen. Currently this state is not reachable in fake landscape.
+ */
override fun measureGroupedTaskViewThumbnailBounds(
primarySnapshot: View,
secondarySnapshot: View,
@@ -460,7 +464,8 @@
parentHeight: Int,
splitBoundsConfig: SplitBounds,
dp: DeviceProfile,
- isRtl: Boolean
+ isRtl: Boolean,
+ inSplitSelection: Boolean
) {
val primaryParams = primarySnapshot.layoutParams as FrameLayout.LayoutParams
val secondaryParams = secondarySnapshot.layoutParams as FrameLayout.LayoutParams
@@ -569,6 +574,10 @@
iconAppChipView.setRotation(degreesRotated)
}
+ /**
+ * @param inSplitSelection Whether user currently has a task from this task group staged for
+ * split screen. Currently this state is not reachable in fake landscape.
+ */
override fun setSplitIconParams(
primaryIconView: View,
secondaryIconView: View,
@@ -579,7 +588,8 @@
groupedTaskViewWidth: Int,
isRtl: Boolean,
deviceProfile: DeviceProfile,
- splitConfig: SplitBounds
+ splitConfig: SplitBounds,
+ inSplitSelection: Boolean
) {
val spaceAboveSnapshot = deviceProfile.overviewTaskThumbnailTopMarginPx
val totalThumbnailHeight = groupedTaskViewHeight - spaceAboveSnapshot
diff --git a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
index cc022b2..c0b697d 100644
--- a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
+++ b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
@@ -530,10 +530,16 @@
}
}
+ /**
+ * @param inSplitSelection Whether user currently has a task from this task group staged for
+ * split screen. If true, we have custom translations/scaling in place
+ * for the remaining snapshot, so we'll skip setting translation/scale
+ * here.
+ */
@Override
public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
int parentWidth, int parentHeight, SplitBounds splitBoundsConfig,
- DeviceProfile dp, boolean isRtl) {
+ DeviceProfile dp, boolean isRtl, boolean inSplitSelection) {
int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
FrameLayout.LayoutParams primaryParams =
@@ -541,11 +547,10 @@
FrameLayout.LayoutParams secondaryParams =
(FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams();
- // Reset margin and translations that aren't used in this method, but are used in other
+ // Reset margins that aren't used in this method, but are used in other
// `RecentsPagedOrientationHandler` variants.
secondaryParams.topMargin = 0;
primaryParams.topMargin = spaceAboveSnapshot;
- primarySnapshot.setTranslationY(0);
int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
float dividerScale = splitBoundsConfig.appsStackedVertically
@@ -553,28 +558,35 @@
: splitBoundsConfig.dividerWidthPercent;
Pair<Point, Point> taskViewSizes =
getGroupedTaskViewSizes(dp, splitBoundsConfig, parentWidth, parentHeight);
- if (dp.isLeftRightSplit) {
- int scaledDividerBar = Math.round(parentWidth * dividerScale);
- if (isRtl) {
- int translationX = taskViewSizes.second.x + scaledDividerBar;
- primarySnapshot.setTranslationX(-translationX);
- secondarySnapshot.setTranslationX(0);
+ if (!inSplitSelection) {
+ // Reset translations that aren't used in this method, but are used in other
+ // `RecentsPagedOrientationHandler` variants.
+ primarySnapshot.setTranslationY(0);
+
+ if (dp.isLeftRightSplit) {
+ int scaledDividerBar = Math.round(parentWidth * dividerScale);
+ if (isRtl) {
+ int translationX = taskViewSizes.second.x + scaledDividerBar;
+ primarySnapshot.setTranslationX(-translationX);
+ secondarySnapshot.setTranslationX(0);
+ } else {
+ int translationX = taskViewSizes.first.x + scaledDividerBar;
+ secondarySnapshot.setTranslationX(translationX);
+ primarySnapshot.setTranslationX(0);
+ }
+ secondarySnapshot.setTranslationY(spaceAboveSnapshot);
} else {
- int translationX = taskViewSizes.first.x + scaledDividerBar;
- secondarySnapshot.setTranslationX(translationX);
+ float finalDividerHeight = Math.round(totalThumbnailHeight * dividerScale);
+ float translationY =
+ taskViewSizes.first.y + spaceAboveSnapshot + finalDividerHeight;
+ secondarySnapshot.setTranslationY(translationY);
+
+ // Reset unused translations.
+ secondarySnapshot.setTranslationX(0);
primarySnapshot.setTranslationX(0);
}
-
- secondarySnapshot.setTranslationY(spaceAboveSnapshot);
- } else {
- float finalDividerHeight = Math.round(totalThumbnailHeight * dividerScale);
- float translationY = taskViewSizes.first.y + spaceAboveSnapshot + finalDividerHeight;
- secondarySnapshot.setTranslationY(translationY);
-
- // Reset unused translations.
- secondarySnapshot.setTranslationX(0);
- primarySnapshot.setTranslationX(0);
}
+
primarySnapshot.measure(
View.MeasureSpec.makeMeasureSpec(taskViewSizes.first.x, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(taskViewSizes.first.y, View.MeasureSpec.EXACTLY));
@@ -582,10 +594,6 @@
View.MeasureSpec.makeMeasureSpec(taskViewSizes.second.x, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(taskViewSizes.second.y,
View.MeasureSpec.EXACTLY));
- primarySnapshot.setScaleX(1);
- secondarySnapshot.setScaleX(1);
- primarySnapshot.setScaleY(1);
- secondarySnapshot.setScaleY(1);
}
@Override
@@ -662,11 +670,16 @@
iconAppChipView.setRotation(getDegreesRotated());
}
+ /**
+ * @param inSplitSelection Whether user currently has a task from this task group staged for
+ * split screen. If true, we have custom translations in place for the
+ * remaining icon, so we'll skip setting translations here.
+ */
@Override
public void setSplitIconParams(View primaryIconView, View secondaryIconView,
int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
- DeviceProfile deviceProfile, SplitBounds splitConfig) {
+ DeviceProfile deviceProfile, SplitBounds splitConfig, boolean inSplitSelection) {
FrameLayout.LayoutParams primaryIconParams =
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams = enableOverviewIconMenu()
@@ -680,20 +693,23 @@
secondaryIconParams.gravity = TOP | START;
secondaryIconParams.topMargin = primaryIconParams.topMargin;
secondaryIconParams.setMarginStart(primaryIconParams.getMarginStart());
- if (deviceProfile.isLeftRightSplit) {
- if (isRtl) {
- int secondarySnapshotWidth = groupedTaskViewWidth - primarySnapshotWidth;
- primaryAppChipView.setSplitTranslationX(-secondarySnapshotWidth);
+ if (!inSplitSelection) {
+ if (deviceProfile.isLeftRightSplit) {
+ if (isRtl) {
+ int secondarySnapshotWidth = groupedTaskViewWidth - primarySnapshotWidth;
+ primaryAppChipView.setSplitTranslationX(-secondarySnapshotWidth);
+ } else {
+ secondaryAppChipView.setSplitTranslationX(primarySnapshotWidth);
+ }
} else {
- secondaryAppChipView.setSplitTranslationX(primarySnapshotWidth);
+ primaryAppChipView.setSplitTranslationX(0);
+ secondaryAppChipView.setSplitTranslationX(0);
+ int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(),
+ splitConfig.visualDividerBounds.height());
+ secondaryAppChipView.setSplitTranslationY(
+ primarySnapshotHeight + (deviceProfile.isTablet ? 0
+ : dividerThickness));
}
- } else {
- primaryAppChipView.setSplitTranslationX(0);
- secondaryAppChipView.setSplitTranslationX(0);
- int dividerThickness = Math.min(splitConfig.visualDividerBounds.width(),
- splitConfig.visualDividerBounds.height());
- secondaryAppChipView.setSplitTranslationY(
- primarySnapshotHeight + (deviceProfile.isTablet ? 0 : dividerThickness));
}
} else if (deviceProfile.isLeftRightSplit) {
// We calculate the "midpoint" of the thumbnail area, and place the icons there.
@@ -716,46 +732,53 @@
if (deviceProfile.isSeascape()) {
primaryIconParams.gravity = TOP | (isRtl ? END : START);
secondaryIconParams.gravity = TOP | (isRtl ? END : START);
- if (splitConfig.initiatedFromSeascape) {
- // if the split was initiated from seascape,
- // the task on the right (secondary) is slightly larger
- primaryIconView.setTranslationX(bottomToMidpointOffset - taskIconHeight);
- secondaryIconView.setTranslationX(bottomToMidpointOffset);
- } else {
- // if not,
- // the task on the left (primary) is slightly larger
- primaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset
- - taskIconHeight);
- secondaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset);
+ if (!inSplitSelection) {
+ if (splitConfig.initiatedFromSeascape) {
+ // if the split was initiated from seascape,
+ // the task on the right (secondary) is slightly larger
+ primaryIconView.setTranslationX(bottomToMidpointOffset - taskIconHeight);
+ secondaryIconView.setTranslationX(bottomToMidpointOffset);
+ } else {
+ // if not,
+ // the task on the left (primary) is slightly larger
+ primaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset
+ - taskIconHeight);
+ secondaryIconView.setTranslationX(bottomToMidpointOffset + insetOffset);
+ }
}
} else {
primaryIconParams.gravity = TOP | (isRtl ? START : END);
secondaryIconParams.gravity = TOP | (isRtl ? START : END);
- if (!splitConfig.initiatedFromSeascape) {
- // if the split was initiated from landscape,
- // the task on the left (primary) is slightly larger
- primaryIconView.setTranslationX(-bottomToMidpointOffset);
- secondaryIconView.setTranslationX(-bottomToMidpointOffset + taskIconHeight);
- } else {
- // if not,
- // the task on the right (secondary) is slightly larger
- primaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset);
- secondaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset
- + taskIconHeight);
+ if (!inSplitSelection) {
+ if (!splitConfig.initiatedFromSeascape) {
+ // if the split was initiated from landscape,
+ // the task on the left (primary) is slightly larger
+ primaryIconView.setTranslationX(-bottomToMidpointOffset);
+ secondaryIconView.setTranslationX(-bottomToMidpointOffset + taskIconHeight);
+ } else {
+ // if not,
+ // the task on the right (secondary) is slightly larger
+ primaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset);
+ secondaryIconView.setTranslationX(-bottomToMidpointOffset - insetOffset
+ + taskIconHeight);
+ }
}
}
} else {
primaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
- // shifts icon half a width left (height is used here since icons are square)
- primaryIconView.setTranslationX(-(taskIconHeight / 2f));
secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
- secondaryIconView.setTranslationX(taskIconHeight / 2f);
+ if (!inSplitSelection) {
+ // shifts icon half a width left (height is used here since icons are square)
+ primaryIconView.setTranslationX(-(taskIconHeight / 2f));
+ secondaryIconView.setTranslationX(taskIconHeight / 2f);
+ }
}
- if (!enableOverviewIconMenu()) {
+ if (!enableOverviewIconMenu() && !inSplitSelection) {
primaryIconView.setTranslationY(0);
secondaryIconView.setTranslationY(0);
}
+
primaryIconView.setLayoutParams(primaryIconParams);
secondaryIconView.setLayoutParams(secondaryIconParams);
}
diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
index 06a0685..b8d0412 100644
--- a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
@@ -184,7 +184,8 @@
parentHeight: Int,
splitBoundsConfig: SplitConfigurationOptions.SplitBounds,
dp: DeviceProfile,
- isRtl: Boolean
+ isRtl: Boolean,
+ inSplitSelection: Boolean
)
/**
@@ -235,7 +236,8 @@
groupedTaskViewWidth: Int,
isRtl: Boolean,
deviceProfile: DeviceProfile,
- splitConfig: SplitConfigurationOptions.SplitBounds
+ splitConfig: SplitConfigurationOptions.SplitBounds,
+ inSplitSelection: Boolean
)
/*
diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
index a972e8c..bc91911 100644
--- a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
@@ -277,6 +277,10 @@
iconAppChipView.setRotation(degreesRotated)
}
+ /**
+ * @param inSplitSelection Whether user currently has a task from this task group staged for
+ * split screen. Currently this state is not reachable in fake seascape.
+ */
override fun measureGroupedTaskViewThumbnailBounds(
primarySnapshot: View,
secondarySnapshot: View,
@@ -284,7 +288,8 @@
parentHeight: Int,
splitBoundsConfig: SplitBounds,
dp: DeviceProfile,
- isRtl: Boolean
+ isRtl: Boolean,
+ inSplitSelection: Boolean
) {
val primaryParams = primarySnapshot.layoutParams as FrameLayout.LayoutParams
val secondaryParams = secondarySnapshot.layoutParams as FrameLayout.LayoutParams
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index eb3c2d1..dc8d537 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -17,6 +17,7 @@
package com.android.quickstep.recents.data
import android.graphics.drawable.Drawable
+import android.util.Log
import com.android.launcher3.util.coroutines.DispatcherProvider
import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskIconChangedCallback
import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbnailChangedCallback
@@ -106,7 +107,7 @@
}
}
.flowOn(dispatcherProvider.io)
- .shareIn(recentsCoroutineScope, SharingStarted.WhileSubscribed(), replay = 1)
+ .shareIn(recentsCoroutineScope, SharingStarted.WhileSubscribed(5000), replay = 1)
override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> {
if (forceRefresh) {
@@ -122,6 +123,7 @@
getTaskDataById(taskId).map { it?.thumbnail }.distinctUntilChangedBy { it?.snapshotId }
override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
+ Log.d(TAG, "setVisibleTasks: $visibleTaskIdList")
this.visibleTaskIds.value = visibleTaskIdList.toSet()
}
@@ -185,7 +187,7 @@
TaskIconQueryResponse(
it.newDrawable().mutate(),
contentDescription,
- title
+ title,
)
)
}
@@ -193,12 +195,16 @@
continuation.invokeOnCancellation { cancellableTask?.cancel() }
}
}
+
+ companion object {
+ private const val TAG = "TasksRepository"
+ }
}
data class TaskIconQueryResponse(
val icon: Drawable,
val contentDescription: String,
- val title: String
+ val title: String,
)
private fun Task.getTaskIconQueryResponse(): TaskIconQueryResponse? {
diff --git a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
index 0a5544f..b53650e 100644
--- a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
+++ b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
@@ -66,7 +66,7 @@
val taskVisualsChangedDelegate =
TaskVisualsChangedDelegateImpl(
recentsModel,
- recentsModel.thumbnailCache.highResLoadingState
+ recentsModel.thumbnailCache.highResLoadingState,
)
set(TaskVisualsChangedDelegate::class.java.simpleName, taskVisualsChangedDelegate)
@@ -79,7 +79,7 @@
iconCache,
taskVisualsChangedDelegate,
recentsCoroutineScope,
- ProductionDispatchers
+ ProductionDispatchers,
)
}
set(RecentTasksRepository::class.java.simpleName, recentTasksRepository)
@@ -155,7 +155,8 @@
scopeId: RecentsScopeId,
extras: RecentsDependenciesExtras,
): T {
- log("createDependency ${modelClass.simpleName} with $scopeId and $extras", Log.WARN)
+ log("createDependency ${modelClass.simpleName} with $scopeId and $extras started", Log.WARN)
+ log("linked scopes: ${getScope(scopeId).scopeIdsLinked}")
val instance: Any =
when (modelClass) {
RecentTasksRepository::class.java -> {
@@ -166,7 +167,7 @@
iconCache,
get(),
get(),
- ProductionDispatchers
+ ProductionDispatchers,
)
}
}
@@ -193,7 +194,7 @@
task = task,
recentsViewData = inject(),
recentTasksRepository = inject(),
- getThumbnailPositionUseCase = inject()
+ getThumbnailPositionUseCase = inject(),
)
}
GetThumbnailUseCase::class.java -> GetThumbnailUseCase(taskRepository = inject())
@@ -203,7 +204,7 @@
GetThumbnailPositionUseCase(
deviceProfileRepository = inject(),
rotationStateRepository = inject(),
- tasksRepository = inject()
+ tasksRepository = inject(),
)
SplashAlphaUseCase::class.java ->
SplashAlphaUseCase(
@@ -218,7 +219,12 @@
error("Factory for ${modelClass.simpleName} not defined!")
}
}
- return instance as T
+ return (instance as T).also {
+ log(
+ "createDependency ${modelClass.simpleName} with $scopeId and $extras completed",
+ Log.WARN,
+ )
+ }
}
private fun createScope(scopeId: RecentsScopeId): RecentsDependenciesScope {
@@ -247,11 +253,7 @@
fun initialize(view: View): RecentsDependencies = initialize(view.context)
fun initialize(context: Context): RecentsDependencies {
- synchronized(this) {
- if (!Companion::instance.isInitialized) {
- instance = RecentsDependencies(context.applicationContext)
- }
- }
+ synchronized(this) { instance = RecentsDependencies(context.applicationContext) }
return instance
}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index 0279818..e7416ec 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -22,6 +22,7 @@
import android.graphics.Outline
import android.graphics.Rect
import android.util.AttributeSet
+import android.util.Log
import android.view.View
import android.view.ViewOutlineProvider
import androidx.annotation.ColorInt
@@ -92,6 +93,7 @@
CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("TaskThumbnailView"))
viewModel.uiState
.onEach { viewModelUiState ->
+ Log.d(TAG, "viewModelUiState changed from $uiState to: $viewModelUiState")
uiState = viewModelUiState
resetViews()
when (viewModelUiState) {
@@ -211,6 +213,10 @@
Utilities.mapRange(
viewModel.cornerRadiusProgress.value,
overviewCornerRadius,
- fullscreenCornerRadius
+ fullscreenCornerRadius,
) / inheritedScale
+
+ private companion object {
+ const val TAG = "TaskThumbnailView"
+ }
}
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt
index b1bb65e..4970685 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskThumbnailViewModel.kt
@@ -19,6 +19,7 @@
import android.annotation.ColorInt
import android.app.ActivityTaskManager.INVALID_TASK_ID
import android.graphics.Matrix
+import android.util.Log
import androidx.core.graphics.ColorUtils
import com.android.quickstep.recents.data.RecentTasksRepository
import com.android.quickstep.recents.usecase.GetThumbnailPositionUseCase
@@ -82,7 +83,7 @@
combine(
task.flatMapLatest { it }.map { it?.key?.id }.distinctUntilChanged(),
recentsViewData.runningTaskIds,
- recentsViewData.runningTaskShowScreenshot
+ recentsViewData.runningTaskShowScreenshot,
) { taskId, runningTaskIds, runningTaskShowScreenshot ->
runningTaskIds.contains(taskId) && !runningTaskShowScreenshot
}
@@ -90,6 +91,13 @@
val uiState: Flow<TaskThumbnailUiState> =
combine(task.flatMapLatest { it }, isLiveTile) { taskVal, isRunning ->
+ // TODO(b/369339561) This log is firing a lot. Reduce emissions from TasksRepository
+ // then re-enable this log.
+ // Log.d(
+ // TAG,
+ // "Received task and / or live tile update. taskVal: $taskVal"
+ // + " isRunning: $isRunning.",
+ // )
when {
taskVal == null -> Uninitialized
isRunning -> LiveTile
@@ -103,6 +111,7 @@
.distinctUntilChanged()
fun bind(taskId: Int) {
+ Log.d(TAG, "bind taskId: $taskId")
this.taskId = taskId
task.value = tasksRepository.getTaskDataById(taskId)
splashProgress.value = splashAlphaUseCase.execute(taskId)
@@ -139,5 +148,6 @@
private companion object {
const val MAX_SCRIM_ALPHA = 0.4f
+ const val TAG = "TaskThumbnailViewModel"
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 256e29e..3449cf2 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -42,6 +42,8 @@
import android.window.TransitionInfo.Change
import android.window.WindowContainerToken
import androidx.annotation.VisibleForTesting
+import androidx.core.util.component1
+import androidx.core.util.component2
import com.android.app.animation.Interpolators
import com.android.launcher3.DeviceProfile
import com.android.launcher3.Flags.enableOverviewIconMenu
@@ -225,10 +227,22 @@
ObjectAnimator.ofFloat(iconView.splitTranslationY, MULTI_PROPERTY_VALUE, 0f)
)
}
+
+ val splitBoundsConfig =
+ (taskContainer.taskView as? GroupedTaskView)?.splitBoundsConfig ?: return
+ val (primarySnapshotViewSize, secondarySnapshotViewSize) =
+ taskContainer.taskView.pagedOrientationHandler.getGroupedTaskViewSizes(
+ deviceProfile,
+ splitBoundsConfig,
+ taskViewWidth,
+ taskViewHeight,
+ )
+ val snapshotViewSize =
+ if (isPrimaryTaskSplitting) primarySnapshotViewSize else secondarySnapshotViewSize
if (deviceProfile.isLeftRightSplit) {
// Center view first so scaling happens uniformly, alternatively we can move pivotX to 0
- val centerThumbnailTranslationX: Float = (taskViewWidth - snapshot.width) / 2f
- val finalScaleX: Float = taskViewWidth.toFloat() / snapshot.width
+ val centerThumbnailTranslationX: Float = (taskViewWidth - snapshotViewSize.x) / 2f
+ val finalScaleX: Float = taskViewWidth.toFloat() / snapshotViewSize.x
builder.add(
ObjectAnimator.ofFloat(snapshot, View.TRANSLATION_X, centerThumbnailTranslationX)
)
@@ -262,13 +276,13 @@
// thumbnail needs to take that into account. We should migrate to only using
// translations otherwise this asymmetry causes problems..
if (isPrimaryTaskSplitting) {
- centerThumbnailTranslationY = (thumbnailSize - snapshot.height) / 2f
+ centerThumbnailTranslationY = (thumbnailSize - snapshotViewSize.y) / 2f
centerThumbnailTranslationY +=
deviceProfile.overviewTaskThumbnailTopMarginPx.toFloat()
} else {
- centerThumbnailTranslationY = (thumbnailSize - snapshot.height) / 2f
+ centerThumbnailTranslationY = (thumbnailSize - snapshotViewSize.y) / 2f
}
- val finalScaleY: Float = thumbnailSize.toFloat() / snapshot.height
+ val finalScaleY: Float = thumbnailSize.toFloat() / snapshotViewSize.y
builder.add(
ObjectAnimator.ofFloat(snapshot, View.TRANSLATION_Y, centerThumbnailTranslationY)
)
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 1af12f1..fbeeef2 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -52,7 +52,6 @@
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -116,7 +115,6 @@
private static final String TAG = "SplitSelectStateCtor";
private RecentsViewContainer mContainer;
- private final Handler mHandler;
private final RecentsModel mRecentTasksModel;
@Nullable
private Runnable mActivityBackCallback;
@@ -182,12 +180,11 @@
}
};
- public SplitSelectStateController(RecentsViewContainer container, Handler handler,
+ public SplitSelectStateController(RecentsViewContainer container,
StateManager stateManager, DepthController depthController,
StatsLogManager statsLogManager, SystemUiProxy systemUiProxy, RecentsModel recentsModel,
Runnable activityBackCallback) {
mContainer = container;
- mHandler = handler;
mStatsLogManager = statsLogManager;
mSystemUiProxy = systemUiProxy;
mStateManager = stateManager;
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
index 7b97c23..c07b7fb 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt
@@ -59,10 +59,10 @@
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
- defStyleRes: Int = 0
+ defStyleRes: Int = 0,
) : TextView(context, attrs, defStyleAttr, defStyleRes) {
- private val recentsViewContainer =
- RecentsViewContainer.containerFromContext<RecentsViewContainer>(context)
+ private val recentsViewContainer: RecentsViewContainer =
+ RecentsViewContainer.containerFromContext(context)
private val launcherApps: LauncherApps? = context.getSystemService(LauncherApps::class.java)
@@ -138,7 +138,7 @@
usageLimit =
launcherApps?.getAppUsageLimit(
task.topComponent.packageName,
- UserHandle.of(task.key.userId)
+ UserHandle.of(task.key.userId),
)
} catch (e: Exception) {
Log.e(TAG, "Error initializing digital well being toast", e)
@@ -162,7 +162,7 @@
task: Task,
taskView: TaskView,
snapshotView: View,
- @StagePosition stagePosition: Int
+ @StagePosition stagePosition: Int,
) {
this.task = task
this.taskView = taskView
@@ -201,7 +201,7 @@
private fun getReadableDuration(
duration: Duration,
- @StringRes durationLessThanOneMinuteStringId: Int
+ @StringRes durationLessThanOneMinuteStringId: Int,
): String {
val hours = Math.toIntExact(duration.toHours())
val minutes = Math.toIntExact(duration.minusHours(hours.toLong()).toMinutes())
@@ -211,7 +211,7 @@
MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.NARROW)
.formatMeasures(
Measure(hours, MeasureUnit.HOUR),
- Measure(minutes, MeasureUnit.MINUTE)
+ Measure(minutes, MeasureUnit.MINUTE),
)
// Apply FormatWidth.WIDE if only the hour part is non-zero (unless forced).
hours > 0 ->
@@ -239,7 +239,7 @@
@VisibleForTesting
fun getBannerText(
remainingTime: Long = appRemainingTimeMs,
- forContentDesc: Boolean = false
+ forContentDesc: Boolean = false,
): String {
val duration =
Duration.ofMillis(
@@ -250,7 +250,7 @@
val readableDuration =
getReadableDuration(
duration,
- R.string.shorter_duration_less_than_one_minute /* forceFormatWidth */
+ R.string.shorter_duration_less_than_one_minute, /* forceFormatWidth */
)
val splitBannerConfig = getSplitBannerConfig()
return when {
@@ -277,7 +277,7 @@
Log.e(
TAG,
"Failed to open app usage settings for task " + task.topComponent.packageName,
- e
+ e,
)
}
}
@@ -285,13 +285,13 @@
private fun getContentDescriptionForTask(
task: Task,
appUsageLimitTimeMs: Long,
- appRemainingTimeMs: Long
+ appRemainingTimeMs: Long,
): String? =
if (appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0)
context.getString(
R.string.task_contents_description_with_remaining_time,
task.titleDescription,
- getBannerText(appRemainingTimeMs, true /* forContentDesc */)
+ getBannerText(appRemainingTimeMs, true /* forContentDesc */),
)
else task.titleDescription
@@ -310,7 +310,7 @@
recentsViewContainer.deviceProfile,
splitBounds,
taskView.layoutParams.width,
- taskView.layoutParams.height
+ taskView.layoutParams.height,
)
if (stagePosition == STAGE_POSITION_TOP_OR_LEFT) {
snapshotWidth = groupedTaskSize.first.x
@@ -327,7 +327,7 @@
recentsViewContainer.deviceProfile,
snapshotWidth,
snapshotHeight,
- this
+ this,
)
}
@@ -340,7 +340,7 @@
recentsViewContainer.deviceProfile,
taskView.snapshotViews,
task.key.id,
- this
+ this,
)
this.translationX = translationX
this.splitOffsetTranslationY = translationY
@@ -372,7 +372,7 @@
if (taskView.containsMultipleTasks())
context.getString(
R.string.split_app_usage_settings,
- TaskUtils.getTitle(context, task)
+ TaskUtils.getTitle(context, task),
)
else context.getString(R.string.accessibility_app_usage_settings)
return AccessibilityNodeInfo.AccessibilityAction(getAccessibilityActionId(), label)
@@ -394,7 +394,7 @@
/** Used for grid task view, only showing icon and time */
SPLIT_GRID_BANNER_LARGE,
/** Used for grid task view, only showing icon */
- SPLIT_GRID_BANNER_SMALL
+ SPLIT_GRID_BANNER_SMALL,
}
val OPEN_APP_USAGE_SETTINGS_TEMPLATE: Intent = Intent(Settings.ACTION_APP_USAGE_SETTINGS)
diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
index 4ea7753..f17be05 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
@@ -32,7 +32,6 @@
import com.android.launcher3.R;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
-import com.android.launcher3.widget.RoundedCornerEnforcement;
import java.util.stream.IntStream;
@@ -171,8 +170,7 @@
/** Corner radius from source view's outline, or enforced view. */
private static float getOutlineRadius(LauncherAppWidgetHostView hostView, View v) {
- if (RoundedCornerEnforcement.isRoundedCornerEnabled()
- && hostView.hasEnforcedCornerRadius()) {
+ if (hostView.hasEnforcedCornerRadius()) {
return hostView.getEnforcedCornerRadius();
} else if (v.getOutlineProvider() instanceof RemoteViewOutlineProvider
&& v.getClipToOutline()) {
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
index 3fd1a6b..92c1e93 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
@@ -65,31 +65,18 @@
val heightSize = MeasureSpec.getSize(heightMeasureSpec)
setMeasuredDimension(widthSize, heightSize)
val splitBoundsConfig = splitBoundsConfig ?: return
- val initSplitTaskId = getThisTaskCurrentlyInSplitSelection()
- if (initSplitTaskId == INVALID_TASK_ID) {
- pagedOrientationHandler.measureGroupedTaskViewThumbnailBounds(
- taskContainers[0].snapshotView,
- taskContainers[1].snapshotView,
- widthSize,
- heightSize,
- splitBoundsConfig,
- container.deviceProfile,
- layoutDirection == LAYOUT_DIRECTION_RTL
- )
- } else {
- // Currently being split with this taskView, let the non-split selected thumbnail
- // take up full thumbnail area
- taskContainers
- .firstOrNull { it.task.key.id != initSplitTaskId }
- ?.snapshotView
- ?.measure(
- widthMeasureSpec,
- MeasureSpec.makeMeasureSpec(
- heightSize - container.deviceProfile.overviewTaskThumbnailTopMarginPx,
- MeasureSpec.EXACTLY
- )
- )
- }
+ val inSplitSelection = getThisTaskCurrentlyInSplitSelection() != INVALID_TASK_ID
+ pagedOrientationHandler.measureGroupedTaskViewThumbnailBounds(
+ taskContainers[0].snapshotView,
+ taskContainers[1].snapshotView,
+ widthSize,
+ heightSize,
+ splitBoundsConfig,
+ container.deviceProfile,
+ layoutDirection == LAYOUT_DIRECTION_RTL,
+ inSplitSelection,
+ )
+
if (!enableOverviewIconMenu()) {
updateIconPlacement()
}
@@ -173,6 +160,8 @@
val splitBoundsConfig = splitBoundsConfig ?: return
val taskIconHeight = container.deviceProfile.overviewTaskIconSizePx
val isRtl = layoutDirection == LAYOUT_DIRECTION_RTL
+ val inSplitSelection = getThisTaskCurrentlyInSplitSelection() != INVALID_TASK_ID
+
if (enableOverviewIconMenu()) {
val groupedTaskViewSizes =
pagedOrientationHandler.getGroupedTaskViewSizes(
@@ -191,7 +180,8 @@
layoutParams.width,
isRtl,
container.deviceProfile,
- splitBoundsConfig
+ splitBoundsConfig,
+ inSplitSelection
)
} else {
pagedOrientationHandler.setSplitIconParams(
@@ -204,7 +194,8 @@
measuredWidth,
isRtl,
container.deviceProfile,
- splitBoundsConfig
+ splitBoundsConfig,
+ inSplitSelection
)
}
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index d20d0a5..8f20cd38 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -16,17 +16,14 @@
package com.android.quickstep.views;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.window.flags.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY;
-import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.CLEAR_ALL_BUTTON;
-import static com.android.launcher3.LauncherState.EDIT_MODE;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK;
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
-import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
-import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import android.annotation.TargetApi;
import android.content.Context;
@@ -173,8 +170,7 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- if (finalState == NORMAL || finalState == SPRING_LOADED || finalState == EDIT_MODE
- || finalState == ALL_APPS) {
+ if (!finalState.isRecentsViewVisible) {
// Clean-up logic that occurs when recents is no longer in use/visible.
reset();
}
@@ -268,7 +264,8 @@
super.onGestureAnimationStart(runningTasks, rotationTouchHelper);
DesktopVisibilityController desktopVisibilityController =
mContainer.getDesktopVisibilityController();
- if (!WALLPAPER_ACTIVITY.isEnabled(mContext) && desktopVisibilityController != null) {
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && desktopVisibilityController != null) {
// TODO: b/333533253 - Remove after flag rollout
desktopVisibilityController.setRecentsGestureStart();
}
@@ -291,7 +288,8 @@
}
}
super.onGestureAnimationEnd();
- if (!WALLPAPER_ACTIVITY.isEnabled(mContext) && desktopVisibilityController != null) {
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && desktopVisibilityController != null) {
// TODO: b/333533253 - Remove after flag rollout
desktopVisibilityController.setRecentsGestureEnd(endTarget);
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index bb46a2c..da68a03 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -236,8 +236,6 @@
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus;
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource;
-import kotlin.Unit;
-
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -251,6 +249,8 @@
import java.util.function.Consumer;
import java.util.stream.Collectors;
+import kotlin.Unit;
+
/**
* A list of recent tasks.
*
@@ -258,7 +258,7 @@
* @param <STATE_TYPE> : the type of base state that will be used
*/
public abstract class RecentsView<
- CONTAINER_TYPE extends Context & RecentsViewContainer,
+ CONTAINER_TYPE extends Context & RecentsViewContainer & StatefulContainer<STATE_TYPE>,
STATE_TYPE extends BaseState<STATE_TYPE>> extends PagedView implements Insettable,
TaskThumbnailCache.HighResLoadingState.HighResLoadingStateChangedCallback,
TaskVisualsChangeListener {
@@ -343,7 +343,7 @@
};
public static final int SCROLL_VIBRATION_PRIMITIVE =
- Utilities.ATLEAST_S ? VibrationEffect.Composition.PRIMITIVE_LOW_TICK : -1;
+ VibrationEffect.Composition.PRIMITIVE_LOW_TICK;
public static final float SCROLL_VIBRATION_PRIMITIVE_SCALE = 0.6f;
public static final VibrationEffect SCROLL_VIBRATION_FALLBACK =
VibrationConstants.EFFECT_TEXTURE_TICK;
@@ -1209,6 +1209,7 @@
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
+
updateTaskStackListenerState();
mModel.getThumbnailCache().getHighResLoadingState().removeCallback(this);
mContainer.removeMultiWindowModeChangedListener(mMultiWindowModeChangedListener);
@@ -4994,7 +4995,8 @@
mSplitSelectStateController.getSplitAnimationController()
.addInitialSplitFromPair(taskContainer, builder,
mContainer.getDeviceProfile(),
- mSplitHiddenTaskView.getWidth(), mSplitHiddenTaskView.getHeight(),
+ mSplitHiddenTaskView.getLayoutParams().width,
+ mSplitHiddenTaskView.getLayoutParams().height,
primaryTaskSelected);
builder.addOnFrameCallback(() -> {
if (!enableRefactorTaskThumbnail()) {
diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
index 8f19444..d8036aa 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java
@@ -17,6 +17,7 @@
package com.android.quickstep.views;
import android.app.Activity;
+import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.LocusId;
@@ -31,7 +32,6 @@
import com.android.launcher3.BaseActivity;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.statehandlers.DesktopVisibilityController;
-import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.ScrimView;
@@ -44,7 +44,7 @@
* Returns an instance of an implementation of RecentsViewContainer
* @param context will find instance of recentsViewContainer from given context.
*/
- static <T extends RecentsViewContainer> T containerFromContext(Context context) {
+ static <T extends Context & RecentsViewContainer> T containerFromContext(Context context) {
if (context instanceof RecentsViewContainer) {
return (T) context;
} else if (context instanceof ContextWrapper) {
@@ -55,11 +55,6 @@
}
/**
- * Returns {@link SystemUiController} to manage various window flags to control system UI.
- */
- SystemUiController getSystemUiController();
-
- /**
* Returns {@link ScrimView}
*/
ScrimView getScrimView();
@@ -95,7 +90,7 @@
/**
* Returns overview actions view as a view
*/
- View getActionsView();
+ OverviewActionsView getActionsView();
/**
* @see BaseActivity#addForceInvisibleFlag(int)
@@ -143,12 +138,6 @@
void runOnBindToTouchInteractionService(Runnable r);
/**
- * @see Activity#getWindow()
- * @return Window
- */
- Window getWindow();
-
- /**
* @see
* BaseActivity#addMultiWindowModeChangedListener(BaseActivity.MultiWindowModeChangedListener)
* @param listener {@link BaseActivity.MultiWindowModeChangedListener}
@@ -177,6 +166,25 @@
boolean isRecentsViewVisible();
/**
+ * Begins transition to start home through container
+ */
+ default void startHome(){
+ // no op
+ }
+
+ /**
+ * Checks container to see if we can start home transition safely
+ */
+ boolean canStartHomeSafely();
+
+
+ /**
+ * Enter staged split directly from the current running app.
+ * @param leftOrTop if the staged split will be positioned left or top.
+ */
+ default void enterStageSplitFromRunningApp(boolean leftOrTop){}
+
+ /**
* Overwrites any logged item in Launcher that doesn't have a container with the
* {@link com.android.launcher3.touch.PagedOrientationHandler} in use for Overview.
*
diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
index 13c4f78..6cb7741 100644
--- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
@@ -56,7 +56,7 @@
@SplitConfigurationOptions.StagePosition val stagePosition: Int,
val digitalWellBeingToast: DigitalWellBeingToast?,
val showWindowsView: View?,
- taskOverlayFactory: TaskOverlayFactory
+ taskOverlayFactory: TaskOverlayFactory,
) {
val overlay: TaskOverlayFactory.TaskOverlay<*> = taskOverlayFactory.createOverlay(this)
lateinit var taskContainerData: TaskContainerData
@@ -160,6 +160,8 @@
if (enableRefactorTaskThumbnail()) {
taskView.removeView(thumbnailView)
}
+ snapshotView.scaleX = 1f
+ snapshotView.scaleY = 1f
overlay.destroy()
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 2ed6ae6..f513a82 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -687,7 +687,6 @@
orientedState: RecentsOrientedState,
taskOverlayFactory: TaskOverlayFactory,
) {
-
cancelPendingLoadTasks()
taskContainers =
listOf(
@@ -720,6 +719,7 @@
thumbnailViewDeprecated.visibility = GONE
val indexOfSnapshotView = indexOfChild(thumbnailViewDeprecated)
LayoutInflater.from(context).inflate(R.layout.task_thumbnail, this, false).also {
+ it.id = thumbnailViewId
addView(it, indexOfSnapshotView, thumbnailViewDeprecated.layoutParams)
}
} else {
diff --git a/quickstep/src_protolog/com/android/quickstep/util/QuickstepProtoLogGroup.java b/quickstep/src_protolog/com/android/quickstep/util/QuickstepProtoLogGroup.java
new file mode 100644
index 0000000..d0863f8
--- /dev/null
+++ b/quickstep/src_protolog/com/android/quickstep/util/QuickstepProtoLogGroup.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util;
+
+import androidx.annotation.NonNull;
+
+import com.android.internal.protolog.ProtoLog;
+import com.android.internal.protolog.common.IProtoLogGroup;
+
+import java.util.UUID;
+
+/** Enums used to interface with the ProtoLog API. */
+public enum QuickstepProtoLogGroup implements IProtoLogGroup {
+
+ ACTIVE_GESTURE_LOG(true, true, false, "ActiveGestureLog");
+
+ private final boolean mEnabled;
+ private volatile boolean mLogToProto;
+ private volatile boolean mLogToLogcat;
+ private final @NonNull String mTag;
+
+ public static void initProtoLog() {
+ ProtoLog.init(QuickstepProtoLogGroup.values());
+ }
+
+ /**
+ * @param enabled set to false to exclude all log statements for this group from
+ * compilation,
+ * they will not be available in runtime.
+ * @param logToProto enable binary logging for the group
+ * @param logToLogcat enable text logging for the group
+ * @param tag name of the source of the logged message
+ */
+ QuickstepProtoLogGroup(
+ boolean enabled, boolean logToProto, boolean logToLogcat, @NonNull String tag) {
+ this.mEnabled = enabled;
+ this.mLogToProto = logToProto;
+ this.mLogToLogcat = logToLogcat;
+ this.mTag = tag;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return mEnabled;
+ }
+
+ @Override
+ public boolean isLogToProto() {
+ return mLogToProto;
+ }
+
+ @Override
+ public boolean isLogToLogcat() {
+ return mLogToLogcat;
+ }
+
+ @Override
+ public boolean isLogToAny() {
+ return mLogToLogcat || mLogToProto;
+ }
+
+ @Override
+ public int getId() {
+ return Constants.LOG_START_ID + this.ordinal();
+ }
+
+ @Override
+ public @NonNull String getTag() {
+ return mTag;
+ }
+
+ @Override
+ public void setLogToProto(boolean logToProto) {
+ this.mLogToProto = logToProto;
+ }
+
+ @Override
+ public void setLogToLogcat(boolean logToLogcat) {
+ this.mLogToLogcat = logToLogcat;
+ }
+
+ private static final class Constants {
+
+ private static final int LOG_START_ID =
+ (int) (UUID.nameUUIDFromBytes(QuickstepProtoLogGroup.class.getName().getBytes())
+ .getMostSignificantBits() % Integer.MAX_VALUE);
+ }
+}
diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt
index b1ff4a1..537a755 100644
--- a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt
+++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt
@@ -56,10 +56,10 @@
)
@Test
- fun bubbleBarFlyoutView_noAvatar() {
- screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar") { activity ->
+ fun bubbleBarFlyoutView_noAvatar_onRight() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar_onRight") { activity ->
activity.actionBar?.hide()
- val flyout = BubbleBarFlyoutView(context)
+ val flyout = BubbleBarFlyoutView(context, onLeft = false)
flyout.setData(
BubbleBarFlyoutMessage(
senderAvatar = null,
@@ -73,10 +73,44 @@
}
@Test
- fun bubbleBarFlyoutView_avatar() {
- screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar") { activity ->
+ fun bubbleBarFlyoutView_noAvatar_onLeft() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar_onLeft") { activity ->
activity.actionBar?.hide()
- val flyout = BubbleBarFlyoutView(context)
+ val flyout = BubbleBarFlyoutView(context, onLeft = true)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = null,
+ senderName = "sender",
+ message = "message",
+ isGroupChat = false,
+ )
+ )
+ flyout
+ }
+ }
+
+ @Test
+ fun bubbleBarFlyoutView_noAvatar_longMessage() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar_longMessage") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context, onLeft = true)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = null,
+ senderName = "sender",
+ message = "really, really, really, really, really long message. like really.",
+ isGroupChat = false,
+ )
+ )
+ flyout
+ }
+ }
+
+ @Test
+ fun bubbleBarFlyoutView_avatar_onRight() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar_onRight") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context, onLeft = false)
flyout.setData(
BubbleBarFlyoutMessage(
senderAvatar = ColorDrawable(Color.RED),
@@ -88,4 +122,38 @@
flyout
}
}
+
+ @Test
+ fun bubbleBarFlyoutView_avatar_onLeft() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar_onLeft") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context, onLeft = true)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = ColorDrawable(Color.RED),
+ senderName = "sender",
+ message = "message",
+ isGroupChat = true,
+ )
+ )
+ flyout
+ }
+ }
+
+ @Test
+ fun bubbleBarFlyoutView_avatar_longMessage() {
+ screenshotRule.screenshotTest("bubbleBarFlyoutView_avatar_longMessage") { activity ->
+ activity.actionBar?.hide()
+ val flyout = BubbleBarFlyoutView(context, onLeft = true)
+ flyout.setData(
+ BubbleBarFlyoutMessage(
+ senderAvatar = ColorDrawable(Color.RED),
+ senderName = "sender",
+ message = "really, really, really, really, really long message. like really.",
+ isGroupChat = true,
+ )
+ )
+ flyout
+ }
+ }
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendControllerTest.kt
new file mode 100644
index 0000000..f3fff9f
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendControllerTest.kt
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2024 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.animation.AnimatorTestRule
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING
+import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER
+import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TOUCHING
+import com.android.launcher3.taskbar.rules.TaskbarModeRule
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.TRANSIENT
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.TaskbarMode
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.quickstep.SystemUiProxy
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.rules.TestRule
+import org.junit.runner.RunWith
+import org.junit.runners.model.Statement
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelTablet2023"])
+class TaskbarAutohideSuspendControllerTest {
+
+ private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
+
+ @get:Rule(order = 0) val animatorTestRule = AnimatorTestRule(this)
+ @get:Rule(order = 1)
+ val systemUiProxyRule = TestRule { base, _ ->
+ object : Statement() {
+ override fun evaluate() {
+ getInstrumentation().runOnMainSync {
+ context.applicationContext.putObject(
+ SystemUiProxy.INSTANCE,
+ object : SystemUiProxy(context) {
+ override fun notifyTaskbarAutohideSuspend(suspend: Boolean) {
+ latestSuspendNotification = suspend
+ }
+ },
+ )
+ }
+ base.evaluate()
+ }
+ }
+ }
+ @get:Rule(order = 2) val taskbarModeRule = TaskbarModeRule(context)
+ @get:Rule(order = 3) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ @InjectController lateinit var autohideSuspendController: TaskbarAutohideSuspendController
+ @InjectController lateinit var stashController: TaskbarStashController
+
+ private var latestSuspendNotification: Boolean? = null
+
+ @Test
+ fun testUpdateFlag_suspendInLauncher_notifiesSuspend() {
+ getInstrumentation().runOnMainSync {
+ autohideSuspendController.updateFlag(FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER, true)
+ }
+ assertThat(latestSuspendNotification).isTrue()
+ }
+
+ @Test
+ fun testUpdateFlag_toggleSuspendDraggingTwice_notifiesUnsuspend() {
+ getInstrumentation().runOnMainSync {
+ autohideSuspendController.updateFlag(FLAG_AUTOHIDE_SUSPEND_DRAGGING, true)
+ autohideSuspendController.updateFlag(FLAG_AUTOHIDE_SUSPEND_DRAGGING, false)
+ }
+ assertThat(latestSuspendNotification).isFalse()
+ }
+
+ @Test
+ fun testUpdateFlag_resetsAlreadyUnsetFlag_noNotifyUnsuspend() {
+ getInstrumentation().runOnMainSync {
+ autohideSuspendController.updateFlag(FLAG_AUTOHIDE_SUSPEND_DRAGGING, false)
+ }
+ assertThat(latestSuspendNotification).isNull()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateFlag_suspendTransientTaskbarForTouch_cancelsAutoStashTimeout() {
+ // Unstash and verify alarm.
+ getInstrumentation().runOnMainSync {
+ stashController.updateAndAnimateTransientTaskbar(false)
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashController.timeoutAlarm.alarmPending()).isTrue()
+
+ // EDU opens while unstashed.
+ getInstrumentation().runOnMainSync {
+ autohideSuspendController.updateFlag(FLAG_AUTOHIDE_SUSPEND_TOUCHING, true)
+ }
+ assertThat(stashController.timeoutAlarm.alarmPending()).isFalse()
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
index 399aea6..02d6218 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
@@ -20,6 +20,7 @@
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
@@ -33,11 +34,13 @@
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.util.AssistUtils;
+import com.android.systemui.contextualeducation.GestureType;
import org.junit.Before;
import org.junit.Test;
@@ -52,6 +55,10 @@
@Mock
SystemUiProxy mockSystemUiProxy;
+
+ @Mock
+ ContextualEduStatsManager mockContextualEduStatsManager;
+
@Mock
TouchInteractionService mockService;
@Mock
@@ -100,6 +107,7 @@
mockService,
mCallbacks,
mockSystemUiProxy,
+ mockContextualEduStatsManager,
mockHandler,
mockAssistUtils);
}
@@ -111,6 +119,13 @@
}
@Test
+ public void testPressBack_updateContextualEduData() {
+ mNavButtonController.onButtonClick(BUTTON_BACK, mockView);
+ verify(mockContextualEduStatsManager, times(1))
+ .updateEduStats(/* isTrackpad= */ eq(false), eq(GestureType.BACK));
+ }
+
+ @Test
public void testPressImeSwitcher() {
mNavButtonController.init(mockTaskbarControllers);
mNavButtonController.onButtonClick(BUTTON_IME_SWITCH, mockView);
@@ -195,12 +210,26 @@
}
@Test
+ public void testPressHome_updateContextualEduData() {
+ mNavButtonController.onButtonClick(BUTTON_HOME, mockView);
+ verify(mockContextualEduStatsManager, times(1))
+ .updateEduStats(/* isTrackpad= */ eq(false), eq(GestureType.HOME));
+ }
+
+ @Test
public void testPressRecents() {
mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
assertThat(mOverviewToggleCount).isEqualTo(1);
}
@Test
+ public void testPressRecents_updateContextualEduData() {
+ mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
+ verify(mockContextualEduStatsManager, times(1))
+ .updateEduStats(/* isTrackpad= */ eq(false), eq(GestureType.OVERVIEW));
+ }
+
+ @Test
public void testPressRecentsWithScreenPinned_noNavigationToOverview() {
mNavButtonController.updateSysuiFlags(SYSUI_STATE_SCREEN_PINNING);
mNavButtonController.onButtonClick(BUTTON_RECENTS, mockView);
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarScrimViewControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarScrimViewControllerTest.kt
new file mode 100644
index 0000000..3524961
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarScrimViewControllerTest.kt
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2024 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.animation.AnimatorTestRule
+import android.view.View.GONE
+import android.view.View.VISIBLE
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.taskbar.rules.TaskbarModeRule
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.PINNED
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.TRANSIENT
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.TaskbarMode
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.quickstep.SystemUiProxy
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
+import com.android.wm.shell.shared.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelTablet2023"])
+class TaskbarScrimViewControllerTest {
+ private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
+
+ @get:Rule(order = 0) val taskbarModeRule = TaskbarModeRule(context)
+ @get:Rule(order = 1) val animatorTestRule = AnimatorTestRule(this)
+ @get:Rule(order = 2) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ @InjectController lateinit var scrimViewController: TaskbarScrimViewController
+
+ // Default animation duration.
+ private val animationDuration =
+ context.resources.getInteger(android.R.integer.config_mediumAnimTime).toLong()
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOnTaskbarVisibleChanged_onlyTaskbarVisible_noScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ scrimViewController.updateStateForSysuiFlags(0, true)
+ }
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOnTaskbarVisibilityChanged_pinnedTaskbarVisibleWithBubblesExpanded_showsScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, true)
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ animatorTestRule.advanceTimeBy(animationDuration)
+ }
+
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(BUBBLE_EXPANDED_SCRIM_ALPHA)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOnTaskbarVisibilityChanged_pinnedTaskbarHiddenDuringScrim_hidesScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ scrimViewController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, true)
+ }
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(BUBBLE_EXPANDED_SCRIM_ALPHA)
+
+ getInstrumentation().runOnMainSync {
+ scrimViewController.onTaskbarVisibilityChanged(GONE)
+ animatorTestRule.advanceTimeBy(animationDuration)
+ }
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOnTaskbarVisibilityChanged_notificationsOverPinnedTaskbarAndBubbles_noScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.updateStateForSysuiFlags(
+ SYSUI_STATE_BUBBLES_EXPANDED or SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE,
+ true,
+ )
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ }
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOnTaskbarVisibilityChanged_pinnedTaskbarWithBubbleMenu_darkerScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ scrimViewController.updateStateForSysuiFlags(
+ SYSUI_STATE_BUBBLES_EXPANDED or SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED,
+ true,
+ )
+ }
+ assertThat(scrimViewController.scrimAlpha).isGreaterThan(BUBBLE_EXPANDED_SCRIM_ALPHA)
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testOnTaskbarVisibilityChanged_stashedTaskbarWithBubbles_noScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, true)
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ }
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testOnClick_scrimShown_performsSystemBack() {
+ var backPressed = false
+ context.applicationContext.putObject(
+ SystemUiProxy.INSTANCE,
+ object : SystemUiProxy(context) {
+ override fun onBackPressed() {
+ backPressed = true
+ }
+ },
+ )
+
+ getInstrumentation().runOnMainSync {
+ scrimViewController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, true)
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ }
+ assertThat(scrimViewController.scrimView.isClickable).isTrue()
+
+ getInstrumentation().runOnMainSync { scrimViewController.scrimView.performClick() }
+ assertThat(backPressed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testOnClick_scrimHidden_notClickable() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, true)
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ }
+ assertThat(scrimViewController.scrimView.isClickable).isFalse()
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt
new file mode 100644
index 0000000..e736446
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarStashControllerTest.kt
@@ -0,0 +1,681 @@
+/*
+ * Copyright (C) 2024 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.animation.AnimatorTestRule
+import android.platform.test.annotations.EnableFlags
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.R
+import com.android.launcher3.taskbar.StashedHandleViewController.ALPHA_INDEX_STASHED
+import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_OVERVIEW
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_DEVICE_LOCKED
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IME
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_APP_AUTO
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_SMALL_SCREEN
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_SYSUI
+import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION
+import com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION_FOR_IME
+import com.android.launcher3.taskbar.TaskbarStashController.TRANSIENT_TASKBAR_STASH_ALPHA_DURATION
+import com.android.launcher3.taskbar.TaskbarStashController.TRANSIENT_TASKBAR_STASH_DURATION
+import com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_STASH
+import com.android.launcher3.taskbar.bubbles.BubbleControllers
+import com.android.launcher3.taskbar.rules.TaskbarModeRule
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.PINNED
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.THREE_BUTTONS
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.TRANSIENT
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.TaskbarMode
+import com.android.launcher3.taskbar.rules.TaskbarPinningPreferenceRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.UserSetupMode
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING
+import com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_BAR
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelTablet2023"])
+class TaskbarStashControllerTest {
+ private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
+
+ @get:Rule(order = 0) val taskbarModeRule = TaskbarModeRule(context)
+ @get:Rule(order = 1) val taskbarPinningPreferenceRule = TaskbarPinningPreferenceRule(context)
+ @get:Rule(order = 2) val animatorTestRule = AnimatorTestRule(this)
+ @get:Rule(order = 3) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ @InjectController lateinit var stashController: TaskbarStashController
+ @InjectController lateinit var viewController: TaskbarViewController
+ @InjectController lateinit var stashedHandleViewController: StashedHandleViewController
+ @InjectController lateinit var dragLayerController: TaskbarDragLayerController
+ @InjectController lateinit var autohideSuspendController: TaskbarAutohideSuspendController
+ @InjectController lateinit var bubbleControllers: Optional<BubbleControllers>
+
+ private val activityContext by taskbarUnitTestRule::activityContext
+
+ // Disable hardware keyboard mode during tests.
+ @Before fun enableSoftwareIme() = TaskbarStashController.enableSoftwareImeForTests(true)
+
+ @After fun resetIme() = TaskbarStashController.enableSoftwareImeForTests(false)
+
+ @After fun cancelTimeoutIfExists() = stashController.cancelTimeoutIfExists()
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testInit_transientMode_stashedInApp() {
+ assertThat(stashController.isStashedInApp).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testInit_pinnedMode_unstashedInApp() {
+ assertThat(stashController.isStashedInApp).isFalse()
+ }
+
+ @Test
+ @UserSetupMode
+ @TaskbarMode(PINNED)
+ fun testInit_userSetupWithPinnedMode_stashedInApp() {
+ assertThat(stashController.isStashedInApp).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testSetSetupUiVisible_true_stashedInApp() {
+ getInstrumentation().runOnMainSync { stashController.setSetupUIVisible(true) }
+ assertThat(stashController.isStashedInApp).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testSetSetupUiVisible_false_unstashedInApp() {
+ getInstrumentation().runOnMainSync { stashController.setSetupUIVisible(false) }
+ assertThat(stashController.isStashedInApp).isFalse()
+ }
+
+ @Test
+ fun testRecreateAsTransient_timeoutStarted() {
+ taskbarPinningPreferenceRule.isPinned = true
+ activityContext.controllers.sharedState?.taskbarWasPinned = true
+
+ taskbarPinningPreferenceRule.isPinned = false
+ assertThat(stashController.timeoutAlarm.alarmPending()).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testSupportsVisualStashing_transientMode_supported() {
+ assertThat(stashController.supportsVisualStashing()).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testSupportsVisualStashing_pinnedMode_supported() {
+ assertThat(stashController.supportsVisualStashing()).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(THREE_BUTTONS)
+ fun testSupportsVisualStashing_threeButtonsMode_unsupported() {
+ assertThat(stashController.supportsVisualStashing()).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testGetStashDuration_transientMode() {
+ assertThat(stashController.stashDuration).isEqualTo(TRANSIENT_TASKBAR_STASH_DURATION)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testGetStashDuration_pinnedMode() {
+ assertThat(stashController.stashDuration).isEqualTo(TASKBAR_STASH_DURATION)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testIsStashed_pinnedInApp_isUnstashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testIsStashed_transientInApp_isStashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testIsStashed_transientNotInApp_isUnstashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ fun testIsStashed_stashedInLauncherState_isStashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testIsStashed_transientInOverview_isUnstashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.updateStateForFlag(FLAG_IN_OVERVIEW, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testIsStashed_pinnedInOverviewWithIme_isStashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.updateStateForFlag(FLAG_IN_OVERVIEW, true)
+ stashController.updateStateForFlag(FLAG_STASHED_IME, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testIsStashed_pinnedTaskbarWithPinnedApp_isStashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, true)
+ stashController.updateStateForFlag(FLAG_STASHED_SYSUI, true) // App pinned.
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ fun testIsInStashedLauncherState_flagUnset_false() {
+ stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, false)
+ assertThat(stashController.isInStashedLauncherState).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(THREE_BUTTONS)
+ fun testIsInStashedLauncherState_flagSetInThreeButtonsMode_false() {
+ stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, true)
+ assertThat(stashController.isInStashedLauncherState).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testIsInStashedLauncherState_flagSetInPinnedMode_true() {
+ stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE, true)
+ assertThat(stashController.isInStashedLauncherState).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testIsTaskbarVisibleAndNotStashing_pinnedButNotVisible_false() {
+ getInstrumentation().runOnMainSync {
+ viewController.taskbarIconAlpha.get(ALPHA_INDEX_STASH).value = 0f
+ }
+ assertThat(stashController.isTaskbarVisibleAndNotStashing).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testIsTaskbarVisibleAndNotStashing_visibleButStashed_false() {
+ getInstrumentation().runOnMainSync {
+ viewController.taskbarIconAlpha.get(ALPHA_INDEX_STASH).value = 1f
+ }
+ assertThat(stashController.isTaskbarVisibleAndNotStashing).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testIsTaskbarVisibleAndNotStashing_pinnedAndVisible_true() {
+ getInstrumentation().runOnMainSync {
+ viewController.taskbarIconAlpha.get(ALPHA_INDEX_STASH).value = 1f
+ }
+ assertThat(stashController.isTaskbarVisibleAndNotStashing).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testGetTouchableHeight_isStashed_stashedHeight() {
+ assertThat(stashController.touchableHeight).isEqualTo(stashController.stashedHeight)
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testGetTouchableHeight_unstashedTransientMode_heightAndBottomMargin() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, false)
+ stashController.applyState(0)
+ }
+
+ val expectedHeight =
+ activityContext.deviceProfile.run { taskbarHeight + taskbarBottomMargin }
+ assertThat(stashController.touchableHeight).isEqualTo(expectedHeight)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testGetTouchableHeight_pinnedMode_taskbarHeight() {
+ assertThat(stashController.touchableHeight)
+ .isEqualTo(activityContext.deviceProfile.taskbarHeight)
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testGetContentHeightToReportToApps_transientMode_stashedHeight() {
+ assertThat(stashController.contentHeightToReportToApps)
+ .isEqualTo(stashController.stashedHeight)
+ }
+
+ @Test
+ @TaskbarMode(THREE_BUTTONS)
+ fun testGetContentHeightToReportToApps_threeButtonsMode_taskbarHeight() {
+ assertThat(stashController.contentHeightToReportToApps)
+ .isEqualTo(activityContext.deviceProfile.taskbarHeight)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testGetContentHeightToReportToApps_pinnedMode_taskbarHeight() {
+ assertThat(stashController.contentHeightToReportToApps)
+ .isEqualTo(activityContext.deviceProfile.taskbarHeight)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ @UserSetupMode
+ fun testGetContentHeightToReportToApps_pinnedInSetupMode_setupWizardInsets() {
+ assertThat(stashController.contentHeightToReportToApps)
+ .isEqualTo(context.resources.getDimensionPixelSize(R.dimen.taskbar_suw_insets))
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testGetContentHeightToReportToApps_pinnedModeButFolded_stashedHeight() {
+ getInstrumentation().runOnMainSync {
+ stashedHandleViewController.stashedHandleAlpha.get(ALPHA_INDEX_STASHED).value = 1f
+ stashController.updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, true)
+ }
+ assertThat(stashController.contentHeightToReportToApps)
+ .isEqualTo(stashController.stashedHeight)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testGetContentHeightToReportToApps_homeDisabledWhenFolded_zeroHeight() {
+ getInstrumentation().runOnMainSync {
+ stashedHandleViewController.stashedHandleAlpha.get(ALPHA_INDEX_STASHED).value = 1f
+ stashedHandleViewController.setIsHomeButtonDisabled(true)
+ stashController.updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, true)
+ }
+ assertThat(stashController.contentHeightToReportToApps).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testGetTappableHeightToReportToApps_transientMode_zeroHeight() {
+ assertThat(stashController.tappableHeightToReportToApps).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testGetTappableHeightToReportToApps_pinnedMode_taskbarHeight() {
+ assertThat(stashController.tappableHeightToReportToApps)
+ .isEqualTo(activityContext.deviceProfile.taskbarHeight)
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_unstashTaskbar_updatesState() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateAndAnimateTransientTaskbar(false)
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_runUnstashAnimation_startsTaskbarTimeout() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateAndAnimateTransientTaskbar(false)
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashController.timeoutAlarm.alarmPending()).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_finishTaskbarTimeout_taskbarStashes() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateAndAnimateTransientTaskbar(false)
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashController.timeoutAlarm.alarmPending()).isTrue()
+
+ getInstrumentation().runOnMainSync {
+ stashController.timeoutAlarm.finishAlarm()
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_autoHideSuspendedForEdu_remainsUnstashed() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateAndAnimateTransientTaskbar(false)
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+
+ getInstrumentation().runOnMainSync {
+ autohideSuspendController.updateFlag(FLAG_AUTOHIDE_SUSPEND_EDU_OPEN, true)
+ stashController.updateAndAnimateTransientTaskbar(true)
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_unstashTaskbarWithBubbles_bubbleBarUnstashes() {
+ getInstrumentation().runOnMainSync {
+ bubbleControllers.get().bubbleBarViewController.setHiddenForBubbles(false)
+ bubbleControllers.get().bubbleStashController.stashBubbleBarImmediate()
+ stashController.updateAndAnimateTransientTaskbar(false, true)
+ }
+ assertThat(bubbleControllers.get().bubbleStashController.isStashed).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_unstashTaskbarWithoutBubbles_bubbleBarStashed() {
+ getInstrumentation().runOnMainSync {
+ bubbleControllers.get().bubbleBarViewController.setHiddenForBubbles(false)
+ bubbleControllers.get().bubbleStashController.stashBubbleBarImmediate()
+ stashController.updateAndAnimateTransientTaskbar(false, false)
+ }
+ assertThat(bubbleControllers.get().bubbleStashController.isStashed).isTrue()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_stashTaskbarWithBubbles_bubbleBarStashes() {
+ getInstrumentation().runOnMainSync {
+ bubbleControllers.get().bubbleBarViewController.setHiddenForBubbles(false)
+ bubbleControllers.get().bubbleStashController.showBubbleBarImmediate()
+ stashController.updateAndAnimateTransientTaskbar(true, true)
+ }
+ assertThat(bubbleControllers.get().bubbleStashController.isStashed).isTrue()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_stashTaskbarWithoutBubbles_bubbleBarUnstashed() {
+ getInstrumentation().runOnMainSync {
+ bubbleControllers.get().bubbleBarViewController.setHiddenForBubbles(false)
+ bubbleControllers.get().bubbleStashController.showBubbleBarImmediate()
+ stashController.updateAndAnimateTransientTaskbar(true, false)
+ }
+ assertThat(bubbleControllers.get().bubbleStashController.isStashed).isFalse()
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @TaskbarMode(TRANSIENT)
+ fun testUpdateAndAnimateTransientTaskbar_bubbleBarExpandedBeforeTimeout_expandedAfterwards() {
+ getInstrumentation().runOnMainSync {
+ bubbleControllers.get().bubbleBarViewController.setHiddenForBubbles(false)
+ bubbleControllers.get().bubbleBarViewController.isExpanded = true
+ stashController.updateAndAnimateTransientTaskbar(false)
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashController.timeoutAlarm.alarmPending()).isTrue()
+
+ getInstrumentation().runOnMainSync {
+ stashController.timeoutAlarm.finishAlarm()
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(bubbleControllers.get().bubbleBarViewController.isExpanded).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testToggleTaskbarStash_pinnedMode_doesNothing() {
+ getInstrumentation().runOnMainSync { stashController.toggleTaskbarStash() }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testToggleTaskbarStash_transientMode_unstashesTaskbar() {
+ getInstrumentation().runOnMainSync { stashController.toggleTaskbarStash() }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testToggleTaskbarStash_twiceInTransientMode_stashesTaskbar() {
+ getInstrumentation().runOnMainSync {
+ stashController.toggleTaskbarStash()
+ stashController.toggleTaskbarStash()
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testToggleTaskbarStash_notInAppWithTransientMode_doesNothing() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.applyState(0)
+ stashController.toggleTaskbarStash()
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testAnimateTransientTaskbar_bubblesShownInOverview_stashesTaskbar() {
+ // Start in Overview. Should unstash Taskbar.
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, false)
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.updateStateForFlag(FLAG_IN_OVERVIEW, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashController.isStashed).isFalse()
+
+ // Expand bubbles. Should stash Taskbar.
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, false)
+ animatorTestRule.advanceTimeBy(TASKBAR_STASH_DURATION)
+ }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testAnimatePinnedTaskbar_imeShown_replacesIconsWithHandle() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_IME_SHOWING, false)
+ animatorTestRule.advanceTimeBy(TASKBAR_STASH_DURATION_FOR_IME)
+ }
+ assertThat(viewController.areIconsVisible()).isFalse()
+ assertThat(stashedHandleViewController.isStashedHandleVisible).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testAnimatePinnedTaskbar_imeHidden_replacesHandleWithIcons() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_IME_SHOWING, true)
+ animatorTestRule.advanceTimeBy(0)
+ }
+
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(0, true)
+ animatorTestRule.advanceTimeBy(0)
+ }
+ assertThat(stashedHandleViewController.isStashedHandleVisible).isFalse()
+ assertThat(viewController.areIconsVisible()).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testAnimatePinnedTaskbar_imeHidden_verifyAnimationDuration() {
+ // Start with IME shown.
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_IME_SHOWING, true)
+ animatorTestRule.advanceTimeBy(0)
+ }
+
+ // Hide IME with animation.
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(0, false)
+ // Fast forward without start delay.
+ animatorTestRule.advanceTimeBy(TASKBAR_STASH_DURATION_FOR_IME)
+ }
+ // Icons should not be visible yet due to start delay.
+ assertThat(viewController.areIconsVisible()).isFalse()
+
+ // Advance by start delay retroactively. Animation should complete.
+ getInstrumentation().runOnMainSync {
+ animatorTestRule.advanceTimeBy(stashController.taskbarStashStartDelayForIme)
+ }
+ assertThat(viewController.areIconsVisible()).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(THREE_BUTTONS)
+ fun testAnimateThreeButtonsTaskbar_imeShown_hidesIconsAndBg() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_IME_SHOWING, false)
+ animatorTestRule.advanceTimeBy(TASKBAR_STASH_DURATION_FOR_IME)
+ }
+ assertThat(viewController.areIconsVisible()).isFalse()
+ assertThat(dragLayerController.imeBgTaskbar.value).isEqualTo(0)
+ }
+
+ @Test
+ @TaskbarMode(THREE_BUTTONS)
+ fun testAnimateThreeButtonsTaskbar_imeHidden_showsIconsAndBg() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_IME_SHOWING, false)
+ animatorTestRule.advanceTimeBy(TASKBAR_STASH_DURATION_FOR_IME)
+ }
+
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(0, false)
+ animatorTestRule.advanceTimeBy(
+ TASKBAR_STASH_DURATION_FOR_IME + stashController.taskbarStashStartDelayForIme
+ )
+ }
+ assertThat(viewController.areIconsVisible()).isTrue()
+ assertThat(dragLayerController.imeBgTaskbar.value).isEqualTo(1)
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testSetSystemGestureInProgress_whileImeShown_unstashesTaskbar() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForSysuiFlags(SYSUI_STATE_IME_SHOWING, true)
+ animatorTestRule.advanceTimeBy(0)
+ }
+
+ getInstrumentation().runOnMainSync {
+ stashController.setSystemGestureInProgress(true)
+ animatorTestRule.advanceTimeBy(
+ TASKBAR_STASH_DURATION_FOR_IME + stashController.taskbarStashStartDelayForIme
+ )
+ }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testUnlockTransition_pinnedMode_fadesOutHandle() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashedHandleViewController.isStashedHandleVisible).isTrue()
+
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, false)
+ stashController.applyState()
+ animatorTestRule.advanceTimeBy(stashController.stashDuration)
+ }
+ assertThat(stashedHandleViewController.isStashedHandleVisible).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testUnlockTransition_transientMode_fadesOutHandleEarly() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_IN_APP, false)
+ stashController.updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, true)
+ stashController.applyState(0)
+ }
+ assertThat(stashedHandleViewController.isStashedHandleVisible).isTrue()
+
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, false)
+ stashController.applyState()
+ // Time it takes for just the handle to hide (full stash animation is longer).
+ animatorTestRule.advanceTimeBy(TRANSIENT_TASKBAR_STASH_ALPHA_DURATION)
+ }
+ assertThat(stashedHandleViewController.isStashedHandleVisible).isFalse()
+ }
+}
+
+private fun TaskbarStashController.updateStateForFlag(flag: Int, value: Boolean) {
+ updateStateForFlag(flag.toLong(), value)
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsControllerTest.kt
index 43d924a..f783e40 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsControllerTest.kt
@@ -199,8 +199,8 @@
assertThat(editText?.hasFocus()).isTrue()
}
- private companion object {
- private val TEST_APPS =
+ companion object {
+ val TEST_APPS =
Array(16) {
AppInfo(
ComponentName(
@@ -213,6 +213,6 @@
)
}
- private val TEST_PREDICTED_APPS = TEST_APPS.take(4).map { WorkspaceItemInfo(it) }
+ val TEST_PREDICTED_APPS = TEST_APPS.take(4).map { WorkspaceItemInfo(it) }
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewControllerTest.kt
new file mode 100644
index 0000000..04f02e9
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewControllerTest.kt
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2024 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.allapps
+
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.R
+import com.android.launcher3.appprediction.AppsDividerView
+import com.android.launcher3.appprediction.AppsDividerView.DividerType
+import com.android.launcher3.appprediction.PredictionRowView
+import com.android.launcher3.taskbar.TaskbarStashController
+import com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_IN_APP_AUTO
+import com.android.launcher3.taskbar.allapps.TaskbarAllAppsControllerTest.Companion.TEST_PREDICTED_APPS
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayController
+import com.android.launcher3.taskbar.rules.TaskbarModeRule
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.PINNED
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.TRANSIENT
+import com.android.launcher3.taskbar.rules.TaskbarModeRule.TaskbarMode
+import com.android.launcher3.taskbar.rules.TaskbarPreferenceRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.rules.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.taskbar.rules.TaskbarWindowSandboxContext
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.launcher3.util.OnboardingPrefs.ALL_APPS_VISITED_COUNT
+import com.android.launcher3.util.TestUtil
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023"])
+class TaskbarAllAppsViewControllerTest {
+
+ private val context = TaskbarWindowSandboxContext.create(getInstrumentation().targetContext)
+
+ @get:Rule(order = 0) val taskbarModeRule = TaskbarModeRule(context)
+ @get:Rule(order = 1)
+ val allAppsVisitedPreferenceRule =
+ TaskbarPreferenceRule(context, ALL_APPS_VISITED_COUNT.prefItem)
+ @get:Rule(order = 2) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+
+ @InjectController lateinit var overlayController: TaskbarOverlayController
+ @InjectController lateinit var stashController: TaskbarStashController
+
+ private val searchSessionController =
+ TestUtil.getOnUiThread { TaskbarSearchSessionController.newInstance(context) }
+
+ @After
+ fun cleanUpSearchSessionController() {
+ getInstrumentation().runOnMainSync { searchSessionController.onDestroy() }
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testShow_transientMode_stashesTaskbar() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_IN_APP_AUTO.toLong(), false)
+ stashController.applyState(0)
+ }
+
+ val viewController = createViewController()
+ getInstrumentation().runOnMainSync { viewController.show(false) }
+ assertThat(stashController.isStashed).isTrue()
+ }
+
+ @Test
+ @TaskbarMode(PINNED)
+ fun testShow_pinnedMode_taskbarDoesNotStash() {
+ val viewController = createViewController()
+ getInstrumentation().runOnMainSync { viewController.show(false) }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ @TaskbarMode(TRANSIENT)
+ fun testHide_transientMode_unstashesTaskbar() {
+ getInstrumentation().runOnMainSync {
+ stashController.updateStateForFlag(FLAG_STASHED_IN_APP_AUTO.toLong(), false)
+ stashController.applyState(0)
+ }
+
+ val viewController = createViewController()
+ getInstrumentation().runOnMainSync { viewController.show(false) }
+ getInstrumentation().runOnMainSync { viewController.close(false) }
+ assertThat(stashController.isStashed).isFalse()
+ }
+
+ @Test
+ fun testShow_firstAllAppsVisit_hasAllAppsTextDivider() {
+ allAppsVisitedPreferenceRule.value = 0
+ val viewController = createViewController()
+ getInstrumentation().runOnMainSync { viewController.show(false) }
+
+ val appsView = overlayController.requestWindow().appsView
+ getInstrumentation().runOnMainSync {
+ appsView.floatingHeaderView
+ .findFixedRowByType(PredictionRowView::class.java)
+ .setPredictedApps(TEST_PREDICTED_APPS)
+ }
+
+ val dividerView =
+ appsView.floatingHeaderView.findFixedRowByType(AppsDividerView::class.java)
+ assertThat(dividerView.dividerType).isEqualTo(DividerType.ALL_APPS_LABEL)
+ }
+
+ @Test
+ fun testShow_maxAllAppsVisitedCount_hasLineDivider() {
+ allAppsVisitedPreferenceRule.value = ALL_APPS_VISITED_COUNT.maxCount
+ val viewController = createViewController()
+ getInstrumentation().runOnMainSync { viewController.show(false) }
+
+ val appsView = overlayController.requestWindow().appsView
+ getInstrumentation().runOnMainSync {
+ appsView.floatingHeaderView
+ .findFixedRowByType(PredictionRowView::class.java)
+ .setPredictedApps(TEST_PREDICTED_APPS)
+ }
+
+ val dividerView =
+ appsView.floatingHeaderView.findFixedRowByType(AppsDividerView::class.java)
+ assertThat(dividerView.dividerType).isEqualTo(DividerType.LINE)
+ }
+
+ private fun createViewController(): TaskbarAllAppsViewController {
+ return TestUtil.getOnUiThread {
+ val overlayContext = overlayController.requestWindow()
+ TaskbarAllAppsViewController(
+ overlayContext,
+ overlayContext.layoutInflater.inflate(
+ R.layout.taskbar_all_apps_sheet,
+ overlayContext.dragLayer,
+ false,
+ ) as TaskbarAllAppsSlideInView,
+ taskbarUnitTestRule.activityContext.controllers,
+ searchSessionController,
+ /* showKeyboard= */ false, // Covered in TaskbarAllAppsControllerTest.
+ )
+ }
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarInputConsumerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarInputConsumerTest.kt
index 785ec66..c8f50f7 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarInputConsumerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarInputConsumerTest.kt
@@ -49,6 +49,7 @@
@Mock private lateinit var bubbleDismissController: BubbleDismissController
@Mock private lateinit var bubbleBarPinController: BubbleBarPinController
@Mock private lateinit var bubblePinController: BubblePinController
+ @Mock private lateinit var bubbleBarSwipeController: BubbleBarSwipeController
@Mock private lateinit var bubbleCreator: BubbleCreator
@Mock private lateinit var motionEvent: MotionEvent
@@ -67,7 +68,8 @@
bubbleDismissController,
bubbleBarPinController,
bubblePinController,
- bubbleCreator
+ Optional.of(bubbleBarSwipeController),
+ bubbleCreator,
)
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeControllerTest.kt
new file mode 100644
index 0000000..97847be
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarSwipeControllerTest.kt
@@ -0,0 +1,327 @@
+/*
+ * Copyright (C) 2024 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.bubbles
+
+import android.animation.AnimatorTestRule
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
+import com.android.launcher3.touch.OverScroll
+import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.atLeastOnce
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@RunWith(AndroidJUnit4::class)
+class BubbleBarSwipeControllerTest {
+
+ companion object {
+ const val UNSTASH_THRESHOLD = 100
+ const val EXPAND_THRESHOLD = 200
+ const val MAX_OVERSCROLL = 300
+
+ const val UP_BELOW_UNSTASH = -UNSTASH_THRESHOLD + 10f
+ const val UP_ABOVE_UNSTASH = -UNSTASH_THRESHOLD - 10f
+ const val UP_ABOVE_EXPAND = -EXPAND_THRESHOLD - 10f
+ const val DOWN_BELOW_UNSTASH = UNSTASH_THRESHOLD + 10f
+ }
+
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+
+ @get:Rule(order = 0) val mockitoRule: MockitoRule = MockitoJUnit.rule()
+ @get:Rule(order = 1) val animatorTestRule: AnimatorTestRule = AnimatorTestRule(this)
+
+ private lateinit var bubbleBarSwipeController: BubbleBarSwipeController
+
+ @Mock private lateinit var bubbleBarController: BubbleBarController
+ @Mock private lateinit var bubbleBarViewController: BubbleBarViewController
+ @Mock private lateinit var bubbleStashController: BubbleStashController
+ @Mock private lateinit var bubbleStashedHandleViewController: BubbleStashedHandleViewController
+ @Mock private lateinit var bubbleDragController: BubbleDragController
+ @Mock private lateinit var bubbleDismissController: BubbleDismissController
+ @Mock private lateinit var bubbleBarPinController: BubbleBarPinController
+ @Mock private lateinit var bubblePinController: BubblePinController
+ @Mock private lateinit var bubbleCreator: BubbleCreator
+
+ @Before
+ fun setUp() {
+ val dimensionProvider =
+ object : BubbleBarSwipeController.DimensionProvider {
+ override val unstashThreshold: Int
+ get() = UNSTASH_THRESHOLD
+
+ override val expandThreshold: Int
+ get() = EXPAND_THRESHOLD
+
+ override val maxOverscroll: Int
+ get() = MAX_OVERSCROLL
+ }
+ bubbleBarSwipeController = BubbleBarSwipeController(context, dimensionProvider)
+
+ val bubbleControllers =
+ BubbleControllers(
+ bubbleBarController,
+ bubbleBarViewController,
+ bubbleStashController,
+ Optional.of(bubbleStashedHandleViewController),
+ bubbleDragController,
+ bubbleDismissController,
+ bubbleBarPinController,
+ bubblePinController,
+ Optional.of(bubbleBarSwipeController),
+ bubbleCreator,
+ )
+
+ bubbleBarSwipeController.init(bubbleControllers)
+ }
+
+ private fun testViewsHaveDampedTranslationOnSwipe(swipe: Float) {
+ val dampedTranslation = -OverScroll.dampedScroll(-swipe, MAX_OVERSCROLL).toFloat()
+ getInstrumentation().runOnMainSync {
+ bubbleBarSwipeController.start()
+ bubbleBarSwipeController.swipeTo(swipe)
+ }
+ verify(bubbleStashedHandleViewController).setTranslationYForSwipe(dampedTranslation)
+ verify(bubbleBarViewController).setTranslationYForSwipe(dampedTranslation)
+ }
+
+ @Test
+ fun swipeUp_stashedBar_belowUnstashThreshold_viewsHaveDampedTranslation() {
+ setUpStashedBar()
+ testViewsHaveDampedTranslationOnSwipe(UP_BELOW_UNSTASH)
+ }
+
+ @Test
+ fun swipeUp_stashedBar_aboveUnstashThreshold_viewsHaveDampedTranslation() {
+ setUpStashedBar()
+ testViewsHaveDampedTranslationOnSwipe(UP_ABOVE_UNSTASH)
+ }
+
+ @Test
+ fun swipeUp_stashedBar_aboveExpandThreshold_viewsHaveDampedTranslation() {
+ setUpStashedBar()
+ testViewsHaveDampedTranslationOnSwipe(UP_ABOVE_EXPAND)
+ }
+
+ @Test
+ fun swipeUp_collapsedBar_aboveUnstashThreshold_viewsHaveDampedTranslation() {
+ setUpCollapsedBar()
+ testViewsHaveDampedTranslationOnSwipe(UP_ABOVE_UNSTASH)
+ }
+
+ @Test
+ fun swipeUp_collapsedBar_aboveExpandThreshold_viewsHaveDampedTranslation() {
+ setUpCollapsedBar()
+ testViewsHaveDampedTranslationOnSwipe(UP_ABOVE_EXPAND)
+ }
+
+ private fun testViewsTranslationResetOnFinish(swipe: Float) {
+ getInstrumentation().runOnMainSync {
+ bubbleBarSwipeController.start()
+ bubbleBarSwipeController.swipeTo(swipe)
+ bubbleBarSwipeController.finish()
+ // We use a spring animation. Advance by 5 seconds to give it time to finish
+ animatorTestRule.advanceTimeBy(5000)
+ }
+ val handleSwipeTranslation = argumentCaptor<Float>()
+ val barSwipeTranslation = argumentCaptor<Float>()
+ verify(bubbleStashedHandleViewController, atLeastOnce())
+ .setTranslationYForSwipe(handleSwipeTranslation.capture())
+ verify(bubbleBarViewController, atLeastOnce())
+ .setTranslationYForSwipe(barSwipeTranslation.capture())
+
+ assertThat(handleSwipeTranslation.firstValue).isNonZero()
+ assertThat(handleSwipeTranslation.lastValue).isZero()
+
+ assertThat(barSwipeTranslation.firstValue).isNonZero()
+ assertThat(barSwipeTranslation.lastValue).isZero()
+ }
+
+ @Test
+ fun swipeUp_stashedBar_belowUnstashThreshold_animateTranslationToZeroOnFinish() {
+ setUpStashedBar()
+ testViewsTranslationResetOnFinish(UP_BELOW_UNSTASH)
+ }
+
+ @Test
+ fun swipeUp_stashedBar_aboveUnstashThreshold_animateTranslationToZeroOnFinish() {
+ setUpStashedBar()
+ testViewsTranslationResetOnFinish(UP_ABOVE_UNSTASH)
+ }
+
+ @Test
+ fun swipeUp_stashedBar_aboveExpandThreshold_animateTranslationToZeroOnFinish() {
+ setUpStashedBar()
+ testViewsTranslationResetOnFinish(UP_ABOVE_EXPAND)
+ }
+
+ @Test
+ fun swipeUp_collapsedBar_aboveUnstashThreshold_animateTranslationToZeroOnFinish() {
+ setUpCollapsedBar()
+ testViewsTranslationResetOnFinish(UP_ABOVE_UNSTASH)
+ }
+
+ @Test
+ fun swipeUp_collapsedBar_aboveExpandThreshold_animateTranslationToZeroOnFinish() {
+ setUpCollapsedBar()
+ testViewsTranslationResetOnFinish(UP_ABOVE_EXPAND)
+ }
+
+ @Test
+ fun swipeUp_stashedBar_belowUnstashThreshold_doesNotShowBar() {
+ setUpStashedBar()
+ getInstrumentation().runOnMainSync {
+ bubbleBarSwipeController.start()
+ bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH)
+ }
+ verify(bubbleStashController, never()).showBubbleBar(any())
+ }
+
+ @Test
+ fun swipeUp_stashedBar_belowUnstashThreshold_isSwipeGestureFalse() {
+ setUpStashedBar()
+ getInstrumentation().runOnMainSync {
+ bubbleBarSwipeController.start()
+ bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH)
+ }
+ assertThat(bubbleBarSwipeController.isSwipeGesture()).isFalse()
+ }
+
+ @Test
+ fun swipeUp_stashedBar_aboveUnstashThreshold_unstashBubbleBar() {
+ setUpStashedBar()
+ getInstrumentation().runOnMainSync {
+ bubbleBarSwipeController.start()
+ bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH)
+ }
+ verify(bubbleStashController).showBubbleBar(expandBubbles = false)
+ }
+
+ @Test
+ fun swipeUp_stashedBar_overUnstashThreshold_isSwipeGestureTrue() {
+ setUpStashedBar()
+ getInstrumentation().runOnMainSync {
+ bubbleBarSwipeController.start()
+ bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH)
+ }
+ assertThat(bubbleBarSwipeController.isSwipeGesture()).isTrue()
+ }
+
+ @Test
+ fun swipeUp_stashedBar_overUnstashThresholdMultipleTimes_unstashBubbleBarOnce() {
+ setUpStashedBar()
+ getInstrumentation().runOnMainSync {
+ bubbleBarSwipeController.start()
+ bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH)
+ bubbleBarSwipeController.swipeTo(UP_BELOW_UNSTASH)
+ bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH)
+ }
+ verify(bubbleStashController).showBubbleBar(expandBubbles = false)
+ }
+
+ @Test
+ fun swipeUp_stashedBar_overExpandThreshold_doesNotExpandBeforeFinish() {
+ setUpStashedBar()
+ getInstrumentation().runOnMainSync {
+ bubbleBarSwipeController.start()
+ bubbleBarSwipeController.swipeTo(UP_ABOVE_EXPAND)
+ }
+ verify(bubbleStashController).showBubbleBar(expandBubbles = false)
+ getInstrumentation().runOnMainSync { bubbleBarSwipeController.finish() }
+ verify(bubbleStashController).showBubbleBar(expandBubbles = true)
+ }
+
+ @Test
+ fun swipeUp_stashedBar_overExpandThreshold_isSwipeGestureTrue() {
+ setUpStashedBar()
+ getInstrumentation().runOnMainSync {
+ bubbleBarSwipeController.start()
+ bubbleBarSwipeController.swipeTo(UP_ABOVE_EXPAND)
+ }
+ assertThat(bubbleBarSwipeController.isSwipeGesture()).isTrue()
+ }
+
+ @Test
+ fun swipeUp_stashedBar_overExpandThresholdAndBackDown_doesNotExpandAfterFinish() {
+ setUpStashedBar()
+ getInstrumentation().runOnMainSync {
+ bubbleBarSwipeController.start()
+ bubbleBarSwipeController.swipeTo(UP_ABOVE_EXPAND)
+ bubbleBarSwipeController.swipeTo(UP_ABOVE_UNSTASH)
+ }
+ verify(bubbleStashController).showBubbleBar(expandBubbles = false)
+ getInstrumentation().runOnMainSync { bubbleBarSwipeController.finish() }
+ verify(bubbleStashController).showBubbleBar(expandBubbles = false)
+ }
+
+ @Test
+ fun swipeUp_expandedBar_swipeIgnored() {
+ setUpExpandedBar()
+ getInstrumentation().runOnMainSync {
+ bubbleBarSwipeController.start()
+ bubbleBarSwipeController.swipeTo(UP_ABOVE_EXPAND)
+ bubbleBarSwipeController.swipeTo(DOWN_BELOW_UNSTASH)
+ bubbleBarSwipeController.finish()
+ }
+ verify(bubbleStashedHandleViewController, never()).setTranslationYForSwipe(any())
+ verify(bubbleBarViewController, never()).setTranslationYForSwipe(any())
+ verify(bubbleStashController, never()).showBubbleBar(any())
+ }
+
+ @Test
+ fun swipeDown_stashedBar_swipeIgnored() {
+ setUpStashedBar()
+ getInstrumentation().runOnMainSync {
+ bubbleBarSwipeController.start()
+ bubbleBarSwipeController.swipeTo(DOWN_BELOW_UNSTASH)
+ }
+ verify(bubbleStashedHandleViewController, never()).setTranslationYForSwipe(any())
+ verify(bubbleBarViewController, never()).setTranslationYForSwipe(any())
+ verify(bubbleStashController, never()).showBubbleBar(any())
+ }
+
+ private fun setUpStashedBar() {
+ whenever(bubbleStashController.isStashed).thenReturn(true)
+ whenever(bubbleStashController.isBubbleBarVisible()).thenReturn(false)
+ whenever(bubbleBarViewController.isExpanded).thenReturn(false)
+ }
+
+ private fun setUpCollapsedBar() {
+ whenever(bubbleStashController.isStashed).thenReturn(false)
+ whenever(bubbleStashController.isBubbleBarVisible()).thenReturn(true)
+ whenever(bubbleBarViewController.isExpanded).thenReturn(false)
+ }
+
+ private fun setUpExpandedBar() {
+ whenever(bubbleStashController.isStashed).thenReturn(false)
+ whenever(bubbleStashController.isBubbleBarVisible()).thenReturn(true)
+ whenever(bubbleBarViewController.isExpanded).thenReturn(true)
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
index 2a0aa4c..87a7cda 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java
@@ -41,11 +41,14 @@
import androidx.test.platform.app.InstrumentationRegistry;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherRootView;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.util.SystemUiController;
+import com.android.quickstep.fallback.window.RecentsWindowManager;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
@@ -62,16 +65,14 @@
import java.util.HashMap;
public abstract class AbsSwipeUpHandlerTestCase<
- RECENTS_CONTAINER extends Context & RecentsViewContainer,
- STATE extends BaseState<STATE>,
- RECENTS_VIEW extends RecentsView<RECENTS_CONTAINER, STATE>,
+ RECENTS_CONTAINER extends Context & RecentsViewContainer & StatefulContainer<STATE>,
+ STATE extends BaseState<STATE>, RECENTS_VIEW extends RecentsView<RECENTS_CONTAINER, STATE>,
ACTIVITY_TYPE extends StatefulActivity<STATE> & RecentsViewContainer,
ACTIVITY_INTERFACE extends BaseActivityInterface<STATE, ACTIVITY_TYPE>,
SWIPE_HANDLER extends AbsSwipeUpHandler<RECENTS_CONTAINER, RECENTS_VIEW, STATE>> {
protected final Context mContext =
InstrumentationRegistry.getInstrumentation().getTargetContext();
- protected final TaskAnimationManager mTaskAnimationManager = new TaskAnimationManager(mContext);
protected final RecentsAnimationDeviceState mRecentsAnimationDeviceState =
new RecentsAnimationDeviceState(mContext, true);
protected final InputConsumerController mInputConsumerController =
@@ -105,6 +106,9 @@
/* minimizedHomeBounds= */ null,
new Bundle());
+ protected RecentsWindowManager mRecentsWindowManager;
+ protected TaskAnimationManager mTaskAnimationManager;
+
@Mock protected ACTIVITY_INTERFACE mActivityInterface;
@Mock protected ActivityInitListener<?> mActivityInitListener;
@Mock protected RecentsAnimationController mRecentsAnimationController;
@@ -119,6 +123,16 @@
public final MockitoRule mMockitoRule = MockitoJUnit.rule();
@Before
+ public void setUpTaskAnimationManager() {
+ runOnMainSync(() -> {
+ if(Flags.enableFallbackOverviewInWindow()){
+ mRecentsWindowManager = new RecentsWindowManager(mContext);
+ }
+ mTaskAnimationManager = new TaskAnimationManager(mContext, mRecentsWindowManager);
+ });
+ }
+
+ @Before
public void setUpRunningTaskInfo() {
mRunningTaskInfo.baseIntent = new Intent(Intent.ACTION_MAIN)
.addCategory(Intent.CATEGORY_HOME)
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java
index dd0b4b3..8d6906f 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/FallbackSwipeHandlerTestCase.java
@@ -30,7 +30,7 @@
public class FallbackSwipeHandlerTestCase extends AbsSwipeUpHandlerTestCase<
RecentsActivity,
RecentsState,
- FallbackRecentsView,
+ FallbackRecentsView<RecentsActivity>,
RecentsActivity,
FallbackActivityInterface,
FallbackSwipeHandler> {
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
index 7c48ea4..0a60774 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
@@ -34,6 +34,7 @@
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_ENABLED
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_DISABLED
import com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY
+import com.android.launcher3.util.DaggerSingletonTracker
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -62,6 +63,7 @@
@Mock private lateinit var mMockLogger: StatsLogManager.StatsLogger
@Captor private lateinit var mEventCaptor: ArgumentCaptor<StatsLogManager.EventEnum>
+ @Mock private lateinit var mTracker: DaggerSingletonTracker
private var mDefaultThemedIcons = false
private var mDefaultAllowRotation = false
@@ -79,7 +81,7 @@
// To match the default value of ALLOW_ROTATION
LauncherPrefs.get(mContext).put(item = ALLOW_ROTATION, value = false)
- mSystemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager)
+ mSystemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager, mTracker)
}
@After
@@ -90,7 +92,7 @@
@Test
fun loggingPrefs_correctDefaultValue() {
- val systemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager)
+ val systemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager, mTracker)
assertThat(systemUnderTest.loggingPrefs[ALLOW_ROTATION_PREFERENCE_KEY]!!.defaultValue)
.isFalse()
@@ -117,7 +119,7 @@
LauncherPrefs.get(mContext).put(item = ALLOW_ROTATION, value = true)
// This a new object so the values of mLoggablePrefs will be different
- SettingsChangeLogger(mContext, mStatsLogManager).logSnapshot(mInstanceId)
+ SettingsChangeLogger(mContext, mStatsLogManager, mTracker).logSnapshot(mInstanceId)
verify(mMockLogger, atLeastOnce()).log(mEventCaptor.capture())
val capturedEvents = mEventCaptor.allValues
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
index f31467f..a87465f 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
@@ -20,6 +20,7 @@
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
+import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.launcher3.util.TestDispatcherProvider
import com.android.quickstep.task.thumbnail.TaskThumbnailViewModelTest
import com.android.quickstep.util.DesktopTask
@@ -36,17 +37,19 @@
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Test
+import org.junit.runner.RunWith
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
@OptIn(ExperimentalCoroutinesApi::class)
+@RunWith(AndroidJUnit4::class)
class TasksRepositoryTest {
private val tasks = (0..5).map(::createTaskWithId)
private val defaultTaskList =
listOf(
GroupTask(tasks[0]),
GroupTask(tasks[1], tasks[2], null),
- DesktopTask(tasks.subList(3, 6))
+ DesktopTask(tasks.subList(3, 6)),
)
private val recentsModel = FakeRecentTasksDataSource()
private val taskThumbnailDataSource = FakeTaskThumbnailDataSource()
@@ -65,7 +68,7 @@
taskIconDataSource,
taskVisualsChangedDelegate,
testScope.backgroundScope,
- TestDispatcherProvider(dispatcher)
+ TestDispatcherProvider(dispatcher),
)
@Test
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index fc4c4f6..936e996 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -22,7 +22,6 @@
import android.content.ComponentName
import android.content.Intent
import android.graphics.Rect
-import android.os.Handler
import android.os.UserHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.launcher3.LauncherState
@@ -40,7 +39,6 @@
import com.android.quickstep.views.RecentsViewContainer
import com.android.systemui.shared.recents.model.Task
import com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50
-import java.util.function.Consumer
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertNull
@@ -54,6 +52,7 @@
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
+import java.util.function.Consumer
@RunWith(AndroidJUnit4::class)
class SplitSelectStateControllerTest {
@@ -63,7 +62,6 @@
private val statsLogManager: StatsLogManager = mock()
private val statsLogger: StatsLogger = mock()
private val stateManager: StateManager<LauncherState, StatefulActivity<LauncherState>> = mock()
- private val handler: Handler = mock()
private val context: RecentsViewContainer = mock()
private val recentsModel: RecentsModel = mock()
private val pendingIntent: PendingIntent = mock()
@@ -87,7 +85,6 @@
splitSelectStateController =
SplitSelectStateController(
context,
- handler,
stateManager,
depthController,
statsLogManager,
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index 885a7f6..231c113 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -24,6 +24,7 @@
import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.launcher3.AbstractFloatingView
import com.android.launcher3.AbstractFloatingViewHelper
+import com.android.launcher3.Flags.enableRefactorTaskThumbnail
import com.android.launcher3.logging.StatsLogManager
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
import com.android.launcher3.model.data.WorkspaceItemInfo
@@ -31,6 +32,7 @@
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.launcher3.util.TransformingTouchDelegate
import com.android.quickstep.TaskOverlayFactory.TaskOverlay
+import com.android.quickstep.task.thumbnail.TaskThumbnailView
import com.android.quickstep.views.LauncherRecentsView
import com.android.quickstep.views.TaskContainer
import com.android.quickstep.views.TaskThumbnailViewDeprecated
@@ -67,7 +69,6 @@
private val taskView: TaskView = mock()
private val workspaceItemInfo: WorkspaceItemInfo = mock()
private val abstractFloatingViewHelper: AbstractFloatingViewHelper = mock()
- private val thumbnailViewDeprecated: TaskThumbnailViewDeprecated = mock()
private val iconView: TaskViewIcon = mock()
private val transformingTouchDelegate: TransformingTouchDelegate = mock()
private val factory: TaskShortcutFactory =
@@ -175,7 +176,7 @@
.moveTaskToDesktop(
eq(taskContainer),
eq(DesktopModeTransitionSource.APP_FROM_OVERVIEW),
- any()
+ any(),
)
verify(statsLogger).withItemInfo(workspaceItemInfo)
verify(statsLogger).log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DESKTOP_TAP)
@@ -188,16 +189,19 @@
}
private fun createTaskContainer(task: Task): TaskContainer {
+ val snapshotView =
+ if (enableRefactorTaskThumbnail()) mock<TaskThumbnailView>()
+ else mock<TaskThumbnailViewDeprecated>()
return TaskContainer(
taskView,
task,
- thumbnailViewDeprecated,
+ snapshotView,
iconView,
transformingTouchDelegate,
SplitConfigurationOptions.STAGE_POSITION_UNDEFINED,
digitalWellBeingToast = null,
showWindowsView = null,
- overlayFactory
+ overlayFactory,
)
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 113b8a4..5ff2af7 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -395,7 +395,6 @@
@Test
@NavigationModeSwitch
@PortraitLandscape
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/325659406
public void testQuickSwitchFromHome() throws Exception {
startTestActivity(2);
mLauncher.goHome().quickSwitchToPreviousApp();
diff --git a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
index 28c8a4a..ec07b93 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
@@ -29,6 +29,8 @@
import androidx.test.filters.SmallTest;
+import com.android.quickstep.fallback.window.RecentsWindowManager;
+
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
@@ -42,6 +44,9 @@
private Context mContext;
@Mock
+ private RecentsWindowManager mRecentsWindowManager;
+
+ @Mock
private SystemUiProxy mSystemUiProxy;
private TaskAnimationManager mTaskAnimationManager;
@@ -49,7 +54,7 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mTaskAnimationManager = new TaskAnimationManager(mContext) {
+ mTaskAnimationManager = new TaskAnimationManager(mContext, mRecentsWindowManager) {
@Override
SystemUiProxy getSystemUiProxy() {
return mSystemUiProxy;
diff --git a/res/drawable/desktop_mode_ic_taskbar_menu_new_window.xml b/res/drawable/desktop_mode_ic_taskbar_menu_new_window.xml
new file mode 100644
index 0000000..b96a596
--- /dev/null
+++ b/res/drawable/desktop_mode_ic_taskbar_menu_new_window.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="20dp"
+ android:height="20dp"
+ android:viewportWidth="20"
+ android:viewportHeight="20">
+ <path
+ android:pathData="M15 16V14H13V12.5H15V10.5H16.5V12.5H18.5V14H16.5V16H15ZM3.5 17C3.09722 17 2.74306 16.8542 2.4375 16.5625C2.14583 16.2569 2 15.9028 2 15.5V4.5C2 4.08333 2.14583 3.72917 2.4375 3.4375C2.74306 3.14583 3.09722 3 3.5 3H14.5C14.9167 3 15.2708 3.14583 15.5625 3.4375C15.8542 3.72917 16 4.08333 16 4.5V9H14.5V7H3.5V15.5H13.625V17H3.5ZM3.5 5.5H14.5V4.5H3.5V5.5ZM3.5 5.5V4.5V5.5Z"
+ android:fillColor="#1C1C14"/>
+</vector>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 490a7c2..4f62bda 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Verdeelde skerm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Programinligting vir %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Gebruikinstellings vir %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Stoor apppaar"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Hierdie apppaar word nie op hierdie toestel gesteun nie"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 7292eec..be91c0b 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"የተከፈለ ማያ ገፅ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"የመተግበሪያ መረጃ ለ%1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"የ%1$s የአጠቃቀም ቅንብሮች"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"የመተግበሪያ ጥምረትን ያስቀምጡ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ይህ የመተግበሪያ ጥምረት በዚህ መሣሪያ ላይ አይደገፍም"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 06fc0a8..04c2f2f 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"تقسيم الشاشة"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"معلومات تطبيق %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"إعدادات استخدام \"%1$s\""</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"حفظ استخدام التطبيقين معًا"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"لا يمكن استخدام هذين التطبيقَين في الوقت نفسه على هذا الجهاز"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index cd6e347..4d377c2 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"বিভাজিত স্ক্ৰীন"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$sৰ বাবে এপৰ তথ্য"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$sৰ বাবে ব্যৱহাৰৰ ছেটিং"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"এপৰ পেয়াৰ ছেভ কৰক"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"এই ডিভাইচটোত এই এপ্ পেয়াৰ কৰাৰ সুবিধাটো সমৰ্থিত নহয়"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index b8d660f..4c2ba9b 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ekran bölünməsi"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ilə bağlı tətbiq məlumatı"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s üzrə istifadə ayarları"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Tətbiq cütünü saxlayın"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Bu tətbiq cütü bu cihazda dəstəklənmir"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 4d4764e..35ba183 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podeljeni ekran"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji za: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Podešavanja potrošnje za %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Sačuvaj par aplikacija"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ovaj par aplikacija nije podržan na ovom uređaju"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 641509e..1a2bcc1 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Падзелены экран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Інфармацыя пра праграму для: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s: налады выкарыстання"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Захаваць спалучэнне праграм"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Дадзенае спалучэнне праграм не падтрымліваецца на гэтай прыладзе"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 3ce3c5f..270374d 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Разделен екран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Информация за приложението за %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Настройки за използването на %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Запазване на двойката приложения"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Тази двойка приложения не се поддържа на устройството"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 9b23590..5097784 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"স্প্লিট স্ক্রিন"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-এর জন্য অ্যাপ সম্পর্কিত তথ্য"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s-এর জন্য ব্যবহারের সেটিংস"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"অ্যাপ পেয়ার সেভ করুন"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"এই ডিভাইসে এই অ্যাপ পেয়ারটি কাজ করে না"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 4a34da7..e4bbd30 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podijeljeni ekran"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Postavke korištenja za: %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Sačuvaj par aplikacija"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Par aplikacija nije podržan na uređaju"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index c341ec7..77642f0 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informació de l\'aplicació %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Configuració d\'ús de %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Desa la parella d\'aplicacions"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Aquesta parella d\'aplicacions no s\'admet en aquest dispositiu"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index d3512c9..08747e0 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Rozdělit obrazovku"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informace o aplikaci %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Nastavení využití pro aplikaci %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Uložit dvojici aplikací"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Tento pár aplikací není na tomto zařízení podporován"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 8aae860..0bf8514 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Opdel skærm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinfo for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Indstillinger for brug af %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Gem appsammenknytning"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Denne appsammenknytning understøttes ikke på enheden"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 374f5a1..c3628ea 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Splitscreen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App-Info für %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Nutzungseinstellungen für %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"App-Paar speichern"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Dieses App-Paar wird auf diesem Gerät nicht unterstützt"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index cafe86e..85c6a31 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Διαχωρισμός οθόνης"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Πληροφορίες εφαρμογής για %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Ρυθμίσεις χρήσης για %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Αποθήκευση ζεύγους εφαρμογών"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Αυτό το ζεύγος εφαρμογών δεν υποστηρίζεται σε αυτή τη συσκευή"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 1b0722d..aee49be 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Usage settings for %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index de41d2c..8feccb0 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -31,6 +31,7 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Usage settings for %1$s"</string>
+ <string name="new_window_option_taskbar" msgid="6448780542727767211">"New Window"</string>
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 1b0722d..aee49be 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Usage settings for %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 1b0722d..aee49be 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Usage settings for %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index a856340..769567c 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -31,6 +31,7 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Usage settings for %1$s"</string>
+ <string name="new_window_option_taskbar" msgid="6448780542727767211">"New Window"</string>
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"This app pair isn\'t supported on this device"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index ba1b0af..e051843 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la app de %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Configuración del uso de %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Guardar vinculación"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"No se admite esta vinculación de apps en este dispositivo"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index ad12192..169afe5 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la aplicación %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Ajustes de uso para %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Guardar apps emparejadas"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"El dispositivo no admite esta aplicación emparejada"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 96d0b2c..844a0c7 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Jagatud ekraanikuva"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Rakenduse teave: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Kasutuse seaded: %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Salvesta rakendusepaar"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"See rakendusepaar ei ole selles seadmes toetatud"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index bc9b8c1..8c9375a 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantaila zatitzea"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s aplikazioari buruzko informazioa"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s aplikazioaren erabilera-ezarpenak"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Gorde aplikazio parea"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Aplikazio pare hori ez da onartzen gailu honetan"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index c167194..d841770 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"صفحهٔ دونیمه"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"اطلاعات برنامه %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"تنظیمات مصرف برای %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ذخیره جفت برنامه"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"از این جفت برنامه در این دستگاه پشتیبانی نمیشود"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 007d077..567a1ea 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Jaettu näyttö"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Sovellustiedot: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Käyttöasetus tälle: %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Tallenna sovelluspari"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Sovellusparia ei tueta tällä laitteella"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index c443505..a886420 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran divisé"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Renseignements sur l\'appli pour %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Paramètres d\'utilisation pour %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Enr. paire d\'applis"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applis n\'est pas prise en charge sur cet appareil"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 4f5d111..d96bd98 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran partagé"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Infos sur l\'appli pour %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Paramètres d\'utilisation pour %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Enregistrer une paire d\'applis"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applications n\'est pas prise en charge sur cet appareil"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index ff7c029..c224a19 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información da aplicación para %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Configuración de uso para %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Gardar parella de apps"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"O dispositivo non admite este emparellamento de aplicacións"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 872faef..732a8e4 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"સ્ક્રીનને વિભાજિત કરો"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s માટે ઍપ માહિતી"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$sના વપરાશ સંબંધિત સેટિંગ"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ઍપની જોડી સાચવો"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"આ ડિવાઇસ પર, આ ઍપની જોડીને સપોર્ટ આપવામાં આવતો નથી"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index a44b874..d4fb0ca 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रीन"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s के लिए ऐप्लिकेशन की जानकारी"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s के लिए खर्च की सेटिंग"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ऐप पेयर सेव करें"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"साथ में इस्तेमाल किए जा सकने वाले ये ऐप्लिकेशन, इस डिवाइस पर काम नहीं कर सकते"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index d9f2072..3d5380a 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podijeljeni zaslon"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Postavke upotrebe za %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Spremi par aplikacija"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Taj par aplikacija nije podržan na ovom uređaju"</string>
@@ -189,7 +191,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrirajte"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
- <string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite da biste postavili ili otvorili"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Dodirnite za postavljanje ili otvaranje"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
<string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privatno, otključano."</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 6bc8b70..1a38777 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Osztott képernyő"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Alkalmazásinformáció a következőhöz: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"A(z) %1$s használati beállításai"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Alkalmazáspár mentése"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ezt az alkalmazáspárt nem támogatja az eszköz"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 69b320d..eaaf435 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Տրոհել էկրանը"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Տեղեկություններ %1$s հավելվածի մասին"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Օգտագործման կարգավորումներ (%1$s)"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Պահել հավելվ. զույգը"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Հավելվածների զույգը չի աջակցվում այս սարքում"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 58a429f..62e9d9d 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Layar terpisah"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Info aplikasi untuk %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Setelan penggunaan untuk %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Simpan pasangan aplikasi"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Pasangan aplikasi ini tidak didukung di perangkat ini"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 95bd21f..7a87b26 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Skipta skjá"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Upplýsingar um forrit fyrir %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Notkunarstillingar fyrir %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Vista forritapar"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Þetta forritapar er ekki stutt í þessu tæki"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 3c01cd4..100da6c 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Schermo diviso"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informazioni sull\'app %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Impostazioni di utilizzo per %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Salva coppia di app"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Questa coppia di app non è supportata su questo dispositivo"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index f198166..f85e571 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"מסך מפוצל"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"פרטים על האפליקציה %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"הגדרות שימוש ב-%1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"שמירת צמד אפליקציות"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"צמד האפליקציות הזה לא נתמך במכשיר הזה"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index d2f9a97..cea0a08 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割画面"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s のアプリ情報"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s の使用設定"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"アプリのペア設定を保存"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"このデバイスは、このアプリのペア設定に対応していません"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index e67cc41..2211a7d 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ეკრანის გაყოფა"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-ის აპის ინფო"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"გამოყენების პარამეტრები %1$s-ისთვის"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"აპთა წყვილის შენახვა"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ამ მოწყობილობაზე აღნიშნული აპთა წყვილი არ არის მხარდაჭერილი"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index d5ccae5..ca26ea4 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Экранды бөлу"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s қолданбасы туралы ақпарат"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s пайдалану параметрлері"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Қолданбаларды жұптау әрекетін сақтау"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Бұл құрылғы қолданбаларды жұптау функциясын қолдамайды."</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 3c9135b..dc4fd80 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"មុខងារបំបែកអេក្រង់"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"ព័ត៌មានកម្មវិធីសម្រាប់ %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"ការកំណត់ការប្រើប្រាស់សម្រាប់ %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"រក្សាទុកគូកម្មវិធី"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"មិនអាចប្រើគូកម្មវិធីនេះនៅលើឧបករណ៍នេះបានទេ"</string>
@@ -117,7 +119,7 @@
<string name="folder_name_format_exact" msgid="8626242716117004803">"ថត៖ <xliff:g id="NAME">%1$s</xliff:g>, ធាតុ <xliff:g id="SIZE">%2$d</xliff:g>"</string>
<string name="folder_name_format_overflow" msgid="4270108890534995199">"ថត៖ <xliff:g id="NAME">%1$s</xliff:g>, ធាតុ <xliff:g id="SIZE">%2$d</xliff:g> ឬច្រើនជាងនេះ"</string>
<string name="app_pair_name_format" msgid="8134106404716224054">"គូកម្មវិធី៖ <xliff:g id="APP1">%1$s</xliff:g> និង <xliff:g id="APP2">%2$s</xliff:g>"</string>
- <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"ផ្ទាំងរូបភាព និងរចនាប័ទ្ម"</string>
+ <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"ផ្ទាំងរូបភាព និងរចនាបថ"</string>
<string name="edit_home_screen" msgid="8947858375782098427">"កែអេក្រង់ដើម"</string>
<string name="settings_button_text" msgid="8873672322605444408">"ការកំណត់ទំព័រដើម"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"បានបិទដំណើរការដោយអ្នកគ្រប់គ្រងរបស់អ្នក"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index ab84833..eda9fb8 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ಗಾಗಿ ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s ಗೆ ಸಂಬಂಧಿಸಿದ ಬಳಕೆಯ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ಆ್ಯಪ್ ಪೇರ್ ಸೇವ್ ಮಾಡಿ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ಈ ಆ್ಯಪ್ ಜೋಡಿಯು ಈ ಸಾಧನದಲ್ಲಿ ಬೆಂಬಲಿತವಾಗಿಲ್ಲ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 318cd00..94ebd15 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"화면 분할"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 앱 정보"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s의 사용량 설정"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"앱 페어링 저장"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"이 앱 페어링은 이 기기에서 지원되지 않습니다"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 856e2b2..b326181 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Экранды бөлүү"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s колдонмосу жөнүндө маалымат"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s колдонмосун пайдалануу параметрлери"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Колдонмолорду сактап коюу"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Бул эки колдонмону бул түзмөктө бир маалда пайдаланууга болбойт"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 3d1a6c9..741556a 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ແບ່ງໜ້າຈໍ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"ຂໍ້ມູນແອັບສຳລັບ %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"ການຕັ້ງຄ່າການນຳໃຊ້ສຳລັບ %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ບັນທຶກຈັບຄູ່ແອັບ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ການຈັບຄູ່ແອັບນີ້ບໍ່ຮອງຮັບຢູ່ອຸປະກອນນີ້"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 4c9bd9b..a613cb1 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Išskaidyto ekrano režimas"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Programos „%1$s“ informacija"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"„%1$s“ naudojimo nustatymai"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Išsaugoti programų porą"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ši programų pora šiame įrenginyje nepalaikoma"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 0a82705..de00e4d 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Sadalīt ekrānu"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s: informācija par lietotni"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Lietojuma iestatījumi: %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Saglabāt lietotņu pāri"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Šis lietotņu pāris netiek atbalstīts šajā ierīcē"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 887ca82..91b30c9 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Поделен екран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Податоци за апликација за %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Поставки за користење за %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Зачувај го парот апликации"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Паров апликации не е поддржан на уредов"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index dda5679..2eb1b2b 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"സ്ക്രീൻ വിഭജന മോഡ്"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s എന്നതിന്റെ ആപ്പ് വിവരങ്ങൾ"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s എന്നതിനുള്ള ഉപയോഗ ക്രമീകരണം"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ആപ്പ് ജോടി സംരക്ഷിക്കുക"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ഈ ഉപകരണത്തിൽ ഈ ആപ്പ് ജോടിക്ക് പിന്തുണയില്ല"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 49d71c2..bba7e16 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Дэлгэцийг хуваах"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-н аппын мэдээлэл"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s-н ашиглалтын тохиргоо"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Апп хослуулалтыг хадгалах"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Энэ апп хослуулалтыг уг төхөөрөмж дээр дэмждэггүй"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index fdf864a..548e764 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रीन"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s साठी ॲपशी संबंधित माहिती"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s साठी वापरासंबंधित सेटिंग्ज"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ॲपची जोडी सेव्ह करा"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"या ॲपची जोडीला या डिव्हाइसवर सपोर्ट नाही"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index b86f657..b548e67 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Skrin pisah"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Maklumat apl untuk %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Tetapan penggunaan sebanyak %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Simpan gandingan apl"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Gandingan apl ini tidak disokong pada peranti ini"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 7e8fd14..e94dd8e 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s အတွက် အက်ပ်အချက်အလက်"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s အတွက် အသုံးပြုမှုဆက်တင်များ"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"အက်ပ်တွဲချိတ်ခြင်း သိမ်းရန်"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ဤအက်ပ်တွဲချိတ်ခြင်းကို ဤစက်တွင် ပံ့ပိုးမထားပါ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index e2be4ff..38003eb 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Delt skjerm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformasjon for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Bruksinnstillinger for %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Lagre app-paret"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Denne apptilkoblingen støttes ikke på denne enheten"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index fa2e59b..93c4339 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रिन"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s का हकमा एपसम्बन्धी जानकारी"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s को प्रयोगसम्बन्धी सेटिङ"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"एपको पेयर सेभ गर्नुहोस्"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"यस डिभाइसमा यो एप पेयर प्रयोग गर्न मिल्दैन"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 9271b96..1c2bdc8 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Gesplitst scherm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App-info voor %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Gebruiksinstellingen voor %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"App-paar opslaan"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Dit app-paar wordt niet ondersteund op dit apparaat"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 98d52de..9a03926 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ସ୍କ୍ରିନକୁ ସ୍ପ୍ଲିଟ କରନ୍ତୁ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ପାଇଁ ଆପ ସୂଚନା"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s ପାଇଁ ବ୍ୟବହାର ସେଟିଂସ"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ଆପ ପେୟାର ସେଭ କରନ୍ତୁ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ଏହି ଆପ ପେୟାର ଏ ଡିଭାଇସରେ ସମର୍ଥିତ ନୁହେଁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 782979e..461513c 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ਲਈ ਐਪ ਜਾਣਕਾਰੀ"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s ਲਈ ਵਰਤੋਂ ਸੈਟਿੰਗਾਂ"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ਐਪ ਜੋੜਾਬੱਧ ਰੱਖਿਅਤ ਕਰੋ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ਇਸ ਐਪ ਜੋੜਾਬੱਧ ਦਾ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਮਰਥਨ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 71e569c..eeb9eb3 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podziel ekran"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacje o aplikacji: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s – ustawienia użycia"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Zapisz parę aplikacji"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ta para aplikacji nie jest obsługiwana na tym urządzeniu"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 1c44d9b..c86c58d 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ecrã dividido"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informações da app para %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Definições de utilização para %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Guardar par de apps"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Este par de apps não é suportado neste dispositivo"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 3f44591..f10b93a 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Tela dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informações do app %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Configurações de uso de %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Salvar par de apps"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Este Par de apps não está disponível no dispositivo"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index b37d93b..fbab69c 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ecran împărțit"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informații despre aplicație pentru %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Setări de utilizare pentru %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Salvează perechea de aplicații"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Perechea de aplicații nu este acceptată pe acest dispozitiv"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 321bf37..aea3d2b 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Разделить экран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Сведения о приложении \"%1$s\""</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Настройки использования приложения \"%1$s\""</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Сохранить приложения"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Одновременно использовать эти два приложения на устройстве нельзя."</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 91c818a..a3b9a71 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"බෙදුම් තිරය"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s සඳහා යෙදුම් තතු"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s සඳහා භාවිත සැකසීම්"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"යෙදුම් යුගල සුරකින්න"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"මෙම යෙදුම් යුගලය මෙම උපාංගයෙහි සහාය නොදක්වයි"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index eaae7c0..c3b3422 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Rozdeliť obrazovku"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informácie o aplikácii pre %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Nastavenia používania pre %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Uložiť pár aplikácií"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Tento pár aplikácií nie je v tomto zariadení podporovaný"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index dccf2f1..51b0c7b 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Razdeljen zaslon"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Podatki o aplikaciji za: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Nastavitve uporabe za »%1$s«"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Shrani par aplikacij"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ta par aplikacij ni podprt v tej napravi"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 84484e8..d3bfce6 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ekrani i ndarë"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacioni i aplikacionit për %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Cilësimet e përdorimit për \"%1$s\""</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Ruaj çiftin e aplikacioneve"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ky çift aplikacionesh nuk mbështetet në këtë pajisje"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 64383f2..c93519f 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Подељени екран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Информације о апликацији за: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Подешавања потрошње за %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Сачувај пар апликација"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Овај пар апликација није подржан на овом уређају"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 47aed86..c92d6f0 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Delad skärm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformation för %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Användningsinställningar för %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Spara app-par"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"De här apparna som ska användas tillsammans stöds inte på den här enheten"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 5eadd1d..7d2768b 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Gawa skrini"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Maelezo ya programu ya %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Mipangilio ya matumizi ya %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Hifadhi jozi ya programu"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Jozi hii ya programu haitumiki kwenye kifaa hiki"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index d84485a..2ae4c30 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"திரைப் பிரிப்பு"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$sக்கான ஆப்ஸ் தகவல்கள்"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$sக்கான உபயோக அமைப்புகள்"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ஆப்ஸ் ஜோடியைச் சேமி"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"இந்தச் சாதனத்தில் இந்த ஆப்ஸ் ஜோடி ஆதரிக்கப்படவில்லை"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 8487e96..5348a22 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"స్ప్లిట్ స్క్రీన్"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s కోసం యాప్ సమాచారం"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$sకు సంబంధించిన వినియోగ సెట్టింగ్లు"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"యాప్ పెయిర్ను సేవ్ చేయండి"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ఈ పరికరంలో ఈ యాప్ పెయిర్ సపోర్ట్ చేయదు"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 71f4d15..a6d3b7e 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"แยกหน้าจอ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"ข้อมูลแอปสำหรับ %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"การตั้งค่าการใช้งานสำหรับ %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"บันทึกคู่แอป"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ไม่รองรับคู่แอปนี้ในอุปกรณ์เครื่องนี้"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 7cf6a44..417962d 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Impormasyon ng app para sa %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Mga setting ng paggamit para sa %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"I-save ang app pair"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Hindi sinusuportahan sa device na ito ang pares ng app na ito"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index d55181c..0caa1f9 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Bölünmüş ekran"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s uygulama bilgileri"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s ile ilgili kullanım ayarları"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Uygulama çiftini kaydedin"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Bu uygulama çifti bu cihazda desteklenmiyor"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index b5c1c70..e980d22 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Розділити екран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Інформація про додаток для %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Параметри використання (%1$s)"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Зберегти пару додатків"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ці два додатки не можна одночасно використовувати на цьому пристрої"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 6fa76dd..4d59e17 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"اسپلٹ اسکرین"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s کے لیے ایپ کی معلومات"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s کیلئے استعمال کی ترتیبات"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"ایپس کے جوڑے کو محفوظ کریں"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ایپس کا یہ جوڑا اس آلے پر تعاون یافتہ نہیں ہے"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 21a8145..d2225c7 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ekranni ikkiga ajratish"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ilovasi axboroti"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s uchun sarf sozlamalari"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Ilova juftini saqlash"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Bu ilova jufti ushbu qurilmada ishlamaydi"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index b0bac73..4c14574 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Chia đôi màn hình"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Thông tin ứng dụng cho %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Chế độ cài đặt mức sử dụng %1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Lưu cặp ứng dụng"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cặp ứng dụng này không hoạt động được trên thiết bị này"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 112b945..92591fb 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分屏"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的应用信息"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s的使用设置"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"保存应用组合"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"在该设备上无法使用此应用对"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index e63093e..05f3320 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割螢幕"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的應用程式資料"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"「%1$s」的用量設定"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"儲存應用程式配對"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"此裝置不支援此應用程式配對"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 25f9703..6ee3e99 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割畫面"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"「%1$s」的應用程式資訊"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"「%1$s」的用量設定"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"儲存應用程式配對"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"這部裝置不支援這組應用程式配對"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index ec1f941..8d2e2f3 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -31,6 +31,8 @@
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Hlukanisa isikrini"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Ulwazi lwe-App ye-%1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Amasethingi okusetshenziswa ka-%1$s"</string>
+ <!-- no translation found for new_window_option_taskbar (6448780542727767211) -->
+ <skip />
<string name="save_app_pair" msgid="5647523853662686243">"Londoloza i-app ebhangqiwe"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Lokhu kubhanqwa kwe-app akusekelwa kule divayisi"</string>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index fd724a5..9d06021 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -45,6 +45,9 @@
<string name="split_app_info_accessibility">App info for %1$s</string>
<string name="split_app_usage_settings">Usage settings for %1$s</string>
+ <!-- Title for an option to open a new window for a given app -->
+ <string name="new_window_option_taskbar">New Window</string>
+
<!-- App pairs -->
<string name="save_app_pair">Save app pair</string>
<!-- App pair default title -->
diff --git a/src/com/android/launcher3/Alarm.java b/src/com/android/launcher3/Alarm.java
index fb8088c..e516ad0 100644
--- a/src/com/android/launcher3/Alarm.java
+++ b/src/com/android/launcher3/Alarm.java
@@ -20,6 +20,8 @@
import android.os.Looper;
import android.os.SystemClock;
+import androidx.annotation.VisibleForTesting;
+
public class Alarm implements Runnable{
// if we reach this time and the alarm hasn't been cancelled, call the listener
private long mAlarmTriggerTime;
@@ -96,4 +98,13 @@
public long getLastSetTimeout() {
return mLastSetTimeout;
}
+
+ /** Simulates the alarm firing for tests. */
+ @VisibleForTesting
+ public void finishAlarm() {
+ if (!mAlarmPending) return;
+ mAlarmPending = false;
+ mHandler.removeCallbacks(this);
+ mAlarmListener.onAlarm(this);
+ }
}
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index fec94fe..2e75261 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -188,7 +188,7 @@
public SystemUiController getSystemUiController() {
if (mSystemUiController == null) {
- mSystemUiController = new SystemUiController(getWindow());
+ mSystemUiController = new SystemUiController(getWindow().getDecorView());
}
return mSystemUiController;
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index cc5baea..483f5f8 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -1056,6 +1056,7 @@
return mHotseatColumnSpan;
}
+ @VisibleForTesting
public int getHotseatWidthPx() {
return mHotseatWidthPx;
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 0bc192d..b0ec9b0 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -448,12 +448,10 @@
.logStart(LAUNCHER_LATENCY_STARTUP_TOTAL_DURATION)
.logStart(LAUNCHER_LATENCY_STARTUP_ACTIVITY_ON_CREATE);
// Only use a hard-coded cookie since we only want to trace this once.
- if (Utilities.ATLEAST_S) {
- Trace.beginAsyncSection(
- DISPLAY_WORKSPACE_TRACE_METHOD_NAME, DISPLAY_WORKSPACE_TRACE_COOKIE);
- Trace.beginAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
- DISPLAY_ALL_APPS_TRACE_COOKIE);
- }
+ Trace.beginAsyncSection(
+ DISPLAY_WORKSPACE_TRACE_METHOD_NAME, DISPLAY_WORKSPACE_TRACE_COOKIE);
+ Trace.beginAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
+ DISPLAY_ALL_APPS_TRACE_COOKIE);
TraceHelper.INSTANCE.beginSection(ON_CREATE_EVT);
if (DEBUG_STRICT_MODE) {
StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
@@ -732,13 +730,6 @@
public void onEnterAnimationComplete() {
super.onEnterAnimationComplete();
mRotationHelper.setCurrentTransitionRequest(REQUEST_NONE);
- // Starting with Android S, onEnterAnimationComplete is sent immediately
- // causing the surface to get removed before the animation completed (b/175345344).
- // Instead we rely on next user touch event to remove the view and optionally a callback
- // from system from Android T onwards.
- if (!Utilities.ATLEAST_S) {
- AbstractFloatingView.closeOpenViews(this, false, TYPE_ICON_SURFACE);
- }
}
@Override
@@ -2579,10 +2570,8 @@
public void bindAllApplications(AppInfo[] apps, int flags,
Map<PackageUserKey, Integer> packageUserKeytoUidMap) {
mModelCallbacks.bindAllApplications(apps, flags, packageUserKeytoUidMap);
- if (Utilities.ATLEAST_S) {
- Trace.endAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
- DISPLAY_ALL_APPS_TRACE_COOKIE);
- }
+ Trace.endAsyncSection(DISPLAY_ALL_APPS_TRACE_METHOD_NAME,
+ DISPLAY_ALL_APPS_TRACE_COOKIE);
}
/**
diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java
index 490186a..4c82e56 100644
--- a/src/com/android/launcher3/LauncherApplication.java
+++ b/src/com/android/launcher3/LauncherApplication.java
@@ -18,6 +18,7 @@
import android.app.Application;
import com.android.launcher3.dagger.DaggerLauncherAppComponent;
+import com.android.launcher3.dagger.LauncherAppComponent;
import com.android.launcher3.dagger.LauncherBaseAppComponent;
/**
@@ -30,10 +31,18 @@
public void onCreate() {
super.onCreate();
MainProcessInitializer.initialize(this);
- mAppComponent = DaggerLauncherAppComponent.builder().appContext(this).build();
+ initDagger();
}
- public LauncherBaseAppComponent getAppComponent() {
- return mAppComponent;
+ public LauncherAppComponent getAppComponent() {
+ // Since supertype setters will return a supertype.builder and @Component.Builder types
+ // must not have any generic types.
+ // We need to cast mAppComponent to {@link LauncherAppComponent} since appContext()
+ // method is defined in the super class LauncherBaseComponent#Builder.
+ return (LauncherAppComponent) mAppComponent;
+ }
+
+ protected void initDagger() {
+ mAppComponent = DaggerLauncherAppComponent.builder().appContext(this).build();
}
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index ca1b2a9..7ad17d9 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -71,6 +71,7 @@
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.shortcuts.ShortcutRequest;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageManagerHelper;
@@ -446,8 +447,8 @@
IconCache iconCache = mApp.getIconCache();
final IntSet removedIds = new IntSet();
HashSet<WorkspaceItemInfo> archivedWorkspaceItemsToCacheRefresh = new HashSet<>();
- boolean isAppArchived = PackageManagerHelper.INSTANCE.get(mApp.getContext())
- .isAppArchivedForUser(packageName, user);
+ boolean isAppArchived =
+ new ApplicationInfoWrapper(mApp.getContext(), packageName, user).isArchived();
synchronized (dataModel) {
if (isAppArchived) {
// Remove package icon cache entry for archived app in case of a session
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 7176733..d645734 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -11,6 +11,7 @@
import com.android.launcher3.graphics.SysUiScrim;
import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.util.window.WindowManagerProxy;
import java.util.Collections;
@@ -20,7 +21,7 @@
private final Rect mTempRect = new Rect();
- private final StatefulActivity mActivity;
+ private final StatefulContainer mStatefulContainer;
@ViewDebug.ExportedProperty(category = "launcher")
private static final List<Rect> SYSTEM_GESTURE_EXCLUSION_RECT =
@@ -36,24 +37,25 @@
public LauncherRootView(Context context, AttributeSet attrs) {
super(context, attrs);
- mActivity = StatefulActivity.fromContext(context);
+ mStatefulContainer = StatefulContainer.fromContext(context);
mSysUiScrim = new SysUiScrim(this);
}
private void handleSystemWindowInsets(Rect insets) {
// Update device profile before notifying the children.
- mActivity.getDeviceProfile().updateInsets(insets);
+ mStatefulContainer.getDeviceProfile().updateInsets(insets);
boolean resetState = !insets.equals(mInsets);
setInsets(insets);
if (resetState) {
- mActivity.getStateManager().reapplyState(true /* cancelCurrentAnimation */);
+ mStatefulContainer.getStateManager().reapplyState(true /* cancelCurrentAnimation */);
}
}
@Override
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
- mActivity.handleConfigurationChanged(mActivity.getResources().getConfiguration());
+ mStatefulContainer.handleConfigurationChanged(
+ mStatefulContainer.getContext().getResources().getConfiguration());
insets = WindowManagerProxy.INSTANCE.get(getContext())
.normalizeWindowInsets(getContext(), insets, mTempRect);
@@ -72,7 +74,7 @@
}
public void dispatchInsets() {
- mActivity.getDeviceProfile().updateInsets(mInsets);
+ mStatefulContainer.getDeviceProfile().updateInsets(mInsets);
super.setInsets(mInsets);
}
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index d57f8a0..496d517 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -61,7 +61,7 @@
AbstractFloatingView.closeOpenViews(
launcher,
true,
- AbstractFloatingView.TYPE_ALL and AbstractFloatingView.TYPE_REBIND_SAFE.inv()
+ AbstractFloatingView.TYPE_ALL and AbstractFloatingView.TYPE_REBIND_SAFE.inv(),
)
workspaceLoading = true
@@ -76,7 +76,7 @@
TAG,
"startBinding: " +
"hotseat layout was vertical: ${launcher.hotseat?.isHasVerticalHotseat}" +
- " and is setting to ${launcher.deviceProfile.isVerticalBarLayout}"
+ " and is setting to ${launcher.deviceProfile.isVerticalBarLayout}",
)
launcher.hotseat?.resetLayout(launcher.deviceProfile.isVerticalBarLayout)
TraceHelper.INSTANCE.endSection()
@@ -88,14 +88,12 @@
pendingTasks: RunnableList,
onCompleteSignal: RunnableList,
workspaceItemCount: Int,
- isBindSync: Boolean
+ isBindSync: Boolean,
) {
- if (Utilities.ATLEAST_S) {
- Trace.endAsyncSection(
- TraceEvents.DISPLAY_WORKSPACE_TRACE_METHOD_NAME,
- TraceEvents.DISPLAY_WORKSPACE_TRACE_COOKIE
- )
- }
+ Trace.endAsyncSection(
+ TraceEvents.DISPLAY_WORKSPACE_TRACE_METHOD_NAME,
+ TraceEvents.DISPLAY_WORKSPACE_TRACE_COOKIE,
+ )
synchronouslyBoundPages = boundPages
pagesToBindSynchronously = LIntSet()
clearPendingBinds()
@@ -149,14 +147,14 @@
// Cache one page worth of icons
launcher.viewCache.setCacheSize(
R.layout.folder_application,
- deviceProfile.numFolderColumns * deviceProfile.numFolderRows
+ deviceProfile.numFolderColumns * deviceProfile.numFolderRows,
)
launcher.viewCache.setCacheSize(R.layout.folder_page, 2)
TraceHelper.INSTANCE.endSection()
launcher.workspace.removeExtraEmptyScreen(/* stripEmptyScreens= */ true)
launcher.workspace.pageIndicator.setPauseScroll(
/*pause=*/ false,
- deviceProfile.isTwoPanels
+ deviceProfile.isTwoPanels,
)
TestEventEmitter.INSTANCE.get(launcher).sendEvent(TestEvent.WORKSPACE_FINISH_LOADING)
}
@@ -182,7 +180,7 @@
val snackbar =
AbstractFloatingView.getOpenView<AbstractFloatingView>(
launcher,
- AbstractFloatingView.TYPE_SNACKBAR
+ AbstractFloatingView.TYPE_SNACKBAR,
)
snackbar?.post { snackbar.close(true) }
}
@@ -191,7 +189,7 @@
override fun bindAllApplications(
apps: Array<AppInfo?>?,
flags: Int,
- packageUserKeytoUidMap: Map<PackageUserKey?, Int?>?
+ packageUserKeytoUidMap: Map<PackageUserKey?, Int?>?,
) {
Preconditions.assertUIThread()
val hadWorkApps = launcher.appsView.shouldShowTabs()
@@ -312,7 +310,7 @@
val info =
PendingAddWidgetInfo(
widgetsListBaseEntry.mWidgets[0].widgetInfo,
- LauncherSettings.Favorites.CONTAINER_DESKTOP
+ LauncherSettings.Favorites.CONTAINER_DESKTOP,
)
launcher.addPendingItem(
info,
@@ -320,14 +318,14 @@
WorkspaceLayoutManager.FIRST_SCREEN_ID,
intArrayOf(0, 0),
info.spanX,
- info.spanY
+ info.spanY,
)
}
override fun bindScreens(orderedScreenIds: LIntArray) {
launcher.workspace.pageIndicator.setPauseScroll(
/*pause=*/ true,
- launcher.deviceProfile.isTwoPanels
+ launcher.deviceProfile.isTwoPanels,
)
val firstScreenPosition = 0
if (
@@ -354,7 +352,7 @@
override fun bindAppsAdded(
newScreens: LIntArray?,
addNotAnimated: java.util.ArrayList<ItemInfo?>?,
- addAnimated: java.util.ArrayList<ItemInfo?>?
+ addAnimated: java.util.ArrayList<ItemInfo?>?,
) {
// Add the new screens
if (newScreens != null) {
diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java
index 8d1e61f..b3cb948 100644
--- a/src/com/android/launcher3/SecondaryDropTarget.java
+++ b/src/com/android/launcher3/SecondaryDropTarget.java
@@ -22,7 +22,6 @@
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.UserHandle;
@@ -44,7 +43,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import java.net.URISyntaxException;
@@ -342,9 +341,8 @@
}
public void onLauncherResume() {
- // We use MATCH_UNINSTALLED_PACKAGES as the app can be on SD card as well.
- if (PackageManagerHelper.INSTANCE.get(mContext).getApplicationInfo(mPackageName,
- mDragObject.dragInfo.user, PackageManager.MATCH_UNINSTALLED_PACKAGES) == null) {
+ if (new ApplicationInfoWrapper(mContext, mPackageName, mDragObject.dragInfo.user)
+ .getInfo() == null) {
mDragObject.dragSource = mOriginal;
mOriginal.onDropCompleted(SecondaryDropTarget.this, mDragObject, true);
mStatsLogManager.logger().withInstanceId(mDragObject.logInstanceId)
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index fde7014..f8ac48a 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -122,9 +122,6 @@
public static final String[] EMPTY_STRING_ARRAY = new String[0];
public static final Person[] EMPTY_PERSON_ARRAY = new Person[0];
- @ChecksSdkIntAtLeast(api = VERSION_CODES.S)
- public static final boolean ATLEAST_S = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;
-
@ChecksSdkIntAtLeast(api = VERSION_CODES.TIRAMISU, codename = "T")
public static final boolean ATLEAST_T = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU;
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index 1a59d82..0a50e8b 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -18,6 +18,8 @@
import android.content.Context;
+import com.android.launcher3.util.DaggerSingletonTracker;
+
import dagger.BindsInstance;
/**
@@ -29,6 +31,7 @@
* See {@link LauncherAppComponent} for the one actually used by AOSP.
*/
public interface LauncherBaseAppComponent {
+ DaggerSingletonTracker getDaggerSingletonTracker();
/** Builder for LauncherBaseAppComponent. */
interface Builder {
@BindsInstance Builder appContext(@ApplicationContext Context context);
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 85eb39b..a3cfe5c 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -68,7 +68,7 @@
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.pm.PinRequestHelper;
import com.android.launcher3.util.ApiWrapper;
-import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.views.AbstractSlideInView;
import com.android.launcher3.views.BaseDragLayer;
@@ -164,8 +164,8 @@
finish();
return;
}
- ApplicationInfo info = PackageManagerHelper.INSTANCE.get(this)
- .getApplicationInfo(targetApp.packageName, targetApp.user, 0);
+ ApplicationInfo info = new ApplicationInfoWrapper(
+ this, targetApp.packageName, targetApp.user).getInfo();
if (info == null) {
finish();
return;
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 8b1f42b..a24f3ff 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -121,7 +121,7 @@
@Override
public void recreateControllers() {
- mControllers = mActivity.createTouchControllers();
+ mControllers = mContainer.createTouchControllers();
}
public ViewGroupFocusHelper getFocusIndicatorHelper() {
@@ -134,15 +134,15 @@
}
private boolean isEventOverAccessibleDropTargetBar(MotionEvent ev) {
- return isInAccessibleDrag() && isEventOverView(mActivity.getDropTargetBar(), ev);
+ return isInAccessibleDrag() && isEventOverView(mContainer.getDropTargetBar(), ev);
}
@Override
public boolean onInterceptHoverEvent(MotionEvent ev) {
- if (mActivity == null || mActivity.getWorkspace() == null) {
+ if (mContainer == null || mContainer.getWorkspace() == null) {
return false;
}
- AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
+ AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mContainer);
if (!(topView instanceof Folder)) {
return false;
} else {
@@ -197,7 +197,7 @@
private boolean isInAccessibleDrag() {
- return mActivity.getAccessibilityDelegate().isInAccessibleDrag();
+ return mContainer.getAccessibilityDelegate().isInAccessibleDrag();
}
@Override
@@ -210,12 +210,12 @@
@Override
public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
- View topView = AbstractFloatingView.getTopOpenViewWithType(mActivity,
+ View topView = AbstractFloatingView.getTopOpenViewWithType(mContainer,
AbstractFloatingView.TYPE_ACCESSIBLE);
if (topView != null) {
addAccessibleChildToList(topView, childrenForAccessibility);
if (isInAccessibleDrag()) {
- addAccessibleChildToList(mActivity.getDropTargetBar(), childrenForAccessibility);
+ addAccessibleChildToList(mContainer.getDropTargetBar(), childrenForAccessibility);
}
} else {
super.addChildrenForAccessibility(childrenForAccessibility);
@@ -420,14 +420,14 @@
public void onViewAdded(View child) {
super.onViewAdded(child);
updateChildIndices();
- mActivity.onDragLayerHierarchyChanged();
+ mContainer.onDragLayerHierarchyChanged();
}
@Override
public void onViewRemoved(View child) {
super.onViewRemoved(child);
updateChildIndices();
- mActivity.onDragLayerHierarchyChanged();
+ mContainer.onDragLayerHierarchyChanged();
}
@Override
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 4af9e2f..40c0cc6 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -69,7 +69,6 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.Workspace;
import com.android.launcher3.WorkspaceLayoutManager;
import com.android.launcher3.apppairs.AppPairIcon;
@@ -207,15 +206,12 @@
mWorkspaceScreens.put(Workspace.SECOND_SCREEN_ID, rightPanel);
}
- if (Utilities.ATLEAST_S) {
- WallpaperColors wallpaperColors = wallpaperColorsOverride != null
- ? wallpaperColorsOverride
- : WallpaperManager.getInstance(context).getWallpaperColors(FLAG_SYSTEM);
- mWallpaperColorResources = wallpaperColors != null ? LocalColorExtractor.newInstance(
- context).generateColorsOverride(wallpaperColors) : null;
- } else {
- mWallpaperColorResources = null;
- }
+ WallpaperColors wallpaperColors = wallpaperColorsOverride != null
+ ? wallpaperColorsOverride
+ : WallpaperManager.getInstance(context).getWallpaperColors(FLAG_SYSTEM);
+ mWallpaperColorResources = wallpaperColors != null
+ ? LocalColorExtractor.newInstance(context).generateColorsOverride(wallpaperColors)
+ : null;
mAppWidgetHost = new LauncherPreviewAppWidgetHost(context);
}
diff --git a/src/com/android/launcher3/graphics/SysUiScrim.java b/src/com/android/launcher3/graphics/SysUiScrim.java
index 077ddfc..d59fc19 100644
--- a/src/com/android/launcher3/graphics/SysUiScrim.java
+++ b/src/com/android/launcher3/graphics/SysUiScrim.java
@@ -32,10 +32,10 @@
import androidx.annotation.ColorInt;
import androidx.annotation.VisibleForTesting;
-import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.util.ScreenOnTracker;
import com.android.launcher3.util.ScreenOnTracker.ScreenOnListener;
@@ -84,7 +84,7 @@
private final int mBottomMaskHeight;
private final View mRoot;
- private final BaseDraggingActivity mActivity;
+ private final StatefulContainer mContainer;
private final boolean mHideSysUiScrim;
private boolean mSkipScrimAnimationForTest = false;
@@ -94,8 +94,8 @@
public SysUiScrim(View view) {
mRoot = view;
- mActivity = BaseDraggingActivity.fromContext(view.getContext());
- DisplayMetrics dm = mActivity.getResources().getDisplayMetrics();
+ mContainer = StatefulContainer.fromContext(view.getContext());
+ DisplayMetrics dm = mContainer.getContext().getResources().getDisplayMetrics();
mTopMaskHeight = ResourceUtils.pxFromDp(TOP_MASK_HEIGHT_DP, dm);
mBottomMaskHeight = ResourceUtils.pxFromDp(BOTTOM_MASK_HEIGHT_DP, dm);
@@ -130,7 +130,7 @@
ObjectAnimator oa = mSysUiAnimMultiplier.animateToValue(1);
oa.setDuration(600);
- oa.setStartDelay(mActivity.getWindow().getTransitionBackgroundFadeDuration());
+ oa.setStartDelay(mContainer.getWindow().getTransitionBackgroundFadeDuration());
oa.start();
mAnimateScrimOnNextDraw = false;
}
@@ -166,19 +166,19 @@
* horizontal
*/
public void onInsetsChanged(Rect insets) {
- DeviceProfile dp = mActivity.getDeviceProfile();
+ DeviceProfile dp = mContainer.getDeviceProfile();
mDrawTopScrim = insets.top > 0;
mDrawBottomScrim = !dp.isVerticalBarLayout() && !dp.isGestureMode && !dp.isTaskbarPresent;
}
@Override
public void onViewAttachedToWindow(View view) {
- ScreenOnTracker.INSTANCE.get(mActivity).addListener(mScreenOnListener);
+ ScreenOnTracker.INSTANCE.get(mContainer.getContext()).addListener(mScreenOnListener);
}
@Override
public void onViewDetachedFromWindow(View view) {
- ScreenOnTracker.INSTANCE.get(mActivity).removeListener(mScreenOnListener);
+ ScreenOnTracker.INSTANCE.get(mContainer.getContext()).removeListener(mScreenOnListener);
}
/**
@@ -213,7 +213,7 @@
}
private Bitmap createDitheredAlphaMask(int height, @ColorInt int[] colors, float[] positions) {
- DisplayMetrics dm = mActivity.getResources().getDisplayMetrics();
+ DisplayMetrics dm = mContainer.getContext().getResources().getDisplayMetrics();
int width = ResourceUtils.pxFromDp(ALPHA_MASK_BITMAP_WIDTH_DP, dm);
Bitmap dst = Bitmap.createBitmap(width, height, Bitmap.Config.ALPHA_8);
Canvas c = new Canvas(dst);
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 427fb97..55bcb70 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -41,6 +41,7 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.pm.PackageInstallInfo;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.PackageManagerHelper;
@@ -103,8 +104,8 @@
}
// b/139663018 Short-circuit this logic if the icon is a system app
- if (PackageManagerHelper.isSystemApp(context,
- Objects.requireNonNull(item.getIntent()))) {
+ if (new ApplicationInfoWrapper(context,
+ Objects.requireNonNull(item.getIntent())).isSystem()) {
continue;
}
diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java
index 1f60f13..7bc9273 100644
--- a/src/com/android/launcher3/model/AllAppsList.java
+++ b/src/com/android/launcher3/model/AllAppsList.java
@@ -40,6 +40,7 @@
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.ApiWrapper;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.SafeCloseable;
@@ -169,8 +170,8 @@
public AppInfo addPromiseApp(
Context context, PackageInstallInfo installInfo, boolean loadIcon) {
// only if not yet installed
- if (PackageManagerHelper.INSTANCE.get(context)
- .isAppInstalled(installInfo.packageName, installInfo.user)) {
+ if (new ApplicationInfoWrapper(context, installInfo.packageName, installInfo.user)
+ .isInstalled()) {
return null;
}
AppInfo promiseAppInfo = new AppInfo(installInfo);
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index 62ab4a4..4c017e9 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -29,8 +29,6 @@
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
@@ -48,7 +46,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.ItemInfo;
-import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.GridOccupancy;
@@ -101,7 +98,7 @@
@VisibleForTesting
public static List<DbEntry> readAllEntries(SQLiteDatabase db, String tableName,
Context context) {
- DbReader dbReader = new DbReader(db, tableName, context, getValidPackages(context));
+ DbReader dbReader = new DbReader(db, tableName, context);
List<DbEntry> result = dbReader.loadAllWorkspaceEntries();
result.addAll(dbReader.loadHotseatEntries());
return result;
@@ -146,11 +143,10 @@
}
copyTable(source, TABLE_NAME, target.getWritableDatabase(), TMP_TABLE, context);
- HashSet<String> validPackages = getValidPackages(context);
long migrationStartTime = System.currentTimeMillis();
try (SQLiteTransaction t = new SQLiteTransaction(target.getWritableDatabase())) {
- DbReader srcReader = new DbReader(t.getDb(), TMP_TABLE, context, validPackages);
- DbReader destReader = new DbReader(t.getDb(), TABLE_NAME, context, validPackages);
+ DbReader srcReader = new DbReader(t.getDb(), TMP_TABLE, context);
+ DbReader destReader = new DbReader(t.getDb(), TABLE_NAME, context);
Point targetSize = new Point(destDeviceState.getColumns(), destDeviceState.getRows());
migrate(target, srcReader, destReader, destDeviceState.getNumHotseat(),
@@ -350,23 +346,6 @@
Utilities.createDbSelectionQuery(LauncherSettings.Favorites._ID, entryIds), null);
}
- private static HashSet<String> getValidPackages(Context context) {
- // Initialize list of valid packages. This contain all the packages which are already on
- // the device and packages which are being installed. Any item which doesn't belong to
- // this set is removed.
- // Since the loader removes such items anyway, removing these items here doesn't cause
- // any extra data loss and gives us more free space on the grid for better migration.
- HashSet<String> validPackages = new HashSet<>();
- for (PackageInfo info : context.getPackageManager()
- .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES)) {
- validPackages.add(info.packageName);
- }
- InstallSessionHelper.INSTANCE.get(context)
- .getActiveSessions().keySet()
- .forEach(packageUserKey -> validPackages.add(packageUserKey.mPackageName));
- return validPackages;
- }
-
private static void solveGridPlacement(@NonNull final DatabaseHelper helper,
@NonNull final DbReader srcReader, @NonNull final DbReader destReader,
final int screenId, final int trgX, final int trgY,
@@ -463,18 +442,15 @@
private final SQLiteDatabase mDb;
private final String mTableName;
private final Context mContext;
- private final Set<String> mValidPackages;
private int mLastScreenId = -1;
private final Map<Integer, ArrayList<DbEntry>> mWorkspaceEntriesByScreenId =
new ArrayMap<>();
- public DbReader(SQLiteDatabase db, String tableName, Context context,
- Set<String> validPackages) {
+ public DbReader(SQLiteDatabase db, String tableName, Context context) {
mDb = db;
mTableName = tableName;
mContext = context;
- mValidPackages = validPackages;
}
protected List<DbEntry> loadHotseatEntries() {
@@ -506,7 +482,6 @@
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: {
entry.mIntent = c.getString(indexIntent);
- verifyIntent(c.getString(indexIntent));
break;
}
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER: {
@@ -588,14 +563,12 @@
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION: {
entry.mIntent = c.getString(indexIntent);
- verifyIntent(entry.mIntent);
break;
}
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: {
entry.mProvider = c.getString(indexAppWidgetProvider);
entry.appWidgetId = c.getInt(indexAppWidgetId);
ComponentName cn = ComponentName.unflattenFromString(entry.mProvider);
- verifyPackage(cn.getPackageName());
LauncherAppWidgetProviderInfo pInfo = widgetManagerHelper
.getLauncherAppWidgetInfo(entry.appWidgetId, cn);
@@ -658,7 +631,6 @@
try {
int id = c.getInt(0);
String intent = c.getString(1);
- verifyIntent(intent);
total++;
if (!entry.mFolderItems.containsKey(intent)) {
entry.mFolderItems.put(intent, new HashSet<>());
@@ -675,27 +647,6 @@
private Cursor queryWorkspace(String[] columns, String where) {
return mDb.query(mTableName, columns, where, null, null, null, null);
}
-
- /** Verifies if the mIntent should be restored. */
- private void verifyIntent(String intentStr)
- throws Exception {
- Intent intent = Intent.parseUri(intentStr, 0);
- if (intent.getComponent() != null) {
- verifyPackage(intent.getComponent().getPackageName());
- } else if (intent.getPackage() != null) {
- // Only verify package if the component was null.
- verifyPackage(intent.getPackage());
- }
- }
-
- /** Verifies if the package should be restored */
- private void verifyPackage(String packageName)
- throws Exception {
- if (!mValidPackages.contains(packageName)) {
- // TODO(b/151468819): Handle promise app icon restoration during grid migration.
- throw new Exception("Package not available");
- }
- }
}
public static class DbEntry extends ItemInfo implements Comparable<DbEntry> {
diff --git a/src/com/android/launcher3/model/SdCardAvailableReceiver.java b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
index 5293316..9e3f0e1 100644
--- a/src/com/android/launcher3/model/SdCardAvailableReceiver.java
+++ b/src/com/android/launcher3/model/SdCardAvailableReceiver.java
@@ -24,7 +24,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
-import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
@@ -52,7 +52,6 @@
@Override
public void onReceive(Context context, Intent intent) {
final LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
- final PackageManagerHelper pmHelper = PackageManagerHelper.INSTANCE.get(context);
for (PackageUserKey puk : mPackages) {
UserHandle user = puk.mUser;
@@ -60,7 +59,7 @@
final ArrayList<String> packagesUnavailable = new ArrayList<>();
if (!launcherApps.isPackageEnabled(puk.mPackageName, user)) {
- if (pmHelper.isAppOnSdcard(puk.mPackageName, user)) {
+ if (new ApplicationInfoWrapper(context, puk.mPackageName, user).isOnSdCard()) {
packagesUnavailable.add(puk.mPackageName);
} else {
packagesRemoved.add(puk.mPackageName);
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 1916d23..55c4d30 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -27,8 +27,8 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.shortcuts.ShortcutRequest;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.ItemInfoMatcher;
-import com.android.launcher3.util.PackageManagerHelper;
import java.util.ArrayList;
import java.util.HashSet;
@@ -80,11 +80,10 @@
if (!matchingWorkspaceItems.isEmpty()) {
if (mShortcuts.isEmpty()) {
- PackageManagerHelper packageManagerHelper =
- PackageManagerHelper.INSTANCE.get(context);
+ ApplicationInfoWrapper infoWrapper =
+ new ApplicationInfoWrapper(context, mPackageName, mUser);
// Verify that the app is indeed installed.
- if (!packageManagerHelper.isAppInstalled(mPackageName, mUser)
- && !packageManagerHelper.isAppArchivedForUser(mPackageName, mUser)) {
+ if (!infoWrapper.isInstalled() && !infoWrapper.isArchived()) {
// App is not installed or archived, ignoring package events
return;
}
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index 3f88717..ac9f2d6 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -4,8 +4,6 @@
import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX;
-import static com.android.launcher3.Utilities.ATLEAST_S;
-
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ActivityInfo;
@@ -48,7 +46,7 @@
super(info.provider, info.getProfile());
label = iconCache.getTitleNoCache(info);
- description = ATLEAST_S ? info.loadDescription(context) : null;
+ description = info.loadDescription(context);
widgetInfo = info;
activityInfo = null;
@@ -107,7 +105,7 @@
/** Returns whether this {@link WidgetItem} has a preview layout that can be used. */
@SuppressLint("NewApi") // Already added API check.
public boolean hasPreviewLayout() {
- return ATLEAST_S && widgetInfo != null && widgetInfo.previewLayout != Resources.ID_NULL;
+ return widgetInfo != null && widgetInfo.previewLayout != Resources.ID_NULL;
}
/** Returns whether this {@link WidgetItem} is for a shortcut rather than an app widget. */
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
index 90e47d6..18c7f95 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -30,7 +30,6 @@
import com.android.launcher3.InvariantDeviceProfile
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherSettings.Favorites
-import com.android.launcher3.Utilities
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError
import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.logging.FileLog
@@ -45,6 +44,7 @@
import com.android.launcher3.pm.UserCache
import com.android.launcher3.shortcuts.ShortcutKey
import com.android.launcher3.util.ApiWrapper
+import com.android.launcher3.util.ApplicationInfoWrapper
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.PackageManagerHelper
import com.android.launcher3.util.PackageUserKey
@@ -76,7 +76,7 @@
private val pmHelper: PackageManagerHelper,
private val iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>>,
private val unlockedUsers: LongSparseArray<Boolean>,
- private val allDeepShortcuts: MutableList<ShortcutInfo>
+ private val allDeepShortcuts: MutableList<ShortcutInfo>,
) {
private val isSafeMode = app.isSafeModeEnabled
@@ -97,7 +97,7 @@
// User has been deleted, remove the item.
c.markDeleted(
"User has been deleted for item id=${c.id}",
- RestoreError.PROFILE_DELETED
+ RestoreError.PROFILE_DELETED,
)
return
}
@@ -153,6 +153,7 @@
c.markDeleted("No target package for item id=${c.id}", RestoreError.MISSING_INFO)
return
}
+ val appInfoWrapper = ApplicationInfoWrapper(app.context, targetPkg, c.user)
var validTarget = launcherApps.isPackageEnabled(targetPkg, c.user)
// If it's a deep shortcut, we'll use pinned shortcuts to restore it
@@ -168,7 +169,7 @@
FileLog.d(
TAG,
"Activity not enabled for id=${c.id}, component=$cn, user=${c.user}." +
- " Will attempt to find fallback Activity for targetPkg=$targetPkg."
+ " Will attempt to find fallback Activity for targetPkg=$targetPkg.",
)
intent = pmHelper.getAppLaunchIntent(targetPkg, c.user)
if (intent != null) {
@@ -178,7 +179,7 @@
c.markDeleted(
"No Activities found for id=${c.id}, targetPkg=$targetPkg, component=$cn." +
" Unable to create launch Intent.",
- RestoreError.MISSING_INFO
+ RestoreError.MISSING_INFO,
)
return
}
@@ -213,13 +214,13 @@
else -> {
c.markDeleted(
"removing app that is not restored and not installing. package: $targetPkg",
- RestoreError.APP_NOT_INSTALLED
+ RestoreError.APP_NOT_INSTALLED,
)
return
}
}
}
- pmHelper.isAppOnSdcard(targetPkg, c.user) -> {
+ appInfoWrapper.isOnSdCard() -> {
// Package is present but not available.
disabledState =
disabledState or WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE
@@ -238,7 +239,7 @@
// Do not wait for external media load anymore.
c.markDeleted(
"Invalid package removed: $targetPkg",
- RestoreError.APP_NOT_INSTALLED
+ RestoreError.APP_NOT_INSTALLED,
)
return
}
@@ -270,7 +271,7 @@
// The shortcut is no longer valid.
c.markDeleted(
"Pinned shortcut not found from request. package=${key.packageName}, user=${c.user}",
- RestoreError.SHORTCUT_NOT_FOUND
+ RestoreError.SHORTCUT_NOT_FOUND,
)
return
}
@@ -278,7 +279,7 @@
// If the pinned deep shortcut is no longer published,
// use the last saved icon instead of the default.
iconCache.getShortcutIcon(info, pinnedShortcut, c::loadIcon)
- if (pmHelper.isAppSuspended(pinnedShortcut.getPackage(), info.user)) {
+ if (appInfoWrapper.isSuspended()) {
info.runtimeStatusFlags =
info.runtimeStatusFlags or ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED
}
@@ -295,7 +296,7 @@
info = c.loadSimpleWorkspaceItem()
// Shortcuts are only available on the primary profile
- if (!TextUtils.isEmpty(targetPkg) && pmHelper.isAppSuspended(targetPkg, c.user)) {
+ if (appInfoWrapper.isSuspended()) {
disabledState = disabledState or ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED
}
info.options = c.options
@@ -326,7 +327,7 @@
info.spanX = 1
info.spanY = 1
info.runtimeStatusFlags = info.runtimeStatusFlags or disabledState
- if (isSafeMode && !PackageManagerHelper.isSystemApp(app.context, intent)) {
+ if (isSafeMode && !appInfoWrapper.isSystem()) {
info.runtimeStatusFlags =
info.runtimeStatusFlags or ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE
}
@@ -337,7 +338,7 @@
activityInfo,
userCache.getUserInfo(c.user),
ApiWrapper.INSTANCE[app.context],
- pmHelper
+ pmHelper,
)
}
if (
@@ -445,7 +446,7 @@
", id=${c.id}," +
", appWidgetId=${c.appWidgetId}," +
", component=${component}",
- RestoreError.INVALID_LOCATION
+ RestoreError.INVALID_LOCATION,
)
return
}
@@ -456,7 +457,7 @@
", appWidgetId=${c.appWidgetId}," +
", component=${component}," +
", container=${c.container}",
- RestoreError.INVALID_LOCATION
+ RestoreError.INVALID_LOCATION,
)
return
}
@@ -470,7 +471,7 @@
TAG,
"processWidget: id=${c.id}" +
", appWidgetId=${c.appWidgetId}" +
- ", inflationResult=$inflationResult"
+ ", inflationResult=$inflationResult",
)
when (inflationResult.type) {
WidgetInflater.TYPE_DELETE -> {
@@ -487,7 +488,8 @@
(si == null) &&
(lapi == null) &&
!(Flags.enableSupportForArchiving() &&
- pmHelper.isAppArchived(component.packageName))
+ ApplicationInfoWrapper(app.context, component.packageName, c.user)
+ .isArchived())
) {
// Restore never started
c.markDeleted(
@@ -496,7 +498,7 @@
", appWidgetId=${c.appWidgetId}" +
", component=${component}" +
", restoreFlag:=${c.restoreFlag}",
- RestoreError.APP_NOT_INSTALLED
+ RestoreError.APP_NOT_INSTALLED,
)
return
} else if (
@@ -512,7 +514,7 @@
WidgetsModel.newPendingItemInfo(
app.context,
appWidgetInfo.providerName,
- appWidgetInfo.user
+ appWidgetInfo.user,
)
iconCache.getTitleAndIconForApp(appWidgetInfo.pendingItemInfo, false)
}
@@ -522,7 +524,7 @@
lapi,
app.context,
appWidgetInfo.spanX,
- appWidgetInfo.spanY
+ appWidgetInfo.spanY,
)
}
@@ -541,7 +543,7 @@
" processWidget: Widget ${lapi.component} minSizes not met: span=${appWidgetInfo.spanX}x${appWidgetInfo.spanY} minSpan=${lapi.minSpanX}x${lapi.minSpanY}," +
" id: ${c.id}," +
" appWidgetId: ${c.appWidgetId}," +
- " component=${component}"
+ " component=${component}",
)
logWidgetInfo(app.invariantDeviceProfile, lapi)
}
@@ -554,7 +556,7 @@
private fun logWidgetInfo(
idp: InvariantDeviceProfile,
- widgetProviderInfo: LauncherAppWidgetProviderInfo
+ widgetProviderInfo: LauncherAppWidgetProviderInfo,
) {
val cellSize = Point()
for (deviceProfile in idp.supportedProfiles) {
@@ -565,7 +567,7 @@
" available height: ${deviceProfile.availableHeightPx}," +
" cellLayoutBorderSpacePx Horizontal: ${deviceProfile.cellLayoutBorderSpacePx.x}," +
" cellLayoutBorderSpacePx Vertical: ${deviceProfile.cellLayoutBorderSpacePx.y}," +
- " cellSize: $cellSize"
+ " cellSize: $cellSize",
)
}
val widgetDimension = StringBuilder()
@@ -583,21 +585,19 @@
.append("defaultHeight: ")
.append(widgetProviderInfo.minHeight)
.append("\n")
- if (Utilities.ATLEAST_S) {
- widgetDimension
- .append("targetCellWidth: ")
- .append(widgetProviderInfo.targetCellWidth)
- .append("\n")
- .append("targetCellHeight: ")
- .append(widgetProviderInfo.targetCellHeight)
- .append("\n")
- .append("maxResizeWidth: ")
- .append(widgetProviderInfo.maxResizeWidth)
- .append("\n")
- .append("maxResizeHeight: ")
- .append(widgetProviderInfo.maxResizeHeight)
- .append("\n")
- }
+ widgetDimension
+ .append("targetCellWidth: ")
+ .append(widgetProviderInfo.targetCellWidth)
+ .append("\n")
+ .append("targetCellHeight: ")
+ .append(widgetProviderInfo.targetCellHeight)
+ .append("\n")
+ .append("maxResizeWidth: ")
+ .append(widgetProviderInfo.maxResizeWidth)
+ .append("\n")
+ .append("maxResizeHeight: ")
+ .append(widgetProviderInfo.maxResizeHeight)
+ .append("\n")
FileLog.d(TAG, widgetDimension.toString())
}
}
diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java
index a4281f8..97b62b4 100644
--- a/src/com/android/launcher3/model/data/AppInfo.java
+++ b/src/com/android/launcher3/model/data/AppInfo.java
@@ -21,7 +21,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.os.UserHandle;
import android.os.UserManager;
@@ -36,6 +35,7 @@
import com.android.launcher3.pm.PackageInstallInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.ApiWrapper;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.UserIconInfo;
@@ -187,8 +187,8 @@
ApiWrapper apiWrapper, PackageManagerHelper pmHelper) {
final int oldProgressLevel = info.getProgressLevel();
final int oldRuntimeStatusFlags = info.runtimeStatusFlags;
- ApplicationInfo appInfo = lai.getApplicationInfo();
- if (PackageManagerHelper.isAppSuspended(appInfo)) {
+ ApplicationInfoWrapper appInfo = new ApplicationInfoWrapper(lai.getApplicationInfo());
+ if (appInfo.isSuspended()) {
info.runtimeStatusFlags |= FLAG_DISABLED_SUSPENDED;
} else {
info.runtimeStatusFlags &= ~FLAG_DISABLED_SUSPENDED;
@@ -200,8 +200,7 @@
info.runtimeStatusFlags &= ~FLAG_ARCHIVED;
}
}
- info.runtimeStatusFlags |= (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0
- ? FLAG_SYSTEM_NO : FLAG_SYSTEM_YES;
+ info.runtimeStatusFlags |= appInfo.isSystem() ? FLAG_SYSTEM_YES : FLAG_SYSTEM_NO;
if (Flags.privateSpaceRestrictAccessibilityDrag()) {
if (userIconInfo.isPrivate()) {
diff --git a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
index f4dda55..361f09d 100644
--- a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
@@ -21,7 +21,6 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PIN_WIDGETS;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
-import static com.android.launcher3.Utilities.ATLEAST_S;
import android.appwidget.AppWidgetHostView;
import android.content.ComponentName;
@@ -233,16 +232,16 @@
if (providerInfo.isConfigurationOptional()) {
widgetFeatures |= FEATURE_OPTIONAL_CONFIGURATION;
}
- if (ATLEAST_S && providerInfo.previewLayout != Resources.ID_NULL) {
+ if (providerInfo.previewLayout != Resources.ID_NULL) {
widgetFeatures |= FEATURE_PREVIEW_LAYOUT;
}
- if (ATLEAST_S && providerInfo.targetCellWidth > 0 || providerInfo.targetCellHeight > 0) {
+ if (providerInfo.targetCellWidth > 0 || providerInfo.targetCellHeight > 0) {
widgetFeatures |= FEATURE_TARGET_CELL_SIZE;
}
if (providerInfo.minResizeWidth > 0 || providerInfo.minResizeHeight > 0) {
widgetFeatures |= FEATURE_MIN_SIZE;
}
- if (ATLEAST_S && providerInfo.maxResizeWidth > 0 || providerInfo.maxResizeHeight > 0) {
+ if (providerInfo.maxResizeWidth > 0 || providerInfo.maxResizeHeight > 0) {
widgetFeatures |= FEATURE_MAX_SIZE;
}
if (hostView instanceof LauncherAppWidgetHostView &&
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index e66f496..124907f 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -17,7 +17,6 @@
package com.android.launcher3.pm;
import android.content.Context;
-import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherApps;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageInstaller.SessionInfo;
@@ -34,10 +33,10 @@
import com.android.launcher3.SessionCommitReceiver;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.ItemInstallQueue;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.MainThreadInitializedObject;
-import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SafeCloseable;
@@ -171,8 +170,7 @@
synchronized (mSessionVerifiedMap) {
if (!mSessionVerifiedMap.containsKey(pkg)) {
boolean hasSystemFlag = DEBUG || mAppContext.getPackageName().equals(pkg)
- || PackageManagerHelper.INSTANCE.get(mAppContext)
- .getApplicationInfo(pkg, user, ApplicationInfo.FLAG_SYSTEM) != null;
+ || new ApplicationInfoWrapper(mAppContext, pkg, user).isSystem();
mSessionVerifiedMap.put(pkg, hasSystemFlag);
}
}
@@ -245,8 +243,8 @@
&& sessionInfo.getInstallReason() == PackageManager.INSTALL_REASON_USER
&& sessionInfo.getAppIcon() != null
&& !TextUtils.isEmpty(sessionInfo.getAppLabel())
- && !PackageManagerHelper.INSTANCE.get(mAppContext).isAppInstalled(
- sessionInfo.getAppPackageName(), getUserHandle(sessionInfo));
+ && !new ApplicationInfoWrapper(mAppContext, sessionInfo.getAppPackageName(),
+ getUserHandle(sessionInfo)).isInstalled();
}
public InstallSessionTracker registerInstallTracker(
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
index 6e697d9..d5c87f4 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDragLayer.java
@@ -65,7 +65,7 @@
@Override
public void recreateControllers() {
mControllers = new TouchController[]{new CloseAllAppsTouchController(),
- mActivity.getDragController()};
+ mContainer.getDragController()};
}
/**
@@ -79,10 +79,10 @@
mAppsView = findViewById(R.id.apps_view);
// Setup workspace
mWorkspace = findViewById(R.id.workspace_grid);
- mPinnedAppsAdapter = new PinnedAppsAdapter(mActivity, mAppsView.getAppsStore(),
+ mPinnedAppsAdapter = new PinnedAppsAdapter(mContainer, mAppsView.getAppsStore(),
this::onIconLongClicked);
mWorkspace.setAdapter(mPinnedAppsAdapter);
- mWorkspace.setNumColumns(mActivity.getDeviceProfile().inv.numColumns);
+ mWorkspace.setNumColumns(mContainer.getDeviceProfile().inv.numColumns);
}
/**
@@ -112,7 +112,7 @@
int height = MeasureSpec.getSize(heightMeasureSpec);
setMeasuredDimension(width, height);
- DeviceProfile grid = mActivity.getDeviceProfile();
+ DeviceProfile grid = mContainer.getDeviceProfile();
int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
@@ -153,17 +153,17 @@
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- if (!mActivity.isAppDrawerShown()) {
+ if (!mContainer.isAppDrawerShown()) {
return false;
}
- if (AbstractFloatingView.getTopOpenView(mActivity) != null) {
+ if (AbstractFloatingView.getTopOpenView(mContainer) != null) {
return false;
}
if (ev.getAction() == MotionEvent.ACTION_DOWN
- && !isEventOverView(mActivity.getAppsView(), ev)) {
- mActivity.showAppDrawer(false);
+ && !isEventOverView(mContainer.getAppsView(), ev)) {
+ mContainer.showAppDrawer(false);
return true;
}
return false;
@@ -178,7 +178,7 @@
if (!(v instanceof BubbleTextView)) {
return false;
}
- if (PopupContainerWithArrow.getOpen(mActivity) != null) {
+ if (PopupContainerWithArrow.getOpen(mContainer) != null) {
// There is already an items container open, so don't open this one.
v.clearFocus();
return false;
@@ -187,32 +187,32 @@
if (!ShortcutUtil.supportsShortcuts(item)) {
return false;
}
- PopupDataProvider popupDataProvider = mActivity.getPopupDataProvider();
+ PopupDataProvider popupDataProvider = mContainer.getPopupDataProvider();
if (popupDataProvider == null) {
return false;
}
// order of this list will reflect in the popup
List<SystemShortcut> systemShortcuts = new ArrayList<>();
- systemShortcuts.add(APP_INFO.getShortcut(mActivity, item, v));
+ systemShortcuts.add(APP_INFO.getShortcut(mContainer, item, v));
// Hide redundant pin shortcut for app drawer icons if drag-n-drop is enabled.
- if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
+ if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mContainer.isAppDrawerShown()) {
systemShortcuts.add(mPinnedAppsAdapter.getSystemShortcut(item, v));
}
int deepShortcutCount = popupDataProvider.getShortcutCountForItem(item);
final PopupContainerWithArrow<SecondaryDisplayLauncher> container;
- container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
- R.layout.popup_container, mActivity.getDragLayer(), false);
+ container = (PopupContainerWithArrow) mContainer.getLayoutInflater().inflate(
+ R.layout.popup_container, mContainer.getDragLayer(), false);
container.populateAndShowRows((BubbleTextView) v, deepShortcutCount,
systemShortcuts);
container.requestFocus();
- if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {
+ if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mContainer.isAppDrawerShown()) {
return true;
}
DragOptions options = new DragOptions();
- DeviceProfile grid = mActivity.getDeviceProfile();
+ DeviceProfile grid = mContainer.getDeviceProfile();
options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx;
options.preDragCondition = container.createPreDragCondition(false);
if (options.preDragCondition == null) {
@@ -229,7 +229,7 @@
mDragView = dragObject.dragView;
if (!shouldStartDrag(0)) {
mDragView.setOnScaleAnimEndCallback(() ->
- mActivity.beginDragShared(v, mActivity.getAppsView(), options));
+ mContainer.beginDragShared(v, mContainer.getAppsView(), options));
}
}
@@ -239,7 +239,7 @@
}
};
}
- mActivity.beginDragShared(v, mActivity.getAppsView(), options);
+ mContainer.beginDragShared(v, mContainer.getAppsView(), options);
return true;
}
}
diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java
index 28f2def..54b2eae 100644
--- a/src/com/android/launcher3/statemanager/StatefulActivity.java
+++ b/src/com/android/launcher3/statemanager/StatefulActivity.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.LauncherState.FLAG_NON_INTERACTIVE;
+import android.content.Context;
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
@@ -195,15 +196,15 @@
mOldRotation = rotation;
}
+ @Override
+ public Context getContext() {
+ return this;
+ }
+
/**
* Logic for when device configuration changes (rotation, screen size change, multi-window,
* etc.)
*/
protected abstract void onHandleConfigurationChanged();
- /**
- * Enter staged split directly from the current running app.
- * @param leftOrTop if the staged split will be positioned left or top.
- */
- public void enterStageSplitFromRunningApp(boolean leftOrTop) { }
}
diff --git a/src/com/android/launcher3/statemanager/StatefulContainer.java b/src/com/android/launcher3/statemanager/StatefulContainer.java
index 0cf0a27..b10af0a 100644
--- a/src/com/android/launcher3/statemanager/StatefulContainer.java
+++ b/src/com/android/launcher3/statemanager/StatefulContainer.java
@@ -20,6 +20,10 @@
import static com.android.launcher3.LauncherState.FLAG_CLOSE_POPUPS;
import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.content.res.Configuration;
+
import androidx.annotation.CallSuper;
import com.android.launcher3.AbstractFloatingView;
@@ -36,6 +40,23 @@
ActivityContext {
/**
+ * Returns an instance of an implementation of StatefulContainer
+ *
+ * @param context will find instance of StatefulContainer from given context.
+ */
+ static <T extends StatefulContainer> T fromContext(Context context) {
+ if (context instanceof StatefulContainer) {
+ return (T) context;
+ } else if (context instanceof ContextWrapper) {
+ return fromContext(((ContextWrapper) context).getBaseContext());
+ } else {
+ throw new IllegalArgumentException("Cannot find StatefulContainer in parent tree");
+ }
+ }
+
+ Context getContext();
+
+ /**
* Creates a factory for atomic state animations
*/
default StateManager.AtomicAnimationFactory<STATE_TYPE> createAtomicAnimationFactory() {
@@ -54,12 +75,15 @@
/**
* Called when transition to state ends
+ *
* @param state current state of State_Type
*/
- default void onStateSetEnd(STATE_TYPE state) { }
+ default void onStateSetEnd(STATE_TYPE state) {
+ }
/**
* Called when transition to state starts
+ *
* @param state current state of State_Type
*/
@CallSuper
@@ -71,6 +95,7 @@
/**
* Returns true if the activity is in the provided state
+ *
* @param state current state of State_Type
*/
default boolean isInState(STATE_TYPE state) {
@@ -81,4 +106,8 @@
* Returns true if state change should transition with animation
*/
boolean shouldAnimateStateChange();
+
+ default void handleConfigurationChanged(Configuration configuration){
+ //no op
+ }
}
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 6d9b891..3a93981 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -168,21 +168,14 @@
}
case TestProtocol.REQUEST_TARGET_INSETS: {
- return getUIProperty(Bundle::putParcelable, activity -> {
- WindowInsets insets = activity.getWindow()
- .getDecorView().getRootWindowInsets();
- return Insets.max(
- insets.getSystemGestureInsets(),
- insets.getSystemWindowInsets());
- }, this::getCurrentActivity);
+ return getUIProperty(Bundle::putParcelable, insets -> Insets.max(
+ insets.getSystemGestureInsets(),
+ insets.getSystemWindowInsets()), this::getWindowInsets);
}
case TestProtocol.REQUEST_WINDOW_INSETS: {
- return getUIProperty(Bundle::putParcelable, activity -> {
- WindowInsets insets = activity.getWindow()
- .getDecorView().getRootWindowInsets();
- return insets.getSystemWindowInsets();
- }, this::getCurrentActivity);
+ return getUIProperty(Bundle::putParcelable,
+ WindowInsets::getSystemWindowInsets, this::getWindowInsets);
}
case TestProtocol.REQUEST_CELL_LAYOUT_BOARDER_HEIGHT: {
@@ -192,13 +185,13 @@
}
case TestProtocol.REQUEST_SYSTEM_GESTURE_REGION: {
- return getUIProperty(Bundle::putParcelable, activity -> {
- WindowInsetsCompat insets = WindowInsetsCompat.toWindowInsetsCompat(
- activity.getWindow().getDecorView().getRootWindowInsets());
+ return getUIProperty(Bundle::putParcelable, windowInsets -> {
+ WindowInsetsCompat insets =
+ WindowInsetsCompat.toWindowInsetsCompat(windowInsets);
return insets.getInsets(WindowInsetsCompat.Type.ime()
| WindowInsetsCompat.Type.systemGestures())
.toPlatformInsets();
- }, this::getCurrentActivity);
+ }, this::getWindowInsets);
}
case TestProtocol.REQUEST_ICON_HEIGHT: {
@@ -486,8 +479,9 @@
|| LauncherAppState.getInstance(mContext).getModel().isModelLoaded();
}
- protected Activity getCurrentActivity() {
- return Launcher.ACTIVITY_TRACKER.getCreatedActivity();
+ protected WindowInsets getWindowInsets(){
+ return Launcher.ACTIVITY_TRACKER.getCreatedActivity().getWindow().getDecorView()
+ .getRootWindowInsets();
}
/**
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index 3817563..efd1f0d 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -40,11 +40,13 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.contextualeducation.ContextualEduStatsManager;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.FlingBlockCheck;
import com.android.launcher3.util.TouchController;
+import com.android.systemui.contextualeducation.GestureType;
/**
* TouchController for handling state changes
@@ -388,6 +390,7 @@
} else {
logReachedState(mToState);
}
+ updateContextualEduStats(targetState);
}
protected void goToTargetState(LauncherState targetState) {
@@ -403,6 +406,21 @@
.setDuration(0).start();
}
+ private void updateContextualEduStats(LauncherState targetState) {
+ if (targetState == NORMAL) {
+ ContextualEduStatsManager.INSTANCE.get(
+ mLauncher).updateEduStats(mDetector.isTrackpadGesture(), GestureType.HOME);
+ } else if (targetState == OVERVIEW) {
+ ContextualEduStatsManager.INSTANCE.get(
+ mLauncher).updateEduStats(mDetector.isTrackpadGesture(), GestureType.OVERVIEW);
+ } else if (targetState == ALL_APPS && !mDetector.isTrackpadGesture()) {
+ // Only update if it is touch gesture as trackpad gesture is not relevant for all apps
+ // which only provides keyboard education.
+ ContextualEduStatsManager.INSTANCE.get(
+ mLauncher).updateEduStats(/* isTrackpadGesture= */ false, GestureType.ALL_APPS);
+ }
+ }
+
private void logReachedState(LauncherState targetState) {
if (mStartState == targetState) {
return;
diff --git a/src/com/android/launcher3/touch/BaseSwipeDetector.java b/src/com/android/launcher3/touch/BaseSwipeDetector.java
index 52c3581..faac4a3 100644
--- a/src/com/android/launcher3/touch/BaseSwipeDetector.java
+++ b/src/com/android/launcher3/touch/BaseSwipeDetector.java
@@ -17,6 +17,8 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
+import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
+
import android.content.Context;
import android.graphics.PointF;
import android.util.Log;
@@ -64,6 +66,7 @@
protected PointF mSubtractDisplacement = new PointF();
@VisibleForTesting ScrollState mState = ScrollState.IDLE;
private boolean mIsSettingState;
+ protected boolean mIsTrackpadGesture;
protected boolean mIgnoreSlopWhenSettling;
protected Context mContext;
@@ -122,6 +125,10 @@
return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING;
}
+ public boolean isTrackpadGesture() {
+ return mIsTrackpadGesture;
+ }
+
public void finishedScrolling() {
setState(ScrollState.IDLE);
}
@@ -147,7 +154,7 @@
mLastPos.set(mDownPos);
mLastDisplacement.set(0, 0);
mDisplacement.set(0, 0);
-
+ mIsTrackpadGesture = isTrackpadMotionEvent(ev);
if (mState == ScrollState.SETTLING && mIgnoreSlopWhenSettling) {
setState(ScrollState.DRAGGING);
}
diff --git a/src/com/android/launcher3/util/ApplicationInfoWrapper.kt b/src/com/android/launcher3/util/ApplicationInfoWrapper.kt
new file mode 100644
index 0000000..e75b3bc
--- /dev/null
+++ b/src/com/android/launcher3/util/ApplicationInfoWrapper.kt
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2024 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.Intent
+import android.content.pm.ApplicationInfo
+import android.content.pm.ApplicationInfo.FLAG_EXTERNAL_STORAGE
+import android.content.pm.ApplicationInfo.FLAG_INSTALLED
+import android.content.pm.ApplicationInfo.FLAG_SUSPENDED
+import android.content.pm.ApplicationInfo.FLAG_SYSTEM
+import android.content.pm.LauncherApps
+import android.content.pm.PackageManager
+import android.content.pm.PackageManager.NameNotFoundException
+import android.os.UserHandle
+import com.android.launcher3.Flags.enableSupportForArchiving
+import com.android.launcher3.Utilities.ATLEAST_V
+import kotlin.LazyThreadSafetyMode.NONE
+
+/**
+ * A set of utility methods around ApplicationInfo with support for fetching the actual info lazily
+ */
+class ApplicationInfoWrapper private constructor(provider: () -> ApplicationInfo?) {
+
+ constructor(appInfo: ApplicationInfo?) : this({ appInfo })
+
+ constructor(
+ ctx: Context,
+ pkg: String,
+ user: UserHandle,
+ ) : this({
+ try {
+ ctx.getSystemService(LauncherApps::class.java)
+ ?.getApplicationInfo(pkg, PackageManager.MATCH_UNINSTALLED_PACKAGES, user)
+ ?.let { ai ->
+ // its enabled and (either installed or archived)
+ if (
+ ai.enabled &&
+ (ai.flags.and(FLAG_INSTALLED) != 0 ||
+ (ATLEAST_V && enableSupportForArchiving() && ai.isArchived))
+ ) {
+ ai
+ } else {
+ null
+ }
+ }
+ } catch (e: NameNotFoundException) {
+ null
+ }
+ })
+
+ constructor(
+ ctx: Context,
+ intent: Intent,
+ ) : this(
+ provider@{
+ try {
+ val pm = ctx.packageManager
+ val packageName: String =
+ intent.component?.packageName
+ ?: intent.getPackage()
+ ?: return@provider pm.resolveActivity(
+ intent,
+ PackageManager.MATCH_DEFAULT_ONLY,
+ )
+ ?.activityInfo
+ ?.applicationInfo
+ pm.getApplicationInfo(packageName, 0)
+ } catch (e: NameNotFoundException) {
+ null
+ }
+ }
+ )
+
+ private val appInfo: ApplicationInfo? by lazy(NONE, provider)
+
+ private fun hasFlag(flag: Int) = appInfo?.let { it.flags.and(flag) != 0 } ?: false
+
+ /**
+ * Returns true if the app can possibly be on the SDCard. This is just a workaround and doesn't
+ * guarantee that the app is on SD card.
+ */
+ fun isOnSdCard() = hasFlag(FLAG_EXTERNAL_STORAGE)
+
+ /** Returns whether the target app is installed for a given user */
+ fun isInstalled() = hasFlag(FLAG_INSTALLED)
+
+ /**
+ * Returns whether the target app is suspended for a given user as per
+ * [android.app.admin.DevicePolicyManager.isPackageSuspended].
+ */
+ fun isSuspended() = hasFlag(FLAG_INSTALLED) && hasFlag(FLAG_SUSPENDED)
+
+ /** Returns whether the target app is archived for a given user */
+ fun isArchived() = ATLEAST_V && enableSupportForArchiving() && appInfo?.isArchived ?: false
+
+ /** Returns whether the target app is a system app */
+ fun isSystem() = hasFlag(FLAG_SYSTEM)
+
+ fun getInfo(): ApplicationInfo? = appInfo
+}
diff --git a/src/com/android/launcher3/util/DaggerSingletonObject.java b/src/com/android/launcher3/util/DaggerSingletonObject.java
new file mode 100644
index 0000000..b8cf2ae
--- /dev/null
+++ b/src/com/android/launcher3/util/DaggerSingletonObject.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2024 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 com.android.launcher3.LauncherApplication;
+import com.android.launcher3.dagger.LauncherAppComponent;
+
+import java.util.function.Function;
+
+/**
+ * A class to provide DaggerSingleton objects in a traditional way for
+ * {@link MainThreadInitializedObject}.
+ * We should delete this class at the end and use @Inject to get dagger provided singletons.
+ */
+
+public class DaggerSingletonObject<T extends SafeCloseable> {
+ private final Function<LauncherAppComponent, T> mFunction;
+
+ public DaggerSingletonObject(Function<LauncherAppComponent, T> function) {
+ mFunction = function;
+ }
+
+ public T get(Context context) {
+ LauncherAppComponent component =
+ ((LauncherApplication) context.getApplicationContext()).getAppComponent();
+ return mFunction.apply(component);
+ }
+}
diff --git a/src/com/android/launcher3/util/DaggerSingletonTracker.java b/src/com/android/launcher3/util/DaggerSingletonTracker.java
new file mode 100644
index 0000000..2946da1
--- /dev/null
+++ b/src/com/android/launcher3/util/DaggerSingletonTracker.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2024 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 com.android.launcher3.dagger.LauncherAppSingleton;
+
+import java.util.ArrayList;
+
+import javax.inject.Inject;
+
+/**
+ * A tracker class for keeping track of Dagger created singletons.
+ * Dagger will take care of creating singletons. But we should take care of unregistering callbacks
+ * if at all registered during singleton construction.
+ * All singletons should be declared as SafeCloseable so that we can call close() method.
+ */
+@LauncherAppSingleton
+public class DaggerSingletonTracker implements SafeCloseable {
+
+ private final ArrayList<SafeCloseable> mLauncherAppSingletons = new ArrayList<>();
+
+ @Inject
+ DaggerSingletonTracker() {
+ }
+
+ /**
+ * Adds the SafeCloseable Singletons to the mLauncherAppSingletons list.
+ * This helps to track the singletons and close them appropriately.
+ * See {@link DaggerSingletonTracker#close()} and
+ * {@link MainThreadInitializedObject.SandboxContext#onDestroy()}
+ */
+ public void addCloseable(SafeCloseable closeable) {
+ mLauncherAppSingletons.add(closeable);
+ }
+
+ @Override
+ public void close() {
+ // Destroy in reverse order
+ for (int i = mLauncherAppSingletons.size() - 1; i >= 0; i--) {
+ mLauncherAppSingletons.get(i).close();
+ }
+ }
+}
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index dff9a07..c59cc81 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -15,7 +15,6 @@
*/
package com.android.launcher3.util;
-import static android.content.Intent.ACTION_CONFIGURATION_CHANGED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
@@ -33,7 +32,6 @@
import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH;
import android.annotation.SuppressLint;
-import android.annotation.TargetApi;
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.Intent;
@@ -42,7 +40,6 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
-import android.os.Build;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
@@ -132,21 +129,15 @@
}
Display display = mDM.getDisplay(DEFAULT_DISPLAY);
- if (Utilities.ATLEAST_S) {
- mWindowContext = mContext.createWindowContext(display, TYPE_APPLICATION, null);
- mWindowContext.registerComponentCallbacks(this);
- } else {
- mWindowContext = null;
- mReceiver.register(mContext, ACTION_CONFIGURATION_CHANGED);
- }
+ mWindowContext = mContext.createWindowContext(display, TYPE_APPLICATION, null);
+ mWindowContext.registerComponentCallbacks(this);
// Initialize navigation mode change listener
mReceiver.registerPkgActions(mContext, TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED);
WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(context);
- Context displayInfoContext = getDisplayInfoContext(display);
- mInfo = new Info(displayInfoContext, wmProxy,
- wmProxy.estimateInternalDisplayBounds(displayInfoContext));
+ mInfo = new Info(mWindowContext, wmProxy,
+ wmProxy.estimateInternalDisplayBounds(mWindowContext));
FileLog.i(TAG, "(CTOR) perDisplayBounds: " + mInfo.mPerDisplayBounds);
}
@@ -161,7 +152,7 @@
&& mInfo.mIsTaskbarPinnedInDesktopMode != prefs.get(
TASKBAR_PINNING_IN_DESKTOP_MODE);
if (isTaskbarPinningChanged || isTaskbarPinningDesktopModeChanged) {
- handleInfoChange(mWindowContext.getDisplay());
+ notifyConfigChange();
}
};
@@ -188,20 +179,6 @@
}
/**
- * Handles info change for desktop mode.
- */
- public static void handleInfoChangeForDesktopMode(Context context) {
- INSTANCE.get(context).handleInfoChange(context.getDisplay());
- }
-
- /**
- * Handles info change for launcher visibility.
- */
- public static void handleInfoChangeForLauncherVisibilityChanged(Context context) {
- INSTANCE.get(context).handleInfoChange(context.getDisplay());
- }
-
- /**
* Enables transient taskbar status for tests.
*/
@VisibleForTesting
@@ -266,36 +243,22 @@
if (mDestroyed) {
return;
}
- boolean reconfigure = false;
if (ACTION_OVERLAY_CHANGED.equals(intent.getAction())) {
- reconfigure = true;
- } else if (ACTION_CONFIGURATION_CHANGED.equals(intent.getAction())) {
- Configuration config = mContext.getResources().getConfiguration();
- reconfigure = mInfo.fontScale != config.fontScale
- || mInfo.densityDpi != config.densityDpi;
- }
-
- if (reconfigure) {
- Log.d(TAG, "Configuration changed, notifying listeners");
- Display display = mDM.getDisplay(DEFAULT_DISPLAY);
- if (display != null) {
- handleInfoChange(display);
- }
+ Log.d(TAG, "Overlay changed, notifying listeners");
+ notifyConfigChange();
}
}
@UiThread
@Override
- @TargetApi(Build.VERSION_CODES.S)
public final void onConfigurationChanged(Configuration config) {
Log.d(TASKBAR_NOT_DESTROYED_TAG, "DisplayController#onConfigurationChanged: " + config);
- Display display = mWindowContext.getDisplay();
if (config.densityDpi != mInfo.densityDpi
|| config.fontScale != mInfo.fontScale
- || display.getRotation() != mInfo.rotation
|| !mInfo.mScreenSizeDp.equals(
- new PortraitSize(config.screenHeightDp, config.screenWidthDp))) {
- handleInfoChange(display);
+ new PortraitSize(config.screenHeightDp, config.screenWidthDp))
+ || mWindowContext.getDisplay().getRotation() != mInfo.rotation) {
+ notifyConfigChange();
}
}
@@ -318,17 +281,12 @@
return mInfo;
}
- private Context getDisplayInfoContext(Display display) {
- return Utilities.ATLEAST_S ? mWindowContext : mContext.createDisplayContext(display);
- }
-
@AnyThread
- @VisibleForTesting
- public void handleInfoChange(Display display) {
+ public void notifyConfigChange() {
WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(mContext);
Info oldInfo = mInfo;
- Context displayInfoContext = getDisplayInfoContext(display);
+ Context displayInfoContext = mWindowContext;
Info newInfo = new Info(displayInfoContext, wmProxy, oldInfo.mPerDisplayBounds);
if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale
diff --git a/src/com/android/launcher3/util/EdgeEffectCompat.java b/src/com/android/launcher3/util/EdgeEffectCompat.java
index ca37259..a949f50 100644
--- a/src/com/android/launcher3/util/EdgeEffectCompat.java
+++ b/src/com/android/launcher3/util/EdgeEffectCompat.java
@@ -19,8 +19,6 @@
import android.view.MotionEvent;
import android.widget.EdgeEffect;
-import com.android.launcher3.Utilities;
-
/**
* Extension of {@link EdgeEffect} to allow backwards compatibility
*/
@@ -30,21 +28,6 @@
super(context);
}
- @Override
- public float getDistance() {
- return Utilities.ATLEAST_S ? super.getDistance() : 0;
- }
-
- @Override
- public float onPullDistance(float deltaDistance, float displacement) {
- if (Utilities.ATLEAST_S) {
- return super.onPullDistance(deltaDistance, displacement);
- } else {
- onPull(deltaDistance, displacement);
- return deltaDistance;
- }
- }
-
public float onPullDistance(float deltaDistance, float displacement, MotionEvent ev) {
return onPullDistance(deltaDistance, displacement);
}
diff --git a/src/com/android/launcher3/util/ExecutorUtil.java b/src/com/android/launcher3/util/ExecutorUtil.java
new file mode 100644
index 0000000..efc0eec
--- /dev/null
+++ b/src/com/android/launcher3/util/ExecutorUtil.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2024 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 static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+
+import android.os.Looper;
+
+import java.util.concurrent.ExecutionException;
+
+public final class ExecutorUtil {
+
+ /**
+ * Executes runnable on {@link Looper#getMainLooper()}, otherwise fails with an exception.
+ */
+ public static void executeSyncOnMainOrFail(Runnable runnable) {
+ try {
+ MAIN_EXECUTOR.submit(runnable).get();
+ } catch (InterruptedException | ExecutionException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
index 63f14bd..e12ccbc 100644
--- a/src/com/android/launcher3/util/MainThreadInitializedObject.java
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -18,13 +18,13 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.content.Context;
-import android.content.ContextWrapper;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.UiThread;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.LauncherApplication;
import com.android.launcher3.util.ResourceBasedOverride.Overrides;
import java.util.ArrayList;
@@ -118,7 +118,7 @@
* Abstract Context which allows custom implementations for
* {@link MainThreadInitializedObject} providers
*/
- public static class SandboxContext extends ContextWrapper implements SandboxApplication {
+ public static class SandboxContext extends LauncherApplication implements SandboxApplication {
private static final String TAG = "SandboxContext";
@@ -129,7 +129,8 @@
private boolean mDestroyed = false;
public SandboxContext(Context base) {
- super(base);
+ attachBaseContext(base);
+ initDagger();
}
@Override
@@ -138,6 +139,7 @@
}
public void onDestroy() {
+ getAppComponent().getDaggerSingletonTracker().close();
synchronized (mDestroyLock) {
// Destroy in reverse order
for (int i = mOrderedObjects.size() - 1; i >= 0; i--) {
diff --git a/src/com/android/launcher3/util/OverlayEdgeEffect.java b/src/com/android/launcher3/util/OverlayEdgeEffect.java
index d09d801..0623af7 100644
--- a/src/com/android/launcher3/util/OverlayEdgeEffect.java
+++ b/src/com/android/launcher3/util/OverlayEdgeEffect.java
@@ -46,6 +46,7 @@
return mDistance;
}
+ @Override
public float onPullDistance(float deltaDistance, float displacement) {
// Fallback implementation, will never actually get called
if (BuildConfig.IS_DEBUG_DEVICE) {
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 469e363..e51609a 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -24,13 +24,10 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.pm.ResolveInfo;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Process;
@@ -42,7 +39,6 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
-import com.android.launcher3.Flags;
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -89,69 +85,6 @@
public void close() { }
/**
- * Returns true if the app can possibly be on the SDCard. This is just a workaround and doesn't
- * guarantee that the app is on SD card.
- */
- public boolean isAppOnSdcard(@NonNull final String packageName,
- @NonNull final UserHandle user) {
- final ApplicationInfo info = getApplicationInfo(
- packageName, user, PackageManager.MATCH_UNINSTALLED_PACKAGES);
- return info != null && (info.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;
- }
-
- /**
- * Returns whether the target app is suspended for a given user as per
- * {@link android.app.admin.DevicePolicyManager#isPackageSuspended}.
- */
- public boolean isAppSuspended(@NonNull final String packageName,
- @NonNull final UserHandle user) {
- final ApplicationInfo info = getApplicationInfo(packageName, user, 0);
- return info != null && isAppSuspended(info);
- }
-
- /**
- * Returns whether the target app is installed for a given user
- */
- public boolean isAppInstalled(@NonNull final String packageName,
- @NonNull final UserHandle user) {
- final ApplicationInfo info = getApplicationInfo(packageName, user, 0);
- return info != null;
- }
-
- /**
- * Returns whether the target app is archived for a given user
- */
- @SuppressWarnings("NewApi")
- public boolean isAppArchivedForUser(@NonNull final String packageName,
- @NonNull final UserHandle user) {
- if (!Flags.enableSupportForArchiving()) {
- return false;
- }
- final ApplicationInfo info = getApplicationInfo(
- // LauncherApps does not support long flags currently. Since archived apps are
- // subset of uninstalled apps, this filter also includes archived apps.
- packageName, user, PackageManager.MATCH_UNINSTALLED_PACKAGES);
- return info != null && info.isArchived;
- }
-
- /**
- * Returns whether the target app is in archived state
- */
- @SuppressWarnings("NewApi")
- public boolean isAppArchived(@NonNull final String packageName) {
- final ApplicationInfo info;
- try {
- info = mPm.getPackageInfo(packageName,
- PackageManager.PackageInfoFlags.of(
- PackageManager.MATCH_ARCHIVED_PACKAGES)).applicationInfo;
- return info.isArchived;
- } catch (NameNotFoundException e) {
- Log.e(TAG, "Failed to get applicationInfo for package: " + packageName, e);
- return false;
- }
- }
-
- /**
* Returns the installing app package for the given package
*/
public String getAppInstallerPackage(@NonNull final String packageName) {
@@ -164,20 +97,6 @@
}
/**
- * Returns the application info for the provided package or null
- */
- @Nullable
- public ApplicationInfo getApplicationInfo(@NonNull final String packageName,
- @NonNull final UserHandle user, final int flags) {
- try {
- ApplicationInfo info = mLauncherApps.getApplicationInfo(packageName, flags, user);
- return !isPackageInstalledOrArchived(info) || !info.enabled ? null : info;
- } catch (PackageManager.NameNotFoundException e) {
- return null;
- }
- }
-
- /**
* Returns the preferred launch activity intent for a given package.
*/
@Nullable
@@ -197,14 +116,6 @@
}
/**
- * Returns whether an application is suspended as per
- * {@link android.app.admin.DevicePolicyManager#isPackageSuspended}.
- */
- public static boolean isAppSuspended(ApplicationInfo info) {
- return (info.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;
- }
-
- /**
* Starts the details activity for {@code info}
*/
public static void startDetailsActivityForInfo(Context context, ItemInfo info,
@@ -236,35 +147,6 @@
}
}
- public static boolean isSystemApp(@NonNull final Context context,
- @NonNull final Intent intent) {
- PackageManager pm = context.getPackageManager();
- ComponentName cn = intent.getComponent();
- String packageName = null;
- if (cn == null) {
- ResolveInfo info = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
- if ((info != null) && (info.activityInfo != null)) {
- packageName = info.activityInfo.packageName;
- }
- } else {
- packageName = cn.getPackageName();
- }
- if (packageName == null) {
- packageName = intent.getPackage();
- }
- if (packageName != null) {
- try {
- PackageInfo info = pm.getPackageInfo(packageName, 0);
- return (info != null) && (info.applicationInfo != null) &&
- ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
- } catch (NameNotFoundException e) {
- return false;
- }
- } else {
- return false;
- }
- }
-
/**
* Returns true if the intent is a valid launch intent for a launcher activity of an app.
* This is used to identify shortcuts which are different from the ones exposed by the
@@ -303,17 +185,7 @@
/** Returns the incremental download progress for the given shortcut's app. */
public static int getLoadingProgress(LauncherActivityInfo info) {
- if (Utilities.ATLEAST_S) {
- return (int) (100 * info.getLoadingProgress());
- }
- return 100;
- }
-
- /** Returns true in case app is installed on the device or in archived state. */
- @SuppressWarnings("NewApi")
- private boolean isPackageInstalledOrArchived(ApplicationInfo info) {
- return (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0 || (
- Flags.enableSupportForArchiving() && info.isArchived);
+ return (int) (100 * info.getLoadingProgress());
}
/**
diff --git a/src/com/android/launcher3/util/SystemUiController.java b/src/com/android/launcher3/util/SystemUiController.java
index df54fd7..368b267 100644
--- a/src/com/android/launcher3/util/SystemUiController.java
+++ b/src/com/android/launcher3/util/SystemUiController.java
@@ -17,7 +17,6 @@
package com.android.launcher3.util;
import android.view.View;
-import android.view.Window;
import androidx.annotation.IntDef;
@@ -54,11 +53,11 @@
})
public @interface SystemUiControllerFlags {}
- private final Window mWindow;
+ private final View mView;
private final int[] mStates = new int[5];
- public SystemUiController(Window window) {
- mWindow = window;
+ public SystemUiController(View view) {
+ mView = view;
}
public void updateUiState(int uiState, boolean isLight) {
@@ -72,14 +71,14 @@
}
mStates[uiState] = flags;
- int oldFlags = mWindow.getDecorView().getSystemUiVisibility();
+ int oldFlags = mView.getSystemUiVisibility();
// Apply the state flags in priority order
int newFlags = oldFlags;
for (int stateFlag : mStates) {
newFlags = getSysUiVisibilityFlags(stateFlag, newFlags);
}
if (newFlags != oldFlags) {
- mWindow.getDecorView().setSystemUiVisibility(newFlags);
+ mView.setSystemUiVisibility(newFlags);
}
}
@@ -88,7 +87,7 @@
*/
public int getBaseSysuiVisibility() {
return getSysUiVisibilityFlags(
- mStates[UI_STATE_BASE_WINDOW], mWindow.getDecorView().getSystemUiVisibility());
+ mStates[UI_STATE_BASE_WINDOW], mView.getSystemUiVisibility());
}
private int getSysUiVisibilityFlags(int stateFlag, int currentVisibility) {
diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java
index 60951ba..104040a 100644
--- a/src/com/android/launcher3/util/Themes.java
+++ b/src/com/android/launcher3/util/Themes.java
@@ -52,10 +52,8 @@
}
public static int getActivityThemeRes(Context context, int wallpaperColorHints) {
- boolean supportsDarkText = Utilities.ATLEAST_S
- && (wallpaperColorHints & HINT_SUPPORTS_DARK_TEXT) != 0;
- boolean isMainColorDark = Utilities.ATLEAST_S
- && (wallpaperColorHints & HINT_SUPPORTS_DARK_THEME) != 0;
+ boolean supportsDarkText = (wallpaperColorHints & HINT_SUPPORTS_DARK_TEXT) != 0;
+ boolean isMainColorDark = (wallpaperColorHints & HINT_SUPPORTS_DARK_THEME) != 0;
if (Utilities.isDarkTheme(context)) {
return supportsDarkText ? R.style.AppTheme_Dark_DarkText
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index a4b8eb0..adb8f9d 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -31,8 +31,6 @@
import androidx.annotation.VisibleForTesting;
-import com.android.launcher3.Utilities;
-
/**
* Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
*/
@@ -129,7 +127,7 @@
/** Indicates that Taskbar has been invoked. */
public void vibrateForTaskbarUnstash() {
- if (Utilities.ATLEAST_S && mVibrator.areAllPrimitivesSupported(PRIMITIVE_LOW_TICK)) {
+ if (mVibrator.areAllPrimitivesSupported(PRIMITIVE_LOW_TICK)) {
VibrationEffect primitiveLowTickEffect = VibrationEffect
.startComposition()
.addPrimitive(PRIMITIVE_LOW_TICK, LOW_TICK_SCALE)
diff --git a/src/com/android/launcher3/util/WallpaperColorHints.kt b/src/com/android/launcher3/util/WallpaperColorHints.kt
index 1361c1e..11d4c25 100644
--- a/src/com/android/launcher3/util/WallpaperColorHints.kt
+++ b/src/com/android/launcher3/util/WallpaperColorHints.kt
@@ -23,7 +23,6 @@
import android.content.Context
import androidx.annotation.MainThread
import androidx.annotation.VisibleForTesting
-import com.android.launcher3.Utilities
import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
@@ -34,36 +33,34 @@
class WallpaperColorHints(private val context: Context) : SafeCloseable {
var hints: Int = 0
private set
+
private val wallpaperManager
get() = context.getSystemService(WallpaperManager::class.java)!!
+
private val onColorHintsChangedListeners = mutableListOf<OnColorHintListener>()
private val onClose: SafeCloseable
init {
- if (Utilities.ATLEAST_S) {
- hints = wallpaperManager.getWallpaperColors(FLAG_SYSTEM)?.colorHints ?: 0
- val onColorsChangedListener = OnColorsChangedListener { colors, which ->
- onColorsChanged(colors, which)
- }
+ hints = wallpaperManager.getWallpaperColors(FLAG_SYSTEM)?.colorHints ?: 0
+ val onColorsChangedListener = OnColorsChangedListener { colors, which ->
+ onColorsChanged(colors, which)
+ }
+ UI_HELPER_EXECUTOR.execute {
+ wallpaperManager.addOnColorsChangedListener(
+ onColorsChangedListener,
+ MAIN_EXECUTOR.handler,
+ )
+ }
+ onClose = SafeCloseable {
UI_HELPER_EXECUTOR.execute {
- wallpaperManager.addOnColorsChangedListener(
- onColorsChangedListener,
- MAIN_EXECUTOR.handler
- )
+ wallpaperManager.removeOnColorsChangedListener(onColorsChangedListener)
}
- onClose = SafeCloseable {
- UI_HELPER_EXECUTOR.execute {
- wallpaperManager.removeOnColorsChangedListener(onColorsChangedListener)
- }
- }
- } else {
- onClose = SafeCloseable {}
}
}
@MainThread
private fun onColorsChanged(colors: WallpaperColors?, which: Int) {
- if ((which and FLAG_SYSTEM) != 0 && Utilities.ATLEAST_S) {
+ if ((which and FLAG_SYSTEM) != 0) {
val newHints = colors?.colorHints ?: 0
if (newHints != hints) {
hints = newHints
@@ -86,6 +83,7 @@
@VisibleForTesting
@JvmField
val INSTANCE = MainThreadInitializedObject { WallpaperColorHints(it) }
+
@JvmStatic fun get(context: Context): WallpaperColorHints = INSTANCE.get(context)
}
}
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 22ecf68..84b4a36 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -32,7 +32,6 @@
import static com.android.launcher3.util.RotationUtils.rotateRect;
import static com.android.launcher3.util.RotationUtils.rotateSize;
-import android.annotation.TargetApi;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
@@ -40,7 +39,6 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.hardware.display.DisplayManager;
-import android.os.Build;
import android.util.ArrayMap;
import android.util.Log;
import android.view.Display;
@@ -54,7 +52,6 @@
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.testing.shared.ResourceUtils;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.NavigationMode;
@@ -230,7 +227,7 @@
int screenWidthPx,
@NonNull WindowInsets windowInsets,
@NonNull WindowInsets.Builder insetsBuilder) {
- if (!isLargeScreen || !Utilities.ATLEAST_S) {
+ if (!isLargeScreen) {
return;
}
@@ -405,25 +402,16 @@
/**
* Returns a CachedDisplayInfo initialized for the current display
*/
- @TargetApi(Build.VERSION_CODES.S)
public CachedDisplayInfo getDisplayInfo(Context displayInfoContext) {
int rotation = getRotation(displayInfoContext);
- if (Utilities.ATLEAST_S) {
- WindowMetrics windowMetrics = displayInfoContext.getSystemService(WindowManager.class)
- .getMaximumWindowMetrics();
- return getDisplayInfo(windowMetrics, rotation);
- } else {
- Point size = new Point();
- Display display = getDisplay(displayInfoContext);
- display.getRealSize(size);
- return new CachedDisplayInfo(size, rotation);
- }
+ WindowMetrics windowMetrics = displayInfoContext.getSystemService(WindowManager.class)
+ .getMaximumWindowMetrics();
+ return getDisplayInfo(windowMetrics, rotation);
}
/**
* Returns a CachedDisplayInfo initialized for the current display
*/
- @TargetApi(Build.VERSION_CODES.S)
protected CachedDisplayInfo getDisplayInfo(WindowMetrics windowMetrics, int rotation) {
Point size = new Point(windowMetrics.getBounds().right, windowMetrics.getBounds().bottom);
return new CachedDisplayInfo(size, rotation,
@@ -492,8 +480,7 @@
}
}
}
- return Utilities.ATLEAST_S ? NavigationMode.NO_BUTTON :
- NavigationMode.THREE_BUTTONS;
+ return NavigationMode.NO_BUTTON;
}
@Override
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index d3160e0..b8481c5 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -26,9 +26,11 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+import android.app.Activity;
import android.app.ActivityOptions;
import android.app.PendingIntent;
import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
@@ -46,6 +48,7 @@
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.AccessibilityDelegate;
+import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowInsetsController;
import android.view.inputmethod.InputMethodManager;
@@ -76,10 +79,11 @@
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.util.ActivityOptionsWrapper;
-import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SplitConfigurationOptions;
+import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.ViewCache;
import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
@@ -175,6 +179,23 @@
BaseDragLayer getDragLayer();
/**
+ * @see Activity#getWindow()
+ * @return Window
+ */
+ @Nullable
+ default Window getWindow() {
+ return null;
+ }
+
+ /**
+ * @see Activity#getComponentName()
+ * @return ComponentName
+ */
+ default ComponentName getComponentName() {
+ return null;
+ }
+
+ /**
* The all apps container, if it exists in this context.
*/
default ActivityAllAppsContainerView<?> getAppsView() {
@@ -216,6 +237,11 @@
return null;
}
+ @Nullable
+ default SystemUiController getSystemUiController() {
+ return null;
+ }
+
/**
* Handler for actions taken on drop targets that require launcher
*/
@@ -391,7 +417,7 @@
View v, Intent intent, @Nullable ItemInfo item) {
Preconditions.assertUIThread();
Context context = (Context) this;
- if (isAppBlockedForSafeMode() && !PackageManagerHelper.isSystemApp(context, intent)) {
+ if (isAppBlockedForSafeMode() && !new ApplicationInfoWrapper(context, intent).isSystem()) {
Toast.makeText(context, R.string.safemode_shortcut_error, Toast.LENGTH_SHORT).show();
return null;
}
diff --git a/src/com/android/launcher3/views/BaseDragLayer.java b/src/com/android/launcher3/views/BaseDragLayer.java
index 5d2d3f4..ea3fb3f 100644
--- a/src/com/android/launcher3/views/BaseDragLayer.java
+++ b/src/com/android/launcher3/views/BaseDragLayer.java
@@ -107,7 +107,7 @@
protected final RectF mSystemGestureRegion = new RectF();
private int mTouchDispatchState = 0;
- protected final T mActivity;
+ protected final T mContainer;
private final MultiValueAlpha mMultiValueAlpha;
// All the touch controllers for the view
@@ -121,7 +121,7 @@
public BaseDragLayer(Context context, AttributeSet attrs, int alphaChannelCount) {
super(context, attrs);
- mActivity = ActivityContext.lookupContext(context);
+ mContainer = ActivityContext.lookupContext(context);
mMultiValueAlpha = new MultiValueAlpha(this, alphaChannelCount);
}
@@ -159,7 +159,7 @@
}
mTouchCompleteListener = null;
} else if (action == MotionEvent.ACTION_DOWN) {
- mActivity.finishAutoCancelActionMode();
+ mContainer.finishAutoCancelActionMode();
}
return findActiveController(ev);
}
@@ -173,7 +173,7 @@
}
private TouchController findControllerToHandleTouch(MotionEvent ev) {
- AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
+ AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mContainer);
if (topView != null
&& (isEventWithinSystemGestureRegion(ev)
|| topView.canInterceptEventsInSystemGestureRegion())
@@ -207,7 +207,7 @@
@Override
public boolean onRequestSendAccessibilityEvent(View child, AccessibilityEvent event) {
// Shortcuts can appear above folder
- View topView = AbstractFloatingView.getTopOpenViewWithType(mActivity,
+ View topView = AbstractFloatingView.getTopOpenViewWithType(mContainer,
AbstractFloatingView.TYPE_ACCESSIBLE);
if (topView != null) {
if (child == topView) {
@@ -222,7 +222,7 @@
@Override
public void addChildrenForAccessibility(ArrayList<View> childrenForAccessibility) {
- View topView = AbstractFloatingView.getTopOpenViewWithType(mActivity,
+ View topView = AbstractFloatingView.getTopOpenViewWithType(mContainer,
AbstractFloatingView.TYPE_ACCESSIBLE);
if (topView != null) {
// Only add the top view as a child for accessibility when it is open
@@ -458,7 +458,7 @@
@Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
- View topView = AbstractFloatingView.getTopOpenView(mActivity);
+ View topView = AbstractFloatingView.getTopOpenView(mContainer);
if (topView != null) {
return topView.requestFocus(direction, previouslyFocusedRect);
} else {
@@ -468,7 +468,7 @@
@Override
public void addFocusables(ArrayList<View> views, int direction, int focusableMode) {
- View topView = AbstractFloatingView.getTopOpenView(mActivity);
+ View topView = AbstractFloatingView.getTopOpenView(mContainer);
if (topView != null) {
topView.addFocusables(views, direction);
} else {
@@ -555,7 +555,7 @@
Insets gestureInsets = insets.getMandatorySystemGestureInsets();
int gestureInsetBottom = gestureInsets.bottom;
Insets imeInset = insets.getInsets(WindowInsets.Type.ime());
- DeviceProfile dp = mActivity.getDeviceProfile();
+ DeviceProfile dp = mContainer.getDeviceProfile();
if (dp.isTaskbarPresent) {
// Ignore taskbar gesture insets to avoid interfering with TouchControllers.
gestureInsetBottom = ResourceUtils.getNavbarSize(
diff --git a/src/com/android/launcher3/views/ScrimView.java b/src/com/android/launcher3/views/ScrimView.java
index f6c4984..ce58de1 100644
--- a/src/com/android/launcher3/views/ScrimView.java
+++ b/src/com/android/launcher3/views/ScrimView.java
@@ -29,7 +29,6 @@
import androidx.annotation.Px;
import androidx.core.graphics.ColorUtils;
-import com.android.launcher3.BaseActivity;
import com.android.launcher3.Insettable;
import com.android.launcher3.util.SystemUiController;
@@ -143,7 +142,8 @@
private SystemUiController getSystemUiController() {
if (mSystemUiController == null) {
- mSystemUiController = BaseActivity.fromContext(getContext()).getSystemUiController();
+ mSystemUiController =
+ ActivityContext.lookupContext(getContext()).getSystemUiController();
}
return mSystemUiController;
}
diff --git a/src/com/android/launcher3/views/SpringRelativeLayout.java b/src/com/android/launcher3/views/SpringRelativeLayout.java
index 923eb19..a13152e 100644
--- a/src/com/android/launcher3/views/SpringRelativeLayout.java
+++ b/src/com/android/launcher3/views/SpringRelativeLayout.java
@@ -25,8 +25,6 @@
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.EdgeEffectFactory;
-import com.android.launcher3.Utilities;
-
/**
* View group to allow rendering overscroll effect in a child at the parent level
*/
@@ -46,10 +44,8 @@
public SpringRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mEdgeGlowTop = Utilities.ATLEAST_S
- ? new EdgeEffect(context, attrs) : new EdgeEffect(context);
- mEdgeGlowBottom = Utilities.ATLEAST_S
- ? new EdgeEffect(context, attrs) : new EdgeEffect(context);
+ mEdgeGlowTop = new EdgeEffect(context, attrs);
+ mEdgeGlowBottom = new EdgeEffect(context, attrs);
setWillNotDraw(false);
}
diff --git a/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java b/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
index 856f4b3..12a14c2 100644
--- a/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java
@@ -104,7 +104,7 @@
@UiThread
private void enforceRoundedCorners() {
- if (mEnforcedCornerRadius <= 0 || !RoundedCornerEnforcement.isRoundedCornerEnabled()) {
+ if (mEnforcedCornerRadius <= 0) {
resetRoundedCorners();
return;
}
diff --git a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
index 2817299..ab42839 100644
--- a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
+++ b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java
@@ -183,19 +183,14 @@
// Draw horizontal and vertical lines to represent individual columns.
final Paint p = new Paint(Paint.ANTI_ALIAS_FLAG);
+ boxRect = new RectF(/* left= */ 0, /* top= */ 0, /* right= */
+ previewWidthF, /* bottom= */ previewHeightF);
- if (Utilities.ATLEAST_S) {
- boxRect = new RectF(/* left= */ 0, /* top= */ 0, /* right= */
- previewWidthF, /* bottom= */ previewHeightF);
-
- p.setStyle(Paint.Style.FILL);
- p.setColor(Color.WHITE);
- float roundedCorner = mContext.getResources().getDimension(
- android.R.dimen.system_app_widget_background_radius);
- c.drawRoundRect(boxRect, roundedCorner, roundedCorner, p);
- } else {
- boxRect = drawBoxWithShadow(c, previewWidthF, previewHeightF);
- }
+ p.setStyle(Paint.Style.FILL);
+ p.setColor(Color.WHITE);
+ float roundedCorner = mContext.getResources().getDimension(
+ android.R.dimen.system_app_widget_background_radius);
+ c.drawRoundRect(boxRect, roundedCorner, roundedCorner, p);
p.setStyle(Paint.Style.STROKE);
p.setStrokeWidth(mContext.getResources()
diff --git a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
index 3e4fd8c..e77ba24 100644
--- a/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
+++ b/src/com/android/launcher3/widget/LauncherAppWidgetProviderInfo.java
@@ -1,7 +1,5 @@
package com.android.launcher3.widget;
-import static com.android.launcher3.Utilities.ATLEAST_S;
-
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
@@ -116,15 +114,13 @@
getSpanY(widgetPadding, minResizeHeight, dp.cellLayoutBorderSpacePx.y,
cellSize.y));
- if (ATLEAST_S) {
- if (maxResizeWidth > 0) {
- maxSpanX = Math.min(maxSpanX, getSpanX(widgetPadding, maxResizeWidth,
- dp.cellLayoutBorderSpacePx.x, cellSize.x));
- }
- if (maxResizeHeight > 0) {
- maxSpanY = Math.min(maxSpanY, getSpanY(widgetPadding, maxResizeHeight,
- dp.cellLayoutBorderSpacePx.y, cellSize.y));
- }
+ if (maxResizeWidth > 0) {
+ maxSpanX = Math.min(maxSpanX, getSpanX(widgetPadding, maxResizeWidth,
+ dp.cellLayoutBorderSpacePx.x, cellSize.x));
+ }
+ if (maxResizeHeight > 0) {
+ maxSpanY = Math.min(maxSpanY, getSpanY(widgetPadding, maxResizeHeight,
+ dp.cellLayoutBorderSpacePx.y, cellSize.y));
}
spanX = Math.max(spanX,
@@ -135,18 +131,16 @@
cellSize.y));
}
- if (ATLEAST_S) {
- // Ensures maxSpan >= minSpan
- maxSpanX = Math.max(maxSpanX, minSpanX);
- maxSpanY = Math.max(maxSpanY, minSpanY);
+ // Ensures maxSpan >= minSpan
+ maxSpanX = Math.max(maxSpanX, minSpanX);
+ maxSpanY = Math.max(maxSpanY, minSpanY);
- // Use targetCellWidth/Height if it is within the min/max ranges.
- // Otherwise, use the span of minWidth/Height.
- if (targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX
- && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {
- spanX = targetCellWidth;
- spanY = targetCellHeight;
- }
+ // Use targetCellWidth/Height if it is within the min/max ranges.
+ // Otherwise, use the span of minWidth/Height.
+ if (targetCellWidth >= minSpanX && targetCellWidth <= maxSpanX
+ && targetCellHeight >= minSpanY && targetCellHeight <= maxSpanY) {
+ spanX = targetCellWidth;
+ spanY = targetCellHeight;
}
// If minSpanX/Y > spanX/Y, ignore the minSpanX/Y to match the behavior described in
@@ -213,8 +207,7 @@
}
public boolean isConfigurationOptional() {
- return ATLEAST_S
- && isReconfigurable()
+ return isReconfigurable()
&& (getWidgetFeatures() & WIDGET_FEATURE_CONFIGURATION_OPTIONAL) != 0;
}
diff --git a/src/com/android/launcher3/widget/PendingItemDragHelper.java b/src/com/android/launcher3/widget/PendingItemDragHelper.java
index 8857774..130d533 100644
--- a/src/com/android/launcher3/widget/PendingItemDragHelper.java
+++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java
@@ -136,9 +136,7 @@
Drawable p = new FastBitmapDrawable(new DatabaseWidgetPreviewLoader(launcher)
.generateWidgetPreview(
createWidgetInfo.info, maxWidth, previewSizeBeforeScale));
- if (RoundedCornerEnforcement.isRoundedCornerEnabled()) {
- p = new RoundDrawableWrapper(p, mEnforcedRoundedCornersForWidget);
- }
+ p = new RoundDrawableWrapper(p, mEnforcedRoundedCornersForWidget);
preview = p;
}
diff --git a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
index a2fac46..cadaf89 100644
--- a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
+++ b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java
@@ -28,7 +28,6 @@
import androidx.annotation.Nullable;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import java.util.ArrayList;
import java.util.List;
@@ -70,11 +69,6 @@
return background.getId() == android.R.id.background && background.getClipToOutline();
}
- /** Check if the app widget is in the deny list. */
- public static boolean isRoundedCornerEnabled() {
- return Utilities.ATLEAST_S;
- }
-
/**
* Computes the rounded rectangle needed for this app widget.
*
@@ -101,9 +95,6 @@
* in the given context.
*/
public static float computeEnforcedRadius(@NonNull Context context) {
- if (!Utilities.ATLEAST_S) {
- return 0;
- }
Resources res = context.getResources();
float systemRadius = res.getDimension(android.R.dimen.system_app_widget_background_radius);
float defaultRadius = res.getDimension(R.dimen.enforced_rounded_corner_max_radius);
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
index 9253b37..f8dc6b0 100644
--- a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
@@ -24,7 +24,7 @@
import com.android.launcher3.R;
import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.ResourceBasedOverride;
@@ -62,14 +62,14 @@
// via the overridden WidgetRecommendationCategoryProvider resource.
Preconditions.assertWorkerThread();
- try (PackageManagerHelper pmHelper = new PackageManagerHelper(context)) {
- if (item.widgetInfo != null && item.widgetInfo.getComponent() != null) {
- ApplicationInfo applicationInfo = pmHelper.getApplicationInfo(
- item.widgetInfo.getComponent().getPackageName(), item.widgetInfo.getUser(),
- 0 /* flags */);
- if (applicationInfo != null) {
- return getCategoryFromApplicationCategory(applicationInfo.category);
- }
+ if (item.widgetInfo != null && item.widgetInfo.getComponent() != null) {
+ ApplicationInfo applicationInfo = new ApplicationInfoWrapper(
+ context,
+ item.widgetInfo.getComponent().getPackageName(),
+ item.widgetInfo.getUser())
+ .getInfo();
+ if (applicationInfo != null) {
+ return getCategoryFromApplicationCategory(applicationInfo.category);
}
}
return null;
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
index 761f06d..f57e8a1 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
@@ -45,7 +45,6 @@
private lateinit var modelHelper: LauncherModelHelper
private lateinit var context: Context
- private lateinit var validPackages: Set<String>
private lateinit var idp: InvariantDeviceProfile
private lateinit var dbHelper: DatabaseHelper
private lateinit var db: SQLiteDatabase
@@ -68,24 +67,10 @@
DatabaseHelper(
context,
null,
- UserCache.INSTANCE.get(context)::getSerialNumberForUser
+ UserCache.INSTANCE.get(context)::getSerialNumberForUser,
) {}
db = dbHelper.writableDatabase
- validPackages =
- setOf(
- testPackage1,
- testPackage2,
- testPackage3,
- testPackage4,
- testPackage5,
- testPackage6,
- testPackage7,
- testPackage8,
- testPackage9,
- testPackage10
- )
-
idp = InvariantDeviceProfile.INSTANCE[context]
val userSerial = UserCache.INSTANCE[context].getSerialNumberForUser(Process.myUserHandle())
LauncherDbUtils.dropTable(db, TMP_TABLE)
@@ -126,8 +111,8 @@
idp.numDatabaseHotseatIcons = 4
idp.numColumns = 4
idp.numRows = 4
- val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
- val destReader = DbReader(db, TABLE_NAME, context, validPackages)
+ val srcReader = DbReader(db, TMP_TABLE, context)
+ val destReader = DbReader(db, TABLE_NAME, context)
GridSizeMigrationUtil.migrate(
dbHelper,
srcReader,
@@ -135,7 +120,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Check hotseat items
@@ -147,9 +132,8 @@
null,
SCREEN,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
assertThat(c.count).isEqualTo(idp.numDatabaseHotseatIcons)
@@ -178,9 +162,8 @@
null,
null,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
intentIndex = c.getColumnIndex(INTENT)
val cellXIndex = c.getColumnIndex(CELLX)
@@ -238,8 +221,8 @@
idp.numDatabaseHotseatIcons = 4
idp.numColumns = 4
idp.numRows = 4
- val readerGridA = DbReader(db, TMP_TABLE, context, validPackages)
- val readerGridB = DbReader(db, TABLE_NAME, context, validPackages)
+ val readerGridA = DbReader(db, TMP_TABLE, context)
+ val readerGridB = DbReader(db, TABLE_NAME, context)
// migrate from A -> B
GridSizeMigrationUtil.migrate(
dbHelper,
@@ -248,7 +231,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Check hotseat items in grid B
@@ -260,15 +243,14 @@
null,
SCREEN,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
// Expected hotseat items in grid B
// 2 1 3 4
verifyHotseat(
c,
idp,
- mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList()
+ mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList(),
)
// Check workspace items in grid B
@@ -280,9 +262,8 @@
null,
null,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
var locMap = parseLocMap(c)
// Expected items in grid B
// _ _ _ _
@@ -306,7 +287,7 @@
5,
Point(5, 5),
DeviceGridState(idp),
- DeviceGridState(context)
+ DeviceGridState(context),
)
// Check hotseat items in grid A
c =
@@ -317,15 +298,14 @@
null,
SCREEN,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
// Expected hotseat items in grid A
// 1 2 _ 3 4
verifyHotseat(
c,
idp,
- mutableListOf(testPackage1, testPackage2, null, testPackage3, testPackage4).toList()
+ mutableListOf(testPackage1, testPackage2, null, testPackage3, testPackage4).toList(),
)
// Check workspace items in grid A
@@ -337,9 +317,8 @@
null,
null,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
locMap = parseLocMap(c)
// Expected workspace items in grid A
// _ _ _ _ _
@@ -367,7 +346,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Check hotseat items in grid B
@@ -379,15 +358,14 @@
null,
SCREEN,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
// Expected hotseat items in grid B
// 2 1 3 4
verifyHotseat(
c,
idp,
- mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList()
+ mutableListOf(testPackage2, testPackage1, testPackage3, testPackage4).toList(),
)
// Check workspace items in grid B
@@ -399,9 +377,8 @@
null,
null,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
locMap = parseLocMap(c)
// Expected workspace items in grid B
// _ _ _ _
@@ -455,7 +432,7 @@
0,
testPackage1,
1,
- TMP_TABLE
+ TMP_TABLE,
),
addItem(
ITEM_TYPE_DEEP_SHORTCUT,
@@ -465,7 +442,7 @@
0,
testPackage2,
2,
- TMP_TABLE
+ TMP_TABLE,
),
addItem(
ITEM_TYPE_APPLICATION,
@@ -475,7 +452,7 @@
0,
testPackage3,
3,
- TMP_TABLE
+ TMP_TABLE,
),
addItem(
ITEM_TYPE_DEEP_SHORTCUT,
@@ -485,15 +462,15 @@
0,
testPackage4,
4,
- TMP_TABLE
- )
+ TMP_TABLE,
+ ),
)
val numSrcDatabaseHotseatIcons = srcHotseatItems.size
idp.numDatabaseHotseatIcons = 6
idp.numColumns = 4
idp.numRows = 4
- val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
- val destReader = DbReader(db, TABLE_NAME, context, validPackages)
+ val srcReader = DbReader(db, TMP_TABLE, context)
+ val destReader = DbReader(db, TABLE_NAME, context)
GridSizeMigrationUtil.migrate(
dbHelper,
srcReader,
@@ -501,7 +478,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Check hotseat items
@@ -513,9 +490,8 @@
null,
SCREEN,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
assertThat(c.count.toLong()).isEqualTo(numSrcDatabaseHotseatIcons.toLong())
val screenIndex = c.getColumnIndex(SCREEN)
@@ -550,8 +526,8 @@
idp.numDatabaseHotseatIcons = 4
idp.numColumns = 4
idp.numRows = 4
- val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
- val destReader = DbReader(db, TABLE_NAME, context, validPackages)
+ val srcReader = DbReader(db, TMP_TABLE, context)
+ val destReader = DbReader(db, TABLE_NAME, context)
GridSizeMigrationUtil.migrate(
dbHelper,
srcReader,
@@ -559,7 +535,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Check hotseat items
@@ -571,9 +547,8 @@
null,
SCREEN,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
assertThat(c.count.toLong()).isEqualTo(idp.numDatabaseHotseatIcons.toLong())
val screenIndex = c.getColumnIndex(SCREEN)
@@ -617,8 +592,8 @@
idp.numDatabaseHotseatIcons = 4
idp.numColumns = 5
idp.numRows = 5
- val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
- val destReader = DbReader(db, TABLE_NAME, context, validPackages)
+ val srcReader = DbReader(db, TMP_TABLE, context)
+ val destReader = DbReader(db, TABLE_NAME, context)
GridSizeMigrationUtil.migrate(
dbHelper,
srcReader,
@@ -626,7 +601,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Get workspace items
@@ -638,9 +613,8 @@
null,
null,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
val intentIndex = c.getColumnIndex(INTENT)
val screenIndex = c.getColumnIndex(SCREEN)
@@ -678,8 +652,8 @@
idp.numDatabaseHotseatIcons = 4
idp.numColumns = 4
idp.numRows = 4
- val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
- val destReader = DbReader(db, TABLE_NAME, context, validPackages)
+ val srcReader = DbReader(db, TMP_TABLE, context)
+ val destReader = DbReader(db, TABLE_NAME, context)
GridSizeMigrationUtil.migrate(
dbHelper,
srcReader,
@@ -687,7 +661,7 @@
idp.numDatabaseHotseatIcons,
Point(idp.numColumns, idp.numRows),
DeviceGridState(context),
- DeviceGridState(idp)
+ DeviceGridState(idp),
)
// Get workspace items
@@ -699,9 +673,8 @@
null,
null,
null,
- null
- )
- ?: throw IllegalStateException()
+ null,
+ ) ?: throw IllegalStateException()
val intentIndex = c.getColumnIndex(INTENT)
val screenIndex = c.getColumnIndex(SCREEN)
@@ -732,7 +705,7 @@
container: Int,
x: Int,
y: Int,
- packageName: String?
+ packageName: String?,
): Int {
return addItem(
type,
@@ -742,7 +715,7 @@
y,
packageName,
dbHelper.generateNewItemId(),
- TABLE_NAME
+ TABLE_NAME,
)
}
@@ -754,7 +727,7 @@
y: Int,
packageName: String?,
id: Int,
- tableName: String
+ tableName: String,
): Int {
val values = ContentValues()
values.put(_ID, id)
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
index 1d9c161..7529ba9 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
@@ -118,11 +118,17 @@
`package` = "pkg"
putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "")
}
+ mockLauncherApps =
+ mock<LauncherApps>().apply {
+ whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
+ whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true)
+ }
mockContext =
mock<Context>().apply {
whenever(packageManager).thenReturn(mock())
whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext())
+ whenever(getSystemService(LauncherApps::class.java)).thenReturn(mockLauncherApps)
}
mockAppState =
mock<LauncherAppState>().apply {
@@ -135,11 +141,6 @@
whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
.thenReturn(intent)
}
- mockLauncherApps =
- mock<LauncherApps>().apply {
- whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
- whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true)
- }
mockCursor =
mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply {
user = mUserHandle
@@ -193,7 +194,7 @@
pendingPackages: MutableSet<PackageUserKey> = mPendingPackages,
unlockedUsers: LongSparseArray<Boolean> = mUnlockedUsersArray,
installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = mInstallingPkgs,
- allDeepShortcuts: MutableList<ShortcutInfo> = mAllDeepShortcuts
+ allDeepShortcuts: MutableList<ShortcutInfo> = mAllDeepShortcuts,
) =
WorkspaceItemProcessor(
c = cursor,
@@ -212,7 +213,7 @@
isSdCardReady = isSdCardReady,
shortcutKeyToPinnedShortcuts = shortcutKeyToPinnedShortcuts,
installingPkgs = installingPkgs,
- allDeepShortcuts = allDeepShortcuts
+ allDeepShortcuts = allDeepShortcuts,
)
@Test
@@ -351,7 +352,7 @@
" targetPkg=package," +
" component=ComponentInfo{package/class}." +
" Unable to create launch Intent.",
- MISSING_INFO
+ MISSING_INFO,
)
verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
}
@@ -412,7 +413,7 @@
verify(mockCursor)
.markDeleted(
"Pinned shortcut not found from request. package=pkg, user=UserHandle{0}",
- "shortcut_not_found"
+ "shortcut_not_found",
)
}
@@ -549,7 +550,7 @@
val inflationResult =
WidgetInflater.InflationResult(
type = WidgetInflater.TYPE_REAL,
- widgetInfo = expectedWidgetProviderInfo
+ widgetInfo = expectedWidgetProviderInfo,
)
mockWidgetInflater =
mock<WidgetInflater>().apply {
@@ -607,7 +608,7 @@
val inflationResult =
WidgetInflater.InflationResult(
type = WidgetInflater.TYPE_PENDING,
- widgetInfo = mockProviderInfo
+ widgetInfo = mockProviderInfo,
)
mockWidgetInflater =
mock<WidgetInflater>().apply {
@@ -662,7 +663,7 @@
verify(mockCursor)
.markDeleted(
"processWidget: Unrestored Pending widget removed: id=1, appWidgetId=0, component=$expectedComponentName, restoreFlag:=4",
- LauncherRestoreEventLogger.RestoreError.APP_NOT_INSTALLED
+ LauncherRestoreEventLogger.RestoreError.APP_NOT_INSTALLED,
)
}
@@ -670,12 +671,6 @@
fun `When widget inflation result is TYPE_DELETE then mark deleted`() {
// Given
val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
- val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
- val expectedPackage = expectedComponentName!!.packageName
- mockPmHelper =
- mock<PackageManagerHelper>().apply {
- whenever(isAppArchived(expectedPackage)).thenReturn(true)
- }
mockCursor =
mock<LoaderCursor>().apply {
itemType = ITEM_TYPE_APPWIDGET
@@ -694,7 +689,7 @@
type = WidgetInflater.TYPE_DELETE,
widgetInfo = null,
reason = "test_delete_reason",
- restoreErrorType = MISSING_WIDGET_PROVIDER
+ restoreErrorType = MISSING_WIDGET_PROVIDER,
)
mockWidgetInflater =
mock<WidgetInflater>().apply {
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/ApplicationInfoWrapperTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/ApplicationInfoWrapperTest.kt
new file mode 100644
index 0000000..86c3fd8
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/ApplicationInfoWrapperTest.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2024 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.pm.ApplicationInfo
+import android.content.pm.ApplicationInfo.FLAG_EXTERNAL_STORAGE
+import android.content.pm.ApplicationInfo.FLAG_INSTALLED
+import android.content.pm.ApplicationInfo.FLAG_SUSPENDED
+import android.content.pm.ApplicationInfo.FLAG_SYSTEM
+import android.content.pm.LauncherApps
+import android.os.UserHandle
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNotNull
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.whenever
+
+/** Unit tests for {@link ApplicationInfoWrapper}. */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ApplicationInfoWrapperTest {
+
+ @get:Rule val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
+
+ private lateinit var context: Context
+ private lateinit var launcherApps: LauncherApps
+
+ @Before
+ fun setup() {
+ context = Mockito.mock(Context::class.java)
+ launcherApps = Mockito.mock(LauncherApps::class.java)
+ whenever(context.getSystemService(eq(LauncherApps::class.java))).thenReturn(launcherApps)
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
+ fun archivedApp_appInfoIsNotNull() {
+ val applicationInfo = ApplicationInfo()
+ applicationInfo.isArchived = true
+ whenever(launcherApps.getApplicationInfo(eq(TEST_PACKAGE), any(), eq(TEST_USER)))
+ .thenReturn(applicationInfo)
+
+ val wrapper = ApplicationInfoWrapper(context, TEST_PACKAGE, TEST_USER)
+ assertNotNull(wrapper.getInfo())
+ assertTrue(wrapper.isArchived())
+ assertFalse(wrapper.isInstalled())
+ }
+
+ @Test
+ fun notInstalledApp_nullAppInfo() {
+ val applicationInfo = ApplicationInfo()
+ whenever(launcherApps.getApplicationInfo(eq(TEST_PACKAGE), any(), eq(TEST_USER)))
+ .thenReturn(applicationInfo)
+
+ val wrapper = ApplicationInfoWrapper(context, TEST_PACKAGE, TEST_USER)
+ assertNull(wrapper.getInfo())
+ assertFalse(wrapper.isInstalled())
+ }
+
+ @Test
+ fun appInfo_suspended() {
+ val wrapper =
+ ApplicationInfoWrapper(
+ ApplicationInfo().apply { flags = FLAG_INSTALLED.or(FLAG_SUSPENDED) }
+ )
+ assertTrue(wrapper.isSuspended())
+ }
+
+ @Test
+ fun appInfo_notSuspended() {
+ val wrapper = ApplicationInfoWrapper(ApplicationInfo())
+ assertFalse(wrapper.isSuspended())
+ }
+
+ @Test
+ fun appInfo_system() {
+ val wrapper = ApplicationInfoWrapper(ApplicationInfo().apply { flags = FLAG_SYSTEM })
+ assertTrue(wrapper.isSystem())
+ }
+
+ @Test
+ fun appInfo_notSystem() {
+ val wrapper = ApplicationInfoWrapper(ApplicationInfo())
+ assertFalse(wrapper.isSystem())
+ }
+
+ @Test
+ fun appInfo_onSDCard() {
+ val wrapper =
+ ApplicationInfoWrapper(ApplicationInfo().apply { flags = FLAG_EXTERNAL_STORAGE })
+ assertTrue(wrapper.isOnSdCard())
+ }
+
+ @Test
+ fun appInfo_notOnSDCard() {
+ val wrapper = ApplicationInfoWrapper(ApplicationInfo())
+ assertFalse(wrapper.isOnSdCard())
+ }
+
+ companion object {
+ const val TEST_PACKAGE = "com.android.test.package"
+ private val TEST_USER = UserHandle.of(3)
+ }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
index d4e4bd2..308f200 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -41,6 +41,7 @@
import junit.framework.Assert.assertFalse
import junit.framework.Assert.assertTrue
import kotlin.math.min
+import org.junit.After
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -81,7 +82,7 @@
WindowBounds(Rect(0, 0, width, height), Rect(0, inset, 0, 0), Surface.ROTATION_0),
WindowBounds(Rect(0, 0, height, width), Rect(0, inset, 0, 0), Surface.ROTATION_90),
WindowBounds(Rect(0, 0, width, height), Rect(0, inset, 0, 0), Surface.ROTATION_180),
- WindowBounds(Rect(0, 0, height, width), Rect(0, inset, 0, 0), Surface.ROTATION_270)
+ WindowBounds(Rect(0, 0, height, width), Rect(0, inset, 0, 0), Surface.ROTATION_270),
)
private val configuration =
Configuration(appContext.resources.configuration).apply {
@@ -137,6 +138,13 @@
displayController.addChangeListener(displayInfoChangeListener)
}
+ @After
+ fun tearDown() {
+ // We need to reset the taskbar mode preference override even if a test throws an exception.
+ // Otherwise, it may break the following tests' assumptions.
+ DisplayController.enableTaskbarModePreferenceForTests(false)
+ }
+
@Test
@UiThreadTest
fun testRotation() {
@@ -170,7 +178,7 @@
@UiThreadTest
fun testTaskbarPinning() {
whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(true)
- displayController.handleInfoChange(display)
+ displayController.notifyConfigChange()
verify(displayInfoChangeListener)
.onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
}
@@ -179,7 +187,7 @@
@UiThreadTest
fun testTaskbarPinningChangeInDesktopMode() {
whenever(launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)).thenReturn(false)
- displayController.handleInfoChange(display)
+ displayController.notifyConfigChange()
verify(displayInfoChangeListener)
.onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
}
@@ -194,7 +202,7 @@
DisplayController.enableTaskbarModePreferenceForTests(true)
assertTrue(displayController.getInfo().isTransientTaskbar())
- displayController.handleInfoChange(display)
+ displayController.notifyConfigChange()
verify(displayInfoChangeListener)
.onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
assertFalse(displayController.getInfo().isTransientTaskbar())
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/PackageManagerHelperTest.java b/tests/multivalentTests/src/com/android/launcher3/util/PackageManagerHelperTest.java
deleted file mode 100644
index b5e797e..0000000
--- a/tests/multivalentTests/src/com/android/launcher3/util/PackageManagerHelperTest.java
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright (C) 2024 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 static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
-
-import static com.google.common.truth.Truth.assertThat;
-
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.LauncherApps;
-import android.content.pm.PackageManager;
-import android.os.UserHandle;
-import android.platform.test.annotations.RequiresFlagsEnabled;
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.DeviceFlagsValueProvider;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-import androidx.test.platform.app.InstrumentationRegistry;
-
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.junit.runner.RunWith;
-
-/** Unit tests for {@link PackageManagerHelper}. */
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public final class PackageManagerHelperTest {
- @Rule
- public ExpectedException exception = ExpectedException.none();
-
- @Rule
- public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
-
- private static final String TEST_PACKAGE = "com.android.test.package";
- private static final int TEST_USER = 2;
-
- private Context mContext;
- private LauncherApps mLauncherApps;
- private PackageManagerHelper mPackageManagerHelper;
-
- @Before
- public void setup() {
- mContext = mock(Context.class);
- mLauncherApps = mock(LauncherApps.class);
- when(mContext.getSystemService(eq(LauncherApps.class))).thenReturn(mLauncherApps);
- when(mContext.getResources()).thenReturn(
- InstrumentationRegistry.getInstrumentation().getTargetContext().getResources());
- mPackageManagerHelper = new PackageManagerHelper(mContext);
- }
-
- @Test
- @RequiresFlagsEnabled(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
- public void getApplicationInfo_archivedApp_appInfoIsNotNull()
- throws PackageManager.NameNotFoundException {
- ApplicationInfo applicationInfo = new ApplicationInfo();
- applicationInfo.isArchived = true;
- when(mLauncherApps.getApplicationInfo(TEST_PACKAGE, 0 /* flags */,
- UserHandle.of(TEST_USER)))
- .thenReturn(applicationInfo);
-
- assertThat(mPackageManagerHelper.getApplicationInfo(TEST_PACKAGE, UserHandle.of(TEST_USER),
- 0 /* flags */))
- .isNotNull();
- }
-}
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/SystemUiControllerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/SystemUiControllerTest.kt
index 612fcd4..043bdac 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/SystemUiControllerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/SystemUiControllerTest.kt
@@ -52,7 +52,7 @@
fun setup() {
MockitoAnnotations.initMocks(this)
`when`(window.decorView).thenReturn(decorView)
- underTest = SystemUiController(window)
+ underTest = SystemUiController(window.decorView)
}
@Test
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProviderTest.java b/tests/multivalentTests/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProviderTest.java
index 3024d26..8b6553f 100644
--- a/tests/multivalentTests/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProviderTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProviderTest.java
@@ -30,14 +30,16 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
import android.content.Context;
-import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
import android.content.pm.LauncherApps;
import android.os.Process;
@@ -102,13 +104,8 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
- mContext = new ContextWrapper(getInstrumentation().getTargetContext()) {
- @Override
- public Object getSystemService(String name) {
- return LAUNCHER_APPS_SERVICE.equals(name) ? mLauncherApps : super.getSystemService(
- name);
- }
- };
+ mContext = spy(getInstrumentation().getTargetContext());
+ doReturn(mLauncherApps).when(mContext).getSystemService(LauncherApps.class);
mTestAppInfo.flags = FLAG_INSTALLED;
mTestProfile = new InvariantDeviceProfile();
mTestProfile.numRows = 5;
@@ -132,7 +129,7 @@
mTestAppInfo.category = testCategory.getKey();
when(mLauncherApps.getApplicationInfo(/*packageName=*/ eq(TEST_PACKAGE),
- /*flags=*/ eq(0),
+ /*flags=*/ anyInt(),
/*user=*/ eq(Process.myUserHandle())))
.thenReturn(mTestAppInfo);
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt
index b93c305..f1b6271 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorExtraTest.kt
@@ -20,6 +20,7 @@
import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.content.pm.ApplicationInfo
import android.content.pm.LauncherApps
import android.content.pm.PackageInstaller
import android.content.pm.ShortcutInfo
@@ -28,14 +29,12 @@
import android.util.LongSparseArray
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
-import com.android.dx.mockito.inline.extended.ExtendedMockito
import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherSettings.Favorites
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET
-import com.android.launcher3.Utilities
import com.android.launcher3.model.data.IconRequestInfo
import com.android.launcher3.model.data.LauncherAppWidgetInfo
import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_RESTORE_STARTED
@@ -48,7 +47,6 @@
import com.android.launcher3.util.PackageUserKey
import com.android.launcher3.util.UserIconInfo
import com.android.launcher3.widget.WidgetInflater
-import com.android.launcher3.widget.WidgetSections
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -63,7 +61,6 @@
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
-import org.mockito.quality.Strictness
@RunWith(AndroidJUnit4::class)
class WorkspaceItemProcessorExtraTest {
@@ -108,11 +105,17 @@
`package` = "pkg"
putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "")
}
+ mockLauncherApps =
+ mock<LauncherApps>().apply {
+ whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
+ whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true)
+ }
mockContext =
mock<Context>().apply {
whenever(packageManager).thenReturn(mock())
whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
whenever(applicationContext).thenReturn(ApplicationProvider.getApplicationContext())
+ whenever(getSystemService(LauncherApps::class.java)).thenReturn(mockLauncherApps)
}
mockAppState =
mock<LauncherAppState>().apply {
@@ -125,11 +128,6 @@
whenever(getAppLaunchIntent(mComponentName.packageName, mUserHandle))
.thenReturn(intent)
}
- mockLauncherApps =
- mock<LauncherApps>().apply {
- whenever(isPackageEnabled("package", mUserHandle)).thenReturn(true)
- whenever(isActivityEnabled(mComponentName, mUserHandle)).thenReturn(true)
- }
mockCursor =
Mockito.mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply {
user = mUserHandle
@@ -163,138 +161,116 @@
@Test
fun `When Pending App Widget has not started restore then update db and add item`() {
-
- val mockitoSession =
- ExtendedMockito.mockitoSession()
- .strictness(Strictness.LENIENT)
- .mockStatic(WidgetSections::class.java)
- .startMocking()
- try {
- // Given
- val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
- val expectedComponentName =
- ComponentName.unflattenFromString(expectedProvider)!!.flattenToString()
- val expectedRestoreStatus = FLAG_UI_NOT_READY or FLAG_RESTORE_STARTED
- val expectedAppWidgetId = 0
- mockCursor.apply {
- itemType = ITEM_TYPE_APPWIDGET
- user = mUserHandle
- restoreFlag = FLAG_UI_NOT_READY
- container = CONTAINER_DESKTOP
- whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
- whenever(appWidgetProvider).thenReturn(expectedProvider)
- whenever(appWidgetId).thenReturn(expectedAppWidgetId)
- whenever(spanX).thenReturn(2)
- whenever(spanY).thenReturn(1)
- whenever(options).thenReturn(0)
- whenever(appWidgetSource).thenReturn(20)
- whenever(applyCommonProperties(any())).thenCallRealMethod()
- whenever(
- updater()
- .put(Favorites.APPWIDGET_PROVIDER, expectedComponentName)
- .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
- .put(Favorites.RESTORED, expectedRestoreStatus)
- .commit()
- )
- .thenReturn(1)
- }
- val inflationResult =
- WidgetInflater.InflationResult(
- type = WidgetInflater.TYPE_PENDING,
- widgetInfo = null
- )
- mockWidgetInflater =
- mock<WidgetInflater>().apply {
- whenever(inflateAppWidget(any())).thenReturn(inflationResult)
- }
- val packageUserKey = PackageUserKey("com.google.android.testApp", mUserHandle)
- mInstallingPkgs[packageUserKey] = PackageInstaller.SessionInfo()
-
- // When
- itemProcessorUnderTest =
- createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
- itemProcessorUnderTest.processItem()
-
- // Then
- val expectedWidgetInfo =
- LauncherAppWidgetInfo().apply {
- appWidgetId = expectedAppWidgetId
- providerName = ComponentName.unflattenFromString(expectedProvider)
- restoreStatus = expectedRestoreStatus
- }
- verify(
- mockCursor
- .updater()
- .put(Favorites.APPWIDGET_PROVIDER, expectedProvider)
+ // Given
+ val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+ val expectedComponentName =
+ ComponentName.unflattenFromString(expectedProvider)!!.flattenToString()
+ val expectedRestoreStatus = FLAG_UI_NOT_READY or FLAG_RESTORE_STARTED
+ val expectedAppWidgetId = 0
+ mockCursor.apply {
+ itemType = ITEM_TYPE_APPWIDGET
+ user = mUserHandle
+ restoreFlag = FLAG_UI_NOT_READY
+ container = CONTAINER_DESKTOP
+ whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+ whenever(appWidgetProvider).thenReturn(expectedProvider)
+ whenever(appWidgetId).thenReturn(expectedAppWidgetId)
+ whenever(spanX).thenReturn(2)
+ whenever(spanY).thenReturn(1)
+ whenever(options).thenReturn(0)
+ whenever(appWidgetSource).thenReturn(20)
+ whenever(applyCommonProperties(any())).thenCallRealMethod()
+ whenever(
+ updater()
+ .put(Favorites.APPWIDGET_PROVIDER, expectedComponentName)
.put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
.put(Favorites.RESTORED, expectedRestoreStatus)
+ .commit()
)
- .commit()
- val widgetInfoCaptor = ArgumentCaptor.forClass(LauncherAppWidgetInfo::class.java)
- verify(mockCursor).checkAndAddItem(widgetInfoCaptor.capture(), eq(mockBgDataModel))
- val actualWidgetInfo = widgetInfoCaptor.value
- with(actualWidgetInfo) {
- assertThat(providerName).isEqualTo(expectedWidgetInfo.providerName)
- assertThat(restoreStatus).isEqualTo(expectedWidgetInfo.restoreStatus)
- assertThat(targetComponent).isEqualTo(expectedWidgetInfo.targetComponent)
- assertThat(appWidgetId).isEqualTo(expectedWidgetInfo.appWidgetId)
+ .thenReturn(1)
+ }
+ val inflationResult =
+ WidgetInflater.InflationResult(type = WidgetInflater.TYPE_PENDING, widgetInfo = null)
+ mockWidgetInflater =
+ mock<WidgetInflater>().apply {
+ whenever(inflateAppWidget(any())).thenReturn(inflationResult)
}
- } finally {
- mockitoSession.finishMocking()
+ val packageUserKey = PackageUserKey("com.google.android.testApp", mUserHandle)
+ mInstallingPkgs[packageUserKey] = PackageInstaller.SessionInfo()
+
+ // When
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ val expectedWidgetInfo =
+ LauncherAppWidgetInfo().apply {
+ appWidgetId = expectedAppWidgetId
+ providerName = ComponentName.unflattenFromString(expectedProvider)
+ restoreStatus = expectedRestoreStatus
+ }
+ verify(
+ mockCursor
+ .updater()
+ .put(Favorites.APPWIDGET_PROVIDER, expectedProvider)
+ .put(Favorites.APPWIDGET_ID, expectedAppWidgetId)
+ .put(Favorites.RESTORED, expectedRestoreStatus)
+ )
+ .commit()
+ val widgetInfoCaptor = ArgumentCaptor.forClass(LauncherAppWidgetInfo::class.java)
+ verify(mockCursor).checkAndAddItem(widgetInfoCaptor.capture(), eq(mockBgDataModel))
+ val actualWidgetInfo = widgetInfoCaptor.value
+ with(actualWidgetInfo) {
+ assertThat(providerName).isEqualTo(expectedWidgetInfo.providerName)
+ assertThat(restoreStatus).isEqualTo(expectedWidgetInfo.restoreStatus)
+ assertThat(targetComponent).isEqualTo(expectedWidgetInfo.targetComponent)
+ assertThat(appWidgetId).isEqualTo(expectedWidgetInfo.appWidgetId)
}
}
@Test
@EnableFlags(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
fun `When Archived Pending App Widget then checkAndAddItem`() {
- val mockitoSession =
- ExtendedMockito.mockitoSession().mockStatic(Utilities::class.java).startMocking()
- try {
- // Given
- val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
- val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
- val expectedPackage = expectedComponentName!!.packageName
- mockPmHelper =
- mock<PackageManagerHelper>().apply {
- whenever(isAppArchived(expectedPackage)).thenReturn(true)
- }
- mockCursor =
- mock<LoaderCursor>().apply {
- itemType = ITEM_TYPE_APPWIDGET
- id = 1
- user = UserHandle(1)
- restoreFlag = FLAG_UI_NOT_READY
- container = CONTAINER_DESKTOP
- whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
- whenever(appWidgetProvider).thenReturn(expectedProvider)
- whenever(appWidgetId).thenReturn(0)
- whenever(spanX).thenReturn(2)
- whenever(spanY).thenReturn(1)
- whenever(options).thenReturn(0)
- whenever(appWidgetSource).thenReturn(20)
- whenever(applyCommonProperties(any())).thenCallRealMethod()
- }
- mInstallingPkgs = hashMapOf()
- val inflationResult =
- WidgetInflater.InflationResult(
- type = WidgetInflater.TYPE_PENDING,
- widgetInfo = null
- )
- mockWidgetInflater =
- mock<WidgetInflater>().apply {
- whenever(inflateAppWidget(any())).thenReturn(inflationResult)
- }
- itemProcessorUnderTest =
- createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
+ // Given
+ val expectedProvider = "com.google.android.testApp/com.android.testApp.testAppProvider"
+ val expectedComponentName = ComponentName.unflattenFromString(expectedProvider)
+ val expectedPackage = expectedComponentName!!.packageName
+ val expectedUser = UserHandle(1)
- // When
- itemProcessorUnderTest.processItem()
+ whenever(mockLauncherApps.getApplicationInfo(eq(expectedPackage), any(), eq(expectedUser)))
+ .thenReturn(ApplicationInfo().apply { isArchived = true })
+ mockCursor =
+ mock<LoaderCursor>().apply {
+ itemType = ITEM_TYPE_APPWIDGET
+ id = 1
+ user = expectedUser
+ restoreFlag = FLAG_UI_NOT_READY
+ container = CONTAINER_DESKTOP
+ whenever(isOnWorkspaceOrHotseat).thenCallRealMethod()
+ whenever(appWidgetProvider).thenReturn(expectedProvider)
+ whenever(appWidgetId).thenReturn(0)
+ whenever(spanX).thenReturn(2)
+ whenever(spanY).thenReturn(1)
+ whenever(options).thenReturn(0)
+ whenever(appWidgetSource).thenReturn(20)
+ whenever(applyCommonProperties(any())).thenCallRealMethod()
+ }
+ mInstallingPkgs = hashMapOf()
+ val inflationResult =
+ WidgetInflater.InflationResult(type = WidgetInflater.TYPE_PENDING, widgetInfo = null)
+ mockWidgetInflater =
+ mock<WidgetInflater>().apply {
+ whenever(inflateAppWidget(any())).thenReturn(inflationResult)
+ }
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(widgetProvidersMap = mWidgetProvidersMap)
- // Then
- verify(mockCursor).checkAndAddItem(any(), any())
- } finally {
- mockitoSession.finishMocking()
- }
+ // When
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ verify(mockCursor).checkAndAddItem(any(), any())
}
private fun createWorkspaceItemProcessorUnderTest(
@@ -314,7 +290,7 @@
pendingPackages: MutableSet<PackageUserKey> = mPendingPackages,
unlockedUsers: LongSparseArray<Boolean> = mUnlockedUsersArray,
installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = mInstallingPkgs,
- allDeepShortcuts: MutableList<ShortcutInfo> = mAllDeepShortcuts
+ allDeepShortcuts: MutableList<ShortcutInfo> = mAllDeepShortcuts,
) =
WorkspaceItemProcessor(
c = cursor,
@@ -333,6 +309,6 @@
isSdCardReady = isSdCardReady,
shortcutKeyToPinnedShortcuts = shortcutKeyToPinnedShortcuts,
installingPkgs = installingPkgs,
- allDeepShortcuts = allDeepShortcuts
+ allDeepShortcuts = allDeepShortcuts,
)
}
diff --git a/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt b/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
index 7182cf3..03d0195 100644
--- a/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
+++ b/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
@@ -114,17 +114,14 @@
}
}
- private fun migrate(
- srcGrid: Grid,
- dstGrid: Grid,
- ): List<WorkspaceItem> {
+ private fun migrate(srcGrid: Grid, dstGrid: Grid): List<WorkspaceItem> {
val userSerial = UserCache.INSTANCE[context].getSerialNumberForUser(Process.myUserHandle())
val dbHelper =
DatabaseHelper(
context,
null,
{ UserCache.INSTANCE.get(context).getSerialNumberForUser(it) },
- {}
+ {},
)
Favorites.addTableToDb(dbHelper.writableDatabase, userSerial, false, srcGrid.tableName)
@@ -135,12 +132,12 @@
LauncherDbUtils.SQLiteTransaction(dbHelper.writableDatabase).use {
GridSizeMigrationUtil.migrate(
dbHelper,
- GridSizeMigrationUtil.DbReader(it.db, srcGrid.tableName, context, MockSet(1)),
- GridSizeMigrationUtil.DbReader(it.db, dstGrid.tableName, context, MockSet(1)),
+ GridSizeMigrationUtil.DbReader(it.db, srcGrid.tableName, context),
+ GridSizeMigrationUtil.DbReader(it.db, dstGrid.tableName, context),
dstGrid.size.x,
dstGrid.size,
srcGrid.toGridState(),
- dstGrid.toGridState()
+ dstGrid.toGridState(),
)
it.commit()
}
@@ -157,7 +154,7 @@
Grid(
tableName = Favorites.TMP_TABLE,
size = testCase.srcSize,
- items = generateItemsForTest(testCase.boards, REPEAT_AFTER)
+ items = generateItemsForTest(testCase.boards, REPEAT_AFTER),
)
val dstGrid =
Grid(tableName = Favorites.TABLE_NAME, size = testCase.targetSize, items = listOf())
@@ -175,13 +172,13 @@
Grid(
tableName = Favorites.TMP_TABLE,
size = testCase.srcSize,
- items = generateItemsForTest(testCase.boards, REPEAT_AFTER)
+ items = generateItemsForTest(testCase.boards, REPEAT_AFTER),
)
val dstGrid =
Grid(
tableName = Favorites.TABLE_NAME,
size = testCase.targetSize,
- items = generateItemsForTest(testCase.destBoards, REPEAT_AFTER_DST)
+ items = generateItemsForTest(testCase.destBoards, REPEAT_AFTER_DST),
)
validate(srcGrid, dstGrid, migrate(srcGrid, dstGrid))
}
@@ -199,7 +196,7 @@
Grid(
tableName = Favorites.TMP_TABLE,
size = testCase.srcSize,
- items = generateItemsForTest(testCase.boards, REPEAT_AFTER)
+ items = generateItemsForTest(testCase.boards, REPEAT_AFTER),
)
val dstGrid =
Grid(tableName = Favorites.TABLE_NAME, size = testCase.targetSize, items = listOf())
diff --git a/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt b/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
index 3dd8dbc..ca2ef42 100644
--- a/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
+++ b/tests/src/com/android/launcher3/pm/InstallSessionHelperTest.kt
@@ -18,6 +18,7 @@
import android.content.pm.ApplicationInfo
import android.content.pm.ApplicationInfo.FLAG_INSTALLED
+import android.content.pm.ApplicationInfo.FLAG_SYSTEM
import android.content.pm.LauncherApps
import android.content.pm.PackageInstaller
import android.content.pm.PackageManager
@@ -35,7 +36,9 @@
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.any
import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.spy
import org.mockito.kotlin.whenever
@@ -126,13 +129,10 @@
fun `isTrustedPackage returns true if LauncherApps finds ApplicationInfo`() {
// Given
val expectedApplicationInfo =
- ApplicationInfo().apply {
- flags = flags or FLAG_INSTALLED
- enabled = true
- }
+ ApplicationInfo().apply { flags = FLAG_SYSTEM or FLAG_INSTALLED }
doReturn(expectedApplicationInfo)
.whenever(launcherApps)
- .getApplicationInfo(expectedAppPackage, ApplicationInfo.FLAG_SYSTEM, UserHandle(0))
+ .getApplicationInfo(eq(expectedAppPackage), any(), eq(UserHandle(0)))
// When
val actualResult = installSessionHelper.isTrustedPackage(expectedAppPackage, UserHandle(0))
// Then
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index b7ebfcd..e1bd686 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -123,10 +123,10 @@
TASK_SELECTOR);
final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
mLauncher.assertTrue(
- "All tasks not to the left of the swiped task",
- tasks.stream()
- .allMatch(
- t -> t.getVisibleBounds().right < centerX));
+ "Task(s) found to the right of the swiped task",
+ tasks.stream().allMatch(t ->
+ t.getVisibleBounds().right < centerX
+ || t.getVisibleBounds().centerX() == centerX));
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 21e93c5..78627e5 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -2423,7 +2423,7 @@
eventChecker.setLogExclusionRule(event -> {
Matcher matcher = Pattern.compile("KeyEvent.*flags=0x([0-9a-fA-F]+)").matcher(event);
if (matcher.find()) {
- int keyEventFlags = Integer.parseInt(matcher.group(1), 16);
+ long keyEventFlags = Long.parseLong(matcher.group(1), 16);
// ignore KeyEvents with FLAG_CANCELED
return (keyEventFlags & KeyEvent.FLAG_CANCELED) != 0;
}