diff options
356 files changed, 6180 insertions, 4572 deletions
diff --git a/Android.bp b/Android.bp index 4274613313..4e1c9d3d11 100644 --- a/Android.bp +++ b/Android.bp @@ -17,7 +17,7 @@ package { 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. @@ -69,6 +69,15 @@ filegroup { ], } +// Source code for quickstep dagger +filegroup { + name: "launcher-quickstep-dagger", + srcs: [ + "quickstep/dagger/**/*.java", + "quickstep/dagger/**/*.kt", + ], +} + // Source code for quickstep build with compose enabled, on top of launcher-src filegroup { name: "launcher-quickstep-compose-enabled-src", @@ -324,7 +333,7 @@ android_library { "com_android_wm_shell_flags_lib", "dagger2", "jsr330", - + "com_android_systemui_shared_flags_lib", ], manifest: "AndroidManifest-common.xml", sdk_version: "current", @@ -411,6 +420,7 @@ android_library { srcs: [ ":launcher-src", ":launcher-quickstep-src", + ":launcher-quickstep-dagger", "go/quickstep/src/**/*.java", "go/quickstep/src/**/*.kt", ], @@ -449,6 +459,7 @@ android_library { srcs: [ ":launcher-src", ":launcher-quickstep-src", + ":launcher-quickstep-dagger", ":launcher-build-config", ], resource_dirs: [], diff --git a/aconfig/Android.bp b/aconfig/Android.bp index bca7494a04..5413601382 100644 --- a/aconfig/Android.bp +++ b/aconfig/Android.bp @@ -20,7 +20,7 @@ package { aconfig_declarations { name: "com_android_launcher3_flags", package: "com.android.launcher3", - container: "system_ext", + container: "system", srcs: ["**/*.aconfig"], } diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig index 40c37979ec..4d6c7ab032 100644 --- a/aconfig/launcher.aconfig +++ b/aconfig/launcher.aconfig @@ -1,5 +1,5 @@ package: "com.android.launcher3" -container: "system_ext" +container: "system" flag { name: "enable_expanding_pause_work_button" @@ -360,3 +360,69 @@ flag { purpose: PURPOSE_BUGFIX } } + +flag { + name: "one_grid_specs" + namespace: "launcher" + description: "Defines the new specs for grids based on OneGrid" + bug: "364711064" +} + +flag { + name: "one_grid_mounted_mode" + namespace: "launcher" + description: "Support a fixed landscape mode for handheld devices" + bug: "364711735" +} + +flag { + name: "one_grid_rotation_handling" + namespace: "launcher" + description: "New landscape approach for the workspace using different rows and columns in landscape and portrait" + bug: "364711814" +} + +flag { + name: "grid_migration_refactor" + namespace: "launcher" + description: "Refactor grid migration such that the code is simpler to understand and update" + bug: "358399271" +} + +flag { + name: "accessibility_scroll_on_allapps" + namespace: "launcher" + description: "Scroll to item position if accessibility focused" + bug: "265392261" + metadata { + purpose: PURPOSE_BUGFIX + } +} + +flag { + name: "enable_dismiss_prediction_undo" + namespace: "launcher" + description: "Show an 'Undo' snackbar when users dismiss a predicted hotseat item" + bug: "270394476" +} + +flag { + name: "enable_all_apps_button_in_hotseat" + namespace: "launcher" + description: "Enables displaying the all apps button in the hotseat." + bug: "270393897" +} + +flag { + name: "taskbar_quiet_mode_change_support" + namespace: "launcher" + description: "Support changing quiet mode for user profiles in taskbar." + bug: "345760034" +} + +flag { + name: "taskbar_overflow" + namespace: "launcher" + description: "Show recent apps in the taskbar overflow." + bug: "368119679" +} diff --git a/aconfig/launcher_overview.aconfig b/aconfig/launcher_overview.aconfig index e11b00c675..853faf8167 100644 --- a/aconfig/launcher_overview.aconfig +++ b/aconfig/launcher_overview.aconfig @@ -1,5 +1,5 @@ package: "com.android.launcher3" -container: "system_ext" +container: "system" flag { name: "enable_grid_only_overview" @@ -39,3 +39,12 @@ flag { bug: "353947137" } +flag { + name: "enable_overview_command_helper_timeout" + namespace: "launcher_overview" + description: "Enables OverviewCommandHelper new version with a timeout to prevent the queue to be unresponsive." + bug: "351122926" + metadata { + purpose: PURPOSE_BUGFIX + } +}
\ No newline at end of file diff --git a/aconfig/launcher_search.aconfig b/aconfig/launcher_search.aconfig index b98eee6e32..72f654e79a 100644 --- a/aconfig/launcher_search.aconfig +++ b/aconfig/launcher_search.aconfig @@ -1,5 +1,5 @@ package: "com.android.launcher3" -container: "system_ext" +container: "system" flag { name: "enable_private_space" diff --git a/quickstep/Android.bp b/quickstep/Android.bp index 1b9c661387..2ef9f82a71 100644 --- a/quickstep/Android.bp +++ b/quickstep/Android.bp @@ -52,6 +52,7 @@ filegroup { "tests/src/com/android/quickstep/TaplOverviewIconTest.java", "tests/src/com/android/quickstep/TaplTestsQuickstep.java", "tests/src/com/android/quickstep/TaplTestsSplitscreen.java", + "tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt", "tests/src/com/android/launcher3/testcomponent/ExcludeFromRecentsTestActivity.java", ], } @@ -63,3 +64,11 @@ filegroup { "tests/multivalentScreenshotTests/src/**/*.kt", ], } + +filegroup { + name: "launcher3-quickstep-testing", + path: "testing", + srcs: [ + "testing/**/*.kt", + ], +} diff --git a/quickstep/src/com/android/launcher3/dagger/LauncherAppComponent.java b/quickstep/dagger/LauncherAppComponent.java index dab25820ce..068f01cc5c 100644 --- a/quickstep/src/com/android/launcher3/dagger/LauncherAppComponent.java +++ b/quickstep/dagger/LauncherAppComponent.java @@ -16,16 +16,18 @@ package com.android.launcher3.dagger; -import dagger.Component; -import javax.inject.Singleton; +import com.android.quickstep.dagger.QuickStepModule; +import com.android.quickstep.dagger.QuickstepBaseAppComponent; + +import dagger.Component; /** * Root component for Dagger injection for Launcher Quickstep. */ -@Singleton -@Component -public interface LauncherAppComponent extends LauncherBaseAppComponent { +@LauncherAppSingleton +@Component(modules = QuickStepModule.class) +public interface LauncherAppComponent extends QuickstepBaseAppComponent { /** Builder for quickstep LauncherAppComponent. */ @Component.Builder interface Builder extends LauncherBaseAppComponent.Builder { diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml index 685a15180b..625d9b361d 100644 --- a/quickstep/res/layout/activity_allset.xml +++ b/quickstep/res/layout/activity_allset.xml @@ -96,7 +96,6 @@ style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:text="@string/allset_hint" android:textSize="@dimen/allset_page_swipe_up_text_size" android:gravity="center_horizontal" diff --git a/quickstep/res/layout/bubblebar_flyout.xml b/quickstep/res/layout/bubblebar_flyout.xml new file mode 100644 index 0000000000..fc1e91457e --- /dev/null +++ b/quickstep/res/layout/bubblebar_flyout.xml @@ -0,0 +1,54 @@ +<?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. + --> +<merge + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto" + xmlns:tools="http://schemas.android.com/tools"> + + <ImageView + android:id="@+id/bubble_flyout_avatar" + android:layout_width="50dp" + android:layout_height="36dp" + 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"/> + + <TextView + android:id="@+id/bubble_flyout_name" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:fontFamily="@*android:string/config_bodyFontFamilyMedium" + android:maxLines="1" + android:ellipsize="end" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintStart_toEndOf="@id/bubble_flyout_avatar" + tools:text="Sender"/> + + <TextView + android:id="@+id/bubble_flyout_text" + android:layout_width="0dp" + android:layout_height="wrap_content" + android:fontFamily="@*android:string/config_bodyFontFamily" + android:maxLines="2" + android:ellipsize="end" + app:layout_constraintTop_toBottomOf="@id/bubble_flyout_name" + app:layout_constraintStart_toEndOf="@id/bubble_flyout_avatar" + tools:text="This is a message"/> + +</merge> diff --git a/quickstep/res/layout/digital_wellbeing_toast.xml b/quickstep/res/layout/digital_wellbeing_toast.xml index 6a99a3bca8..0551c12dc0 100644 --- a/quickstep/res/layout/digital_wellbeing_toast.xml +++ b/quickstep/res/layout/digital_wellbeing_toast.xml @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. --> -<TextView +<com.android.quickstep.views.DigitalWellBeingToast xmlns:android="http://schemas.android.com/apk/res/android" xmlns:androidprv="http://schemas.android.com/apk/prv/res/android" style="@style/TextTitle" @@ -27,4 +27,5 @@ android:textColor="?attr/materialColorOnSecondaryFixed" android:textSize="14sp" android:autoSizeTextType="uniform" - android:autoSizeMaxTextSize="14sp"/>
\ No newline at end of file + android:autoSizeMaxTextSize="14sp" + android:visibility="gone"/>
\ No newline at end of file diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml index 34193d34c6..760bcdbf11 100644 --- a/quickstep/res/layout/task.xml +++ b/quickstep/res/layout/task.xml @@ -47,4 +47,7 @@ android:inflatedId="@id/icon" android:layout_height="wrap_content" android:layout_width="wrap_content" /> + + <include layout="@layout/digital_wellbeing_toast" + android:id="@+id/digital_wellbeing_toast"/> </com.android.quickstep.views.TaskView>
\ No newline at end of file diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml index cb4b98fd4c..c36a45e86c 100644 --- a/quickstep/res/layout/task_grouped.xml +++ b/quickstep/res/layout/task_grouped.xml @@ -73,4 +73,10 @@ android:inflatedId="@id/bottomRight_icon" android:layout_height="wrap_content" android:layout_width="wrap_content" /> + + <include layout="@layout/digital_wellbeing_toast" + android:id="@+id/digital_wellbeing_toast"/> + + <include layout="@layout/digital_wellbeing_toast" + android:id="@+id/bottomRight_digital_wellbeing_toast"/> </com.android.quickstep.views.GroupedTaskView>
\ No newline at end of file diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml index c146b51513..4122637fa1 100644 --- a/quickstep/res/values-af/strings.xml +++ b/quickstep/res/values-af/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taakbalkverdeler"</string> <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="6935266023013283353">"{count,plural, =1{Wys nog # app.}other{Wys nog # apps.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Wys # rekenaarapp.}other{Wys # rekenaarapps.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{meer app}other{meer apps}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Werkskerm"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Borrel"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oorvloei"</string> diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml index 4ed18364ee..956767eedd 100644 --- a/quickstep/res/values-am/strings.xml +++ b/quickstep/res/values-am/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"የተግባር አሞሌ አካፋይ"</string> <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="6935266023013283353">"{count,plural, =1{ተጨማሪ # መተግበሪያ አሳይ።}one{ተጨማሪ # መተግበሪያ አሳይ።}other{ተጨማሪ # መተግበሪያዎች አሳይ።}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# የዴስክቶፕ መተግበሪያ አሳይ።}one{# የዴስክቶፕ መተግበሪያ አሳይ።}other{# የዴስክቶፕ መተግበሪያዎች አሳይ።}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ተጨማሪ መተግበሪያ}one{ተጨማሪ መተግበሪያ}other{ተጨማሪ መተግበሪያዎች}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"ዴስክቶፕ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> እና <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"አረፋ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ትርፍ ፍሰት"</string> diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml index 74509acf84..e69166357f 100644 --- a/quickstep/res/values-ar/strings.xml +++ b/quickstep/res/values-ar/strings.xml @@ -89,7 +89,7 @@ <string name="gesture_tutorial_nice" msgid="2936275692616928280">"أحسنت"</string> <string name="gesture_tutorial_step" msgid="1279786122817620968">"الدليل التوجيهي <xliff:g id="CURRENT">%1$d</xliff:g> من إجمالي <xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"اكتملت عملية الإعداد"</string> - <string name="allset_hint" msgid="459504134589971527">"يمكنك التمرير سريعًا إلى الأعلى للانتقال إلى الشاشة الرئيسية"</string> + <string name="allset_hint" msgid="459504134589971527">"مرّر سريعًا للأعلى للانتقال إلى الشاشة الرئيسية"</string> <string name="allset_button_hint" msgid="2395219947744706291">"انقر على زر الشاشة الرئيسية للانتقال إلى الشاشة الرئيسية."</string> <string name="allset_description_generic" msgid="5385500062202019855">"يمكنك الآن بدء استخدام <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="default_device_name" msgid="6660656727127422487">"الجهاز"</string> @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"مقسِّم شريط التطبيقات"</string> <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="6935266023013283353">"{count,plural, =1{إظهار تطبيق واحد آخر}zero{إظهار # تطبيق آخر}two{إظهار تطبيقَين آخرَين}few{إظهار # تطبيقات أخرى}many{إظهار # تطبيقًا آخر}other{إظهار # تطبيق آخر}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{عرض تطبيق واحد متوافق مع الكمبيوتر المكتبي}zero{عرض # تطبيق متوافق مع الكمبيوتر المكتبي}two{عرض تطبيقَين متوافقين مع الكمبيوتر المكتبي}few{عرض # تطبيقات متوافقة مع الكمبيوتر المكتبي}many{عرض # تطبيقًا متوافقًا مع الكمبيوتر المكتبي}other{عرض # تطبيق متوافق مع الكمبيوتر المكتبي}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{تطبيق واحد آخر}zero{تطبيق آخر}two{تطبيقان آخران}few{تطبيقات أخرى}many{تطبيقًا آخر}other{تطبيق آخر}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"وضع الكمبيوتر المكتبي"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"\"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" و\"<xliff:g id="APP_NAME_2">%2$s</xliff:g>\""</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"فقاعة"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"القائمة الكاملة"</string> diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml index ea8268e475..912003b5bd 100644 --- a/quickstep/res/values-as/strings.xml +++ b/quickstep/res/values-as/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"টাস্কবাৰ বিভাজক"</string> <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="6935266023013283353">"{count,plural, =1{আৰু # টা এপ্ দেখুৱাওক।}one{আৰু # টা এপ্ দেখুৱাওক।}other{আৰু # টা এপ্ দেখুৱাওক।}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# টা ডেস্কটপ এপ্ দেখুৱাওক।}one{# টা ডেস্কটপ এপ্ দেখুৱাওক।}other{# টা ডেস্কটপ এপ্ দেখুৱাওক।}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{অধিক এপ্}one{অধিক এপ্}other{অধিক এপ্}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"ডেস্কটপ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> আৰু <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"অ’ভাৰফ্ল’"</string> diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml index 13b2c11fdc..b89b7076e0 100644 --- a/quickstep/res/values-az/strings.xml +++ b/quickstep/res/values-az/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"İşləmə paneli ayırıcısı"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Yuxarı/sola köçürün"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Aşağı/sağa köçürün"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Daha # tətbiqi göstərin.}other{Daha # tətbiqi göstərin.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# masaüstü tətbiqini göstərin.}other{# masaüstü tətbiqini göstərin.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{əlavə tətbiq}other{əlavə tətbiq}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Masaüstü"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> və <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Yumrucuq"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kənara çıxma"</string> diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml index 2a1969108c..4ef487e481 100644 --- a/quickstep/res/values-b+sr+Latn/strings.xml +++ b/quickstep/res/values-b+sr+Latn/strings.xml @@ -90,7 +90,7 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Gotovo!"</string> <string name="allset_hint" msgid="459504134589971527">"Prevucite nagore da biste otvorili početni ekran"</string> - <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme Početak da bisti išli na početni ekran"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme Početak da biste otišli na početni ekran"</string> <string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste da počnete da koristite <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="default_device_name" msgid="6660656727127422487">"uređaj"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Podešavanja kretanja kroz sistem"</annotation></string> @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdelnik trake zadataka"</string> <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="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju.}one{Prikaži još # aplikaciju.}few{Prikaži još # aplikacije.}other{Prikaži još # aplikacija.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # aplikaciju za računare.}one{Prikaži # aplikaciju za računare.}few{Prikaži # aplikacije za računare.}other{Prikaži # aplikacija za računare.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Računar"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni"</string> diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml index 7b99a6f458..c506acb071 100644 --- a/quickstep/res/values-be/strings.xml +++ b/quickstep/res/values-be/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Раздзяляльнік панэлі задач"</string> <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="6935266023013283353">"{count,plural, =1{Паказаць ячшэ # праграму.}one{Паказаць ячшэ # праграму.}few{Паказаць ячшэ # праграмы.}many{Паказаць ячшэ # праграм.}other{Паказаць ячшэ # праграмы.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Паказаць # праграму для ПК.}one{Паказаць # праграму для ПК.}few{Паказаць # праграмы для ПК.}many{Паказаць # праграм для ПК.}other{Паказаць # праграмы для ПК.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{даступная праграма}one{даступная праграма}few{даступныя праграмы}many{даступных праграм}other{даступнай праграмы}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Працоўны стол"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> і <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бурбалкі"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Меню з пашырэннем"</string> diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml index 2ed92c3aa9..d03e4f7856 100644 --- a/quickstep/res/values-bg/strings.xml +++ b/quickstep/res/values-bg/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделител на лентата на задачите"</string> <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="6935266023013283353">"{count,plural, =1{Показване на още # приложение.}other{Показване на още # приложения.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показване на # настолно приложение.}other{Показване на # настолни приложения.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{допълнително приложение}other{допълнителни приложения}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим за настолни компютри"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Препълване"</string> diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml index 0762805535..0c568d94bd 100644 --- a/quickstep/res/values-bn/strings.xml +++ b/quickstep/res/values-bn/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"টাস্কবার ডিভাইডার"</string> <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="6935266023013283353">"{count,plural, =1{আরও #টি অ্যাপ দেখুন।}one{আরও #টি অ্যাপ দেখুন।}other{আরও #টি অ্যাপ দেখুন।}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{#টি ডেস্কটপ অ্যাপ দেখুন।}one{#টি ডেস্কটপ অ্যাপ দেখুন।}other{#টি ডেস্কটপ অ্যাপ দেখুন।}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{আরও অ্যাপ}one{আরও অ্যাপ}other{আরও অ্যাপ}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"ডেস্কটপ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ও <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ওভারফ্লো"</string> diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml index 283cb6739a..922883e708 100644 --- a/quickstep/res/values-bs/strings.xml +++ b/quickstep/res/values-bs/strings.xml @@ -90,7 +90,7 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Vodič <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Sve je spremno!"</string> <string name="allset_hint" msgid="459504134589971527">"Prevucite prema gore da odete na početni ekran"</string> - <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme za početni ekran da odete napočetni ekran"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Dodirnite dugme za početni ekran da odete na početni ekran"</string> <string name="allset_description_generic" msgid="5385500062202019855">"Spremni ste da počnete koristiti <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="default_device_name" msgid="6660656727127422487">"uređaj"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Postavke navigacije sistemom"</annotation></string> @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdjelnik trake zadataka"</string> <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="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju.}one{Prikaži još # aplikaciju.}few{Prikaži još # aplikacije.}other{Prikaži još # aplikacija.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # aplikaciju za računar.}one{Prikaži # aplikaciju za računar.}few{Prikaži # aplikacije za računar.}other{Prikaži # aplikacija za računar.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Računar"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni meni"</string> diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml index 460f2fce6f..fe7933b92f 100644 --- a/quickstep/res/values-ca/strings.xml +++ b/quickstep/res/values-ca/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separador de la Barra de tasques"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mou a la part superior o a l\'esquerra"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mou a la part inferior o a la dreta"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # aplicació més.}other{Mostra # aplicacions més.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostra # aplicació per a ordinadors.}other{Mostra # aplicacions per a ordinadors.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicació més}other{aplicacions més}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Escriptori"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bombolla"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Desbordament"</string> diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml index 1e5df41b20..3047d05843 100644 --- a/quickstep/res/values-cs/strings.xml +++ b/quickstep/res/values-cs/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Rozdělovač panelu aplikací"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Přesunout doleva nahoru"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Přesunout doprava dolů"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobrazit # další aplikaci.}few{Zobrazit # další aplikace.}many{Zobrazit # další aplikace.}other{Zobrazit # dalších aplikací.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Zobrazit # aplikaci pro počítač.}few{Zobrazit # aplikace pro počítač.}many{Zobrazit # aplikace pro počítač.}other{Zobrazit # aplikací pro počítač.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{další aplikace}few{další aplikace}many{další aplikace}other{dalších aplikací}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Počítač"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbalovací nabídka"</string> diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml index 4f61b86b9a..6e2130c552 100644 --- a/quickstep/res/values-da/strings.xml +++ b/quickstep/res/values-da/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Opdeling af proceslinjen"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flyt til toppen eller venstre side"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flyt til bunden eller højre side"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app mere.}one{Vis # app mere.}other{Vis # apps mere.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Vis # computerprogram.}one{Vis # computerprogram.}other{Vis # computerprogrammer.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{yderligere app}one{yderligere app}other{yderligere apps}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Computer"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overløb"</string> diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml index ac5e7aa9b2..54961fe435 100644 --- a/quickstep/res/values-de/strings.xml +++ b/quickstep/res/values-de/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskleisten-Teiler"</string> <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="6935266023013283353">"{count,plural, =1{# weitere App anzeigen}other{# weitere Apps anzeigen}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# Desktop-App anzeigen.}other{# Desktop-Apps anzeigen.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{weitere App}other{weitere Apps}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktopmodus"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> und <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Weitere Optionen"</string> diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml index ddd81d24f7..6cbb833267 100644 --- a/quickstep/res/values-el/strings.xml +++ b/quickstep/res/values-el/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Διαχωριστικό Γραμμής εργαλείων"</string> <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="6935266023013283353">"{count,plural, =1{Εμφάνιση # ακόμα εφαρμογής.}other{Εμφάνιση # ακόμα εφαρμογών.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Εμφάνιση # εφαρμογής υπολογιστή.}other{Εμφάνιση # εφαρμογών υπολογιστή.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ακόμη εφαρμογή}other{ακόμη εφαρμογές}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Υπολογιστής"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> και <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Συννεφάκι"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Υπερχείλιση"</string> diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml index bc2f91a7c2..dcbaa7a10b 100644 --- a/quickstep/res/values-en-rAU/strings.xml +++ b/quickstep/res/values-en-rAU/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar divider"</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="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string> diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml index f4396fa6ea..c00e6cda6a 100644 --- a/quickstep/res/values-en-rCA/strings.xml +++ b/quickstep/res/values-en-rCA/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar Divider"</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="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string> diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml index bc2f91a7c2..dcbaa7a10b 100644 --- a/quickstep/res/values-en-rGB/strings.xml +++ b/quickstep/res/values-en-rGB/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar divider"</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="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string> diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml index bc2f91a7c2..dcbaa7a10b 100644 --- a/quickstep/res/values-en-rIN/strings.xml +++ b/quickstep/res/values-en-rIN/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar divider"</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="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string> diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml index 65f0d39272..2abef91a6f 100644 --- a/quickstep/res/values-en-rXC/strings.xml +++ b/quickstep/res/values-en-rXC/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskbar Divider"</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="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{more app}other{more apps}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string> diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml index 87a05efc4e..f09fae6674 100644 --- a/quickstep/res/values-es-rUS/strings.xml +++ b/quickstep/res/values-es-rUS/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor de la Barra de tareas"</string> <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="6935266023013283353">"{count,plural, =1{Mostrar # app más.}other{Mostrar # apps más.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computadoras.}other{Mostrar # apps para computadoras.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app más}other{apps más}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Escritorio"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ampliada"</string> diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml index 8bd5fb8c04..356a38bb05 100644 --- a/quickstep/res/values-es/strings.xml +++ b/quickstep/res/values-es/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor de Barra de Tareas"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover arriba/a la izquierda"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover abajo/a la derecha"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación más.}other{Mostrar # aplicaciones más.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # aplicación para ordenadores.}other{Mostrar # aplicaciones para ordenadores.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicación más}other{aplicaciones más}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordenador"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string> diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml index 32d29c8ae2..fccbeda5bd 100644 --- a/quickstep/res/values-et/strings.xml +++ b/quickstep/res/values-et/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Tegumiriba jagaja"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Teisalda üles/vasakule"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Teisalda alla/paremale"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Kuva veel # rakendus.}other{Kuva veel # rakendust.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Kuva # töölauarakendus.}other{Kuva # töölauarakendust.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{rakendus veel}other{rakendust veel}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Lauaarvuti"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Mull"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ületäide"</string> diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml index 210e2a2689..a1d8cc3f55 100644 --- a/quickstep/res/values-eu/strings.xml +++ b/quickstep/res/values-eu/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Zereginen barraren zatitzailea"</string> <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="6935266023013283353">"{count,plural, =1{Erakutsi beste # aplikazio.}other{Erakutsi beste # aplikazio.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Erakutsi ordenagailuetarako # aplikazio.}other{Erakutsi ordenagailuetarako # aplikazio.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikazio gehiago}other{aplikazio gehiago}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordenagailua"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> eta <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuila"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Luzapena"</string> diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml index ef214029c0..8f3768656f 100644 --- a/quickstep/res/values-fa/strings.xml +++ b/quickstep/res/values-fa/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"جداکننده نوار وظیفه"</string> <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="6935266023013283353">"{count,plural, =1{نمایش # برنامه دیگر.}one{نمایش # برنامه دیگر.}other{نمایش # برنامه دیگر.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{نمایش # برنامه رایانه.}one{نمایش # برنامه رایانه.}other{نمایش # برنامه رایانه.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{برنامه دیگر}one{برنامه دیگر}other{برنامه دیگر}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"رایانه"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> و <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"حبابک"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"سرریز"</string> diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml index 8288cb5bba..175a896264 100644 --- a/quickstep/res/values-fi/strings.xml +++ b/quickstep/res/values-fi/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Tehtäväpalkin jakaja"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Siirrä ylös tai vasemmalle"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Siirrä alas tai oikealle"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Näytä # muu sovellus.}other{Näytä # muuta sovellusta.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Näytä # työpöytäsovellus.}other{Näytä # työpöytäsovellusta.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{muu sovellus}other{muuta sovellusta}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Tietokone"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kupla"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ylivuoto"</string> diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml index e3089b6927..6d6c67c372 100644 --- a/quickstep/res/values-fr-rCA/strings.xml +++ b/quickstep/res/values-fr-rCA/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Séparateur de la barre des tâches"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer vers le coin supérieur gauche de l\'écran"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer vers le coin inférieur droit de l\'écran"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli.}one{Afficher # autre appli.}other{Afficher # autres applis.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # appli de bureau.}one{Afficher # appli de bureau.}other{Afficher # applis de bureau.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{autre appli}one{autre appli}other{autres applis}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordinateur de bureau"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bulle à développer"</string> diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml index b68378b1a1..a395266ace 100644 --- a/quickstep/res/values-fr/strings.xml +++ b/quickstep/res/values-fr/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Séparateur de barre des tâches"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer en haut ou à gauche"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer en bas ou à droite"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli}one{Afficher # autre appli}other{Afficher # autre applis}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # application de bureau.}one{Afficher # application de bureau.}other{Afficher # applications de bureau.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{autre application}one{autre application}other{autres applications}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Ordinateur"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dépassement"</string> diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml index b4c91ba5ec..5b04960dee 100644 --- a/quickstep/res/values-gl/strings.xml +++ b/quickstep/res/values-gl/strings.xml @@ -91,8 +91,8 @@ <string name="allset_title" msgid="5021126669778966707">"Todo listo"</string> <string name="allset_hint" msgid="459504134589971527">"Pasa o dedo cara arriba para ir á pantalla de inicio"</string> <string name="allset_button_hint" msgid="2395219947744706291">"Toca o botón de inicio para ir á pantalla de inicio"</string> - <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> xa está dispoñible para comezar a utilizar"</string> - <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string> + <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> dispoñible para comezar a utilizar"</string> + <string name="default_device_name" msgid="6660656727127422487">"Dispositivo"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Configuración da navegación do sistema"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Compartir"</string> <string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string> @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor da Barra de tarefas"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mover á parte superior ou á esquerda"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mover á parte inferior ou á dereita"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación máis.}other{Mostrar # aplicacións máis.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # aplicación para ordenadores.}other{Mostrar # aplicacións para ordenadores.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplicación máis}other{aplicacións máis}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Escritorio"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulla"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string> diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml index dcbcd584f3..fc253bd8e5 100644 --- a/quickstep/res/values-gu/strings.xml +++ b/quickstep/res/values-gu/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ટાસ્કબાર વિભાજક"</string> <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="6935266023013283353">"{count,plural, =1{વધુ # ઍપ બતાવો.}one{વધુ # ઍપ બતાવો.}other{વધુ # ઍપ બતાવો.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ડેસ્કટૉપ ઍપ બતાવો.}one{# ડેસ્કટૉપ ઍપ બતાવો.}other{# ડેસ્કટૉપ ઍપ બતાવો.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{વધુ ઍપ}one{વધુ ઍપ}other{વધુ ઍપ}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"ડેસ્કટૉપ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> અને <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"બબલ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ઓવરફ્લો"</string> diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml index 137f809ca3..30a17db93f 100644 --- a/quickstep/res/values-hi/strings.xml +++ b/quickstep/res/values-hi/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार डिवाइडर"</string> <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="6935266023013283353">"{count,plural, =1{# और ऐप्लिकेशन दिखाएं.}one{# और ऐप्लिकेशन दिखाएं.}other{# और ऐप्लिकेशन दिखाएं.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}one{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}other{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ज़्यादा ऐप्लिकेशन}one{ज़्यादा ऐप्लिकेशन}other{ज़्यादा ऐप्लिकेशन}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटॉप"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> और <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओवरफ़्लो"</string> diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml index 6178570a8e..06511e9fd1 100644 --- a/quickstep/res/values-hr/strings.xml +++ b/quickstep/res/values-hr/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdjelnik trake sa zadacima"</string> <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="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju}one{Prikaži još # aplikaciju}few{Prikaži još # aplikacije}other{Prikaži još # aplikacija}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # računalnu aplikaciju.}one{Prikaži # računalnu aplikaciju.}few{Prikaži # računalne aplikacije.}other{Prikaži # računalnih aplikacija.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{dodatna aplikacija}one{dodatna aplikacija}few{dodatne aplikacije}other{dodatnih aplikacija}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Računalo"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dodatni izbornik"</string> diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml index 99c39f1ddf..9bd947821f 100644 --- a/quickstep/res/values-hu/strings.xml +++ b/quickstep/res/values-hu/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Feladatsáv-elválasztó"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Mozgatás felülre vagy a bal oldalra"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Mozgatás alulra vagy a jobb oldalra"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# további alkalmazás megjelenítése.}other{# további alkalmazás megjelenítése.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# asztali alkalmazás megjelenítése.}other{# asztali alkalmazás megjelenítése.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{további alkalmazás}other{további alkalmazás}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Asztali"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> és <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Buborék"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Túlcsordulás"</string> diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml index 0dda363101..e1481ecdd2 100644 --- a/quickstep/res/values-hy/strings.xml +++ b/quickstep/res/values-hy/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Հավելվածների վահանակի բաժանիչ"</string> <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="6935266023013283353">"{count,plural, =1{Ցուցադրել ևս # հավելված։}one{Ցուցադրել ևս # հավելված։}other{Ցուցադրել ևս # հավելված։}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Ցույց տալ # համակարգչային հավելված։}one{Ցույց տալ # համակարգչային հավելված։}other{Ցույց տալ # համակարգչային հավելված։}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{լրացուցիչ հավելված}one{լրացուցիչ հավելված}other{լրացուցիչ հավելված}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Համակարգիչ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> և <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ամպիկ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Լրացուցիչ ընտրացանկ"</string> diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml index b6e492dea0..f8345b5a4c 100644 --- a/quickstep/res/values-in/strings.xml +++ b/quickstep/res/values-in/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Pemisah Taskbar"</string> <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="6935266023013283353">"{count,plural, =1{Tampilkan # aplikasi lainnya.}other{Tampilkan # aplikasi lainnya.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Tampilkan # aplikasi desktop.}other{Tampilkan # aplikasi desktop.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikasi lainnya}other{aplikasi lainnya}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tambahan"</string> diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml index ad388c0c06..017d1087a9 100644 --- a/quickstep/res/values-is/strings.xml +++ b/quickstep/res/values-is/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Skipting forritastiku"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Færa efst/til vinstri"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Færa neðst/til hægri"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Sýna # forrit í viðbót.}one{Sýna # forrit í viðbót.}other{Sýna # forrit í viðbót.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Sýna # skjáborðsforrit.}one{Sýna # skjáborðsforrit.}other{Sýna # skjáborðsforrit.}}"</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> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Skjáborð"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Blaðra"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Yfirflæði"</string> diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml index 9ddd4da37a..1983ee3991 100644 --- a/quickstep/res/values-it/strings.xml +++ b/quickstep/res/values-it/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisore barra delle app"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sposta in alto/a sinistra"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sposta in basso/a destra"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # altra app.}other{Mostra altre # app.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostra # app desktop.}other{Mostra # app desktop.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{altra app}other{altre app}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Fumetto"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Extra"</string> diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml index c5c714537e..a7115e342f 100644 --- a/quickstep/res/values-iw/strings.xml +++ b/quickstep/res/values-iw/strings.xml @@ -93,7 +93,7 @@ <string name="allset_button_hint" msgid="2395219947744706291">"כדי לעבור אל מסך הבית צריך להקיש על הלחצן הראשי"</string> <string name="allset_description_generic" msgid="5385500062202019855">"הכול מוכן ואפשר להתחיל להשתמש ב<xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="default_device_name" msgid="6660656727127422487">"מכשיר"</string> - <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"הגדרות הניווט של המערכת"</annotation></string> + <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"הגדרות הניווט במערכת"</annotation></string> <string name="action_share" msgid="2648470652637092375">"שיתוף"</string> <string name="action_screenshot" msgid="8171125848358142917">"צילום מסך"</string> <string name="action_split" msgid="2098009717623550676">"פיצול"</string> @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"המחיצה בסרגל האפליקציות"</string> <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="6935266023013283353">"{count,plural, =1{הצגת אפליקציה אחת (#) נוספת.}one{הצגת # אפליקציות נוספות.}two{הצגת # אפליקציות נוספות.}other{הצגת # אפליקציות נוספות.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{הצגת אפליקציה אחת (#) למחשב.}one{הצגת # אפליקציות למחשב.}two{הצגת # אפליקציות למחשב.}other{הצגת # אפליקציות למחשב.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{אפליקציה נוספת}one{אפליקציות נוספות}two{אפליקציות נוספות}other{אפליקציות נוספות}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"מחשב"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ו-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"בועה"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"אפשרויות נוספות"</string> diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml index b2732a6d6a..fa3c01d680 100644 --- a/quickstep/res/values-ja/strings.xml +++ b/quickstep/res/values-ja/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"タスクバーの区切り"</string> <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="6935266023013283353">"{count,plural, =1{他 # 件のアプリを表示できます。}other{他 # 件のアプリを表示できます。}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# 個のデスクトップ アプリが表示されます。}other{# 個のデスクトップ アプリが表示されます。}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個のその他のアプリ}other{個のその他のアプリ}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"パソコン"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> と <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ふきだし"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"オーバーフロー"</string> diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml index a23201d0c1..a0327319d3 100644 --- a/quickstep/res/values-ka/strings.xml +++ b/quickstep/res/values-ka/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ამოცანათა ზოლის გამყოფი"</string> <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="6935266023013283353">"{count,plural, =1{#-ით მეტი აპის ჩენება}other{#-ით მეტი აპის ჩვენება.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# დესკტოპის აპის ჩვენება.}other{# დესკტოპის აპის ჩვენება.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{სხვა აპი}other{სხვა აპი}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"დესკტოპი"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> და <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ბუშტი"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"გადავსება"</string> diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml index a7b3d6f1ac..e1a9e8e073 100644 --- a/quickstep/res/values-kk/strings.xml +++ b/quickstep/res/values-kk/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Тапсырмалар жолағын бөлгіш"</string> <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="6935266023013283353">"{count,plural, =1{Тағы # қолданбаны көрсету.}other{Тағы # қолданбаны көрсету.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерге арналған # қолданбаны көрсету}other{Компьютерге арналған # қолданбаны көрсету}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{қосымша қолданба}other{қосымша қолданба}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Компьютер"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> және <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Қалқыма терезе"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Қосымша мәзір"</string> diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml index f83b09b27f..2eb3114d1d 100644 --- a/quickstep/res/values-km/strings.xml +++ b/quickstep/res/values-km/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"បន្ទាត់ខណ្ឌចែករបារកិច្ចការ"</string> <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="6935266023013283353">"{count,plural, =1{បង្ហាញកម្មវិធី # ទៀត។}other{បង្ហាញកម្មវិធី # ទៀត។}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{បង្ហាញកម្មវិធីកុំព្យូទ័រ #។}other{បង្ហាញកម្មវិធីកុំព្យូទ័រ #។}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{កម្មវិធីច្រើនទៀត}other{កម្មវិធីច្រើនទៀត}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"អេក្រង់ដើម"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> និង <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ផ្ទាំងសារ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ម៉ឺនុយបន្ថែម"</string> diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml index 48093b35c8..bb6062052a 100644 --- a/quickstep/res/values-kn/strings.xml +++ b/quickstep/res/values-kn/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ಟಾಸ್ಕ್ಬಾರ್ ಡಿವೈಡರ್"</string> <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="6935266023013283353">"{count,plural, =1{ಇನ್ನೂ # ಆ್ಯಪ್ ಅನ್ನು ತೋರಿಸಿ.}one{ಇನ್ನೂ # ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}other{ಇನ್ನೂ # ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ಡೆಸ್ಕ್ಟಾಪ್ ಆ್ಯಪ್ ತೋರಿಸಿ.}one{# ಡೆಸ್ಕ್ಟಾಪ್ ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}other{# ಡೆಸ್ಕ್ಟಾಪ್ ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ಹೆಚ್ಚಿನ ಆ್ಯಪ್}one{ಹೆಚ್ಚಿನ ಆ್ಯಪ್ಗಳು}other{ಹೆಚ್ಚಿನ ಆ್ಯಪ್ಗಳು}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"ಡೆಸ್ಕ್ಟಾಪ್"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ಮತ್ತು <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ಬಬಲ್"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ಓವರ್ಫ್ಲೋ"</string> diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml index 1aca7a2d04..e6a80c38f0 100644 --- a/quickstep/res/values-ko/strings.xml +++ b/quickstep/res/values-ko/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"태스크 바 분할"</string> <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="6935266023013283353">"{count,plural, =1{앱 #개 더 표시}other{앱 #개 더 표시}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{데스크톱 앱 #개를 표시합니다.}other{데스크톱 앱 #개를 표시합니다.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{추가 앱}other{추가 앱}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"데스크톱"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> 및 <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"풍선"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"더보기"</string> diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml index e440b40eb7..04e7f6e944 100644 --- a/quickstep/res/values-ky/strings.xml +++ b/quickstep/res/values-ky/strings.xml @@ -92,7 +92,7 @@ <string name="allset_hint" msgid="459504134589971527">"Башкы бетке өтүү үчүн экранды өйдө сүрүңүз"</string> <string name="allset_button_hint" msgid="2395219947744706291">"Башкы экранга өтүү үчүн башкы бет баскычын таптап коюңуз"</string> <string name="allset_description_generic" msgid="5385500062202019855">"<xliff:g id="DEVICE">%1$s</xliff:g> колдоно берсеңиз болот"</string> - <string name="default_device_name" msgid="6660656727127422487">"түзмөк"</string> + <string name="default_device_name" msgid="6660656727127422487">"Түзмөктү"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Өтүү аракетинин системалык параметрлери"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Бөлүшүү"</string> <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string> @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Тапшырмалар панелин бөлгүч"</string> <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="6935266023013283353">"{count,plural, =1{Дагы # колдонмону көрсөтүү.}other{Дагы # колдонмону көрсөтүү.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# иш такта колдонмосун көрсөтүү.}other{# иш такта колдонмосун көрсөтүү.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{колдонмо бар}other{колдонмо бар}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Компьютер"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> жана <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Көбүкчө"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Кошумча меню"</string> diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml index a2ba90c0d9..b3ca11688b 100644 --- a/quickstep/res/values-lo/strings.xml +++ b/quickstep/res/values-lo/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ເສັ້ນແບ່ງແຖບໜ້າວຽກ"</string> <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="6935266023013283353">"{count,plural, =1{ສະແດງອີກ # ແອັບ.}other{ສະແດງອີກ # ແອັບ.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{ສະແດງແອັບເດັສທັອບ # ລາຍການ.}other{ສະແດງແອັບເດັສທັອບ # ລາຍການ.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ແອັບເພີ່ມເຕີມ}other{ແອັບເພີ່ມເຕີມ}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"ເດັສທັອບ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ແລະ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ຟອງ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ລາຍການເພີ່ມເຕີມ"</string> diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml index a70f1bdf8f..4f3f36ec5f 100644 --- a/quickstep/res/values-lt/strings.xml +++ b/quickstep/res/values-lt/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Užduočių juostos daliklis"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Perkelti aukštyn, kairėn"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Perkelti žemyn, dešinėn"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rodyti dar # programą.}one{Rodyti dar # programą.}few{Rodyti dar # programas.}many{Rodyti dar # programos.}other{Rodyti dar # programų.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Rodyti # darbalaukio programą.}one{Rodyti # darbalaukio programą.}few{Rodyti # darbalaukio programas.}many{Rodyti # darbalaukio programos.}other{Rodyti # darbalaukio programų.}}"</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> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Stalinis kompiuteris"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"„<xliff:g id="APP_NAME_1">%1$s</xliff:g>“ ir „<xliff:g id="APP_NAME_2">%2$s</xliff:g>“"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulas"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Perpildymas"</string> diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml index b3d9c01972..fd75fc4293 100644 --- a/quickstep/res/values-lv/strings.xml +++ b/quickstep/res/values-lv/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Uzdevumu joslas atdalītājs"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pārvietot uz augšējo/kreiso stūri"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pārvietot uz apakšējo/labo stūri"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rādīt vēl # lietotni}zero{Rādīt vēl # lietotnes}one{Rādīt vēl # lietotni}other{Rādīt vēl # lietotnes}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Rādīt # datora lietotni.}zero{Rādīt # datora lietotnes.}one{Rādīt # datora lietotni.}other{Rādīt # datora lietotnes.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{papildu lietotne}zero{papildu lietotņu}one{papildu lietotne}other{papildu lietotnes}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Darbvirsma"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"“<xliff:g id="APP_NAME_1">%1$s</xliff:g>” un “<xliff:g id="APP_NAME_2">%2$s</xliff:g>”"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulis"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Pārpilde"</string> diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml index 2cd67c2c05..b50277b345 100644 --- a/quickstep/res/values-mk/strings.xml +++ b/quickstep/res/values-mk/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделник на „Лента со задачи“"</string> <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="6935266023013283353">"{count,plural, =1{Прикажи уште # апликација.}one{Прикажи уште # апликација.}other{Прикажи уште # апликации.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Прикажи # апликација за компјутер.}one{Прикажи # апликација за компјутер.}other{Прикажи # апликации за компјутер.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{дополнителна апликација}one{дополнителна апликација}other{дополнителни апликации}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим за компјутер"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Проширено балонче"</string> diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml index 74271a62d3..ef72da14ea 100644 --- a/quickstep/res/values-ml/strings.xml +++ b/quickstep/res/values-ml/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ടാസ്ക്ബാർ ഡിവൈഡർ"</string> <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="6935266023013283353">"{count,plural, =1{# ആപ്പ് കൂടി കാണിക്കുക.}other{# ആപ്പുകൾ കൂടി കാണിക്കുക.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ഡെസ്ക്ടോപ്പ് ആപ്പ് കാണിക്കുക.}other{# ഡെസ്ക്ടോപ്പ് ആപ്പുകൾ കാണിക്കുക.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{കൂടുതൽ ആപ്പ്}other{കൂടുതൽ ആപ്പുകൾ}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"ഡെസ്ക്ടോപ്പ്"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ബബിൾ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ഓവർഫ്ലോ"</string> diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml index fd71823098..2ca2e26d6e 100644 --- a/quickstep/res/values-mn/strings.xml +++ b/quickstep/res/values-mn/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Ажлын хэсгийг хуваагч"</string> <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="6935266023013283353">"{count,plural, =1{Өөр # аппыг харуулна уу.}other{Өөр # аппыг харуулна уу.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерын # аппыг харуулна уу.}other{Компьютерын # аппыг харуулна уу.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{бусад апп}other{бусад апп}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Дэлгэц"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> болон <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бөмбөлөг"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Илүү хэсэг"</string> diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml index 685b38df37..159368d449 100644 --- a/quickstep/res/values-mr/strings.xml +++ b/quickstep/res/values-mr/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार विभाजक"</string> <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="6935266023013283353">"{count,plural, =1{आणखी # अॅप दाखवा.}other{आणखी # अॅप्स दाखवा.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटॉप अॅप दाखवा.}other{# डेस्कटॉप अॅप्स दाखवा.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{आणखी अॅप}other{आणखी अॅप्स}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटॉप"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> आणि <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओव्हरफ्लो"</string> diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml index cb72b8223d..9a27e51542 100644 --- a/quickstep/res/values-ms/strings.xml +++ b/quickstep/res/values-ms/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Pembahagi Bar Tugas"</string> <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="6935266023013283353">"{count,plural, =1{Tunjukkan # lagi apl.}other{Tunjukkan # lagi apl.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Tunjukkan # apl desktop.}other{Tunjukkan # apl desktop.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{apl lagi}other{apl lagi}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Gelembung"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Limpahan"</string> diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml index a3c462de61..7e298fbd86 100644 --- a/quickstep/res/values-my/strings.xml +++ b/quickstep/res/values-my/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"လုပ်ဆောင်စရာဘား ပိုင်းခြားစနစ်"</string> <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="6935266023013283353">"{count,plural, =1{နောက်ထပ်အက်ပ် # ခု ပြပါ။}other{နောက်ထပ်အက်ပ် # ခု ပြပါ။}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{ဒက်စတော့ အက်ပ် # ခု ပြပါ။}other{ဒက်စတော့ အက်ပ် # ခု ပြပါ။}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{နောက်ထပ်အက်ပ်}other{နောက်ထပ်အက်ပ်များ}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"ဒက်စ်တော့"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> နှင့် <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ပူဖောင်းကွက်"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"မီနူးအပို"</string> diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml index e486ad8b75..21b5fd47b2 100644 --- a/quickstep/res/values-nb/strings.xml +++ b/quickstep/res/values-nb/strings.xml @@ -97,7 +97,7 @@ <string name="action_share" msgid="2648470652637092375">"Del"</string> <string name="action_screenshot" msgid="8171125848358142917">"Skjermbilde"</string> <string name="action_split" msgid="2098009717623550676">"Del opp"</string> - <string name="action_save_app_pair" msgid="5974823919237645229">"Lagre apptilkobling"</string> + <string name="action_save_app_pair" msgid="5974823919237645229">"Lagre app-paret"</string> <string name="toast_split_select_app" msgid="8464310533320556058">"Trykk på en annen app for å bruke delt skjerm"</string> <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Velg en annen app for å bruke delt skjerm"</string> <string name="toast_split_select_app_cancel" msgid="1939025102486630426">"Avbryt"</string> @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Skille for oppgavelinjen"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytt til øverst/venstre"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytt til nederst/høyre"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app til.}other{Vis # apper til.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Vis # datamaskinprogram.}other{Vis # datamaskinprogrammer.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app til}other{apper til}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Datamaskin"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflyt"</string> diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml index 25c5901554..326222ba82 100644 --- a/quickstep/res/values-ne/strings.xml +++ b/quickstep/res/values-ne/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"टास्कबार डिभाइडर"</string> <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="6935266023013283353">"{count,plural, =1{थप # एप देखाउनुहोस्।}other{थप # वटा एप देखाउनुहोस्।}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटप एप देखाउनुहोस्।}other{# वटा डेस्कटप एप देखाउनुहोस्।}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{थप एप}other{थप एपहरू}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"डेस्कटप"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> र <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओभरफ्लो"</string> diff --git a/quickstep/res/values-night/colors.xml b/quickstep/res/values-night/colors.xml index 2052446bba..98e4871da2 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 2b5bd499f7..8a923b511e 100644 --- a/quickstep/res/values-nl/strings.xml +++ b/quickstep/res/values-nl/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Scheiding voor Taakbalk"</string> <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="6935266023013283353">"{count,plural, =1{Nog # app tonen.}other{Nog # apps tonen.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# desktop-app tonen.}other{# desktop-apps tonen.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{extra app}other{extra apps}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbel"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overloop"</string> diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml index 6628826a29..3150ded5a0 100644 --- a/quickstep/res/values-or/strings.xml +++ b/quickstep/res/values-or/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ଟାସ୍କବାର ଡିଭାଇଡର"</string> <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="6935266023013283353">"{count,plural, =1{ଅଧିକ #ଟି ଆପ ଦେଖାନ୍ତୁ।}other{ଅଧିକ #ଟି ଆପ୍ସ ଦେଖାନ୍ତୁ।}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ଡେସ୍କଟପ ଆପ ଦେଖାନ୍ତୁ।}other{# ଡେସ୍କଟପ ଆପ୍ସ ଦେଖାନ୍ତୁ।}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ଅଧିକ ଆପ}other{ଅଧିକ ଆପ୍ସ}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"ଡେସ୍କଟପ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ଏବଂ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ବବଲ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ଓଭରଫ୍ଲୋ"</string> diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml index 6d4d28723b..7da7555e2b 100644 --- a/quickstep/res/values-pa/strings.xml +++ b/quickstep/res/values-pa/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ਟਾਸਕਬਾਰ ਵਿਭਾਜਕ"</string> <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="6935266023013283353">"{count,plural, =1{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}one{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}other{# ਹੋਰ ਐਪਾਂ ਦਿਖਾਓ।}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ਡੈਸਕਟਾਪ ਐਪ ਦਿਖਾਓ।}one{# ਡੈਸਕਟਾਪ ਐਪ ਦਿਖਾਓ।}other{# ਡੈਸਕਟਾਪ ਐਪਾਂ ਦਿਖਾਓ।}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ਹੋਰ ਐਪ}one{ਹੋਰ ਐਪ}other{ਹੋਰ ਐਪਾਂ}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"ਡੈਸਕਟਾਪ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ਅਤੇ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ਬਬਲ"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ਓਵਰਫ਼ਲੋ"</string> diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml index f001a88826..0cc49e263e 100644 --- a/quickstep/res/values-pl/strings.xml +++ b/quickstep/res/values-pl/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Linia dzielenia paska aplikacji"</string> <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="6935266023013283353">"{count,plural, =1{Pokaż jeszcze # aplikację.}few{Pokaż jeszcze # aplikacje.}many{Pokaż jeszcze # aplikacji.}other{Pokaż jeszcze # aplikacji.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Pokaż # aplikację komputerową.}few{Pokaż # aplikacje komputerowe.}many{Pokaż # aplikacji komputerowych.}other{Pokaż # aplikacji komputerowej.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{inna aplikacja}few{inne aplikacje}many{innych aplikacji}other{innej aplikacji}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Pulpit"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Dymek"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozwijany"</string> diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml index 1d65cce2e5..33b87df643 100644 --- a/quickstep/res/values-pt-rPT/strings.xml +++ b/quickstep/res/values-pt-rPT/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divisor da Barra de tarefas"</string> <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="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computador.}other{Mostrar # apps para computador.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{outra app}other{outras apps}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Computador"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menu adicional"</string> diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml index e09490802c..0aa629511d 100644 --- a/quickstep/res/values-pt/strings.xml +++ b/quickstep/res/values-pt/strings.xml @@ -90,7 +90,7 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Tutorial <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Tudo pronto!"</string> <string name="allset_hint" msgid="459504134589971527">"Deslize para cima para acessar a tela inicial"</string> - <string name="allset_button_hint" msgid="2395219947744706291">"Toque no botão home para ir para a tela inicial"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Toque no botão home para acessar a tela inicial"</string> <string name="allset_description_generic" msgid="5385500062202019855">"Você já pode começar a usar seu <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="default_device_name" msgid="6660656727127422487">"dispositivo"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Configurações de navegação do sistema"</annotation></string> @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separador da Barra de tarefas"</string> <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="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}one{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computador.}one{Mostrar # app para computador.}other{Mostrar # apps para computador.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{outro app}one{outro app}other{outros apps}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Computador"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Balão flutuante"</string> diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml index be813d5b06..2f9d287535 100644 --- a/quickstep/res/values-ro/strings.xml +++ b/quickstep/res/values-ro/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Separator pentru bara de activități"</string> <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="6935266023013283353">"{count,plural, =1{Afișează încă # aplicație}few{Afișează încă # aplicații}other{Afișează încă # de aplicații}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afișează # aplicație pentru computer.}few{Afișează # aplicații pentru computer.}other{Afișează # de aplicații pentru computer.}}"</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> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Computer"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> și <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Suplimentar"</string> diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml index 5e1c79dead..2722ca9464 100644 --- a/quickstep/res/values-ru/strings.xml +++ b/quickstep/res/values-ru/strings.xml @@ -93,7 +93,7 @@ <string name="allset_button_hint" msgid="2395219947744706291">"Нажмите кнопку главного экрана, чтобы открыть его."</string> <string name="allset_description_generic" msgid="5385500062202019855">"Теперь вы можете использовать <xliff:g id="DEVICE">%1$s</xliff:g>."</string> <string name="default_device_name" msgid="6660656727127422487">"устройство"</string> - <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Системные настройки навигации"</annotation></string> + <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Настройки навигации в системе"</annotation></string> <string name="action_share" msgid="2648470652637092375">"Поделиться"</string> <string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string> <string name="action_split" msgid="2098009717623550676">"Разделить"</string> @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделитель панели задач"</string> <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="6935266023013283353">"{count,plural, =1{Показать ещё # приложение}one{Показать ещё # приложение}few{Показать ещё # приложения}many{Показать ещё # приложений}other{Показать ещё # приложения}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показать # компьютерное приложение.}one{Показать # компьютерное приложение.}few{Показать # компьютерных приложения.}many{Показать # компьютерных приложений.}other{Показать # компьютерного приложения.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{дополнительное приложение}one{дополнительное приложение}few{дополнительных приложения}many{дополнительных приложений}other{дополнительного приложения}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Режим компьютера"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Всплывающая подсказка"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Дополнительное меню"</string> diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml index 1b6ec0fcd0..19b61f7dd0 100644 --- a/quickstep/res/values-si/strings.xml +++ b/quickstep/res/values-si/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"කාර්ය තීරු බෙදනය"</string> <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="6935266023013283353">"{count,plural, =1{තවත් # යෙදුමක් පෙන්වන්න.}one{තවත් යෙදුම් #ක් පෙන්වන්න.}other{තවත් යෙදුම් #ක් පෙන්වන්න.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ඩෙස්ක්ටොප් යෙදුමක් පෙන්වන්න.}one{ඩෙස්ක්ටොප් යෙදුම් # ක් පෙන්වන්න.}other{ඩෙස්ක්ටොප් යෙදුම් # ක් පෙන්වන්න.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{තව යෙදුම}one{තවත් යෙදුම්}other{තවත් යෙදුම්}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"ඩෙස්ක්ටොපය"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> සහ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"බුබුළු"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"පිටාර යාම"</string> diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml index 12a00a3c43..0f0ec278e3 100644 --- a/quickstep/res/values-sk/strings.xml +++ b/quickstep/res/values-sk/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Rozdeľovač panela aplikácií"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Presunúť hore alebo doľava"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Presunúť dole alebo doprava"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobraziť # ďalšiu aplikáciu.}few{Zobraziť # ďalšie aplikácie.}many{Show # more apps.}other{Zobraziť # ďalších aplikácií.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Zobraziť # aplikáciu pre počítač.}few{Zobraziť # aplikácie pre počítač.}many{Show # desktop apps.}other{Zobraziť # aplikácií pre počítač.}}"</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> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Počítač"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbaľovacia ponuka"</string> diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml index 912ef83d04..972ced5410 100644 --- a/quickstep/res/values-sl/strings.xml +++ b/quickstep/res/values-sl/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdelilnik opravilne vrstice"</string> <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="6935266023013283353">"{count,plural, =1{Pokaži še # aplikacijo.}one{Pokaži še # aplikacijo.}two{Pokaži še # aplikaciji.}few{Pokaži še # aplikacije.}other{Pokaži še # aplikacij.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaz # aplikacije za namizni računalnik.}one{Prikaz # aplikacije za namizni računalnik.}two{Prikaz # aplikacij za namizni računalnik.}few{Prikaz # aplikacij za namizni računalnik.}other{Prikaz # aplikacij za namizni računalnik.}}"</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> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Namizni računalnik"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> in <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblaček"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oblaček z dodatnimi elementi"</string> diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml index 2be5e2b78c..d2a72811d9 100644 --- a/quickstep/res/values-sq/strings.xml +++ b/quickstep/res/values-sq/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Ndarësi i shiritit të detyrave"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Lëviz në krye/majtas"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Lëviz në fund/djathtas"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Shfaq # aplikacion tjetër.}other{Shfaq # aplikacione të tjera.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Shfaq # aplikacion për desktop.}other{Shfaq # aplikacione për desktop.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{aplikacion tjetër}other{aplikacione të tjera}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dhe <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Flluska"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tejkalimi"</string> diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml index 88e58f3fd9..81204afd58 100644 --- a/quickstep/res/values-sr/strings.xml +++ b/quickstep/res/values-sr/strings.xml @@ -90,7 +90,7 @@ <string name="gesture_tutorial_step" msgid="1279786122817620968">"Водич <xliff:g id="CURRENT">%1$d</xliff:g>/<xliff:g id="TOTAL">%2$d</xliff:g>"</string> <string name="allset_title" msgid="5021126669778966707">"Готово!"</string> <string name="allset_hint" msgid="459504134589971527">"Превуците нагоре да бисте отворили почетни екран"</string> - <string name="allset_button_hint" msgid="2395219947744706291">"Додирните дугме Почетак да бисти ишли на почетни екран"</string> + <string name="allset_button_hint" msgid="2395219947744706291">"Додирните дугме Почетак да бисте отишли на почетни екран"</string> <string name="allset_description_generic" msgid="5385500062202019855">"Спремни сте да почнете да користите <xliff:g id="DEVICE">%1$s</xliff:g>"</string> <string name="default_device_name" msgid="6660656727127422487">"уређај"</string> <string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Подешавања кретања кроз систем"</annotation></string> @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Разделник траке задатака"</string> <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="6935266023013283353">"{count,plural, =1{Прикажи још # апликацију.}one{Прикажи још # апликацију.}few{Прикажи још # апликације.}other{Прикажи још # апликација.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Прикажи # апликацију за рачунаре.}one{Прикажи # апликацију за рачунаре.}few{Прикажи # апликације за рачунаре.}other{Прикажи # апликација за рачунаре.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{додатна апликација}one{додатна апликација}few{додатне апликације}other{додатних апликација}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Рачунар"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Облачић"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Преклопни"</string> diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml index bc58772407..5d0c7a38fa 100644 --- a/quickstep/res/values-sv/strings.xml +++ b/quickstep/res/values-sv/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Avdelare för aktivitetsfältet"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Flytta högst upp/till vänster"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Flytta längst ned/till höger"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Visa # app till.}other{Visa # appar till.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Visa # datorapp.}other{Visa # datorappar.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{app till}other{appar till}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Dator"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> och <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbla"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Fler alternativ"</string> diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml index f2935b5353..e133ba30aa 100644 --- a/quickstep/res/values-sw/strings.xml +++ b/quickstep/res/values-sw/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Kitenganishi cha Upauzana"</string> <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="6935266023013283353">"{count,plural, =1{Onyesha programu # zaidi.}other{Onyesha programu # zaidi.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Onyesha programu # ya kompyuta ya mezani.}other{Onyesha programu # za kompyuta ya mezani.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{programu nyingine}other{programu zingine}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Kompyuta ya Mezani"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> na <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kiputo"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kiputo cha vipengee vya ziada"</string> diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml index 28585a41dc..95d0fa9ab4 100644 --- a/quickstep/res/values-ta/strings.xml +++ b/quickstep/res/values-ta/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"செயல் பட்டிப் பிரிப்பான்"</string> <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="6935266023013283353">"{count,plural, =1{மேலும் # ஆப்ஸைக் காட்டு.}other{மேலும் # ஆப்ஸைக் காட்டு.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# டெஸ்க்டாப் ஆப்ஸைக் காட்டு.}other{# டெஸ்க்டாப் ஆப்ஸைக் காட்டு.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{கூடுதல் ஆப்ஸ்}other{கூடுதல் ஆப்ஸ்}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"டெஸ்க்டாப்"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> மற்றும் <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"குமிழ்"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"கூடுதல் விருப்பங்களைக் காட்டும்"</string> diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml index 6255cfca77..116d388e43 100644 --- a/quickstep/res/values-te/strings.xml +++ b/quickstep/res/values-te/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"టాస్క్బార్ డివైడర్"</string> <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="6935266023013283353">"{count,plural, =1{మరో # యాప్ను చూడండి.}other{మరో # యాప్లను చూడండి.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# డెస్క్టాప్ యాప్ను చూపండి.}other{# డెస్క్టాప్ యాప్లను చూపండి.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{మరో యాప్}other{మరిన్ని యాప్లు}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"డెస్క్టాప్"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"బబుల్"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ఓవర్ఫ్లో"</string> diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml index f47e34d762..ecdb3b5570 100644 --- a/quickstep/res/values-th/strings.xml +++ b/quickstep/res/values-th/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ตัวแบ่งแถบงาน"</string> <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="6935266023013283353">"{count,plural, =1{แสดงเพิ่มเติมอีก # แอป}other{แสดงเพิ่มเติมอีก # แอป}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{แสดงแอปบนเดสก์ท็อป # รายการ}other{แสดงแอปบนเดสก์ท็อป # รายการ}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{แอปเพิ่มเติม}other{แอปเพิ่มเติม}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"เดสก์ท็อป"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> และ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"บับเบิล"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"การดำเนินการเพิ่มเติม"</string> diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml index 582b756cd7..da646a4d41 100644 --- a/quickstep/res/values-tl/strings.xml +++ b/quickstep/res/values-tl/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Divider ng Taskbar"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Ilipat sa itaas/kaliwa"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Ilipat sa ibaba/kanan"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Magpakita ng # pang app.}one{Magpakita ng # pang app.}other{Magpakita ng # pang app.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Ipakita ang # desktop app.}one{Ipakita ang # desktop app.}other{Ipakita ang # na desktop app.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{pang app}one{pang app}other{pang app}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Desktop"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> at <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string> diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml index 9842ebcd2d..7be5464a19 100644 --- a/quickstep/res/values-tr/strings.xml +++ b/quickstep/res/values-tr/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Görev Çubuğu Ayırıcısı"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Sol üste taşı"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Sağ alta taşı"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# uygulama daha göster.}other{# uygulama daha göster}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# masaüstü uygulamasını göster.}other{# masaüstü uygulamasını göster.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{uygulama daha}other{uygulama daha}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Masaüstü"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ve <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Taşma"</string> diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml index 20564c3ceb..216ae0b700 100644 --- a/quickstep/res/values-uk/strings.xml +++ b/quickstep/res/values-uk/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Розділювач панелі завдань"</string> <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="6935266023013283353">"{count,plural, =1{Показати ще # додаток.}one{Показати ще # додаток.}few{Показати ще # додатки.}many{Показати ще # додатків.}other{Показати ще # додатка.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показати # комп’ютерну програму.}one{Показати # комп’ютерну програму.}few{Показати # комп’ютерні програми.}many{Показати # комп’ютерних програм.}other{Показати # комп’ютерної програми.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{інший додаток}one{інший додаток}few{інші додатки}many{інших додатків}other{іншого додатка}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Комп’ютер"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> та <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Повідомлення"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Додаткове повідомлення"</string> diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml index 7c3a41fad7..2307cb12e1 100644 --- a/quickstep/res/values-ur/strings.xml +++ b/quickstep/res/values-ur/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"ٹاسک بار ڈیوائیڈر"</string> <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="6935266023013283353">"{count,plural, =1{# مزید ایپ دکھائیں۔}other{# مزید ایپس دکھائیں۔}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ڈیسک ٹاپ ایپ دکھائیں۔}other{# ڈیسک ٹاپ ایپس دکھائیں۔}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{مزید ایپ}other{مزید ایپس}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"ڈیسک ٹاپ"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> اور <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ببل"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"اوورفلو"</string> diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml index ac024136ec..9f98b55452 100644 --- a/quickstep/res/values-uz/strings.xml +++ b/quickstep/res/values-uz/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Vazifalar panelini ajratkich"</string> <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="6935266023013283353">"{count,plural, =1{Yana # ta ilovani chiqarish}other{Yana # ta ilovani chiqarish}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ta desktop ilovani chiqarish.}other{# ta desktop ilovani chiqarish.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{boshqa ilova}other{boshqa ilovalar}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Kompyuter"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> va <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Pufak"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kengaytirish"</string> diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml index 4c1195798d..50acbbc7ac 100644 --- a/quickstep/res/values-vi/strings.xml +++ b/quickstep/res/values-vi/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Đường phân chia Taskbar"</string> <string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Chuyển lên trên cùng/sang bên trái"</string> <string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Chuyển xuống dưới cùng/sang bên phải"</string> - <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Hiện thêm # ứng dụng.}other{Hiện thêm # ứng dụng.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Hiện # ứng dụng dành cho máy tính.}other{Hiện # ứng dụng dành cho máy tính.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{ứng dụng khác}other{ứng dụng khác}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Máy tính"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> và <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bong bóng"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bong bóng bổ sung"</string> diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml index bdc99df040..1b6c4e4a6f 100644 --- a/quickstep/res/values-zh-rCN/strings.xml +++ b/quickstep/res/values-zh-rCN/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"任务栏分隔线"</string> <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="6935266023013283353">"{count,plural, =1{显示另外 # 个应用。}other{显示另外 # 个应用。}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{显示 # 款桌面应用。}other{显示 # 款桌面应用。}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{多个应用}other{多个应用}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"桌面模式"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>和<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"气泡框"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢出式气泡框"</string> diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml index abdb91c637..38608e52b8 100644 --- a/quickstep/res/values-zh-rHK/strings.xml +++ b/quickstep/res/values-zh-rHK/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"工作列分隔線"</string> <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="6935266023013283353">"{count,plural, =1{顯示另外 # 個應用程式。}other{顯示另外 # 個應用程式。}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{顯示 # 個桌面應用程式。}other{顯示 # 個桌面應用程式。}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個其他應用程式}other{個其他應用程式}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"桌面"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"對話氣泡"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"展開式"</string> diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml index 91da74e42e..3e46779019 100644 --- a/quickstep/res/values-zh-rTW/strings.xml +++ b/quickstep/res/values-zh-rTW/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"工作列分隔線"</string> <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="6935266023013283353">"{count,plural, =1{再多顯示 # 個應用程式。}other{再多顯示 # 個應用程式。}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{顯示 # 個電腦版應用程式。}other{顯示 # 個電腦版應用程式。}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{個其他應用程式}other{個其他應用程式}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"電腦"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"泡泡"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢位"</string> diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml index 718400dd59..120b38763d 100644 --- a/quickstep/res/values-zu/strings.xml +++ b/quickstep/res/values-zu/strings.xml @@ -141,8 +141,8 @@ <string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Isihlukanisi se-Taskbar"</string> <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="6935266023013283353">"{count,plural, =1{Bonisa i-app e-# ngaphezulu.}one{Bonisa ama-app angu-# ngaphezulu.}other{Bonisa ama-app angu-# ngaphezulu.}}"</string> - <string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Bonisa i-app engu-# yedeskithophu.}one{Bonisa ama-app angu-# wedeskithophu.}other{Bonisa ama-app angu-# wedeskithophu.}}"</string> + <string name="quick_switch_overflow" msgid="3679780650881041632">"{count,plural, =1{i-app eyengeziwe}one{ama-app engeziwe}other{ama-app engeziwe}}"</string> + <string name="quick_switch_desktop" msgid="8393802056024499749">"Ideskithophu"</string> <string name="quick_switch_split_task" msgid="5598194724255333896">"I-<xliff:g id="APP_NAME_1">%1$s</xliff:g> ne-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string> <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ibhamuza"</string> <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ukugcwala kakhulu"</string> diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml index 0bb971e166..4c48bd3f99 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 ce3f3ac561..8957e0d16e 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -350,7 +350,6 @@ <dimen name="taskbar_back_button_left_margin_kids">48dp</dimen> <dimen name="taskbar_home_button_left_margin_kids">48dp</dimen> <dimen name="taskbar_icon_size_kids">32dp</dimen> - <dimen name="taskbar_all_apps_button_translation_x_offset">6dp</dimen> <dimen name="taskbar_all_apps_search_button_translation_x_offset">6dp</dimen> <dimen name="taskbar_contextual_button_suw_margin">64dp</dimen> <dimen name="taskbar_contextual_button_suw_height">64dp</dimen> @@ -480,6 +479,17 @@ <dimen name="bubble_expanded_view_drop_target_padding">24dp</dimen> <dimen name="bubble_expanded_view_drop_target_margin">16dp</dimen> + <!-- Bubble bar flyout view --> + <dimen name="bubblebar_flyout_padding">16dp</dimen> + <dimen name="bubblebar_flyout_elevation">4dp</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 --> <!-- starting_surface_exit_animation_window_shift_length --> diff --git a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java index e940553a93..a63ba0f8e6 100644 --- a/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java +++ b/quickstep/src/com/android/launcher3/LauncherAnimationRunner.java @@ -26,7 +26,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.content.Context; import android.os.Handler; -import android.os.RemoteException; import android.util.Log; import android.view.IRemoteAnimationFinishedCallback; import android.view.RemoteAnimationTarget; @@ -210,7 +209,7 @@ public class LauncherAnimationRunner extends RemoteAnimationRunnerCompat { * animation finished runnable. */ @Override - public void onAnimationFinished() throws RemoteException { + public void onAnimationFinished() { mASyncFinishRunnable.run(); } } @@ -240,12 +239,5 @@ public class LauncherAnimationRunner extends RemoteAnimationRunnerCompat { @Override @UiThread default void onAnimationCancelled() {} - - /** - * Returns whether this animation factory supports a tightly coupled return animation. - */ - default boolean supportsReturnTransition() { - return false; - } } } diff --git a/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java b/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java index 962fd91c2e..1161720e3b 100644 --- a/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java +++ b/quickstep/src/com/android/launcher3/QuickstepAccessibilityDelegate.java @@ -15,10 +15,19 @@ */ package com.android.launcher3; +import static androidx.recyclerview.widget.RecyclerView.NO_POSITION; + import android.view.KeyEvent; import android.view.View; +import android.view.accessibility.AccessibilityEvent; + +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.LinearSmoothScroller; +import androidx.recyclerview.widget.RecyclerView; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; +import com.android.launcher3.allapps.AllAppsRecyclerView; +import com.android.launcher3.allapps.SearchRecyclerView; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.uioverrides.PredictedAppIcon; import com.android.launcher3.uioverrides.QuickstepLauncher; @@ -26,14 +35,61 @@ import com.android.launcher3.uioverrides.QuickstepLauncher; import java.util.List; public class QuickstepAccessibilityDelegate extends LauncherAccessibilityDelegate { + private QuickstepLauncher mLauncher; public QuickstepAccessibilityDelegate(QuickstepLauncher launcher) { super(launcher); + mLauncher = launcher; mActions.put(PIN_PREDICTION, new LauncherAction( PIN_PREDICTION, R.string.pin_prediction, KeyEvent.KEYCODE_P)); } @Override + public void onPopulateAccessibilityEvent(View view, AccessibilityEvent event) { + super.onPopulateAccessibilityEvent(view, event); + // Scroll to the position if focused view in main allapps list and not completely visible. + scrollToPositionIfNeeded(view); + } + + private void scrollToPositionIfNeeded(View view) { + if (!Flags.accessibilityScrollOnAllapps()) { + return; + } + AllAppsRecyclerView contentView = mLauncher.getAppsView().getActiveRecyclerView(); + if (contentView instanceof SearchRecyclerView) { + return; + } + LinearLayoutManager layoutManager = (LinearLayoutManager) contentView.getLayoutManager(); + if (layoutManager == null) { + return; + } + RecyclerView.ViewHolder vh = contentView.findContainingViewHolder(view); + if (vh == null) { + return; + } + int itemPosition = vh.getBindingAdapterPosition(); + if (itemPosition == NO_POSITION) { + return; + } + int firstCompletelyVisible = layoutManager.findFirstCompletelyVisibleItemPosition(); + int lastCompletelyVisible = layoutManager.findLastCompletelyVisibleItemPosition(); + boolean itemCompletelyVisible = firstCompletelyVisible <= itemPosition + && lastCompletelyVisible >= itemPosition; + if (itemCompletelyVisible) { + return; + } + RecyclerView.SmoothScroller smoothScroller = + new LinearSmoothScroller(mLauncher.asContext()) { + @Override + protected int getVerticalSnapPreference() { + return LinearSmoothScroller.SNAP_TO_ANY; + } + }; + smoothScroller.setTargetPosition(itemPosition); + layoutManager.startSmoothScroll(smoothScroller); + } + + @Override protected void getSupportedActions(View host, ItemInfo item, List<LauncherAction> out) { if (host instanceof PredictedAppIcon && !((PredictedAppIcon) host).isPinned()) { out.add(new LauncherAction(PIN_PREDICTION, R.string.pin_prediction, diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index e51c956016..a64936d287 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -46,17 +46,12 @@ import static com.android.launcher3.BaseActivity.PENDING_INVISIBLE_BY_WALLPAPER_ import static com.android.launcher3.Flags.enableContainerReturnAnimations; import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; -import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.BACKGROUND_APP; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.Utilities.mapBoundToRange; -import static com.android.launcher3.config.FeatureFlags.ENABLE_BACK_SWIPE_HOME_ANIMATION; -import static com.android.launcher3.config.FeatureFlags.ENABLE_SCRIM_FOR_APP_LAUNCH; -import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION; import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY; -import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.testing.shared.TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE; import static com.android.launcher3.util.DisplayController.isTransientTaskbar; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; @@ -89,7 +84,6 @@ import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; -import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.os.Handler; import android.os.IBinder; @@ -116,6 +110,7 @@ import android.view.animation.Interpolator; import android.view.animation.PathInterpolator; import android.window.RemoteTransition; import android.window.TransitionFilter; +import android.window.WindowAnimationState; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -138,16 +133,17 @@ import com.android.launcher3.touch.PagedOrientationHandler; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.ActivityOptionsWrapper; import com.android.launcher3.util.DynamicResource; -import com.android.launcher3.util.ObjectWrapper; import com.android.launcher3.util.RunnableList; -import com.android.launcher3.util.Themes; +import com.android.launcher3.util.StableViewInfo; import com.android.launcher3.views.FloatingIconView; -import com.android.launcher3.views.ScrimView; import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.quickstep.LauncherBackAnimationController; import com.android.quickstep.RemoteAnimationTargets; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TaskViewUtils; +import com.android.quickstep.util.AlreadyStartedBackAnimState; +import com.android.quickstep.util.AnimatorBackState; +import com.android.quickstep.util.BackAnimState; import com.android.quickstep.util.MultiValueUpdateListener; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.RectFSpringAnim.DefaultSpringConfig; @@ -174,6 +170,7 @@ import com.android.wm.shell.startingsurface.IStartingWindowListener; import java.io.PrintWriter; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -182,9 +179,6 @@ import java.util.List; */ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener { - private static final String TRANSITION_COOKIE_PREFIX = - "com.android.launcher3.QuickstepTransitionManager_activityLaunch"; - private static final boolean ENABLE_SHELL_STARTING_SURFACE = SystemProperties.getBoolean("persist.debug.shell_starting_surface", true); @@ -258,7 +252,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener // Strong refs to runners which are cleared when the launcher activity is destroyed private RemoteAnimationFactory mWallpaperOpenRunner; private RemoteAnimationFactory mAppLaunchRunner; - private RemoteAnimationFactory mKeyguardGoingAwayRunner; private RemoteAnimationFactory mWallpaperOpenTransitionRunner; private RemoteTransition mLauncherOpenTransition; @@ -327,7 +320,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * @return ActivityOptions with remote animations that controls how the window of the opening * targets are displayed. */ - public ActivityOptionsWrapper getActivityLaunchOptions(View v) { + public ActivityOptionsWrapper getActivityLaunchOptions(View v, ItemInfo itemInfo) { boolean fromRecents = isLaunchingFromRecents(v, null /* targets */); RunnableList onEndCallback = new RunnableList(); @@ -354,14 +347,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener IRemoteCallback endCallback = completeRunnableListCallback(onEndCallback); options.setOnAnimationAbortListener(endCallback); options.setOnAnimationFinishedListener(endCallback); - - IBinder cookie = mAppLaunchRunner.supportsReturnTransition() - ? ((ContainerAnimationRunner) mAppLaunchRunner).getCookie() : null; - addLaunchCookie(cookie, (ItemInfo) v.getTag(), options); - - // Register the return animation so it can be triggered on back from the app to home. - maybeRegisterAppReturnTransition(v); - + options.setLaunchCookie(StableViewInfo.toLaunchCookie(itemInfo)); return new ActivityOptionsWrapper(options, onEndCallback); } @@ -374,21 +360,9 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener ItemInfo tag = (ItemInfo) v.getTag(); ContainerAnimationRunner containerRunner = null; if (tag != null && tag.shouldUseBackgroundAnimation()) { - // The cookie should only override the default used by launcher if container return - // animations are enabled. - ActivityTransitionAnimator.TransitionCookie cookie = - checkReturnAnimationsFlags() - ? new ActivityTransitionAnimator.TransitionCookie( - TRANSITION_COOKIE_PREFIX + tag.id) - : null; - ContainerAnimationRunner launchAnimationRunner = - ContainerAnimationRunner.fromView( - v, cookie, true /* forLaunch */, mLauncher, mStartingWindowListener, - onEndCallback); - - if (launchAnimationRunner != null) { - containerRunner = launchAnimationRunner; - } + containerRunner = ContainerAnimationRunner.fromView( + v, true /* forLaunch */, mLauncher, mStartingWindowListener, onEndCallback, + null /* windowState */); } mAppLaunchRunner = containerRunner != null @@ -398,51 +372,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener } /** - * If container return animations are enabled and the current launch runner is itself a - * {@link ContainerAnimationRunner}, registers a matching return animation that de-registers - * itself after it has run once or is made obsolete by the view going away. - */ - private void maybeRegisterAppReturnTransition(View v) { - if (!checkReturnAnimationsFlags() || !mAppLaunchRunner.supportsReturnTransition()) { - return; - } - - ActivityTransitionAnimator.TransitionCookie cookie = - ((ContainerAnimationRunner) mAppLaunchRunner).getCookie(); - RunnableList onEndCallback = new RunnableList(); - ContainerAnimationRunner runner = - ContainerAnimationRunner.fromView( - v, cookie, false /* forLaunch */, mLauncher, mStartingWindowListener, - onEndCallback); - RemoteTransition transition = - new RemoteTransition( - new LauncherAnimationRunner( - mHandler, runner, true /* startAtFrontOfQueue */ - ).toRemoteTransition() - ); - - SystemUiProxy.INSTANCE.get(mLauncher).registerRemoteTransition( - transition, ContainerAnimationRunner.buildBackToHomeFilter(cookie, mLauncher)); - ContainerAnimationRunner.setUpRemoteAnimationCleanup( - v, transition, onEndCallback, mLauncher); - } - - /** - * Adds a new launch cookie for the activity launch if supported. - * Prioritizes the explicitly provided cookie, falling back on extracting one from the given - * {@link ItemInfo} if necessary. - */ - private void addLaunchCookie(IBinder cookie, ItemInfo info, ActivityOptions options) { - if (cookie == null) { - cookie = mLauncher.getLaunchCookie(info); - } - - if (cookie != null) { - options.setLaunchCookie(cookie); - } - } - - /** * Whether the launch is a recents app transition and we should do a launch animation * from the recents view. Note that if the remote animation targets are not provided, this * may not always be correct as we may resolve the opening app to a task when the animation @@ -667,34 +596,11 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener launcherAnimator.play(scaleAnim); }); - final boolean scrimEnabled = ENABLE_SCRIM_FOR_APP_LAUNCH.get(); - if (scrimEnabled) { - int scrimColor = Themes.getAttrColor(mLauncher, R.attr.overviewScrimColor); - int scrimColorTrans = ColorUtils.setAlphaComponent(scrimColor, 0); - int[] colors = isAppOpening - ? new int[]{scrimColorTrans, scrimColor} - : new int[]{scrimColor, scrimColorTrans}; - ScrimView scrimView = mLauncher.getScrimView(); - if (scrimView.getBackground() instanceof ColorDrawable) { - scrimView.setBackgroundColor(colors[0]); - - ObjectAnimator scrim = ObjectAnimator.ofArgb(scrimView, VIEW_BACKGROUND_COLOR, - colors); - scrim.setDuration(CONTENT_SCRIM_DURATION); - scrim.setInterpolator(DECELERATE_1_5); - - launcherAnimator.play(scrim); - } - } - endListener = () -> { viewsToAnimate.forEach(view -> { SCALE_PROPERTY.set(view, 1f); view.setLayerType(View.LAYER_TYPE_NONE, null); }); - if (scrimEnabled) { - mLauncher.getScrimView().setBackgroundColor(Color.TRANSPARENT); - } mLauncher.resumeExpensiveViewUpdates(); }; } @@ -1203,24 +1109,13 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * additional animations. */ private void addRemoteAnimations(RemoteAnimationDefinition definition) { - mWallpaperOpenRunner = createWallpaperOpenRunner(false /* fromUnlock */); + mWallpaperOpenRunner = new WallpaperOpenLauncherAnimationRunner(); definition.addRemoteAnimation(WindowManager.TRANSIT_OLD_WALLPAPER_OPEN, WindowConfiguration.ACTIVITY_TYPE_STANDARD, new RemoteAnimationAdapter( new LauncherAnimationRunner(mHandler, mWallpaperOpenRunner, false /* startAtFrontOfQueue */), CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */)); - - if (KEYGUARD_ANIMATION.get()) { - mKeyguardGoingAwayRunner = createWallpaperOpenRunner(true /* fromUnlock */); - definition.addRemoteAnimation( - WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER, - new RemoteAnimationAdapter( - new LauncherAnimationRunner( - mHandler, mKeyguardGoingAwayRunner, - true /* startAtFrontOfQueue */), - CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */)); - } } /** @@ -1232,7 +1127,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener return; } - mWallpaperOpenTransitionRunner = createWallpaperOpenRunner(false /* fromUnlock */); + mWallpaperOpenTransitionRunner = new WallpaperOpenLauncherAnimationRunner(); mLauncherOpenTransition = new RemoteTransition( new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner, false /* startAtFrontOfQueue */).toRemoteTransition(), @@ -1287,7 +1182,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener // definition so we don't have to wait for the system gc mWallpaperOpenRunner = null; mAppLaunchRunner = null; - mKeyguardGoingAwayRunner = null; } protected void unregisterRemoteTransitions() { @@ -1345,41 +1239,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener return false; } - /** - * @return Runner that plays when user goes to Launcher - * ie. pressing home, swiping up from nav bar. - */ - RemoteAnimationFactory createWallpaperOpenRunner(boolean fromUnlock) { - return new WallpaperOpenLauncherAnimationRunner(fromUnlock); - } - - /** - * Animator that controls the transformations of the windows when unlocking the device. - */ - private Animator getUnlockWindowAnimator(RemoteAnimationTarget[] appTargets, - RemoteAnimationTarget[] wallpaperTargets) { - SurfaceTransactionApplier surfaceApplier = new SurfaceTransactionApplier(mDragLayer); - ValueAnimator unlockAnimator = ValueAnimator.ofFloat(0, 1); - unlockAnimator.setDuration(CLOSING_TRANSITION_DURATION_MS); - float cornerRadius = mDeviceProfile.isMultiWindowMode ? 0 : - QuickStepContract.getWindowCornerRadius(mLauncher); - unlockAnimator.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - SurfaceTransaction transaction = new SurfaceTransaction(); - for (int i = appTargets.length - 1; i >= 0; i--) { - RemoteAnimationTarget target = appTargets[i]; - transaction.forSurface(target.leash) - .setAlpha(1f) - .setWindowCrop(target.screenSpaceBounds) - .setCornerRadius(cornerRadius); - } - surfaceApplier.scheduleApply(transaction); - } - }); - return unlockAnimator; - } - private static int getRotationChange(RemoteAnimationTarget[] appTargets) { int rotationChange = 0; for (RemoteAnimationTarget target : appTargets) { @@ -1433,20 +1292,12 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener // Find the associated item info for the launch cookie (if available), note that predicted // apps actually have an id of -1, so use another default id here - final ArrayList<IBinder> launchCookies = runningTaskTarget.taskInfo.launchCookies == null - ? new ArrayList<>() + final List<IBinder> launchCookies = runningTaskTarget.taskInfo.launchCookies == null + ? Collections.EMPTY_LIST : runningTaskTarget.taskInfo.launchCookies; - int launchCookieItemId = NO_MATCHING_ID; - for (IBinder cookie : launchCookies) { - Integer itemId = ObjectWrapper.unwrap(cookie); - if (itemId != null) { - launchCookieItemId = itemId; - break; - } - } - - return mLauncher.getFirstMatchForAppClose(launchCookieItemId, packageName, + return mLauncher.getFirstMatchForAppClose( + StableViewInfo.fromLaunchCookies(launchCookies), packageName, UserHandle.of(runningTaskTarget.taskInfo.userId), true /* supportsAllAppsState */); } @@ -1698,20 +1549,48 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener * Creates the {@link RectFSpringAnim} and {@link AnimatorSet} required to animate * the transition. */ - public Pair<RectFSpringAnim, AnimatorSet> createWallpaperOpenAnimations( + @NonNull + public BackAnimState createWallpaperOpenAnimations( RemoteAnimationTarget[] appTargets, - RemoteAnimationTarget[] wallpaperTargets, - boolean fromUnlock, + RemoteAnimationTarget[] wallpapers, + RemoteAnimationTarget[] nonAppTargets, RectF startRect, float startWindowCornerRadius, boolean fromPredictiveBack) { + View launcherView = findLauncherView(appTargets); + if (checkReturnAnimationsFlags() + && launcherView != null + && launcherView.getTag() instanceof ItemInfo info + && info.shouldUseBackgroundAnimation()) { + // Try to create a return animation + RunnableList onEndCallback = new RunnableList(); + WindowAnimationState windowState = new WindowAnimationState(); + windowState.bounds = startRect; + windowState.bottomLeftRadius = windowState.bottomRightRadius = + windowState.topLeftRadius = windowState.topRightRadius = + startWindowCornerRadius; + ContainerAnimationRunner runner = ContainerAnimationRunner.fromView( + launcherView, false /* forLaunch */, mLauncher, mStartingWindowListener, + onEndCallback, windowState); + if (runner != null) { + runner.startAnimation(TRANSIT_CLOSE, + appTargets, wallpapers, nonAppTargets, + new IRemoteAnimationFinishedCallback.Stub() { + @Override + public void onAnimationFinished() { + onEndCallback.executeAllAndDestroy(); + } + }); + return new AlreadyStartedBackAnimState(onEndCallback); + } + } + AnimatorSet anim = new AnimatorSet(); RectFSpringAnim rectFSpringAnim = null; final boolean launcherIsForceInvisibleOrOpening = mLauncher.isForceInvisible() || launcherIsATargetWithMode(appTargets, MODE_OPENING); - View launcherView = findLauncherView(appTargets); boolean playFallBackAnimation = (launcherView == null && launcherIsForceInvisibleOrOpening) || mLauncher.getWorkspace().isOverlayShown() @@ -1719,10 +1598,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener boolean playWorkspaceReveal = !fromPredictiveBack; boolean skipAllAppsScale = false; - if (fromUnlock) { - anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets)); - } else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get() - && !playFallBackAnimation) { + if (!playFallBackAnimation) { PointF velocity; if (enableScalingRevealHomeAnimation()) { velocity = new PointF(); @@ -1814,7 +1690,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener } } - return new Pair(rectFSpringAnim, anim); + return new AnimatorBackState(rectFSpringAnim, anim); } public static int getTaskbarToHomeDuration() { @@ -1834,12 +1710,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener */ protected class WallpaperOpenLauncherAnimationRunner implements RemoteAnimationFactory { - private final boolean mFromUnlock; - - public WallpaperOpenLauncherAnimationRunner(boolean fromUnlock) { - mFromUnlock = fromUnlock; - } - @Override public void onAnimationStart(int transit, RemoteAnimationTarget[] appTargets, @@ -1870,14 +1740,14 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener } } - Pair<RectFSpringAnim, AnimatorSet> pair = createWallpaperOpenAnimations( - appTargets, wallpaperTargets, mFromUnlock, resolveRectF, + BackAnimState bankAnimState = createWallpaperOpenAnimations( + appTargets, wallpaperTargets, nonAppTargets, resolveRectF, QuickStepContract.getWindowCornerRadius(mLauncher), false /* fromPredictiveBack */); TaskViewUtils.createSplitAuxiliarySurfacesAnimator(nonAppTargets, false, null); mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL); - result.setAnimation(pair.second, mLauncher); + bankAnimState.applyToAnimationResult(result, mLauncher); } } @@ -1945,29 +1815,19 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener /** The delegate runner that handles the actual animation. */ private final RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> mDelegate; - @Nullable - private final ActivityTransitionAnimator.TransitionCookie mCookie; - private ContainerAnimationRunner( - RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> delegate, - ActivityTransitionAnimator.TransitionCookie cookie) { + RemoteAnimationDelegate<IRemoteAnimationFinishedCallback> delegate) { mDelegate = delegate; - mCookie = cookie; - } - - @Nullable - ActivityTransitionAnimator.TransitionCookie getCookie() { - return mCookie; } @Nullable static ContainerAnimationRunner fromView( View v, - ActivityTransitionAnimator.TransitionCookie cookie, boolean forLaunch, Launcher launcher, StartingWindowListener startingWindowListener, - RunnableList onEndCallback) { + RunnableList onEndCallback, + @Nullable WindowAnimationState windowState) { if (!forLaunch && !checkReturnAnimationsFlags()) { throw new IllegalStateException( "forLaunch cannot be false when the enableContainerReturnAnimations or " @@ -1977,7 +1837,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener // First the controller is created. This is used by the runner to animate the // origin/target view. ActivityTransitionAnimator.Controller controller = - buildController(v, cookie, forLaunch); + buildController(v, forLaunch, windowState); if (controller == null) { return null; } @@ -2002,8 +1862,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener return new ContainerAnimationRunner( new ActivityTransitionAnimator.AnimationDelegate( - MAIN_EXECUTOR, controller, callback, listener), - cookie); + MAIN_EXECUTOR, controller, callback, listener)); } /** @@ -2013,7 +1872,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener */ @Nullable private static ActivityTransitionAnimator.Controller buildController( - View v, ActivityTransitionAnimator.TransitionCookie cookie, boolean isLaunching) { + View v, boolean isLaunching, @Nullable WindowAnimationState windowState) { View viewToUse = findLaunchableViewWithBackground(v); if (viewToUse == null) { return null; @@ -2044,8 +1903,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener @Nullable @Override - public ActivityTransitionAnimator.TransitionCookie getTransitionCookie() { - return cookie; + public WindowAnimationState getWindowAnimatorState() { + return windowState; } }; } @@ -2059,81 +1918,26 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener View view) { View current = view; while (current.getBackground() == null || !(current instanceof LaunchableView)) { - if (!(current.getParent() instanceof View)) { + if (current.getParent() instanceof View v) { + current = v; + } else { return null; } - - current = (View) current.getParent(); } - return (T) current; } - /** - * Builds the filter used by WM Shell to match app closing transitions (only back, no home - * button/gesture) to the given launch cookie. - */ - static TransitionFilter buildBackToHomeFilter( - ActivityTransitionAnimator.TransitionCookie cookie, Launcher launcher) { - // Closing activity must include the cookie in its list of launch cookies. - TransitionFilter.Requirement appRequirement = new TransitionFilter.Requirement(); - appRequirement.mActivityType = ACTIVITY_TYPE_STANDARD; - appRequirement.mLaunchCookie = cookie; - appRequirement.mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK}; - // Opening activity must be Launcher. - TransitionFilter.Requirement launcherRequirement = new TransitionFilter.Requirement(); - launcherRequirement.mActivityType = ACTIVITY_TYPE_HOME; - launcherRequirement.mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT}; - launcherRequirement.mTopActivity = launcher.getComponentName(); - // Transition types CLOSE and TO_BACK match the back button/gesture but not the home - // button/gesture. - TransitionFilter filter = new TransitionFilter(); - filter.mTypeSet = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK}; - filter.mRequirements = - new TransitionFilter.Requirement[]{appRequirement, launcherRequirement}; - return filter; - } - - /** - * Creates various conditions to ensure that the given transition is cleaned up correctly - * when necessary: - * - if the transition has run, it is the callback that unregisters it; - * - if the associated view is detached before the transition has had an opportunity to run, - * a {@link View.OnAttachStateChangeListener} allows us to do the same (and removes - * itself). - */ - static void setUpRemoteAnimationCleanup( - View v, RemoteTransition transition, RunnableList callback, Launcher launcher) { - View.OnAttachStateChangeListener listener = new View.OnAttachStateChangeListener() { - @Override - public void onViewAttachedToWindow(@NonNull View v) {} - - @Override - public void onViewDetachedFromWindow(@NonNull View v) { - SystemUiProxy.INSTANCE.get(launcher) - .unregisterRemoteTransition(transition); - v.removeOnAttachStateChangeListener(this); - } - }; - - // Remove the animation as soon as it has run once. - callback.add(() -> { - SystemUiProxy.INSTANCE.get(launcher).unregisterRemoteTransition(transition); - if (v != null) { - v.removeOnAttachStateChangeListener(listener); - } - }); - - // Remove the animation when the view is detached from the hierarchy. - // This is so that if back is not invoked (e.g. if we go back home through the home - // gesture) we don't have obsolete transitions staying registered. - v.addOnAttachStateChangeListener(listener); - } - @Override public void onAnimationStart(int transit, RemoteAnimationTarget[] appTargets, RemoteAnimationTarget[] wallpaperTargets, RemoteAnimationTarget[] nonAppTargets, LauncherAnimationRunner.AnimationResult result) { + startAnimation( + transit, appTargets, wallpaperTargets, nonAppTargets, result); + } + + public void startAnimation(int transit, RemoteAnimationTarget[] appTargets, + RemoteAnimationTarget[] wallpaperTargets, RemoteAnimationTarget[] nonAppTargets, + IRemoteAnimationFinishedCallback result) { mDelegate.onAnimationStart( transit, appTargets, wallpaperTargets, nonAppTargets, result); } @@ -2142,11 +1946,6 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener public void onAnimationCancelled() { mDelegate.onAnimationCancelled(); } - - @Override - public boolean supportsReturnTransition() { - return true; - } } /** diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java index 50e8e5e077..955388dec7 100644 --- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java +++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java @@ -41,6 +41,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.dragndrop.SimpleDragLayer; +import com.android.launcher3.model.StringCache; import com.android.launcher3.model.WidgetItem; import com.android.launcher3.model.WidgetPredictionsRequester; import com.android.launcher3.model.WidgetsModel; @@ -107,6 +108,7 @@ public class WidgetPickerActivity extends BaseActivity { private SimpleDragLayer<WidgetPickerActivity> mDragLayer; private WidgetsModel mModel; private LauncherAppState mApp; + private StringCache mStringCache; private WidgetPredictionsRequester mWidgetPredictionsRequester; private final WidgetPickerDataProvider mWidgetPickerDataProvider = new WidgetPickerDataProvider(); @@ -287,6 +289,11 @@ public class WidgetPickerActivity extends BaseActivity { MODEL_EXECUTOR.execute(() -> { LauncherAppState app = LauncherAppState.getInstance(this); mModel.update(app, null); + + StringCache stringCache = new StringCache(); + stringCache.loadStrings(this); + + bindStringCache(stringCache); bindWidgets(mModel.getWidgetsByPackageItem()); // Open sheet once widgets are available, so that it doesn't interrupt the open // animation. @@ -299,6 +306,10 @@ public class WidgetPickerActivity extends BaseActivity { }); } + private void bindStringCache(final StringCache stringCache) { + MAIN_EXECUTOR.execute(() -> mStringCache = stringCache); + } + private void bindWidgets(Map<PackageItemInfo, List<WidgetItem>> widgets) { WidgetsListBaseEntriesBuilder builder = new WidgetsListBaseEntriesBuilder( mApp.getContext()); @@ -336,6 +347,12 @@ public class WidgetPickerActivity extends BaseActivity { } } + @Nullable + @Override + public StringCache getStringCache() { + return mStringCache; + } + /** * Animation callback for different predictive back animation states for the widget picker. */ diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java index e31b1d4075..4e6d00afe5 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java +++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java @@ -16,11 +16,11 @@ 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.LauncherState.BACKGROUND_APP; 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; import android.util.Log; import android.view.View; @@ -30,14 +30,18 @@ import androidx.annotation.Nullable; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; +import com.android.launcher3.statemanager.BaseState; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.DisplayController; +import com.android.launcher3.views.ActivityContext; import com.android.quickstep.GestureState; import com.android.quickstep.SystemUiProxy; +import com.android.quickstep.fallback.RecentsState; import com.android.wm.shell.desktopmode.IDesktopTaskListener; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; +import java.io.PrintWriter; import java.util.HashSet; import java.util.Set; @@ -49,7 +53,6 @@ public class DesktopVisibilityController { private static final String TAG = "DesktopVisController"; private static final boolean DEBUG = false; - private final Launcher mLauncher; private final Set<DesktopVisibilityListener> mDesktopVisibilityListeners = new HashSet<>(); private final Set<TaskbarDesktopModeListener> mTaskbarDesktopModeListeners = new HashSet<>(); @@ -61,23 +64,43 @@ public class DesktopVisibilityController { @Nullable private DesktopTaskListenerImpl mDesktopTaskListener; - public DesktopVisibilityController(Launcher launcher) { - mLauncher = launcher; + @Nullable + private Context mContext; + + public DesktopVisibilityController(@NonNull Context context) { + setContext(context); } - /** - * Register a listener with System UI to receive updates about desktop tasks state - */ - public void registerSystemUiListener() { - mDesktopTaskListener = new DesktopTaskListenerImpl(this, mLauncher.getDisplayId()); - SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(mDesktopTaskListener); + /** Sets the context and re-registers the System Ui listener */ + private void setContext(@Nullable Context context) { + unregisterSystemUiListener(); + mContext = context; + registerSystemUiListener(); + } + + /** Register a listener with System UI to receive updates about desktop tasks state */ + private void registerSystemUiListener() { + if (mContext == null) { + return; + } + if (mDesktopTaskListener != null) { + return; + } + mDesktopTaskListener = new DesktopTaskListenerImpl(this, mContext.getDisplayId()); + SystemUiProxy.INSTANCE.get(mContext).setDesktopTaskListener(mDesktopTaskListener); } /** * Clear listener from System UI that was set with {@link #registerSystemUiListener()} */ - public void unregisterSystemUiListener() { - SystemUiProxy.INSTANCE.get(mLauncher).setDesktopTaskListener(null); + private void unregisterSystemUiListener() { + if (mContext == null) { + return; + } + if (mDesktopTaskListener == null) { + return; + } + SystemUiProxy.INSTANCE.get(mContext).setDesktopTaskListener(null); mDesktopTaskListener.release(); mDesktopTaskListener = null; } @@ -126,6 +149,9 @@ public class DesktopVisibilityController { * it. */ public void setVisibleDesktopTasksCount(int visibleTasksCount) { + if (mContext == null) { + return; + } if (DEBUG) { Log.d(TAG, "setVisibleDesktopTasksCount: visibleTasksCount=" + visibleTasksCount + " currentValue=" + mVisibleDesktopTasksCount); @@ -141,7 +167,8 @@ public class DesktopVisibilityController { notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow); } - if (!WALLPAPER_ACTIVITY.isEnabled(mLauncher) && wasVisible != isVisible) { + if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue() + && wasVisible != isVisible) { // TODO: b/333533253 - Remove after flag rollout if (mVisibleDesktopTasksCount > 0) { setLauncherViewsVisibility(View.INVISIBLE); @@ -160,19 +187,33 @@ public class DesktopVisibilityController { } } + public void onLauncherStateChanged(LauncherState state) { + onLauncherStateChanged( + state, state == LauncherState.BACKGROUND_APP, state.isRecentsViewVisible); + } + + public void onLauncherStateChanged(RecentsState state) { + onLauncherStateChanged( + state, state == RecentsState.BACKGROUND_APP, state.isRecentsViewVisible()); + } + /** * Process launcher state change and update launcher view visibility based on desktop state */ - public void onLauncherStateChanged(LauncherState state) { + public void onLauncherStateChanged( + BaseState<?> state, boolean isBackgroundAppState, boolean isRecentsViewVisible) { if (DEBUG) { Log.d(TAG, "onLauncherStateChanged: newState=" + state); } - setBackgroundStateEnabled(state == BACKGROUND_APP); + setBackgroundStateEnabled(isBackgroundAppState); // Desktop visibility tracks overview and background state separately - setOverviewStateEnabled(state != BACKGROUND_APP && state.isRecentsViewVisible); + setOverviewStateEnabled(!isBackgroundAppState && isRecentsViewVisible); } private void setOverviewStateEnabled(boolean overviewStateEnabled) { + if (mContext == null) { + return; + } if (DEBUG) { Log.d(TAG, "setOverviewStateEnabled: enabled=" + overviewStateEnabled + " currentValue=" + mInOverviewState); @@ -185,7 +226,7 @@ public class DesktopVisibilityController { notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow); } - if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) { + if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) { return; } // TODO: b/333533253 - Clean up after flag rollout @@ -203,13 +244,16 @@ public class DesktopVisibilityController { } private void notifyDesktopVisibilityListeners(boolean areDesktopTasksVisible) { + if (mContext == null) { + return; + } if (DEBUG) { Log.d(TAG, "notifyDesktopVisibilityListeners: visible=" + areDesktopTasksVisible); } for (DesktopVisibilityListener listener : mDesktopVisibilityListeners) { listener.onDesktopVisibilityChanged(areDesktopTasksVisible); } - DisplayController.handleInfoChangeForDesktopMode(mLauncher); + DisplayController.handleInfoChangeForDesktopMode(mContext); } private void notifyTaskbarDesktopModeListeners(boolean doesAnyTaskRequireTaskbarRounding) { @@ -295,22 +339,32 @@ public class DesktopVisibilityController { * TODO: b/333533253 - Remove after flag rollout */ private void setLauncherViewsVisibility(int visibility) { - if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) { + if (mContext == null) { + return; + } + if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) { return; } if (DEBUG) { Log.d(TAG, "setLauncherViewsVisibility: visibility=" + visibility + " " + Debug.getCaller()); } - View workspaceView = mLauncher.getWorkspace(); - if (workspaceView != null) { - workspaceView.setVisibility(visibility); + if (!(mContext instanceof ActivityContext activity)) { + return; } - View dragLayer = mLauncher.getDragLayer(); + View dragLayer = activity.getDragLayer(); if (dragLayer != null) { dragLayer.setVisibility(visibility); } - if (mLauncher instanceof QuickstepLauncher ql && ql.getTaskbarUIController() != null + if (!(activity instanceof Launcher launcher)) { + return; + } + View workspaceView = launcher.getWorkspace(); + if (workspaceView != null) { + workspaceView.setVisibility(visibility); + } + if (launcher instanceof QuickstepLauncher ql + && ql.getTaskbarUIController() != null && mVisibleDesktopTasksCount != 0) { ql.getTaskbarUIController().onLauncherVisibilityChanged(visibility == VISIBLE); } @@ -320,7 +374,10 @@ public class DesktopVisibilityController { * TODO: b/333533253 - Remove after flag rollout */ private void markLauncherPaused() { - if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) { + if (mContext == null) { + return; + } + if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) { return; } if (DEBUG) { @@ -337,7 +394,10 @@ public class DesktopVisibilityController { * TODO: b/333533253 - Remove after flag rollout */ private void markLauncherResumed() { - if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) { + if (mContext == null) { + return; + } + if (ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()) { return; } if (DEBUG) { @@ -353,6 +413,22 @@ public class DesktopVisibilityController { } } + public void onDestroy() { + setContext(null); + } + + public void dumpLogs(String prefix, PrintWriter pw) { + pw.println(prefix + "DesktopVisibilityController:"); + + pw.println(prefix + "\tmDesktopVisibilityListeners=" + mDesktopVisibilityListeners); + pw.println(prefix + "\tmVisibleDesktopTasksCount=" + mVisibleDesktopTasksCount); + pw.println(prefix + "\tmInOverviewState=" + mInOverviewState); + pw.println(prefix + "\tmBackgroundStateEnabled=" + mBackgroundStateEnabled); + pw.println(prefix + "\tmGestureInProgress=" + mGestureInProgress); + pw.println(prefix + "\tmDesktopTaskListener=" + mDesktopTaskListener); + pw.println(prefix + "\tmContext=" + mContext); + } + /** A listener for when the user enters/exits Desktop Mode. */ public interface DesktopVisibilityListener { /** diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java index 06d9ee6c96..929e7936e0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java @@ -70,7 +70,6 @@ public class FallbackTaskbarUIController extends TaskbarUIController { @Override protected void init(TaskbarControllers taskbarControllers) { super.init(taskbarControllers); - mRecentsActivity.setTaskbarUIController(this); mRecentsActivity.getStateManager().addStateListener(mStateListener); } @@ -78,6 +77,7 @@ public class FallbackTaskbarUIController extends TaskbarUIController { @Override protected void onDestroy() { super.onDestroy(); + getRecentsView().setTaskLaunchListener(null); mRecentsActivity.setTaskbarUIController(null); mRecentsActivity.getStateManager().removeStateListener(mStateListener); } diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java index e4cc6bbd77..ea432f3d28 100644 --- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java +++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java @@ -23,9 +23,7 @@ import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.launcher3.R; -import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; -import com.android.quickstep.LauncherActivityInterface; import com.android.quickstep.RecentsModel; import com.android.quickstep.util.DesktopTask; import com.android.quickstep.util.GroupTask; @@ -116,10 +114,8 @@ public final class KeyboardQuickSwitchController implements mQuickSwitchViewController = new KeyboardQuickSwitchViewController( mControllers, overlayContext, keyboardQuickSwitchView, mControllerCallbacks); - DesktopVisibilityController desktopController = - LauncherActivityInterface.INSTANCE.getDesktopVisibilityController(); final boolean onDesktop = - desktopController != null && desktopController.areDesktopTasksVisible(); + mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible(); if (mModel.isTaskListValid(mTaskListChangeId)) { // When we are opening the KQS with no focus override, check if the first task is diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java index 8ceb77d5f2..ce9655646a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java +++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java @@ -36,14 +36,15 @@ import androidx.constraintlayout.widget.ConstraintLayout; import com.android.launcher3.R; import com.android.launcher3.util.Preconditions; +import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds; import com.android.quickstep.util.BorderAnimator; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; -import java.util.function.Consumer; - import kotlin.Unit; +import java.util.function.Consumer; + /** * A view that displays a recent task during a keyboard quick switch. */ @@ -173,6 +174,61 @@ public class KeyboardQuickSwitchTaskView extends ConstraintLayout { }); } + protected void setThumbnailsForSplitTasks( + @NonNull Task task1, + @Nullable Task task2, + @Nullable ThumbnailUpdateFunction thumbnailUpdateFunction, + @Nullable IconUpdateFunction iconUpdateFunction, + @Nullable SplitBounds splitBounds) { + setThumbnails(task1, task2, thumbnailUpdateFunction, iconUpdateFunction); + + if (splitBounds == null) { + return; + } + + + final boolean isLeftRightSplit = !splitBounds.appsStackedVertically; + final float leftOrTopTaskPercent = isLeftRightSplit + ? splitBounds.leftTaskPercent : splitBounds.topTaskPercent; + + ConstraintLayout.LayoutParams leftTopParams = (ConstraintLayout.LayoutParams) + mThumbnailView1.getLayoutParams(); + ConstraintLayout.LayoutParams rightBottomParams = (ConstraintLayout.LayoutParams) + mThumbnailView2.getLayoutParams(); + + if (isLeftRightSplit) { + // Set thumbnail view ratio in left right split mode. + leftTopParams.width = 0; // Set width to 0dp, so it uses the constraint dimension ratio. + leftTopParams.height = ConstraintLayout.LayoutParams.MATCH_PARENT; + leftTopParams.matchConstraintPercentWidth = leftOrTopTaskPercent; + leftTopParams.leftToLeft = ConstraintLayout.LayoutParams.PARENT_ID; + leftTopParams.rightToLeft = R.id.thumbnail_2; + mThumbnailView1.setLayoutParams(leftTopParams); + + rightBottomParams.width = 0; + rightBottomParams.height = ConstraintLayout.LayoutParams.MATCH_PARENT; + rightBottomParams.matchConstraintPercentWidth = 1 - leftOrTopTaskPercent; + rightBottomParams.leftToRight = R.id.thumbnail_1; + rightBottomParams.rightToRight = ConstraintLayout.LayoutParams.PARENT_ID; + mThumbnailView2.setLayoutParams(rightBottomParams); + } else { + // Set thumbnail view ratio in top bottom split mode. + leftTopParams.height = 0; + leftTopParams.width = ConstraintLayout.LayoutParams.MATCH_PARENT; + leftTopParams.matchConstraintPercentHeight = leftOrTopTaskPercent; + leftTopParams.topToTop = ConstraintLayout.LayoutParams.PARENT_ID; + leftTopParams.bottomToTop = R.id.thumbnail_2; + mThumbnailView1.setLayoutParams(leftTopParams); + + rightBottomParams.height = 0; + rightBottomParams.width = ConstraintLayout.LayoutParams.MATCH_PARENT; + rightBottomParams.matchConstraintPercentHeight = 1 - leftOrTopTaskPercent; + rightBottomParams.topToBottom = R.id.thumbnail_1; + rightBottomParams.bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID; + mThumbnailView2.setLayoutParams(rightBottomParams); + } + } + private void applyThumbnail( @Nullable ImageView thumbnailView, @Nullable Task task, diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java index a527c82864..b4102a9fce 100644 --- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java +++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java @@ -214,11 +214,13 @@ public class KeyboardQuickSwitchView extends ConstraintLayout { groupTask.mSplitBounds == null || groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id || groupTask.task2 == null; - currentTaskView.setThumbnails( + + currentTaskView.setThumbnailsForSplitTasks( firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2, firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1, updateTasks ? mViewCallbacks::updateThumbnailInBackground : null, - updateTasks ? mViewCallbacks::updateIconInBackground : null); + updateTasks ? mViewCallbacks::updateIconInBackground : null, + groupTask.mSplitBounds); previousTaskView = currentTaskView; } diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 69da7b6c02..02201c08c8 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -15,11 +15,12 @@ */ 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; @@ -38,20 +39,19 @@ import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.InstanceIdSequence; import com.android.launcher3.model.data.ItemInfo; -import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.taskbar.bubbles.BubbleBarController; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.MultiPropertyFactory; import com.android.launcher3.util.OnboardingPrefs; import com.android.quickstep.HomeVisibilityState; -import com.android.quickstep.LauncherActivityInterface; import com.android.quickstep.RecentsAnimationCallbacks; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.GroupTask; import com.android.quickstep.util.TISBindHelper; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; +import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import java.io.PrintWriter; import java.util.Arrays; @@ -128,8 +128,8 @@ public class LauncherTaskbarUIController extends TaskbarUIController { @Override protected void onDestroy() { - super.onDestroy(); onLauncherVisibilityChanged(false); + super.onDestroy(); mTaskbarLauncherStateController.onDestroy(); mLauncher.setTaskbarUIController(null); @@ -137,11 +137,6 @@ public class LauncherTaskbarUIController extends TaskbarUIController { mHomeState.removeListener(mVisibilityChangeListener); } - /** Returns {@code true} if launcher is currently presenting the home screen. */ - public boolean isOnHome() { - return mTaskbarLauncherStateController.isOnHome(); - } - private void onInAppDisplayProgressChanged() { if (mControllers != null) { // Update our shared state so we can restore it if taskbar gets recreated. @@ -165,6 +160,16 @@ public class LauncherTaskbarUIController extends TaskbarUIController { shouldDelayLauncherStateAnim); } + @Override + public void stashHotseat(boolean stash) { + mTaskbarLauncherStateController.stashHotseat(stash); + } + + @Override + public void unStashHotseatInstantly() { + mTaskbarLauncherStateController.unStashHotseatInstantly(); + } + /** * Adds the Launcher resume animator to the given animator set. * @@ -207,6 +212,9 @@ public class LauncherTaskbarUIController extends TaskbarUIController { */ @Override public void onLauncherVisibilityChanged(boolean isVisible) { + if (DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(mLauncher)) { + DisplayController.handleInfoChangeForLauncherVisibilityChanged(mLauncher); + } onLauncherVisibilityChanged(isVisible, false /* fromInit */); } @@ -235,11 +243,8 @@ public class LauncherTaskbarUIController extends TaskbarUIController { return null; } - DesktopVisibilityController desktopController = - LauncherActivityInterface.INSTANCE.getDesktopVisibilityController(); - if (!WALLPAPER_ACTIVITY.isEnabled(mLauncher) - && desktopController != null - && desktopController.areDesktopTasksVisible()) { + if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue() + && mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) { // TODO: b/333533253 - Remove after flag rollout isVisible = false; } @@ -481,4 +486,13 @@ public class LauncherTaskbarUIController extends TaskbarUIController { protected String getTaskbarUIControllerName() { return "LauncherTaskbarUIController"; } + + @Override + public void onSwipeToUnstashTaskbar() { + // Once taskbar is unstashed, the user cannot return back to the overlay. We can + // clear it here to set the expected state once the user goes home. + if (mLauncher.getWorkspace().isOverlayShown()) { + mLauncher.getWorkspace().onOverlayScrollChanged(0); + } + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java index a979d5859c..e9bd30ace9 100644 --- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java @@ -91,6 +91,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AlphaUpdateListener; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton; +import com.android.launcher3.taskbar.bubbles.BubbleBarController; import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory; import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter; import com.android.launcher3.taskbar.navbutton.NearestTouchFrame; @@ -106,6 +107,7 @@ import com.android.systemui.shared.rotation.RotationButton; import com.android.systemui.shared.statusbar.phone.BarTransitions; import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; +import com.android.wm.shell.shared.bubbles.BubbleBarLocation; import java.io.PrintWriter; import java.util.ArrayList; @@ -115,7 +117,8 @@ import java.util.function.IntPredicate; /** * Controller for managing nav bar buttons in taskbar */ -public class NavbarButtonsViewController implements TaskbarControllers.LoggableTaskbarController { +public class NavbarButtonsViewController implements TaskbarControllers.LoggableTaskbarController, + BubbleBarController.BubbleBarLocationListener { private final Rect mTempRect = new Rect(); @@ -397,6 +400,12 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT } }; 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, @@ -1168,6 +1177,52 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT mHitboxExtender.onAnimationProgressToOverview(alignment); } + /** Adjusts navigation buttons layout accordingly to the bubble bar position. */ + @Override + public void onBubbleBarLocationUpdated(BubbleBarLocation location) { + mNavButtonContainer.setTranslationX(getNavBarTranslationX(location)); + } + + /** Animates navigation buttons accordingly to the bubble bar position. */ + @Override + public void onBubbleBarLocationAnimated(BubbleBarLocation location) { + // TODO(b/346381754) add the teleport animation similarly to the bubble bar + mNavButtonContainer.setTranslationX(getNavBarTranslationX(location)); + } + + private int getNavBarTranslationX(BubbleBarLocation location) { + boolean isNavbarOnRight = location.isOnLeft(mNavButtonsView.isLayoutRtl()); + DeviceProfile dp = mContext.getDeviceProfile(); + float navBarTargetStartX; + if (mContext.shouldStartAlignTaskbar()) { + int navBarSpacing = dp.inlineNavButtonsEndSpacingPx; + // If the taskbar is start aligned the navigation bar is aligned to the start or end of + // the container, depending on the bubble bar location + if (isNavbarOnRight) { + navBarTargetStartX = dp.widthPx - navBarSpacing - mNavButtonContainer.getWidth(); + } else { + navBarTargetStartX = navBarSpacing; + } + } else { + // If the task bar is not start aligned, the navigation bar is located in the center + // between the taskbar and screen edges, depending on the bubble bar location. + float navbarWidth = mNavButtonContainer.getWidth(); + Rect taskbarBounds = mControllers.taskbarViewController.getIconLayoutBounds(); + if (isNavbarOnRight) { + if (mNavButtonsView.isLayoutRtl()) { + float taskBarEnd = taskbarBounds.right; + navBarTargetStartX = (dp.widthPx + taskBarEnd - navbarWidth) / 2; + } else { + navBarTargetStartX = mNavButtonContainer.getLeft(); + } + } else { + float taskBarStart = taskbarBounds.left; + navBarTargetStartX = (taskBarStart - navbarWidth) / 2; + } + } + return (int) navBarTargetStartX - mNavButtonContainer.getLeft(); + } + private class RotationButtonListener implements RotationButton.RotationButtonUpdatesCallback { @Override public void onVisibilityChanged(boolean isVisible) { diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java index ec710c5229..fabf3a5acd 100644 --- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java @@ -94,6 +94,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT // States that affect whether region sampling is enabled or not private boolean mIsStashed; private boolean mIsLumaSamplingEnabled; + private boolean mIsAppTransitionPending; private boolean mTaskbarHidden; private float mTranslationYForSwipe; @@ -267,6 +268,11 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT updateSamplingState(); } + public void setIsAppTransitionPending(boolean pending) { + mIsAppTransitionPending = pending; + updateSamplingState(); + } + private void updateSamplingState() { updateRegionSamplingWindowVisibility(); if (shouldSample()) { @@ -278,7 +284,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT } private boolean shouldSample() { - return mIsStashed && mIsLumaSamplingEnabled; + return mIsStashed && mIsLumaSamplingEnabled && !mIsAppTransitionPending; } protected void updateStashedHandleHintScale() { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 47ae741908..b95c406b88 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -37,6 +37,7 @@ import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN; import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING; import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN; +import static com.android.launcher3.taskbar.TaskbarStashController.SHOULD_BUBBLES_FOLLOW_DEFAULT_VALUE; import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback; @@ -100,6 +101,7 @@ import com.android.launcher3.model.data.TaskItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.popup.PopupDataProvider; +import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.AutohideSuspendFlag; import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback; import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController; @@ -140,7 +142,6 @@ import com.android.launcher3.util.TraceHelper; import com.android.launcher3.util.VibratorWrapper; import com.android.launcher3.util.ViewCache; import com.android.launcher3.views.ActivityContext; -import com.android.quickstep.LauncherActivityInterface; import com.android.quickstep.NavHandle; import com.android.quickstep.RecentsModel; import com.android.quickstep.SystemUiProxy; @@ -223,7 +224,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext { public TaskbarActivityContext(Context windowContext, @Nullable Context navigationBarPanelContext, DeviceProfile launcherDp, TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider - unfoldTransitionProgressProvider) { + unfoldTransitionProgressProvider, + @NonNull DesktopVisibilityController desktopVisibilityController) { super(windowContext); mNavigationBarPanelContext = navigationBarPanelContext; @@ -336,17 +338,13 @@ public class TaskbarActivityContext extends BaseTaskbarContext { new VoiceInteractionWindowController(this), new TaskbarTranslationController(this), new TaskbarSpringOnStashController(this), - new TaskbarRecentAppsController( - this, - RecentsModel.INSTANCE.get(this), - LauncherActivityInterface.INSTANCE::getDesktopVisibilityController), + new TaskbarRecentAppsController(this, RecentsModel.INSTANCE.get(this)), TaskbarEduTooltipController.newInstance(this), new KeyboardQuickSwitchController(), - new TaskbarPinningController(this, () -> - DisplayController.isInDesktopMode(this)), + new TaskbarPinningController(this), bubbleControllersOptional, - new TaskbarDesktopModeController( - LauncherActivityInterface.INSTANCE::getDesktopVisibilityController)); + new TaskbarDesktopModeController(desktopVisibilityController)); + mLauncherPrefs = LauncherPrefs.get(this); } @@ -690,6 +688,11 @@ public class TaskbarActivityContext extends BaseTaskbarContext { return mNavMode == NavigationMode.THREE_BUTTONS; } + /** Returns whether taskbar should start align. */ + public boolean shouldStartAlignTaskbar() { + return isThreeButtonNav() && mDeviceProfile.startAlignTaskbar; + } + public boolean isGestureNav() { return mNavMode == NavigationMode.NO_BUTTON; } @@ -914,11 +917,16 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mControllers.navbarButtonsViewController.transitionTo(barMode, animate); } + public void appTransitionPending(boolean pending) { + mControllers.stashedHandleViewController.setIsAppTransitionPending(pending); + } + /** * Called when this instance of taskbar is no longer needed */ public void onDestroy() { mIsDestroyed = true; + mTaskbarFeatureEvaluator.onDestroy(); setUIController(TaskbarUIController.DEFAULT); mControllers.onDestroy(); if (!enableTaskbarNoRecreate() && !ENABLE_TASKBAR_NAVBAR_UNIFICATION) { @@ -1203,14 +1211,21 @@ public class TaskbarActivityContext extends BaseTaskbarContext { mControllers.uiController.startSplitSelection(splitSelectSource); } + boolean areDesktopTasksVisible() { + return mControllers != null + && mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible(); + } + protected void onTaskbarIconClicked(View view) { TaskbarUIController taskbarUIController = mControllers.uiController; RecentsView recents = taskbarUIController.getRecentsView(); boolean shouldCloseAllOpenViews = true; Object tag = view.getTag(); if (tag instanceof GroupTask groupTask) { - handleGroupTaskLaunch(groupTask, /* remoteTransition = */ null, - DisplayController.isInDesktopMode(this)); + handleGroupTaskLaunch( + groupTask, + /* remoteTransition= */ null, + areDesktopTasksVisible()); mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true); } else if (tag instanceof FolderInfo) { // Tapping an expandable folder icon on Taskbar @@ -1431,7 +1446,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { && !(foundTaskView instanceof DesktopTaskView)) { TestLogging.recordEvent( TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon"); - foundTaskView.launchTasks(); + foundTaskView.launchWithAnimation(); return; } } @@ -1541,10 +1556,14 @@ public class TaskbarActivityContext extends BaseTaskbarContext { /** * Called when we want to unstash taskbar when user performs swipes up gesture. + * @param delayTaskbarBackground whether we will delay the taskbar background animation */ - public void onSwipeToUnstashTaskbar() { + public void onSwipeToUnstashTaskbar(boolean delayTaskbarBackground) { + mControllers.uiController.onSwipeToUnstashTaskbar(); + boolean wasStashed = mControllers.taskbarStashController.isStashed(); - mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(/* stash= */ false); + mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(/* stash= */ false, + SHOULD_BUBBLES_FOLLOW_DEFAULT_VALUE, delayTaskbarBackground); boolean isStashed = mControllers.taskbarStashController.isStashed(); if (isStashed != wasStashed) { VibratorWrapper.INSTANCE.get(this).vibrateForTaskbarUnstash(); @@ -1678,7 +1697,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext { duration); View allAppsButton = mControllers.taskbarViewController.getAllAppsButtonView(); - if (allAppsButton != null && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) { + if (allAppsButton != null && !FeatureFlags.enableAllAppsButtonInHotseat()) { ValueAnimator alphaOverride = ValueAnimator.ofFloat(0, 1); alphaOverride.setDuration(duration); alphaOverride.addUpdateListener(a -> { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt index 4ac7514f2f..d6ce3a43fd 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt @@ -102,7 +102,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { shadowAlpha = LIGHT_THEME_SHADOW_ALPHA } - if (DisplayController.isInDesktopMode(context)) { + if (context.areDesktopTasksVisible()) { fullCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context) cornerRadius = fullCornerRadius } else { @@ -200,7 +200,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { mapRange( scale, 0f, - res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin).toFloat() + res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin).toFloat(), ) .toInt() shadowBlur = @@ -245,7 +245,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { -mapRange( 1f - progress, 0f, - if (isAnimatingPinning) 0f else stashedHandleHeight / 2f + if (isAnimatingPinning) 0f else stashedHandleHeight / 2f, ) // Draw shadow. @@ -255,7 +255,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { shadowBlur, 0f, keyShadowDistance, - setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha)) + setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha)), ) strokePaint.alpha = (paint.alpha * strokeAlpha) / 255 @@ -263,7 +263,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) { transientBackgroundBounds.left + halfWidthDelta + hotseatOffsetLeft, bottom - newBackgroundHeight + hotseatOffsetTop, transientBackgroundBounds.right - halfWidthDelta + hotseatOffsetRight, - bottom + hotseatOffsetBottom + bottom + hotseatOffsetBottom, ) val horizontalInset = fullWidth * widthInsetPercentage lastDrawnTransientRect.inset(horizontalInset, 0f) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index 34ab9f0d67..56fd2bb66d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -25,7 +25,6 @@ import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController; import com.android.launcher3.taskbar.bubbles.BubbleControllers; import com.android.launcher3.taskbar.overlay.TaskbarOverlayController; -import com.android.launcher3.util.DisplayController; import com.android.systemui.shared.rotation.RotationButtonController; import java.io.PrintWriter; @@ -194,13 +193,17 @@ public class TaskbarControllers { voiceInteractionWindowController }; - if (DisplayController.isInDesktopMode(taskbarActivityContext)) { + if (taskbarDesktopModeController.getAreDesktopTasksVisible()) { mCornerRoundness.updateValue(taskbarDesktopModeController.getTaskbarCornerRoundness( mSharedState.showCornerRadiusInDesktopMode)); } else { mCornerRoundness.updateValue(TaskbarBackgroundRenderer.MAX_ROUNDNESS); } + onPostInit(); + } + @VisibleForTesting + public void onPostInit() { mAreAllControllersInitialized = true; for (Runnable postInitCallback : mPostInitCallbacks) { postInitCallback.run(); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt index a376531b11..47a35c55ab 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt @@ -22,18 +22,18 @@ import com.android.launcher3.taskbar.TaskbarBackgroundRenderer.Companion.MAX_ROU /** Handles Taskbar in Desktop Windowing mode. */ class TaskbarDesktopModeController( - private val desktopVisibilityControllerProvider: () -> DesktopVisibilityController? + private val desktopVisibilityController: DesktopVisibilityController ) : TaskbarDesktopModeListener { private lateinit var taskbarControllers: TaskbarControllers private lateinit var taskbarSharedState: TaskbarSharedState - private val desktopVisibilityController: DesktopVisibilityController? - get() = desktopVisibilityControllerProvider() + val areDesktopTasksVisible: Boolean + get() = desktopVisibilityController.areDesktopTasksVisible() fun init(controllers: TaskbarControllers, sharedState: TaskbarSharedState) { taskbarControllers = controllers taskbarSharedState = sharedState - desktopVisibilityController?.registerTaskbarDesktopModeListener(this) + desktopVisibilityController.registerTaskbarDesktopModeListener(this) } override fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) { @@ -50,5 +50,5 @@ class TaskbarDesktopModeController( } } - fun onDestroy() = desktopVisibilityController?.unregisterTaskbarDesktopModeListener(this) + fun onDestroy() = desktopVisibilityController.unregisterTaskbarDesktopModeListener(this) } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java index 5bbf4b2a2a..fc307b2e88 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java @@ -74,14 +74,12 @@ import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.shortcuts.DeepShortcutView; import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; -import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.shared.TestProtocol; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.IntSet; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.views.BubbleTextHolder; -import com.android.quickstep.LauncherActivityInterface; import com.android.quickstep.util.GroupTask; import com.android.quickstep.util.LogUtils; import com.android.quickstep.util.MultiValueUpdateListener; @@ -344,12 +342,9 @@ public class TaskbarDragController extends DragController<BaseTaskbarContext> im protected void callOnDragStart() { super.callOnDragStart(); // TODO(297921594) clean it up when taskbar to desktop drag is implemented. - DesktopVisibilityController desktopController = - LauncherActivityInterface.INSTANCE.getDesktopVisibilityController(); - // Pre-drag has ended, start the global system drag. - if (mDisallowGlobalDrag || (desktopController != null - && desktopController.areDesktopTasksVisible())) { + if (mDisallowGlobalDrag + || mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) { AbstractFloatingView.closeAllOpenViewsExcept(mActivity, TYPE_TASKBAR_ALL_APPS); return; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt index 221504dd64..685c109eec 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt @@ -147,7 +147,11 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas defaultTouchableRegion.addBoundsToRegion(bubbleBarViewController.bubbleBarBounds) } } - if (taskbarStashController.isInApp || taskbarStashController.isInOverview) { + if ( + taskbarStashController.isInApp || + taskbarStashController.isInOverview || + DisplayController.showLockedTaskbarOnHome(context) + ) { // only add the taskbar touch region if not on home val bottom = windowLayoutParams.height val top = bottom - taskbarTouchableHeight diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 63fae8cad8..876221b1d7 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -16,9 +16,13 @@ package com.android.launcher3.taskbar; import static com.android.app.animation.Interpolators.EMPHASIZED; +import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_TASKBAR_ALIGNMENT; +import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_TASKBAR_STASH; +import static com.android.launcher3.LauncherState.HOTSEAT_ICONS; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_OVERVIEW; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE; +import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_FOR_BUBBLES; import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME; import static com.android.launcher3.util.FlagDebugUtils.appendFlag; import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange; @@ -40,6 +44,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Hotseat.HotseatQsbAlphaId; import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepTransitionManager; import com.android.launcher3.Utilities; @@ -145,7 +150,7 @@ public class TaskbarLauncherStateController { private AnimatedFloat mTaskbarBackgroundAlpha; private AnimatedFloat mTaskbarAlpha; private AnimatedFloat mTaskbarCornerRoundness; - private MultiProperty mIconAlphaForHome; + private MultiProperty mTaskbarAlphaForHome; private QuickstepLauncher mLauncher; private boolean mIsDestroyed = false; @@ -175,11 +180,11 @@ public class TaskbarLauncherStateController { if (mIsQsbInline && !dp.isQsbInline) { // We only modify QSB alpha if isQsbInline = true. If we switch to a DP // where isQsbInline = false, then we need to reset the alpha. - mLauncher.getHotseat().setQsbAlpha(1f); + mLauncher.getHotseat().setQsbAlpha(1f, ALPHA_CHANNEL_TASKBAR_ALIGNMENT); } mIsQsbInline = dp.isQsbInline; TaskbarLauncherStateController.this.updateIconAlphaForHome( - mIconAlphaForHome.getValue()); + mTaskbarAlphaForHome.getValue(), ALPHA_CHANNEL_TASKBAR_ALIGNMENT); } }; @@ -242,7 +247,7 @@ public class TaskbarLauncherStateController { .getTaskbarBackgroundAlpha(); mTaskbarAlpha = mControllers.taskbarDragLayerController.getTaskbarAlpha(); mTaskbarCornerRoundness = mControllers.getTaskbarCornerRoundness(); - mIconAlphaForHome = mControllers.taskbarViewController + mTaskbarAlphaForHome = mControllers.taskbarViewController .getTaskbarIconAlpha().get(ALPHA_INDEX_HOME); resetIconAlignment(); @@ -266,7 +271,7 @@ public class TaskbarLauncherStateController { mIconAlignment.finishAnimation(); - mLauncher.getHotseat().setIconsAlpha(1f); + mLauncher.getHotseat().setIconsAlpha(1f, ALPHA_CHANNEL_TASKBAR_ALIGNMENT); mLauncher.getStateManager().removeStateListener(mStateListener); mCanSyncViews = !mControllers.taskbarActivityContext.isPhoneMode(); @@ -295,6 +300,7 @@ public class TaskbarLauncherStateController { stashController.updateStateForFlag(FLAG_IN_APP, false); updateStateForFlag(FLAG_TRANSITION_TO_VISIBLE, true); + mLauncherState = toState; animatorSet.play(stashController.createApplyStateAnimator(duration)); animatorSet.play(applyState(duration, false)); @@ -375,7 +381,7 @@ public class TaskbarLauncherStateController { private void updateOverviewDragState(LauncherState launcherState) { boolean disallowLongClick = FeatureFlags.enableSplitContextually() - ? mLauncher.isSplitSelectionActive() + ? mLauncher.isSplitSelectionActive() || mIsAnimatingToLauncher : launcherState == LauncherState.OVERVIEW_SPLIT_SELECT; com.android.launcher3.taskbar.Utilities.setOverviewDragState( mControllers, launcherState.disallowTaskbarGlobalDrag(), @@ -441,11 +447,6 @@ public class TaskbarLauncherStateController { return animator; } - /** Returns {@code true} if launcher is currently presenting the home screen. */ - public boolean isOnHome() { - return isInLauncher() && mLauncherState == LauncherState.NORMAL; - } - private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) { final boolean isInLauncher = isInLauncher(); final boolean isIconAlignedWithHotseat = isIconAlignedWithHotseat(); @@ -457,13 +458,16 @@ public class TaskbarLauncherStateController { + ", toAlignment: " + toAlignment); } mControllers.bubbleControllers.ifPresent(controllers -> { - // Show the bubble bar when on launcher home or in overview. + // Show the bubble bar when on launcher home (hotseat icons visible) or in overview boolean onOverview = mLauncherState == LauncherState.OVERVIEW; - controllers.bubbleStashController.setBubblesShowingOnHome(isOnHome()); + boolean hotseatIconsVisible = isInLauncher && mLauncherState.areElementsVisible( + mLauncher, HOTSEAT_ICONS); + controllers.bubbleStashController.setBubblesShowingOnHome(hotseatIconsVisible); controllers.bubbleStashController.setBubblesShowingOnOverview(onOverview); }); - mControllers.taskbarStashController.updateStateForFlag(FLAG_IN_OVERVIEW, + TaskbarStashController stashController = mControllers.taskbarStashController; + stashController.updateStateForFlag(FLAG_IN_OVERVIEW, mLauncherState == LauncherState.OVERVIEW); AnimatorSet animatorSet = new AnimatorSet(); @@ -495,8 +499,6 @@ public class TaskbarLauncherStateController { public void onAnimationStart(Animator animation) { mIsAnimatingToLauncher = isInLauncher; - TaskbarStashController stashController = - mControllers.taskbarStashController; if (DEBUG) { Log.d(TAG, "onAnimationStart - FLAG_IN_APP: " + !isInLauncher); } @@ -512,6 +514,8 @@ public class TaskbarLauncherStateController { // Handle closing open popups when going home/overview handleOpenFloatingViews = true; + } else { + stashController.applyState(); } if (handleOpenFloatingViews && isInLauncher) { @@ -592,7 +596,8 @@ public class TaskbarLauncherStateController { float cornerRoundness = isInLauncher ? 0 : 1; - if (DisplayController.isInDesktopMode(mLauncher) && mControllers.getSharedState() != null) { + if (mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible() + && mControllers.getSharedState() != null) { cornerRoundness = mControllers.taskbarDesktopModeController.getTaskbarCornerRoundness( mControllers.getSharedState().showCornerRadiusInDesktopMode); @@ -659,6 +664,9 @@ public class TaskbarLauncherStateController { * This refers to the intended state - a transition to this state might be in progress. */ public boolean isTaskbarAlignedWithHotseat() { + if (DisplayController.showLockedTaskbarOnHome(mLauncher) && isInLauncher()) { + return false; + } return mLauncherState.isTaskbarAlignedWithHotseat(mLauncher); } @@ -670,8 +678,7 @@ public class TaskbarLauncherStateController { boolean isInStashedState = mLauncherState.isTaskbarStashed(mLauncher); boolean willStashVisually = isInStashedState && mControllers.taskbarStashController.supportsVisualStashing(); - boolean isTaskbarAlignedWithHotseat = - mLauncherState.isTaskbarAlignedWithHotseat(mLauncher); + boolean isTaskbarAlignedWithHotseat = isTaskbarAlignedWithHotseat(); return isTaskbarAlignedWithHotseat && !willStashVisually; } else { return false; @@ -702,14 +709,17 @@ public class TaskbarLauncherStateController { public void onAnimationEnd(Animator animation) { if (isInStashedState && committed) { // Reset hotseat alpha to default - mLauncher.getHotseat().setIconsAlpha(1); + mLauncher.getHotseat().setIconsAlpha(1, ALPHA_CHANNEL_TASKBAR_ALIGNMENT); } } @Override public void onAnimationStart(Animator animation) { - if (mLauncher.getHotseat().getIconsAlpha() > 0) { - updateIconAlphaForHome(mLauncher.getHotseat().getIconsAlpha()); + float hotseatIconsAlpha = mLauncher.getHotseat() + .getIconsAlpha(ALPHA_CHANNEL_TASKBAR_ALIGNMENT) + .getValue(); + if (hotseatIconsAlpha > 0) { + updateIconAlphaForHome(hotseatIconsAlpha, ALPHA_CHANNEL_TASKBAR_ALIGNMENT); } } }); @@ -738,6 +748,33 @@ public class TaskbarLauncherStateController { } } + protected void stashHotseat(boolean stash) { + TaskbarStashController stashController = mControllers.taskbarStashController; + stashController.updateStateForFlag(FLAG_STASHED_FOR_BUBBLES, stash); + Runnable swapHotseatWithTaskbar = new Runnable() { + @Override + public void run() { + updateIconAlphaForHome(stash ? 1 : 0, ALPHA_CHANNEL_TASKBAR_STASH); + } + }; + if (stash) { + stashController.applyState(); + // if we stashing the hotseat we need to immediately swap it with the animating taskbar + swapHotseatWithTaskbar.run(); + } else { + // if we revert stashing make swap after taskbar animation is complete + stashController.applyState(/* postApplyAction = */ swapHotseatWithTaskbar); + } + } + + protected void unStashHotseatInstantly() { + TaskbarStashController stashController = mControllers.taskbarStashController; + stashController.updateStateForFlag(FLAG_STASHED_FOR_BUBBLES, false); + stashController.applyState(/* duration = */ 0); + updateIconAlphaForHome(/* taskbarAlpha = */ 0, + ALPHA_CHANNEL_TASKBAR_STASH, /* updateTaskbarAlpha = */ false); + } + /** * Resets and updates the icon alignment. */ @@ -747,7 +784,7 @@ public class TaskbarLauncherStateController { } private void onIconAlignmentRatioChanged() { - float currentValue = mIconAlphaForHome.getValue(); + float currentValue = mTaskbarAlphaForHome.getValue(); boolean taskbarWillBeVisible = mIconAlignment.value < 1; boolean firstFrameVisChanged = (taskbarWillBeVisible && Float.compare(currentValue, 1) != 0) || (!taskbarWillBeVisible && Float.compare(currentValue, 0) != 0); @@ -755,8 +792,10 @@ public class TaskbarLauncherStateController { mControllers.taskbarViewController.setLauncherIconAlignment( mIconAlignment.value, mLauncher.getDeviceProfile()); mControllers.navbarButtonsViewController.updateTaskbarAlignment(mIconAlignment.value); - // Switch taskbar and hotseat in last frame - updateIconAlphaForHome(taskbarWillBeVisible ? 1 : 0); + // Switch taskbar and hotseat in last frame and if taskbar is not hidden for bubbles + boolean isHiddenForBubbles = mControllers.taskbarStashController.isHiddenForBubbles(); + updateIconAlphaForHome(taskbarWillBeVisible ? 1 : 0, ALPHA_CHANNEL_TASKBAR_ALIGNMENT, + /* updateTaskbarAlpha = */ !isHiddenForBubbles); // Sync the first frame where we swap taskbar and hotseat. if (firstFrameVisChanged && mCanSyncViews && !Utilities.isRunningInTestHarness()) { @@ -766,12 +805,20 @@ public class TaskbarLauncherStateController { } } - private void updateIconAlphaForHome(float alpha) { + private void updateIconAlphaForHome(float taskbarAlpha, @HotseatQsbAlphaId int alphaChannel) { + updateIconAlphaForHome(taskbarAlpha, alphaChannel, /* updateTaskbarAlpha = */ true); + } + + private void updateIconAlphaForHome(float taskbarAlpha, + @HotseatQsbAlphaId int alphaChannel, + boolean updateTaskbarAlpha) { if (mIsDestroyed) { return; } - mIconAlphaForHome.setValue(alpha); - boolean hotseatVisible = alpha == 0 + if (updateTaskbarAlpha) { + mTaskbarAlphaForHome.setValue(taskbarAlpha); + } + boolean hotseatVisible = taskbarAlpha == 0 || mControllers.taskbarActivityContext.isPhoneMode() || (!mControllers.uiController.isHotseatIconOnTopWhenAligned() && mIconAlignment.value > 0); @@ -779,9 +826,10 @@ public class TaskbarLauncherStateController { * Hide Launcher Hotseat icons when Taskbar icons have opacity. Both icon sets * should not be visible at the same time. */ - mLauncher.getHotseat().setIconsAlpha(hotseatVisible ? 1 : 0); + float targetAlpha = hotseatVisible ? 1 : 0; + mLauncher.getHotseat().setIconsAlpha(targetAlpha, alphaChannel); if (mIsQsbInline) { - mLauncher.getHotseat().setQsbAlpha(hotseatVisible ? 1 : 0); + mLauncher.getHotseat().setQsbAlpha(targetAlpha, alphaChannel); } } @@ -869,7 +917,7 @@ public class TaskbarLauncherStateController { pw.println(String.format( "%s\tmTaskbarBackgroundAlpha=%.2f", prefix, mTaskbarBackgroundAlpha.value)); pw.println(String.format( - "%s\tmIconAlphaForHome=%.2f", prefix, mIconAlphaForHome.getValue())); + "%s\tmTaskbarAlphaForHome=%.2f", prefix, mTaskbarAlphaForHome.getValue())); pw.println(String.format("%s\tmPrevState=%s", prefix, mPrevState == null ? null : getStateString(mPrevState))); pw.println(String.format("%s\tmState=%s", prefix, getStateString(mState))); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index 8c87fa65d5..78e7b470ff 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -60,6 +60,8 @@ import com.android.launcher3.DeviceProfile; 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; import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider; @@ -209,12 +211,14 @@ public class TaskbarManager { } }; + @NonNull private final DesktopVisibilityController mDesktopVisibilityController; + @SuppressLint("WrongConstant") public TaskbarManager( Context context, AllAppsActionManager allAppsActionManager, - TaskbarNavButtonCallbacks navCallbacks) { - + TaskbarNavButtonCallbacks navCallbacks, + @NonNull DesktopVisibilityController desktopVisibilityController) { Display display = context.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY); mContext = context.createWindowContext(display, @@ -224,6 +228,7 @@ public class TaskbarManager { mNavigationBarPanelContext = ENABLE_TASKBAR_NAVBAR_UNIFICATION ? context.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null) : null; + mDesktopVisibilityController = desktopVisibilityController; if (enableTaskbarNoRecreate()) { mWindowManager = mContext.getSystemService(WindowManager.class); mTaskbarRootLayout = new FrameLayout(mContext) { @@ -243,6 +248,7 @@ public class TaskbarManager { context, navCallbacks, SystemUiProxy.INSTANCE.get(mContext), + ContextualEduStatsManager.INSTANCE.get(mContext), new Handler(), AssistUtils.newInstance(mContext)); mComponentCallbacks = new ComponentCallbacks() { @@ -470,7 +476,7 @@ public class TaskbarManager { if (enableTaskbarNoRecreate() || mTaskbarActivityContext == null) { mTaskbarActivityContext = new TaskbarActivityContext(mContext, mNavigationBarPanelContext, dp, mNavButtonController, - mUnfoldProgressProvider); + mUnfoldProgressProvider, mDesktopVisibilityController); } else { mTaskbarActivityContext.updateDeviceProfile(dp); } @@ -549,7 +555,15 @@ public class TaskbarManager { public void transitionTo(@BarTransitions.TransitionMode int barMode, boolean animate) { - mTaskbarActivityContext.transitionTo(barMode, animate); + if (mTaskbarActivityContext != null) { + mTaskbarActivityContext.transitionTo(barMode, animate); + } + } + + public void appTransitionPending(boolean pending) { + if (mTaskbarActivityContext != null) { + mTaskbarActivityContext.appTransitionPending(pending); + } } private boolean isTaskbarEnabled(DeviceProfile deviceProfile) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java index 872a4d087b..15c35b644e 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.Nullable; 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 @@ public class TaskbarNavButtonController implements TaskbarControllers.LoggableTa 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 @@ public class TaskbarNavButtonController implements TaskbarControllers.LoggableTa 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 @@ public class TaskbarNavButtonController implements TaskbarControllers.LoggableTa 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/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt index 6c9cc642be..1867cd08c0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt @@ -32,10 +32,8 @@ import com.android.launcher3.taskbar.TaskbarDividerPopupView.Companion.createAnd import java.io.PrintWriter /** Controls taskbar pinning through a popup view. */ -class TaskbarPinningController( - private val context: TaskbarActivityContext, - private val isInDesktopModeProvider: () -> Boolean, -) : TaskbarControllers.LoggableTaskbarController { +class TaskbarPinningController(private val context: TaskbarActivityContext) : + TaskbarControllers.LoggableTaskbarController { private lateinit var controllers: TaskbarControllers private lateinit var taskbarSharedState: TaskbarSharedState @@ -58,7 +56,7 @@ class TaskbarPinningController( return } val shouldPinTaskbar = - if (isInDesktopModeProvider()) { + if (controllers.taskbarDesktopModeController.areDesktopTasksVisible) { !launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE) } else { !launcherPrefs.get(TASKBAR_PINNING) @@ -119,7 +117,7 @@ class TaskbarPinningController( dragLayerController.taskbarBackgroundProgress.animateToValue(animateToValue), taskbarViewController.taskbarIconTranslationYForPinning.animateToValue(animateToValue), taskbarViewController.taskbarIconScaleForPinning.animateToValue(animateToValue), - taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue) + taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue), ) animatorSet.interpolator = Interpolators.EMPHASIZED @@ -134,10 +132,10 @@ class TaskbarPinningController( @VisibleForTesting fun recreateTaskbarAndUpdatePinningValue() { updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(false) - if (isInDesktopModeProvider()) { + if (controllers.taskbarDesktopModeController.areDesktopTasksVisible) { launcherPrefs.put( TASKBAR_PINNING_IN_DESKTOP_MODE, - !launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE) + !launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE), ) } else { launcherPrefs.put(TASKBAR_PINNING, !launcherPrefs.get(TASKBAR_PINNING)) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java index 0cce166c53..70d4bb10f2 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java @@ -195,7 +195,7 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba // here will reflect in the popup ArrayList<SystemShortcut.Factory> shortcuts = new ArrayList<>(); shortcuts.add(APP_INFO); - if (!mControllers.taskbarRecentAppsController.isInDesktopMode()) { + if (!mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) { shortcuts.addAll(mControllers.uiController.getSplitMenuOptions().toList()); } if (com.android.wm.shell.Flags.enableBubbleAnything()) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt index 737d03198e..57d4dbb80a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt @@ -16,18 +16,17 @@ 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 import com.android.launcher3.model.data.TaskItemInfo import com.android.launcher3.model.data.WorkspaceItemInfo -import com.android.launcher3.statehandlers.DesktopVisibilityController import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController import com.android.launcher3.util.CancellableTask 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 @@ -36,17 +35,12 @@ import java.io.PrintWriter * - When in Fullscreen mode: show the N most recent Tasks * - When in Desktop Mode: show the currently running (open) Tasks */ -class TaskbarRecentAppsController( - context: Context, - private val recentsModel: RecentsModel, - // Pass a provider here instead of the actual DesktopVisibilityController instance since that - // instance might not be available when this constructor is called. - private val desktopVisibilityControllerProvider: () -> DesktopVisibilityController?, -) : LoggableTaskbarController { +class TaskbarRecentAppsController(context: Context, private val recentsModel: RecentsModel) : + LoggableTaskbarController { var canShowRunningApps = DesktopModeStatus.canEnterDesktopMode(context) && - DesktopModeFlags.TASKBAR_RUNNING_APPS.isEnabled(context) + DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASKBAR_RUNNING_APPS.isTrue @VisibleForTesting set(isEnabledFromTest) { field = isEnabledFromTest @@ -78,19 +72,16 @@ class TaskbarRecentAppsController( var shownTasks: List<GroupTask> = emptyList() private set - private val desktopVisibilityController: DesktopVisibilityController? - get() = desktopVisibilityControllerProvider() - - val isInDesktopMode: Boolean - get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false - val runningTaskIds: Set<Int> /** * Returns the task IDs of apps that should be indicated as "running" to the user. * Specifically, we return all the open tasks if we are in Desktop mode, else emptySet(). */ get() { - if (!canShowRunningApps || !isInDesktopMode) { + if ( + !canShowRunningApps || + !controllers.taskbarDesktopModeController.areDesktopTasksVisible + ) { return emptySet() } val tasks = desktopTask?.tasks ?: return emptySet() @@ -102,7 +93,10 @@ class TaskbarRecentAppsController( * Returns the task IDs for the tasks that should be indicated as "minimized" to the user. */ get() { - if (!canShowRunningApps || !isInDesktopMode) { + if ( + !canShowRunningApps || + !controllers.taskbarDesktopModeController.areDesktopTasksVisible + ) { return emptySet() } val desktopTasks = desktopTask?.tasks ?: return emptySet() @@ -124,7 +118,7 @@ class TaskbarRecentAppsController( controllers = taskbarControllers if (canShowRunningApps || canShowRecentApps) { recentsModel.registerRecentTasksChangedListener(recentTasksChangedListener) - reloadRecentTasksIfNeeded() + controllers.runAfterInit { reloadRecentTasksIfNeeded() } } } @@ -137,8 +131,10 @@ class TaskbarRecentAppsController( /** Called to update hotseatItems, in order to de-dupe them from Recent/Running tasks later. */ fun updateHotseatItemInfos(hotseatItems: Array<ItemInfo?>): Array<ItemInfo?> { // Ignore predicted apps - we show running or recent apps instead. + val areDesktopTasksVisible = controllers.taskbarDesktopModeController.areDesktopTasksVisible val removePredictions = - (isInDesktopMode && canShowRunningApps) || (!isInDesktopMode && canShowRecentApps) + (areDesktopTasksVisible && canShowRunningApps) || + (!areDesktopTasksVisible && canShowRecentApps) if (!removePredictions) { shownHotseatItems = hotseatItems.filterNotNull() onRecentsOrHotseatChanged() @@ -150,11 +146,11 @@ class TaskbarRecentAppsController( .filter { itemInfo -> !itemInfo.isPredictedItem } .toMutableList() - if (isInDesktopMode && canShowRunningApps) { + if (areDesktopTasksVisible && canShowRunningApps) { shownHotseatItems = updateHotseatItemsFromRunningTasks( getOrderedAndWrappedDesktopTasks(), - shownHotseatItems + shownHotseatItems, ) } @@ -199,7 +195,7 @@ class TaskbarRecentAppsController( val oldShownTasks = shownTasks orderedRunningTaskIds = updateOrderedRunningTaskIds() shownTasks = - if (isInDesktopMode) { + if (controllers.taskbarDesktopModeController.areDesktopTasksVisible) { computeShownRunningTasks() } else { computeShownRecentTasks() @@ -281,7 +277,7 @@ class TaskbarRecentAppsController( private fun dedupeHotseatTasks( groupTasks: List<GroupTask>, - shownHotseatItems: List<ItemInfo> + shownHotseatItems: List<ItemInfo>, ): List<GroupTask> { val hotseatPackages = shownHotseatItems.map { item -> item.targetPackage } return groupTasks.filter { groupTask -> @@ -296,7 +292,7 @@ class TaskbarRecentAppsController( */ private fun updateHotseatItemsFromRunningTasks( groupTasks: List<GroupTask>, - shownHotseatItems: List<ItemInfo> + shownHotseatItems: List<ItemInfo>, ): List<ItemInfo> = shownHotseatItems.map { itemInfo -> if (itemInfo is TaskItemInfo) { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java index 2370dfdd8a..751a42ad31 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java @@ -115,7 +115,8 @@ public class TaskbarScrimViewController implements TaskbarControllers.LoggableTa return bubblesExpanded && !mControllers.navbarButtonsViewController.isImeVisible() && !isShadeVisible && !mControllers.taskbarStashController.isStashed() - && (mTaskbarVisible || showScrimForBubbles); + && (mTaskbarVisible || showScrimForBubbles) + && !mControllers.taskbarStashController.isHiddenForBubbles(); } private float getScrimAlpha() { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 56f88d12f5..7624afb440 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -63,10 +63,8 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimatorListeners; -import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; -import com.android.quickstep.LauncherActivityInterface; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.util.SystemUiFlagUtils; @@ -84,6 +82,11 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba private static final String TAG = "TaskbarStashController"; private static final boolean DEBUG = false; + /** + * Def. value for @param shouldBubblesFollow in + * {@link #updateAndAnimateTransientTaskbar(boolean)} */ + public static boolean SHOULD_BUBBLES_FOLLOW_DEFAULT_VALUE = true; + public static final int FLAG_IN_APP = 1 << 0; public static final int FLAG_STASHED_IN_APP_SYSUI = 1 << 1; // shade open, ... public static final int FLAG_STASHED_IN_APP_SETUP = 1 << 2; // setup wizard and AllSetActivity @@ -96,6 +99,9 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba public static final int FLAG_STASHED_SYSUI = 1 << 9; // app pinning,... public static final int FLAG_STASHED_DEVICE_LOCKED = 1 << 10; // device is locked: keyguard, ... public static final int FLAG_IN_OVERVIEW = 1 << 11; // launcher is in overview + // An internal no-op flag to determine whether we should delay the taskbar background animation + private static final int FLAG_DELAY_TASKBAR_BG_TAG = 1 << 12; + public static final int FLAG_STASHED_FOR_BUBBLES = 1 << 13; // show handle for stashed hotseat // If any of these flags are enabled, isInApp should return true. private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP; @@ -117,7 +123,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba // If any of these flags are enabled, the taskbar must be stashed. private static final int FLAGS_FORCE_STASHED = FLAG_STASHED_SYSUI | FLAG_STASHED_DEVICE_LOCKED - | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN; + | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN + | FLAG_STASHED_FOR_BUBBLES; /** * How long to stash/unstash when manually invoked via long press. @@ -152,12 +159,12 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** * How long to delay the icon/stash handle alpha. */ - private static final long TASKBAR_STASH_ALPHA_START_DELAY = 33; + public static final long TASKBAR_STASH_ALPHA_START_DELAY = 33; /** * How long the icon/stash handle alpha animation plays. */ - private static final long TASKBAR_STASH_ALPHA_DURATION = 50; + public static final long TASKBAR_STASH_ALPHA_DURATION = 50; /** * How long to delay the icon/stash handle alpha for the home to app taskbar animation. @@ -390,6 +397,16 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba return mIsStashed; } + /** Sets the hotseat stashed. */ + public void stashHotseat(boolean stash) { + mControllers.uiController.stashHotseat(stash); + } + + /** Instantly un-stashes the hotseat. */ + public void unStashHotseatInstantly() { + mControllers.uiController.unStashHotseatInstantly(); + } + /** * Returns whether the taskbar should be stashed in apps (e.g. user long pressed to stash). */ @@ -429,6 +446,11 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba return hasAnyFlag(FLAG_IN_OVERVIEW); } + /** Returns whether taskbar is hidden for bubbles. */ + public boolean isHiddenForBubbles() { + return hasAnyFlag(FLAG_STASHED_FOR_BUBBLES); + } + /** * Returns the height that taskbar will be touchable. */ @@ -491,9 +513,17 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** * Stash or unstashes the transient taskbar, using the default TASKBAR_STASH_DURATION. * If bubble bar exists, it will match taskbars stashing behavior. + * Will not delay taskbar background by default. */ public void updateAndAnimateTransientTaskbar(boolean stash) { - updateAndAnimateTransientTaskbar(stash, /* shouldBubblesFollow= */ true); + updateAndAnimateTransientTaskbar(stash, SHOULD_BUBBLES_FOLLOW_DEFAULT_VALUE, false); + } + + /** + * Stash or unstashes the transient taskbar, using the default TASKBAR_STASH_DURATION. + */ + public void updateAndAnimateTransientTaskbar(boolean stash, boolean shouldBubblesFollow) { + updateAndAnimateTransientTaskbar(stash, shouldBubblesFollow, false); } /** @@ -501,28 +531,47 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba * * @param stash whether transient taskbar should be stashed. * @param shouldBubblesFollow whether bubbles should match taskbars behavior. + * @param delayTaskbarBackground whether we will delay the taskbar background animation */ - public void updateAndAnimateTransientTaskbar(boolean stash, boolean shouldBubblesFollow) { + public void updateAndAnimateTransientTaskbar(boolean stash, boolean shouldBubblesFollow, + boolean delayTaskbarBackground) { if (!DisplayController.isTransientTaskbar(mActivity)) { return; } - if ( - stash - && !mControllers.taskbarAutohideSuspendController - .isSuspendedForTransientTaskbarInLauncher() - && mControllers.taskbarAutohideSuspendController - .isTransientTaskbarStashingSuspended()) { + if (stash + && !mControllers.taskbarAutohideSuspendController + .isSuspendedForTransientTaskbarInLauncher() + && mControllers.taskbarAutohideSuspendController + .isTransientTaskbarStashingSuspended()) { // Avoid stashing if autohide is currently suspended. return; } + boolean shouldApplyState = false; + + if (delayTaskbarBackground) { + mControllers.taskbarStashController.updateStateForFlag(FLAG_DELAY_TASKBAR_BG_TAG, true); + shouldApplyState = true; + } + if (hasAnyFlag(FLAG_STASHED_IN_APP_AUTO) != stash) { mTaskbarSharedState.taskbarWasStashedAuto = stash; updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, stash); + shouldApplyState = true; + } + + if (shouldApplyState) { applyState(); } + // Effectively a no-opp to remove the tag. + if (delayTaskbarBackground) { + mControllers.taskbarStashController.updateStateForFlag(FLAG_DELAY_TASKBAR_BG_TAG, + false); + mControllers.taskbarStashController.applyState(0); + } + mControllers.bubbleControllers.ifPresent(controllers -> { if (shouldBubblesFollow) { final boolean willStash = mIsStashedPredicate.test(mState); @@ -576,6 +625,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /* isStashed= */ mActivity.isPhoneMode(), placeholderDuration, TRANSITION_UNSTASH_SUW_MANUAL, + /* skipTaskbarBackgroundDelay */ false, /* jankTag= */ "SUW_MANUAL"); animation.addListener(AnimatorListeners.forEndCallback( () -> mControllers.taskbarViewController.setDeferUpdatesForSUW(false))); @@ -585,13 +635,14 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** * Create a stash animation and save to {@link #mAnimator}. * - * @param isStashed whether it's a stash animation or an unstash animation - * @param duration duration of the animation - * @param animationType what transition type to play. - * @param jankTag tag to be used in jank monitor trace. + * @param isStashed whether it's a stash animation or an unstash animation + * @param duration duration of the animation + * @param animationType what transition type to play. + * @param shouldDelayBackground whether we should delay the taskbar bg animation + * @param jankTag tag to be used in jank monitor trace. */ private void createAnimToIsStashed(boolean isStashed, long duration, - @StashAnimation int animationType, String jankTag) { + @StashAnimation int animationType, boolean shouldDelayBackground, String jankTag) { if (animationType == TRANSITION_UNSTASH_SUW_MANUAL && isStashed) { // The STASH_ANIMATION_SUW_MANUAL must only be used during an unstash animation. Log.e(TAG, "Illegal arguments:Using TRANSITION_UNSTASH_SUW_MANUAL to stash taskbar"); @@ -629,7 +680,8 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba } if (isTransientTaskbar) { - createTransientAnimToIsStashed(mAnimator, isStashed, duration, animationType); + createTransientAnimToIsStashed(mAnimator, isStashed, duration, + shouldDelayBackground, animationType); } else { createAnimToIsStashed(mAnimator, isStashed, duration, stashTranslation, animationType); } @@ -735,7 +787,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba } private void createTransientAnimToIsStashed(AnimatorSet as, boolean isStashed, long duration, - @StashAnimation int animationType) { + boolean shouldDelayBackground, @StashAnimation int animationType) { // Target values of the properties this is going to set final float backgroundOffsetTarget = isStashed ? 1 : 0; final float iconAlphaTarget = isStashed ? 0 : 1; @@ -786,7 +838,10 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba backgroundAndHandleAlphaStartDelay, backgroundAndHandleAlphaDuration, LINEAR); - if (enableScalingRevealHomeAnimation() && !isStashed) { + + if (enableScalingRevealHomeAnimation() + && !isStashed + && shouldDelayBackground) { play(as, getTaskbarBackgroundAnimatorWhenNotGoingHome(duration), 0, 0, LINEAR); as.addListener(AnimatorListeners.forEndCallback( @@ -957,13 +1012,29 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba } public void applyState() { - applyState(hasAnyFlag(FLAG_IN_SETUP) ? 0 : TASKBAR_STASH_DURATION); + applyState(/* postApplyAction = */ null); + } + + /** Applies state and performs action after state is applied. */ + public void applyState(@Nullable Runnable postApplyAction) { + applyState(hasAnyFlag(FLAG_IN_SETUP) ? 0 : TASKBAR_STASH_DURATION, postApplyAction); } public void applyState(long duration) { + applyState(duration, /* postApplyAction = */ null); + } + + private void applyState(long duration, @Nullable Runnable postApplyAction) { Animator animator = createApplyStateAnimator(duration); if (animator != null) { + if (postApplyAction != null) { + // performs action on animation end + animator.addListener(AnimatorListeners.forEndCallback(postApplyAction)); + } animator.start(); + } else if (postApplyAction != null) { + // animator was not created, just execute the action + postApplyAction.run(); } } @@ -981,6 +1052,9 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba */ @Nullable public Animator createApplyStateAnimator(long duration) { + if (mActivity.isPhoneMode()) { + return null; + } return mStatePropertyHolder.createSetStateAnimator(mState, duration); } @@ -1026,10 +1100,6 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba /** Called when some system ui state has changed. (See SYSUI_STATE_... in QuickstepContract) */ public void updateStateForSysuiFlags(long systemUiStateFlags, boolean skipAnim) { - if (mActivity.isPhoneMode()) { - return; - } - long animDuration = TASKBAR_STASH_DURATION; long startDelay = 0; @@ -1079,10 +1149,9 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba } // Do not stash if hardware keyboard is attached, in 3 button nav and desktop windowing mode - DesktopVisibilityController visibilityController = - LauncherActivityInterface.INSTANCE.getDesktopVisibilityController(); - if (visibilityController != null && mActivity.isHardwareKeyboard() - && mActivity.isThreeButtonNav() && visibilityController.areDesktopTasksVisible()) { + if (mActivity.isHardwareKeyboard() + && mActivity.isThreeButtonNav() + && mControllers.taskbarDesktopModeController.getAreDesktopTasksVisible()) { return false; } @@ -1137,6 +1206,10 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR, !hasAnyFlag(FLAG_STASHED_IN_APP_AUTO)); } + if (hasAnyFlag(changedFlags, FLAG_IN_OVERVIEW | FLAG_IN_APP)) { + mControllers.runAfterInit(() -> mControllers.taskbarInsetsController + .onTaskbarOrBubblebarWindowHeightOrInsetsChanged()); + } mActivity.applyForciblyShownFlagWhileTransientTaskbarUnstashed(!isStashedInApp()); } @@ -1176,6 +1249,12 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba * Clean up on destroy from TaskbarControllers */ public void onDestroy() { + // If the controller is destroyed before the animation finishes, we cancel the animation + // so that we don't finish the CUJ. + if (mAnimator != null) { + mAnimator.cancel(); + mAnimator = null; + } UI_HELPER_EXECUTOR.execute( () -> mAccessibilityManager.unregisterSystemAction(SYSTEM_ACTION_ID_TASKBAR)); } @@ -1339,8 +1418,9 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba mIsStashed = isStashed; mLastStartedTransitionType = animationType; + boolean shouldDelayBackground = hasAnyFlag(FLAG_DELAY_TASKBAR_BG_TAG); // This sets mAnimator. - createAnimToIsStashed(mIsStashed, duration, animationType, + createAnimToIsStashed(mIsStashed, duration, animationType, shouldDelayBackground, computeTaskbarJankMonitorTag(changedFlags)); return mAnimator; } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarThresholdUtils.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarThresholdUtils.java index 5b6fbef4fd..17516f3616 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarThresholdUtils.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarThresholdUtils.java @@ -25,7 +25,6 @@ import androidx.core.content.res.ResourcesCompat; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; -import com.android.launcher3.config.FeatureFlags; /** * Utility class that contains the different taskbar thresholds logic. @@ -39,10 +38,6 @@ public class TaskbarThresholdUtils { private static int getThreshold(Resources r, DeviceProfile dp, int thresholdDimen, int multiplierDimen) { - if (!FeatureFlags.ENABLE_DYNAMIC_TASKBAR_THRESHOLDS.get()) { - return r.getDimensionPixelSize(thresholdDimen); - } - float landscapeScreenHeight = dp.isLandscape ? dp.heightPx : dp.widthPx; float screenPart = (landscapeScreenHeight * SCREEN_UNITS); float defaultDp = dpiFromPx(screenPart, DisplayMetrics.DENSITY_DEVICE_STABLE); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index 6b1173a516..9c8c2a9fda 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -428,4 +428,18 @@ public class TaskbarUIController { public void setSkipLauncherVisibilityChange(boolean skip) { mSkipLauncherVisibilityChange = skip; } + + /** Sets whether the hotseat is stashed */ + public void stashHotseat(boolean stash) { + } + + /** Un-stash the hotseat instantly */ + public void unStashHotseatInstantly() { + } + + /** + * Called when we want to unstash taskbar when user performs swipes up gesture. + */ + public void onSwipeToUnstashTaskbar() { + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index 32d656163e..0389a11019 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -87,6 +87,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar private final boolean mIsRtl; private final TaskbarActivityContext mActivityContext; + @Nullable private BubbleBarLocation mBubbleBarLocation = null; // Initialized in init. private TaskbarViewCallbacks mControllerCallbacks; @@ -197,7 +198,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar @Override public void onDeviceProfileChanged(DeviceProfile dp) { - mShouldTryStartAlign = mActivityContext.isThreeButtonNav() && dp.startAlignTaskbar; + mShouldTryStartAlign = mActivityContext.shouldStartAlignTaskbar(); } @Override @@ -494,39 +495,60 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar icon.setOnHoverListener(mControllerCallbacks.getIconOnHoverListener(icon)); } + /** Updates taskbar icons accordingly to the new bubble bar location. */ + public void onBubbleBarLocationUpdated(BubbleBarLocation location) { + if (mBubbleBarLocation == location) return; + mBubbleBarLocation = location; + requestLayout(); + } + + /** + * Returns translation X for the taskbar icons for provided {@link BubbleBarLocation}. If the + * bubble bar is not enabled, or location of the bubble bar is the same, or taskbar is not start + * aligned - returns 0. + */ + public float getTranslationXForBubbleBarPosition(BubbleBarLocation location) { + if (!mControllerCallbacks.isBubbleBarEnabledInPersistentTaskbar() + || location == mBubbleBarLocation + || !mActivityContext.shouldStartAlignTaskbar() + ) { + return 0; + } + Rect iconsBounds = getIconLayoutBounds(); + return getTaskBarIconsEndForBubbleBarLocation(location) - iconsBounds.right; + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - int count = getChildCount(); - DeviceProfile deviceProfile = mActivityContext.getDeviceProfile(); int spaceNeeded = getIconLayoutWidth(); - int navSpaceNeeded = deviceProfile.hotseatBarEndOffset; boolean layoutRtl = isLayoutRtl(); - int centerAlignIconEnd = right - (right - left - spaceNeeded) / 2; - int iconEnd; - + DeviceProfile deviceProfile = mActivityContext.getDeviceProfile(); + int navSpaceNeeded = deviceProfile.hotseatBarEndOffset; + int centerAlignIconEnd = (right + left + spaceNeeded) / 2; + int iconEnd = centerAlignIconEnd; if (mShouldTryStartAlign) { - // Taskbar is aligned to the start int startSpacingPx = deviceProfile.inlineNavButtonsEndSpacingPx; - - if (layoutRtl) { - iconEnd = right - startSpacingPx; + if (mControllerCallbacks.isBubbleBarEnabledInPersistentTaskbar() + && mBubbleBarLocation != null + && mActivityContext.shouldStartAlignTaskbar()) { + iconEnd = (int) getTaskBarIconsEndForBubbleBarLocation(mBubbleBarLocation); } else { - iconEnd = startSpacingPx + spaceNeeded; + if (layoutRtl) { + iconEnd = right - startSpacingPx; + } else { + iconEnd = startSpacingPx + spaceNeeded; + } + boolean needMoreSpaceForNav = layoutRtl + ? navSpaceNeeded > (iconEnd - spaceNeeded) + : iconEnd > (right - navSpaceNeeded); + if (needMoreSpaceForNav) { + // Add offset to account for nav bar when taskbar is centered + int offset = layoutRtl + ? navSpaceNeeded - (centerAlignIconEnd - spaceNeeded) + : (right - navSpaceNeeded) - centerAlignIconEnd; + iconEnd = centerAlignIconEnd + offset; + } } - } else { - iconEnd = centerAlignIconEnd; - } - - boolean needMoreSpaceForNav = layoutRtl - ? navSpaceNeeded > (iconEnd - spaceNeeded) - : iconEnd > (right - navSpaceNeeded); - if (needMoreSpaceForNav) { - // Add offset to account for nav bar when taskbar is centered - int offset = layoutRtl - ? navSpaceNeeded - (centerAlignIconEnd - spaceNeeded) - : (right - navSpaceNeeded) - centerAlignIconEnd; - - iconEnd = centerAlignIconEnd + offset; } // Currently, we support only one device with display cutout and we only are concern about @@ -558,6 +580,7 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar mIconLayoutBounds.right = iconEnd; mIconLayoutBounds.top = (bottom - top - mIconTouchSize) / 2; mIconLayoutBounds.bottom = mIconLayoutBounds.top + mIconTouchSize; + int count = getChildCount(); for (int i = count; i > 0; i--) { View child = getChildAt(i - 1); if (child == mQsb) { @@ -770,4 +793,19 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar } return mAllAppsButtonContainer; } + + /** + * This method only works for bubble bar enabled in persistent task bar and the taskbar is start + * aligned. + */ + private float getTaskBarIconsEndForBubbleBarLocation(BubbleBarLocation location) { + DeviceProfile deviceProfile = mActivityContext.getDeviceProfile(); + boolean navbarOnRight = location.isOnLeft(isLayoutRtl()); + int navSpaceNeeded = deviceProfile.hotseatBarEndOffset; + if (navbarOnRight) { + return getWidth() - navSpaceNeeded; + } else { + return navSpaceNeeded + getIconLayoutWidth(); + } + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java index 5ec00ac413..5c8d439a13 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java @@ -28,6 +28,7 @@ import androidx.annotation.Nullable; import com.android.internal.jank.Cuj; import com.android.launcher3.taskbar.bubbles.BubbleBarViewController; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; +import com.android.wm.shell.Flags; import com.android.wm.shell.shared.bubbles.BubbleBarLocation; /** @@ -127,4 +128,10 @@ public class TaskbarViewCallbacks { } return null; } + + /** Returns true if bubble bar controllers present and enabled in persistent taskbar. */ + public boolean isBubbleBarEnabledInPersistentTaskbar() { + return Flags.enableBubbleBarInPersistentTaskBar() + && mControllers.bubbleControllers.isPresent(); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index aa3e6bffb8..b663ccb44e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -29,7 +29,10 @@ import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UN import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning; import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT; import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT; +import static com.android.launcher3.taskbar.bubbles.BubbleBarView.FADE_IN_ANIM_ALPHA_DURATION_MS; +import static com.android.launcher3.taskbar.bubbles.BubbleBarView.FADE_OUT_ANIM_POSITION_DURATION_MS; import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE; +import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_NAV_BAR_ANIM; 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; @@ -66,6 +69,7 @@ import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.TaskItemInfo; +import com.android.launcher3.taskbar.bubbles.BubbleBarController; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.ItemInfoMatcher; import com.android.launcher3.util.LauncherBindableItemsContainer; @@ -74,6 +78,8 @@ import com.android.launcher3.util.MultiTranslateDelegate; import com.android.launcher3.util.MultiValueAlpha; import com.android.quickstep.util.GroupTask; import com.android.systemui.shared.recents.model.Task; +import com.android.wm.shell.Flags; +import com.android.wm.shell.shared.bubbles.BubbleBarLocation; import java.io.PrintWriter; import java.util.Set; @@ -82,7 +88,8 @@ import java.util.function.Predicate; /** * Handles properties/data collection, then passes the results to TaskbarView to render. */ -public class TaskbarViewController implements TaskbarControllers.LoggableTaskbarController { +public class TaskbarViewController implements TaskbarControllers.LoggableTaskbarController, + BubbleBarController.BubbleBarLocationListener { private static final String TAG = "TaskbarViewController"; @@ -122,6 +129,14 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar private final AnimatedFloat mTaskbarIconTranslationXForPinning = new AnimatedFloat( this::updateTaskbarIconTranslationXForPinning); + private final AnimatedFloat mIconsTranslationXForNavbar = new AnimatedFloat( + this::updateTranslationXForNavBar); + + @Nullable + private Animator mTaskbarShiftXAnim; + @Nullable + private BubbleBarLocation mCurrentBubbleBarLocation; + private final AnimatedFloat mTaskbarIconTranslationYForPinning = new AnimatedFloat( this::updateTranslationY); @@ -206,7 +221,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar mModelCallbacks.init(controllers); if (mActivity.isUserSetupComplete() && sEnableModelLoadingForTests) { // Only load the callbacks if user setup is completed - LauncherAppState.getInstance(mActivity).getModel().addCallbacksAndLoad(mModelCallbacks); + controllers.runAfterInit(() -> LauncherAppState.getInstance(mActivity).getModel() + .addCallbacksAndLoad(mModelCallbacks)); } mTaskbarNavButtonTranslationY = controllers.navbarButtonsViewController.getTaskbarNavButtonTranslationY(); @@ -226,6 +242,54 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar } } + /** Adjusts start aligned taskbar layout accordingly to the bubble bar position. */ + @Override + public void onBubbleBarLocationUpdated(BubbleBarLocation location) { + updateCurrentBubbleBarLocation(location); + if (!shouldMoveTaskbarOnBubbleBarLocationUpdate()) return; + cancelTaskbarShiftAnimation(); + // reset translation x, taskbar will position icons with the updated location + mIconsTranslationXForNavbar.updateValue(0); + mTaskbarView.onBubbleBarLocationUpdated(location); + } + + /** Animates start aligned taskbar accordingly to the bubble bar position. */ + @Override + public void onBubbleBarLocationAnimated(BubbleBarLocation location) { + if (!updateCurrentBubbleBarLocation(location) + || !shouldMoveTaskbarOnBubbleBarLocationUpdate()) { + return; + } + cancelTaskbarShiftAnimation(); + float translationX = mTaskbarView.getTranslationXForBubbleBarPosition(location); + mTaskbarShiftXAnim = createTaskbarIconsShiftAnimator(translationX); + mTaskbarShiftXAnim.start(); + } + + /** Updates the mCurrentBubbleBarLocation, returns {@code} true if location is updated. */ + private boolean updateCurrentBubbleBarLocation(BubbleBarLocation location) { + if (mCurrentBubbleBarLocation == location || location == null) { + return false; + } else { + mCurrentBubbleBarLocation = location; + return true; + } + } + + /** Returns whether taskbar should be moved on the bubble bar location update. */ + private boolean shouldMoveTaskbarOnBubbleBarLocationUpdate() { + return Flags.enableBubbleBarInPersistentTaskBar() + && mControllers.bubbleControllers.isPresent() + && mActivity.shouldStartAlignTaskbar() + && mActivity.isThreeButtonNav(); + } + + private void cancelTaskbarShiftAnimation() { + if (mTaskbarShiftXAnim != null) { + mTaskbarShiftXAnim.cancel(); + } + } + /** * Announcement for Accessibility when Taskbar stashes/unstashes. */ @@ -459,6 +523,17 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar + mTaskbarIconTranslationYForSpringOnStash); } + private void updateTranslationXForNavBar() { + View[] iconViews = mTaskbarView.getIconViews(); + float translationX = mIconsTranslationXForNavbar.value; + for (int iconIndex = 0; iconIndex < iconViews.length; iconIndex++) { + View iconView = iconViews[iconIndex]; + MultiTranslateDelegate translateDelegate = + ((Reorderable) iconView).getTranslateDelegate(); + translateDelegate.getTranslationX(INDEX_NAV_BAR_ANIM).setValue(translationX); + } + } + /** * Computes translation y for taskbar pinning. */ @@ -762,7 +837,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar // plays iconAlignment to 1 really fast, therefore moving the fading towards the end // to avoid icons disappearing rather than fading out visually. setter.setViewAlpha(child, 0, Interpolators.clampToProgress(LINEAR, 0.8f, 1f)); - } else if ((isAllAppsButton && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) + } else if ((isAllAppsButton && !FeatureFlags.enableAllAppsButtonInHotseat()) || (isTaskbarDividerView && enableTaskbarPinning()) || (isRecentTask && !isRecentsInHotseat)) { if (!isToHome @@ -1017,4 +1092,12 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar public static void enableModelLoadingForTests(boolean enable) { sEnableModelLoadingForTests = enable; } + + private ObjectAnimator createTaskbarIconsShiftAnimator(float translationX) { + ObjectAnimator animator = mIconsTranslationXForNavbar.animateToValue(translationX); + animator.setStartDelay(FADE_OUT_ANIM_POSITION_DURATION_MS); + animator.setDuration(FADE_IN_ANIM_ALPHA_DURATION_MS); + animator.setInterpolator(Interpolators.EMPHASIZED); + return animator; + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java index 5d91acd3e1..a46845affa 100644 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsContainerView.java @@ -17,13 +17,10 @@ package com.android.launcher3.taskbar.allapps; import android.content.Context; import android.util.AttributeSet; -import android.view.View; import androidx.annotation.Nullable; -import com.android.launcher3.R; import com.android.launcher3.allapps.ActivityAllAppsContainerView; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; import java.util.Optional; @@ -47,23 +44,6 @@ public class TaskbarAllAppsContainerView extends } @Override - protected View inflateSearchBar() { - if (isSearchSupported()) { - return super.inflateSearchBar(); - } - - // Remove top padding of header, since we do not have any search - mHeader.setPadding(mHeader.getPaddingLeft(), 0, - mHeader.getPaddingRight(), mHeader.getPaddingBottom()); - - TaskbarAllAppsFallbackSearchContainer searchView = - new TaskbarAllAppsFallbackSearchContainer(getContext(), null); - searchView.setId(R.id.search_container_all_apps); - searchView.setVisibility(GONE); - return searchView; - } - - @Override public void invalidateHeader() { super.invalidateHeader(); Optional.ofNullable(mOnInvalidateHeaderListener).ifPresent( @@ -71,11 +51,6 @@ public class TaskbarAllAppsContainerView extends } @Override - protected boolean isSearchSupported() { - return FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get(); - } - - @Override public boolean isInAllApps() { // All apps is always open return true; diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsFallbackSearchContainer.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsFallbackSearchContainer.java deleted file mode 100644 index 53fe06d32c..0000000000 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsFallbackSearchContainer.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.taskbar.allapps; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.View; - -import androidx.annotation.Nullable; - -import com.android.launcher3.ExtendedEditText; -import com.android.launcher3.allapps.ActivityAllAppsContainerView; -import com.android.launcher3.allapps.SearchUiManager; - -/** Empty search container for Taskbar All Apps used as a fallback if search is not supported. */ -public class TaskbarAllAppsFallbackSearchContainer extends View implements SearchUiManager { - public TaskbarAllAppsFallbackSearchContainer(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public TaskbarAllAppsFallbackSearchContainer( - Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @Override - public void initializeSearch(ActivityAllAppsContainerView<?> containerView) { - // Do nothing. - } - - @Override - public void resetSearch() { - // Do nothing. - } - - @Nullable - @Override - public ExtendedEditText getEditText() { - return null; - } -} diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java index f5ac66f776..5830095fa6 100644 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java @@ -39,7 +39,6 @@ import com.android.launcher3.Insettable; import com.android.launcher3.R; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.anim.PendingAnimation; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.taskbar.allapps.TaskbarAllAppsViewController.TaskbarAllAppsCallbacks; import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext; import com.android.launcher3.util.Themes; @@ -180,9 +179,7 @@ public class TaskbarAllAppsSlideInView extends AbstractSlideInView<TaskbarOverla mContent = mAppsView; // Setup header protection for search bar, if enabled. - if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) { - mAppsView.setOnInvalidateHeaderListener(this::invalidate); - } + mAppsView.setOnInvalidateHeaderListener(this::invalidate); DeviceProfile dp = mActivityContext.getDeviceProfile(); setShiftRange(dp.allAppsShiftRange); diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt index 4d0b376351..6b72ab68cf 100644 --- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt @@ -21,7 +21,6 @@ import android.view.View import com.android.launcher3.R import com.android.launcher3.allapps.AllAppsTransitionListener import com.android.launcher3.anim.PendingAnimation -import com.android.launcher3.config.FeatureFlags import com.android.launcher3.dragndrop.DragOptions.PreDragCondition import com.android.launcher3.model.data.ItemInfo import com.android.launcher3.util.ResourceBasedOverride @@ -61,16 +60,11 @@ open class TaskbarSearchSessionController : ResourceBasedOverride, AllAppsTransi companion object { @JvmStatic - fun newInstance(context: Context): TaskbarSearchSessionController { - if (!FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) { - return TaskbarSearchSessionController() - } - - return Overrides.getObject( + fun newInstance(context: Context): TaskbarSearchSessionController = + Overrides.getObject( TaskbarSearchSessionController::class.java, context, R.string.taskbar_search_session_controller_class, ) - } } } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt index 25939e1eb5..f08318e54a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt @@ -71,6 +71,27 @@ class BubbleBarBackground(context: Context, private var backgroundHeight: Float) } } + /** + * Scale of the background in the x direction. Pivot is at the left edge if [anchorLeft] is + * `true` and at the right edge if it is `false` + */ + var scaleX: Float = 1f + set(value) { + if (field != value) { + field = value + invalidateSelf() + } + } + + /** Scale of the background in the y direction. Pivot is at the bottom edge. */ + var scaleY: Float = 1f + set(value) { + if (field != value) { + field = value + invalidateSelf() + } + } + init { val res = context.resources // configure fill paint @@ -123,13 +144,17 @@ class BubbleBarBackground(context: Context, private var backgroundHeight: Float) ) // Create background path val backgroundPath = Path() - val topOffset = backgroundHeight - bounds.height().toFloat() + val scaledBackgroundHeight = backgroundHeight * scaleY + val scaledWidth = width * scaleX + val topOffset = scaledBackgroundHeight - bounds.height().toFloat() val radius = backgroundHeight / 2f - val left = bounds.left + (if (anchorLeft) 0f else bounds.width().toFloat() - width) - val right = bounds.left + (if (anchorLeft) width else bounds.width().toFloat()) - val top = bounds.top - topOffset + arrowVisibleHeight - val bottom = bounds.top + bounds.height().toFloat() + val left = bounds.left + (if (anchorLeft) 0f else bounds.width().toFloat() - scaledWidth) + val right = bounds.left + (if (anchorLeft) scaledWidth else bounds.width().toFloat()) + // Calculate top with scaled heights for background and arrow to align with stash handle + val top = bounds.bottom - scaledBackgroundHeight + getScaledArrowVisibleHeight() + val bottom = bounds.bottom.toFloat() + backgroundPath.addRoundRect(left, top, right, bottom, radius, radius, Path.Direction.CW) addArrowPathIfNeeded(backgroundPath, topOffset) @@ -142,19 +167,20 @@ class BubbleBarBackground(context: Context, private var backgroundHeight: Float) private fun addArrowPathIfNeeded(sourcePath: Path, topOffset: Float) { if (!showingArrow || arrowHeightFraction <= 0) return val arrowPath = Path() + val scaledHeight = getScaledArrowHeight() RoundedArrowDrawable.addDownPointingRoundedTriangleToPath( arrowWidth, - arrowHeight, + scaledHeight, arrowTipRadius, arrowPath ) // flip it horizontally val pathTransform = Matrix() - pathTransform.setRotate(180f, arrowWidth * 0.5f, arrowHeight * 0.5f) + pathTransform.setRotate(180f, arrowWidth * 0.5f, scaledHeight * 0.5f) arrowPath.transform(pathTransform) // shift to arrow position val arrowStart = bounds.left + arrowPositionX - (arrowWidth / 2f) - val arrowTop = (1 - arrowHeightFraction) * arrowVisibleHeight - topOffset + val arrowTop = (1 - arrowHeightFraction) * getScaledArrowVisibleHeight() - topOffset arrowPath.offset(arrowStart, arrowTop) // union with rectangle sourcePath.op(arrowPath, Path.Op.UNION) @@ -183,6 +209,7 @@ class BubbleBarBackground(context: Context, private var backgroundHeight: Float) fun setBackgroundHeight(newHeight: Float) { backgroundHeight = newHeight + invalidateSelf() } /** @@ -199,6 +226,14 @@ class BubbleBarBackground(context: Context, private var backgroundHeight: Float) invalidateSelf() } + private fun getScaledArrowHeight(): Float { + return arrowHeight * scaleY + } + + private fun getScaledArrowVisibleHeight(): Float { + return max(0f, getScaledArrowHeight() - (arrowHeight - arrowVisibleHeight)) + } + companion object { private const val DARK_THEME_STROKE_ALPHA = 51 private const val LIGHT_THEME_STROKE_ALPHA = 41 diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java index d70a317666..6860004133 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java @@ -118,6 +118,7 @@ public class BubbleBarController extends IBubblesListener.Stub { private Optional<BubbleStashedHandleViewController> mBubbleStashedHandleViewController; private BubblePinController mBubblePinController; private BubbleCreator mBubbleCreator; + private BubbleBarLocationListener mBubbleBarLocationListener; // Cache last sent top coordinate to avoid sending duplicate updates to shell private int mLastSentBubbleBarTop; @@ -176,6 +177,7 @@ public class BubbleBarController extends IBubblesListener.Stub { /** Initializes controllers. */ public void init(BubbleControllers bubbleControllers, + BubbleBarLocationListener bubbleBarLocationListener, ImeVisibilityChecker imeVisibilityChecker) { mImeVisibilityChecker = imeVisibilityChecker; mBubbleBarViewController = bubbleControllers.bubbleBarViewController; @@ -183,6 +185,7 @@ public class BubbleBarController extends IBubblesListener.Stub { mBubbleStashedHandleViewController = bubbleControllers.bubbleStashedHandleViewController; mBubblePinController = bubbleControllers.bubblePinController; mBubbleCreator = bubbleControllers.bubbleCreator; + mBubbleBarLocationListener = bubbleBarLocationListener; bubbleControllers.runAfterInit(() -> { mBubbleBarViewController.setHiddenForBubbles( @@ -488,12 +491,16 @@ public class BubbleBarController extends IBubblesListener.Stub { private void updateBubbleBarLocationInternal(BubbleBarLocation location) { mBubbleBarViewController.setBubbleBarLocation(location); mBubbleStashController.setBubbleBarLocation(location); + mBubbleBarLocationListener.onBubbleBarLocationUpdated(location); } @Override public void animateBubbleBarLocation(BubbleBarLocation bubbleBarLocation) { MAIN_EXECUTOR.execute( - () -> mBubbleBarViewController.animateBubbleBarLocation(bubbleBarLocation)); + () -> { + mBubbleBarViewController.animateBubbleBarLocation(bubbleBarLocation); + mBubbleBarLocationListener.onBubbleBarLocationAnimated(bubbleBarLocation); + }); } /** Notifies WMShell to show the expanded view. */ @@ -518,4 +525,14 @@ public class BubbleBarController extends IBubblesListener.Stub { /** Whether the IME is visible. */ boolean isImeVisible(); } + + /** Listener of {@link BubbleBarLocation} updates. */ + public interface BubbleBarLocationListener { + + /** Called when {@link BubbleBarLocation} is animated, but change is not yet final. */ + void onBubbleBarLocationAnimated(BubbleBarLocation location); + + /** Called when {@link BubbleBarLocation} is updated permanently. */ + void onBubbleBarLocationUpdated(BubbleBarLocation location); + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationCompositeListener.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationCompositeListener.kt new file mode 100644 index 0000000000..8e176ac6bd --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarLocationCompositeListener.kt @@ -0,0 +1,35 @@ +/* + * 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 com.android.launcher3.taskbar.bubbles.BubbleBarController.BubbleBarLocationListener +import com.android.wm.shell.shared.bubbles.BubbleBarLocation + +/** Composite implementation of [BubbleBarLocationListener] interface */ +class BubbleBarLocationCompositeListener(private val listeners: List<BubbleBarLocationListener>) : + BubbleBarLocationListener { + + constructor(vararg listeners: BubbleBarLocationListener) : this(listOf(*listeners)) + + override fun onBubbleBarLocationAnimated(location: BubbleBarLocation?) { + listeners.forEach { it.onBubbleBarLocationAnimated(location) } + } + + override fun onBubbleBarLocationUpdated(location: BubbleBarLocation?) { + listeners.forEach { it.onBubbleBarLocationUpdated(location) } + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt index 9c34307214..a34fab2b8f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt @@ -27,6 +27,7 @@ import android.view.View import android.widget.FrameLayout import androidx.core.view.updateLayoutParams import com.android.launcher3.R +import com.android.launcher3.taskbar.bubbles.BubbleBarController.BubbleBarLocationListener import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController import com.android.wm.shell.shared.bubbles.BaseBubblePinController import com.android.wm.shell.shared.bubbles.BubbleBarLocation @@ -42,12 +43,17 @@ class BubbleBarPinController( private lateinit var bubbleBarViewController: BubbleBarViewController private lateinit var bubbleStashController: BubbleStashController + private lateinit var bubbleBarLocationListener: BubbleBarLocationListener private var exclRectWidth: Float = 0f private var exclRectHeight: Float = 0f private var dropTargetView: View? = null - fun init(bubbleControllers: BubbleControllers) { + fun init( + bubbleControllers: BubbleControllers, + bubbleBarLocationListener: BubbleBarLocationListener + ) { + this.bubbleBarLocationListener = bubbleBarLocationListener bubbleBarViewController = bubbleControllers.bubbleBarViewController bubbleStashController = bubbleControllers.bubbleStashController exclRectWidth = context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_width) @@ -86,6 +92,7 @@ class BubbleBarPinController( val bounds = bubbleBarViewController.bubbleBarBounds val horizontalMargin = bubbleBarViewController.horizontalMargin + bubbleBarLocationListener.onBubbleBarLocationAnimated(location) dropTargetView?.updateLayoutParams<FrameLayout.LayoutParams> { width = bounds.width() height = bounds.height() diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java index 06301c7453..d454fd7b8e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java @@ -95,11 +95,11 @@ public class BubbleBarView extends FrameLayout { private static final long FADE_OUT_ANIM_ALPHA_DURATION_MS = 50L; private static final long FADE_OUT_ANIM_ALPHA_DELAY_MS = 50L; - private static final long FADE_OUT_ANIM_POSITION_DURATION_MS = 100L; + public static final long FADE_OUT_ANIM_POSITION_DURATION_MS = 100L; // During fade out animation we shift the bubble bar 1/80th of the screen width private static final float FADE_OUT_ANIM_POSITION_SHIFT = 1 / 80f; - private static final long FADE_IN_ANIM_ALPHA_DURATION_MS = 100L; + public static final long FADE_IN_ANIM_ALPHA_DURATION_MS = 100L; // Use STIFFNESS_MEDIUMLOW which is not defined in the API constants private static final float FADE_IN_ANIM_POSITION_SPRING_STIFFNESS = 400f; // During fade in animation we shift the bubble bar 1/60th of the screen width @@ -187,6 +187,9 @@ public class BubbleBarView extends FrameLayout { private BubbleView mDismissedByDragBubbleView; private float mAlphaDuringDrag = 1f; + /** Additional translation in the y direction that is applied to each bubble */ + private float mBubbleOffsetY; + private Controller mController; private int mPreviousLayoutDirection = LayoutDirection.UNDEFINED; @@ -205,7 +208,6 @@ public class BubbleBarView extends FrameLayout { public BubbleBarView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); - setAlpha(0); setVisibility(INVISIBLE); mIconOverlapAmount = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_overlap); mBubbleBarPadding = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing); @@ -306,6 +308,46 @@ public class BubbleBarView extends FrameLayout { } /** + * Set scale for bubble bar background in x direction + */ + public void setBackgroundScaleX(float scaleX) { + mBubbleBarBackground.setScaleX(scaleX); + } + + /** + * Set scale for bubble bar background in y direction + */ + public void setBackgroundScaleY(float scaleY) { + mBubbleBarBackground.setScaleY(scaleY); + } + + /** + * Set alpha for bubble views + */ + public void setBubbleAlpha(float alpha) { + for (int i = 0; i < getChildCount(); i++) { + getChildAt(i).setAlpha(alpha); + } + } + + /** + * Set alpha for bar background + */ + public void setBackgroundAlpha(float alpha) { + mBubbleBarBackground.setAlpha((int) (255 * alpha)); + } + + /** + * Sets offset of each bubble view in the y direction from the base position in the bar. + */ + public void setBubbleOffsetY(float offsetY) { + mBubbleOffsetY = offsetY; + for (int i = 0; i < getChildCount(); i++) { + getChildAt(i).setTranslationY(getBubbleTranslationY()); + } + } + + /** * Sets new icon sizes and newBubbleBarPadding between icons and bubble bar borders. * * @param newIconSize new icon size @@ -322,7 +364,7 @@ public class BubbleBarView extends FrameLayout { int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); - childView.setScaleY(mIconScale); + childView.setScaleX(mIconScale); childView.setScaleY(mIconScale); FrameLayout.LayoutParams params = (LayoutParams) childView.getLayoutParams(); params.height = (int) mIconSize; @@ -647,7 +689,7 @@ public class BubbleBarView extends FrameLayout { } setAlphaDuringBubbleDrag(1f); setTranslationX(0f); - if (getBubbleChildCount() > 0) { + if (mIsBarExpanded && getBubbleChildCount() > 0) { setAlpha(1f); } } @@ -770,6 +812,9 @@ public class BubbleBarView extends FrameLayout { removeView(removedBubble); int index = addingOverflow ? getChildCount() : 0; addView(addedBubble, index, lp); + if (onEndRunnable != null) { + onEndRunnable.run(); + } return; } int index = addingOverflow ? getChildCount() : 0; @@ -965,10 +1010,7 @@ public class BubbleBarView extends FrameLayout { final float expandedWidth = expandedWidth(); final float collapsedWidth = collapsedWidth(); int childCount = getChildCount(); - float viewBottom = mBubbleBarBounds.height() + (isExpanded() ? mPointerSize : 0); - float bubbleBarAnimatedTop = viewBottom - getBubbleBarHeight(); - // When translating X & Y the scale is ignored, so need to deduct it from the translations - final float ty = bubbleBarAnimatedTop + mBubbleBarPadding - getScaleIconShift(); + final float ty = getBubbleTranslationY(); final boolean onLeft = bubbleBarLocation.isOnLeft(isLayoutRtl()); // elevation state is opposite to widthState - when expanded all icons are flat float elevationState = (1 - widthState); @@ -1015,7 +1057,7 @@ public class BubbleBarView extends FrameLayout { // where the bubble will end up when the animation ends final float targetX = expandedX + expandedBarShift; bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX); - bv.setAlpha(1); + bv.setVisibility(VISIBLE); } else { // If bar is on the right, account for bubble bar expanding and shifting left final float collapsedBarShift = onLeft ? 0 : currentWidth - collapsedWidth; @@ -1025,9 +1067,9 @@ public class BubbleBarView extends FrameLayout { // the overflow. if (widthState == 0) { if (bv.isOverflow() || i > MAX_VISIBLE_BUBBLES_COLLAPSED - 1) { - bv.setAlpha(0); + bv.setVisibility(INVISIBLE); } else { - bv.setAlpha(1); + bv.setVisibility(VISIBLE); } } } @@ -1093,15 +1135,25 @@ public class BubbleBarView extends FrameLayout { translationX = 0f; } } else { - if (bubbleIndex == 1 && getBubbleChildCount() >= MAX_VISIBLE_BUBBLES_COLLAPSED) { - translationX = mIconOverlapAmount; - } else { + // when the bar is on the right, the first bubble always has translation 0. the only + // case where another bubble has translation 0 is when we only have 1 bubble and the + // overflow. otherwise all other bubbles should be shifted by the overlap amount. + if (bubbleIndex == 0 || getBubbleChildCount() == 1) { translationX = 0f; + } else { + translationX = mIconOverlapAmount; } } return mBubbleBarPadding + translationX - getScaleIconShift(); } + private float getBubbleTranslationY() { + float viewBottom = mBubbleBarBounds.height() + (isExpanded() ? mPointerSize : 0); + float bubbleBarAnimatedTop = viewBottom - getBubbleBarHeight(); + // When translating X & Y the scale is ignored, so need to deduct it from the translations + return mBubbleOffsetY + bubbleBarAnimatedTop + mBubbleBarPadding - getScaleIconShift(); + } + /** * Reorders the views to match the provided list. */ @@ -1335,7 +1387,7 @@ public class BubbleBarView extends FrameLayout { * touch bounds. */ public boolean isEventOverAnyItem(MotionEvent ev) { - if (getVisibility() == View.VISIBLE) { + if (getVisibility() == VISIBLE) { getBoundsOnScreen(mTempRect); return mTempRect.contains((int) ev.getX(), (int) ev.getY()); } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index d9e3406d3a..025c03860c 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -18,6 +18,8 @@ package com.android.launcher3.taskbar.bubbles; import static android.view.View.INVISIBLE; import static android.view.View.VISIBLE; +import android.animation.Animator; +import android.animation.AnimatorSet; import android.content.res.Resources; import android.graphics.Point; import android.graphics.PointF; @@ -34,6 +36,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; import com.android.launcher3.anim.AnimatedFloat; +import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarControllers; import com.android.launcher3.taskbar.TaskbarInsetsController; @@ -80,10 +83,19 @@ public class BubbleBarViewController { // These are exposed to {@link BubbleStashController} to animate for stashing/un-stashing private final MultiValueAlpha mBubbleBarAlpha; + private final AnimatedFloat mBubbleBarBubbleAlpha = new AnimatedFloat(this::updateBubbleAlpha); + private final AnimatedFloat mBubbleBarBackgroundAlpha = new AnimatedFloat( + this::updateBackgroundAlpha); private final AnimatedFloat mBubbleBarScaleX = new AnimatedFloat(this::updateScaleX); private final AnimatedFloat mBubbleBarScaleY = new AnimatedFloat(this::updateScaleY); + private final AnimatedFloat mBubbleBarBackgroundScaleX = new AnimatedFloat( + this::updateBackgroundScaleX); + private final AnimatedFloat mBubbleBarBackgroundScaleY = new AnimatedFloat( + this::updateBackgroundScaleY); private final AnimatedFloat mBubbleBarTranslationY = new AnimatedFloat( this::updateTranslationY); + private final AnimatedFloat mBubbleOffsetY = new AnimatedFloat( + this::updateBubbleOffsetY); // Modified when swipe up is happening on the bubble bar or task bar. private float mBubbleBarSwipeUpTranslationY; @@ -258,6 +270,14 @@ public class BubbleBarViewController { return mBubbleBarAlpha; } + public AnimatedFloat getBubbleBarBubbleAlpha() { + return mBubbleBarBubbleAlpha; + } + + public AnimatedFloat getBubbleBarBackgroundAlpha() { + return mBubbleBarBackgroundAlpha; + } + public AnimatedFloat getBubbleBarScaleX() { return mBubbleBarScaleX; } @@ -266,10 +286,22 @@ public class BubbleBarViewController { return mBubbleBarScaleY; } + public AnimatedFloat getBubbleBarBackgroundScaleX() { + return mBubbleBarBackgroundScaleX; + } + + public AnimatedFloat getBubbleBarBackgroundScaleY() { + return mBubbleBarBackgroundScaleY; + } + public AnimatedFloat getBubbleBarTranslationY() { return mBubbleBarTranslationY; } + public AnimatedFloat getBubbleOffsetY() { + return mBubbleOffsetY; + } + public float getBubbleBarCollapsedWidth() { return mBarView.collapsedWidth(); } @@ -408,7 +440,7 @@ public class BubbleBarViewController { if (hidden) { mBarView.setAlpha(0); mBarView.setExpanded(false); - updatePersistentTaskbar(/* isBubbleBarExpanded = */ false); + adjustTaskbarAndHotseatToBubbleBarState(/* isBubbleBarExpanded = */ false); } mActivity.bubbleBarVisibilityChanged(!hidden); } @@ -535,6 +567,26 @@ public class BubbleBarViewController { mBarView.setScaleY(scale); } + private void updateBackgroundScaleX(float scale) { + mBarView.setBackgroundScaleX(scale); + } + + private void updateBackgroundScaleY(float scale) { + mBarView.setBackgroundScaleY(scale); + } + + private void updateBubbleAlpha(float alpha) { + mBarView.setBubbleAlpha(alpha); + } + + private void updateBubbleOffsetY(float transY) { + mBarView.setBubbleOffsetY(transY); + } + + private void updateBackgroundAlpha(float alpha) { + mBarView.setBackgroundAlpha(alpha); + } + // // Manipulating the specific bubble views in the bar // @@ -683,7 +735,7 @@ public class BubbleBarViewController { public void setExpanded(boolean isExpanded) { if (isExpanded != mBarView.isExpanded()) { mBarView.setExpanded(isExpanded); - updatePersistentTaskbar(isExpanded); + adjustTaskbarAndHotseatToBubbleBarState(isExpanded); if (!isExpanded) { mSystemUiProxy.collapseBubbles(); } else { @@ -694,13 +746,25 @@ public class BubbleBarViewController { } } - private void updatePersistentTaskbar(boolean isBubbleBarExpanded) { - if (mBubbleStashController.isTransientTaskBar()) return; - boolean hideTaskbar = isBubbleBarExpanded && isIntersectingTaskbar(); - mTaskbarViewPropertiesProvider - .getIconsAlpha() - .animateToValue(hideTaskbar ? 0 : 1) - .start(); + /** + * Hides the persistent taskbar if it is going to intersect with the expanded bubble bar if in + * app or overview. Set the hotseat stashed state if on launcher home screen. If not on launcher + * home screen and hotseat is stashed immediately un-stashes the hotseat. + */ + private void adjustTaskbarAndHotseatToBubbleBarState(boolean isBubbleBarExpanded) { + if (mBubbleStashController.isBubblesShowingOnHome()) { + mTaskbarStashController.stashHotseat(isBubbleBarExpanded); + } else if (!mBubbleStashController.isTransientTaskBar()) { + boolean hideTaskbar = isBubbleBarExpanded && isIntersectingTaskbar(); + mTaskbarViewPropertiesProvider + .getIconsAlpha() + .animateToValue(hideTaskbar ? 0 : 1) + .start(); + } + if (!mBubbleStashController.isBubblesShowingOnHome() + && mTaskbarStashController.isHiddenForBubbles()) { + mTaskbarStashController.unStashHotseatInstantly(); + } } /** Return {@code true} if expanded bubble bar would intersect the taskbar. */ @@ -819,6 +883,53 @@ public class BubbleBarViewController { mBoundsChangeListener = listener; } + /** Called when the controller is destroyed. */ + public void onDestroy() { + adjustTaskbarAndHotseatToBubbleBarState(/*isBubbleBarExpanded = */false); + } + + /** + * Create an animator for showing or hiding bubbles when stashed state changes + * + * @param isStashed {@code true} when bubble bar should be stashed to the handle + */ + public Animator createRevealAnimatorForStashChange(boolean isStashed) { + Rect stashedHandleBounds = new Rect(); + mBubbleStashController.getHandleBounds(stashedHandleBounds); + int childCount = mBarView.getChildCount(); + float newChildWidth = (float) stashedHandleBounds.width() / childCount; + AnimatorSet animatorSet = new AnimatorSet(); + for (int i = 0; i < childCount; i++) { + BubbleView child = (BubbleView) mBarView.getChildAt(i); + animatorSet.play( + createRevealAnimForBubble(child, isStashed, stashedHandleBounds, + newChildWidth)); + } + return animatorSet; + } + + private Animator createRevealAnimForBubble(BubbleView bubbleView, boolean isStashed, + Rect stashedHandleBounds, float newWidth) { + Rect viewBounds = new Rect(0, 0, bubbleView.getWidth(), bubbleView.getHeight()); + + int viewCenterY = viewBounds.centerY(); + int halfHandleHeight = stashedHandleBounds.height() / 2; + int widthDelta = Math.max(0, (int) (viewBounds.width() - newWidth) / 2); + + Rect stashedViewBounds = new Rect( + viewBounds.left + widthDelta, + viewCenterY - halfHandleHeight, + viewBounds.right - widthDelta, + viewCenterY + halfHandleHeight + ); + + float viewRadius = 0f; // Use 0 to not clip the new message dot or the app icon + float stashedRadius = stashedViewBounds.height() / 2f; + + return new RoundedRectRevealOutlineProvider(viewRadius, stashedRadius, viewBounds, + stashedViewBounds).createRevealAnimator(bubbleView, !isStashed, 0); + } + /** * Listener to receive updates about bubble bar bounds changing */ diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java index e00916af6c..a66df4c357 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java @@ -76,7 +76,14 @@ public class BubbleControllers { * in constructors for now, as some controllers may still be waiting for init(). */ public void init(TaskbarControllers taskbarControllers) { + // TODO(b/346381754) add TaskbarLauncherStateController implementation to adjust the hotseat + BubbleBarLocationCompositeListener bubbleBarLocationListeners = + new BubbleBarLocationCompositeListener( + taskbarControllers.navbarButtonsViewController, + taskbarControllers.taskbarViewController + ); bubbleBarController.init(this, + bubbleBarLocationListeners, taskbarControllers.navbarButtonsViewController::isImeVisible); bubbleStashedHandleViewController.ifPresent( controller -> controller.init(/* bubbleControllers = */ this)); @@ -102,7 +109,7 @@ public class BubbleControllers { }); bubbleDragController.init(/* bubbleControllers = */ this); bubbleDismissController.init(/* bubbleControllers = */ this); - bubbleBarPinController.init(this); + bubbleBarPinController.init(this, bubbleBarLocationListeners); bubblePinController.init(this); mPostInitRunnables.executeAllAndDestroy(); @@ -124,6 +131,7 @@ public class BubbleControllers { public void onDestroy() { bubbleStashedHandleViewController.ifPresent(BubbleStashedHandleViewController::onDestroy); bubbleBarController.onDestroy(); + bubbleBarViewController.onDestroy(); } /** Dumps bubble controllers state. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java index fdd385a796..3640c3b60e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java @@ -187,6 +187,13 @@ public class BubbleStashedHandleViewController { } /** + * Returns bounds of the stashed handle view + */ + public void getBounds(Rect bounds) { + bounds.set(mStashedHandleBounds); + } + + /** * Called when system ui state changes. Bubbles don't show when the device is locked. */ public void setHiddenForSysui(boolean hidden) { diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java index 591a9da5df..561df5c2ee 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java @@ -20,6 +20,7 @@ import android.app.Notification; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.Path; import android.graphics.Rect; import android.graphics.drawable.BitmapDrawable; @@ -110,6 +111,10 @@ public class BubbleView extends ConstraintLayout { setFocusable(true); setClickable(true); + + // We manage the shadow ourselves when creating the bitmap + setOutlineAmbientShadowColor(Color.TRANSPARENT); + setOutlineSpotShadowColor(Color.TRANSPARENT); } private void updateBubbleSizeAndDotRender() { @@ -152,16 +157,16 @@ public class BubbleView extends ConstraintLayout { applyDragTranslation(); } + private void applyDragTranslation() { + setTranslationX(mDragTranslationX + mOffsetX); + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); updateBubbleSizeAndDotRender(); } - private void applyDragTranslation() { - setTranslationX(mDragTranslationX + mOffsetX); - } - @Override public void dispatchDraw(Canvas canvas) { super.dispatchDraw(canvas); diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt index 99c50f248d..6a955d92a0 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt @@ -169,6 +169,8 @@ constructor( bubbleBarView.translationY = 0f bubbleBarView.scaleX = 1f bubbleBarView.scaleY = BUBBLE_ANIMATION_INITIAL_SCALE_Y + bubbleBarView.setBackgroundScaleX(1f) + bubbleBarView.setBackgroundScaleY(1f) bubbleBarView.relativePivotY = 0.5f // this is the offset between the center of the bubble bar and the center of the stash @@ -311,6 +313,7 @@ constructor( animatingBubble = null if (!canceled) bubbleStashController.stashBubbleBarImmediate() bubbleBarView.relativePivotY = 1f + bubbleBarView.scaleY = 1f bubbleStashController.updateTaskbarTouchRegion() } animator.start() diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt new file mode 100644 index 0000000000..4939c993e0 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt @@ -0,0 +1,59 @@ +/* + * 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.flyout + +import android.view.Gravity +import android.view.ViewGroup +import android.widget.FrameLayout +import com.android.launcher3.R + +/** Creates and manages the visibility of the [BubbleBarFlyoutView]. */ +class BubbleBarFlyoutController( + private val container: FrameLayout, + private val positioner: BubbleBarFlyoutPositioner, +) { + + private var flyout: BubbleBarFlyoutView? = null + 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, onLeft = positioner.isOnLeft) + + flyout.translationY = positioner.targetTy + + val lp = + FrameLayout.LayoutParams( + ViewGroup.LayoutParams.WRAP_CONTENT, + ViewGroup.LayoutParams.WRAP_CONTENT, + Gravity.BOTTOM or if (positioner.isOnLeft) Gravity.LEFT else Gravity.RIGHT, + ) + lp.marginStart = horizontalMargin + lp.marginEnd = horizontalMargin + container.addView(flyout, lp) + + flyout.setData(message) + this.flyout = flyout + } + + fun hideFlyout() { + val flyout = this.flyout ?: return + container.removeView(flyout) + this.flyout = null + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutMessage.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutMessage.kt new file mode 100644 index 0000000000..7298297d5c --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutMessage.kt @@ -0,0 +1,26 @@ +/* + * 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.flyout + +import android.graphics.drawable.Drawable + +data class BubbleBarFlyoutMessage( + val senderAvatar: Drawable?, + val senderName: CharSequence, + val message: CharSequence, + val isGroupChat: Boolean, +) diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutPositioner.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutPositioner.kt new file mode 100644 index 0000000000..deed1f5900 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutPositioner.kt @@ -0,0 +1,27 @@ +/* + * 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.flyout + +/** Provides positioning data to the flyout view. */ +interface BubbleBarFlyoutPositioner { + + /** Whether the flyout view should be positioned on left or the right edge. */ + val isOnLeft: Boolean + + /** The target translation Y that the flyout view should have when displayed. */ + val targetTy: Float +} diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt new file mode 100644 index 0000000000..4b91f461e9 --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt @@ -0,0 +1,195 @@ +/* + * 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.flyout + +import android.content.Context +import android.content.res.Configuration +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, private val onLeft: Boolean) : + ConstraintLayout(context) { + + private val sender: TextView by + lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_name) } + + private val avatar: ImageView by + lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_avatar) } + + private val message: TextView by + lazy(LazyThreadSafetyMode.NONE) { findViewById(R.id.bubble_flyout_text) } + + private val flyoutPadding by + lazy(LazyThreadSafetyMode.NONE) { + 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 + lazy(LazyThreadSafetyMode.NONE) { + context.resources.getDimensionPixelSize(R.dimen.bubblebar_flyout_max_width) + } + + private val cornerRadius: Float + private val triangle: Path = Path() + private var backgroundColor = Color.BLACK + + /** + * The paint used to draw the background, whose color changes as the flyout transitions to the + * tinted notification dot. + */ + private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG) + + init { + LayoutInflater.from(context).inflate(R.layout.bubblebar_flyout, this, true) + + val ta = context.obtainStyledAttributes(intArrayOf(android.R.attr.dialogCornerRadius)) + cornerRadius = ta.getDimensionPixelSize(0, 0).toFloat() + ta.recycle() + + setWillNotDraw(false) + clipChildren = false + clipToPadding = false + + 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) + } + + fun setData(flyoutMessage: BubbleBarFlyoutMessage) { + // the avatar is only displayed in group chat messages + if (flyoutMessage.senderAvatar != null && flyoutMessage.isGroupChat) { + avatar.visibility = VISIBLE + avatar.setImageDrawable(flyoutMessage.senderAvatar) + } else { + avatar.visibility = GONE + } + + 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 + } + + override fun onDraw(canvas: Canvas) { + canvas.drawRoundRect( + 0f, + 0f, + width.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 + val defaultBackgroundColor = if (isNightModeOn) Color.BLACK else Color.WHITE + val defaultTextColor = if (isNightModeOn) Color.WHITE else Color.BLACK + val ta = + context.obtainStyledAttributes( + intArrayOf( + com.android.internal.R.attr.materialColorSurfaceContainer, + com.android.internal.R.attr.materialColorOnSurface, + com.android.internal.R.attr.materialColorOnSurfaceVariant, + ) + ) + backgroundColor = ta.getColor(0, defaultBackgroundColor) + sender.setTextColor(ta.getColor(1, defaultTextColor)) + message.setTextColor(ta.getColor(2, defaultTextColor)) + ta.recycle() + backgroundPaint.color = backgroundColor + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt index 76ed3fc22a..9721792540 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt @@ -16,6 +16,7 @@ package com.android.launcher3.taskbar.bubbles.stashing +import android.graphics.Rect import android.view.InsetsController import android.view.MotionEvent import android.view.View @@ -146,6 +147,9 @@ interface BubbleStashController { /** Returns the translation of the handle. */ fun getHandleTranslationY(): Float? + /** Returns bounds of the handle */ + fun getHandleBounds(bounds: Rect) + /** * Returns bubble bar Y position according to [isBubblesShowingOnHome] and * [isBubblesShowingOnOverview] values. Default implementation only analyse @@ -179,9 +183,6 @@ interface BubbleStashController { /** How long to stash/unstash. */ const val BAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE.toLong() - const val BAR_STASH_ALPHA_DURATION = 50L - const val BAR_STASH_ALPHA_DELAY = 33L - /** How long to translate Y coordinate of the BubbleBar. */ const val BAR_TRANSLATION_DURATION = 300L } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt index eaf4bf9fc7..7d6f7adbbf 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt @@ -19,6 +19,7 @@ package com.android.launcher3.taskbar.bubbles.stashing import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.AnimatorSet +import android.graphics.Rect import android.view.MotionEvent import android.view.View import com.android.launcher3.anim.AnimatedFloat @@ -200,6 +201,10 @@ class PersistentBubbleStashController( override fun getHandleTranslationY(): Float? = null + override fun getHandleBounds(bounds: Rect) { + // no op since does not have a handle view + } + private fun updateExpandedState(expand: Boolean) { if (bubbleBarViewController.isHiddenForNoBubbles) { // If there are no bubbles the bar is invisible, nothing to do here. 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 6787b3fc40..4f0337ddc1 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt @@ -19,6 +19,7 @@ package com.android.launcher3.taskbar.bubbles.stashing import android.animation.Animator import android.animation.AnimatorSet import android.content.Context +import android.graphics.Rect import android.view.MotionEvent import android.view.View import androidx.annotation.VisibleForTesting @@ -31,10 +32,10 @@ import com.android.launcher3.R 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.bubbles.BubbleBarViewController import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController -import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_ALPHA_DELAY -import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_ALPHA_DURATION import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_DURATION import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_TRANSLATION_DURATION import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.ControllersAfterInitAction @@ -46,7 +47,7 @@ import kotlin.math.max class TransientBubbleStashController( private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider, - private val context: Context + private val context: Context, ) : BubbleStashController { private lateinit var bubbleBarViewController: BubbleBarViewController @@ -66,9 +67,12 @@ class TransientBubbleStashController( // bubble bar properties private lateinit var bubbleBarAlpha: MultiPropertyFactory<View>.MultiProperty + private lateinit var bubbleBarBubbleAlpha: AnimatedFloat + private lateinit var bubbleBarBackgroundAlpha: AnimatedFloat private lateinit var bubbleBarTranslationYAnimator: AnimatedFloat - private lateinit var bubbleBarScaleX: AnimatedFloat - private lateinit var bubbleBarScaleY: AnimatedFloat + private lateinit var bubbleBarBubbleTranslationY: AnimatedFloat + private lateinit var bubbleBarBackgroundScaleX: AnimatedFloat + private lateinit var bubbleBarBackgroundScaleY: AnimatedFloat private val handleCenterFromScreenBottom = context.resources.getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f @@ -140,17 +144,20 @@ class TransientBubbleStashController( taskbarInsetsController: TaskbarInsetsController, bubbleBarViewController: BubbleBarViewController, bubbleStashedHandleViewController: BubbleStashedHandleViewController?, - controllersAfterInitAction: ControllersAfterInitAction + controllersAfterInitAction: ControllersAfterInitAction, ) { this.taskbarInsetsController = taskbarInsetsController this.bubbleBarViewController = bubbleBarViewController this.bubbleStashedHandleViewController = bubbleStashedHandleViewController this.controllersAfterInitAction = controllersAfterInitAction bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY + bubbleBarBubbleTranslationY = bubbleBarViewController.bubbleOffsetY // bubble bar has only alpha property, getting it at index 0 bubbleBarAlpha = bubbleBarViewController.bubbleBarAlpha.get(/* index= */ 0) - bubbleBarScaleX = bubbleBarViewController.bubbleBarScaleX - bubbleBarScaleY = bubbleBarViewController.bubbleBarScaleY + bubbleBarBubbleAlpha = bubbleBarViewController.bubbleBarBubbleAlpha + bubbleBarBackgroundAlpha = bubbleBarViewController.bubbleBarBackgroundAlpha + bubbleBarBackgroundScaleX = bubbleBarViewController.bubbleBarBackgroundScaleX + bubbleBarBackgroundScaleY = bubbleBarViewController.bubbleBarBackgroundScaleY stashedHeight = bubbleStashedHandleViewController?.stashedHeight ?: 0 stashHandleViewAlpha = bubbleStashedHandleViewController?.stashedHandleAlpha?.get(0) } @@ -160,10 +167,12 @@ class TransientBubbleStashController( if (isBubblesShowingOnHome || isBubblesShowingOnOverview) { isStashed = false animatorSet.playTogether( - bubbleBarScaleX.animateToValue(1f), - bubbleBarScaleY.animateToValue(1f), + bubbleBarBackgroundScaleX.animateToValue(1f), + bubbleBarBackgroundScaleY.animateToValue(1f), bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY), - bubbleBarAlpha.animateToValue(1f) + bubbleBarAlpha.animateToValue(1f), + bubbleBarBubbleAlpha.animateToValue(1f), + bubbleBarBackgroundAlpha.animateToValue(1f), ) } else { isStashed = true @@ -181,8 +190,10 @@ class TransientBubbleStashController( stashHandleViewAlpha?.value = 0f this.bubbleBarTranslationYAnimator.updateValue(bubbleBarTranslationY) bubbleBarAlpha.setValue(1f) - bubbleBarScaleX.updateValue(1f) - bubbleBarScaleY.updateValue(1f) + bubbleBarBubbleAlpha.updateValue(1f) + bubbleBarBackgroundAlpha.updateValue(1f) + bubbleBarBackgroundScaleX.updateValue(1f) + bubbleBarBackgroundScaleY.updateValue(1f) isStashed = false onIsStashedChanged() } @@ -192,8 +203,11 @@ class TransientBubbleStashController( stashHandleViewAlpha?.value = 1f this.bubbleBarTranslationYAnimator.updateValue(getStashTranslation()) bubbleBarAlpha.setValue(0f) - bubbleBarScaleX.updateValue(getStashScaleX()) - bubbleBarScaleY.updateValue(getStashScaleY()) + // Reset bubble and background alpha to 1 and only keep the bubble bar alpha at 0 + bubbleBarBubbleAlpha.updateValue(1f) + bubbleBarBackgroundAlpha.updateValue(1f) + bubbleBarBackgroundScaleX.updateValue(getStashScaleX()) + bubbleBarBackgroundScaleY.updateValue(getStashScaleY()) isStashed = true onIsStashedChanged() } @@ -258,8 +272,12 @@ class TransientBubbleStashController( override fun getHandleTranslationY(): Float? = bubbleStashedHandleViewController?.translationY + override fun getHandleBounds(bounds: Rect) { + bubbleStashedHandleViewController?.getBounds(bounds) + } + private fun getStashTranslation(): Float { - return bubbleBarTranslationY / 2f + return (bubbleBarTranslationY - stashedHeight) / 2f } @VisibleForTesting @@ -285,10 +303,10 @@ class TransientBubbleStashController( private fun createStashAnimator(isStashed: Boolean, duration: Long): AnimatorSet { val animatorSet = AnimatorSet() - val alphaDuration = if (isStashed) duration else BAR_STASH_ALPHA_DURATION - val alphaDelay = if (isStashed) BAR_STASH_ALPHA_DELAY else 0L animatorSet.play( - createStashAlphaAnimator(isStashed).apply { + createBackgroundAlphaAnimator(isStashed).apply { + val alphaDuration = if (isStashed) duration else TASKBAR_STASH_ALPHA_DURATION + val alphaDelay = if (isStashed) TASKBAR_STASH_ALPHA_START_DELAY else 0L this.duration = max(0L, alphaDuration - alphaDelay) this.startDelay = alphaDelay this.interpolator = LINEAR @@ -296,6 +314,16 @@ class TransientBubbleStashController( ) animatorSet.play( + bubbleBarBubbleAlpha + .animateToValue(getBarAlphaStart(isStashed), getBarAlphaEnd(isStashed)) + .apply { + this.duration = TASKBAR_STASH_ALPHA_DURATION + this.startDelay = TASKBAR_STASH_ALPHA_START_DELAY + this.interpolator = LINEAR + } + ) + + animatorSet.play( createSpringOnStashAnimator(isStashed).apply { this.duration = duration this.interpolator = LINEAR @@ -303,6 +331,23 @@ class TransientBubbleStashController( ) animatorSet.play( + bubbleBarViewController.createRevealAnimatorForStashChange(isStashed).apply { + this.duration = duration + this.interpolator = EMPHASIZED + } + ) + + // Animate bubble translation to keep reveal animation in the bounds of the bar + val bubbleTyStart = if (isStashed) 0f else -bubbleBarTranslationY + val bubbleTyEnd = if (isStashed) -bubbleBarTranslationY else 0f + animatorSet.play( + bubbleBarBubbleTranslationY.animateToValue(bubbleTyStart, bubbleTyEnd).apply { + this.duration = duration + this.interpolator = EMPHASIZED + } + ) + + animatorSet.play( bubbleStashedHandleViewController?.createRevealAnimToIsStashed(isStashed)?.apply { this.duration = duration this.interpolator = EMPHASIZED @@ -326,10 +371,28 @@ class TransientBubbleStashController( } ) + animatorSet.doOnStart { + // Update the start value for bubble view and background alpha when the entire animation + // begins. + // Alpha animation has a delay, and if we set the initial values at the start of the + // alpha animation, it will cause flickers. + bubbleBarBubbleAlpha.updateValue(getBarAlphaStart(isStashed)) + bubbleBarBackgroundAlpha.updateValue(getBarAlphaStart(isStashed)) + // We animate alpha for background and bubble views separately. Make sure the container + // is always visible. + bubbleBarAlpha.value = 1f + } animatorSet.doOnEnd { animator = null controllersAfterInitAction.runAfterInit { if (isStashed) { + bubbleBarAlpha.value = 0f + // reset bubble view alpha + bubbleBarBubbleAlpha.updateValue(1f) + bubbleBarBackgroundAlpha.updateValue(1f) + // reset stash translation + translationYDuringStash.updateValue(0f) + bubbleBarBubbleTranslationY.updateValue(0f) bubbleBarViewController.isExpanded = false } taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged() @@ -338,15 +401,30 @@ class TransientBubbleStashController( return animatorSet } - private fun createStashAlphaAnimator(isStashed: Boolean): AnimatorSet { - val stashHandleAlphaTarget = if (isStashed) 1f else 0f - val barAlphaTarget = if (isStashed) 0f else 1f + private fun createBackgroundAlphaAnimator(isStashed: Boolean): AnimatorSet { return AnimatorSet().apply { - play(bubbleBarAlpha.animateToValue(barAlphaTarget)) - play(stashHandleViewAlpha?.animateToValue(stashHandleAlphaTarget)) + play( + bubbleBarBackgroundAlpha.animateToValue( + getBarAlphaStart(isStashed), + getBarAlphaEnd(isStashed), + ) + ) + play(stashHandleViewAlpha?.animateToValue(getHandleAlphaEnd(isStashed))) } } + private fun getBarAlphaStart(isStashed: Boolean): Float { + return if (isStashed) 1f else 0f + } + + private fun getBarAlphaEnd(isStashed: Boolean): Float { + return if (isStashed) 0f else 1f + } + + private fun getHandleAlphaEnd(isStashed: Boolean): Float { + return if (isStashed) 1f else 0f + } + private fun createSpringOnStashAnimator(isStashed: Boolean): Animator { if (!isStashed) { // Animate the stash translation back to 0 @@ -366,8 +444,8 @@ class TransientBubbleStashController( val scaleXTarget = if (isStashed) getStashScaleX() else 1f val scaleYTarget = if (isStashed) getStashScaleY() else 1f return AnimatorSet().apply { - play(bubbleBarScaleX.animateToValue(scaleXTarget)) - play(bubbleBarScaleY.animateToValue(scaleYTarget)) + play(bubbleBarBackgroundScaleX.animateToValue(scaleXTarget)) + play(bubbleBarBackgroundScaleY.animateToValue(scaleYTarget)) } } diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt index 726800c2da..e6c0b2f087 100644 --- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt +++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarAllAppsButtonContainer.kt @@ -30,7 +30,6 @@ import androidx.annotation.DrawableRes import androidx.core.view.setPadding import com.android.launcher3.R import com.android.launcher3.Utilities.dpToPx -import com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning import com.android.launcher3.taskbar.TaskbarActivityContext import com.android.launcher3.taskbar.TaskbarViewCallbacks @@ -43,11 +42,8 @@ import com.android.quickstep.util.AssistStateManager /** Taskbar all apps button container for customizable taskbar. */ class TaskbarAllAppsButtonContainer @JvmOverloads -constructor( - context: Context, - attrs: AttributeSet? = null, - defStyleAttr: Int = 0, -) : IconButtonView(context, attrs), TaskbarContainer { +constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : + IconButtonView(context, attrs), TaskbarContainer { private val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context) private var allAppsTouchTriggered = false @@ -101,23 +97,16 @@ constructor( private fun getAllAppsButton(isTransientTaskbar: Boolean): Int { val shouldSelectTransientIcon = isTransientTaskbar || (enableTaskbarPinning() && !activityContext.isThreeButtonNav) - return if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) { - if (shouldSelectTransientIcon) R.drawable.ic_transient_taskbar_all_apps_search_button - else R.drawable.ic_taskbar_all_apps_search_button - } else { - if (shouldSelectTransientIcon) R.drawable.ic_transient_taskbar_all_apps_button - else R.drawable.ic_taskbar_all_apps_button - } + return if (shouldSelectTransientIcon) R.drawable.ic_transient_taskbar_all_apps_search_button + else R.drawable.ic_taskbar_all_apps_search_button } @DimenRes fun getAllAppsButtonTranslationXOffset(isTransientTaskbar: Boolean): Int { return if (isTransientTaskbar) { R.dimen.transient_taskbar_all_apps_button_translation_x_offset - } else if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) { - R.dimen.taskbar_all_apps_search_button_translation_x_offset } else { - R.dimen.taskbar_all_apps_button_translation_x_offset + R.dimen.taskbar_all_apps_search_button_translation_x_offset } } diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt index c83ac5097e..7739a0e3df 100644 --- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt +++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarFeatureEvaluator.kt @@ -26,23 +26,6 @@ class TaskbarFeatureEvaluator private constructor( private val taskbarActivityContext: TaskbarActivityContext, ) { - - companion object { - @Volatile private lateinit var taskbarFeatureEvaluator: TaskbarFeatureEvaluator - - @JvmStatic - fun getInstance( - taskbarActivityContext: TaskbarActivityContext, - ): TaskbarFeatureEvaluator { - synchronized(this) { - if (!::taskbarFeatureEvaluator.isInitialized) { - taskbarFeatureEvaluator = TaskbarFeatureEvaluator(taskbarActivityContext) - } - return taskbarFeatureEvaluator - } - } - } - val hasAllApps = true val hasAppIcons = true val hasBubbles = false @@ -59,4 +42,24 @@ private constructor( val isLandscape: Boolean get() = taskbarActivityContext.deviceProfile.isLandscape + + fun onDestroy() { + taskbarFeatureEvaluator = null + } + + companion object { + @Volatile private var taskbarFeatureEvaluator: TaskbarFeatureEvaluator? = null + + @JvmStatic + fun getInstance( + taskbarActivityContext: TaskbarActivityContext, + ): TaskbarFeatureEvaluator { + synchronized(this) { + if (taskbarFeatureEvaluator == null) { + taskbarFeatureEvaluator = TaskbarFeatureEvaluator(taskbarActivityContext) + } + return taskbarFeatureEvaluator!! + } + } + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt index 6be0828e0f..e55cb1f50d 100644 --- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt +++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarIconSpecs.kt @@ -37,6 +37,8 @@ object TaskbarIconSpecs { val minimumTaskbarIconTouchSize = TaskbarIconSize(48) + val transientOrPinnedTaskbarIconPaddingSize = iconSize52dp + val transientTaskbarIconSizeByGridSize = mapOf( TransientTaskbarIconSizeKey(6, 5, false) to iconSize52dp, diff --git a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt index f37b2c15bf..822ca6460f 100644 --- a/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt +++ b/quickstep/src/com/android/launcher3/taskbar/customization/TaskbarSpecsEvaluator.kt @@ -31,7 +31,10 @@ class TaskbarSpecsEvaluator( private var taskbarContainer: List<TaskbarContainer> = emptyList() val taskbarIconPadding: Int = - if (TaskbarIconSpecs.iconSize52dp.size > taskbarIconSize.size) { + if ( + TaskbarIconSpecs.transientOrPinnedTaskbarIconPaddingSize.size > taskbarIconSize.size && + !taskbarFeatureEvaluator.hasNavButtons + ) { (TaskbarIconSpecs.iconSize52dp.size - taskbarIconSize.size) / 2 } else { 0 diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java index 039c0a0ad8..26a1322ea6 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepInteractionHandler.java @@ -22,7 +22,6 @@ import android.app.ActivityOptions; import android.app.ActivityTaskManager; import android.app.PendingIntent; import android.content.Intent; -import android.os.IBinder; import android.os.RemoteException; import android.util.Log; import android.util.Pair; @@ -30,7 +29,6 @@ import android.view.View; 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,14 +64,8 @@ class QuickstepInteractionHandler implements RemoteViews.InteractionHandler { } Pair<Intent, ActivityOptions> options = remoteResponse.getLaunchOptions(view); ActivityOptionsWrapper activityOptions = mLauncher.getAppTransitionManager() - .getActivityLaunchOptions(hostView); - Object itemInfo = hostView.getTag(); - IBinder launchCookie = null; - if (itemInfo instanceof ItemInfo) { - launchCookie = mLauncher.getLaunchCookie((ItemInfo) itemInfo); - activityOptions.options.setLaunchCookie(launchCookie); - } - if (Utilities.ATLEAST_S && !pendingIntent.isActivity()) { + .getActivityLaunchOptions(hostView, (ItemInfo) hostView.getTag()); + if (!pendingIntent.isActivity()) { // In the event this pending intent eventually launches an activity, i.e. a trampoline, // use the Quickstep transition animation. try { @@ -81,7 +73,7 @@ class QuickstepInteractionHandler implements RemoteViews.InteractionHandler { .registerRemoteAnimationForNextActivityStart( pendingIntent.getCreatorPackage(), activityOptions.options.getRemoteAnimationAdapter(), - launchCookie); + activityOptions.options.getLaunchCookie()); } catch (RemoteException e) { // Do nothing. } @@ -92,7 +84,7 @@ class QuickstepInteractionHandler implements RemoteViews.InteractionHandler { ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED); options = Pair.create(options.first, activityOptions.options); if (pendingIntent.isActivity()) { - logAppLaunch(itemInfo); + logAppLaunch(hostView.getTag()); } return RemoteViews.startPendingIntent(hostView, pendingIntent, options); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 55c1885793..e80e838e90 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.app.ActivityTaskManager.INVALID_TASK_ID; 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; @@ -41,7 +42,6 @@ import static com.android.launcher3.config.FeatureFlags.enableSplitContextually; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED; -import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition; import static com.android.launcher3.popup.SystemShortcut.APP_INFO; import static com.android.launcher3.popup.SystemShortcut.BUBBLE_SHORTCUT; @@ -64,7 +64,6 @@ import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.QUICK_SWITCH_FROM_HOME_FALLBACK; import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback; import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT; -import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY; import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50; @@ -83,7 +82,6 @@ import android.hardware.display.DisplayManager; import android.media.permission.SafeCloseable; import android.os.Build; import android.os.Bundle; -import android.os.IBinder; import android.os.IRemoteCallback; import android.os.SystemProperties; import android.os.Trace; @@ -229,7 +227,6 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, private FixedContainerItems mAllAppsPredictions; private HotseatPredictionController mHotseatPredictionController; private DepthController mDepthController; - private @Nullable DesktopVisibilityController mDesktopVisibilityController; private QuickstepTransitionManager mAppTransitionManager; private OverviewActionsView<?> mActionsView; @@ -303,8 +300,6 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, mTISBindHelper = new TISBindHelper(this, this::onTISConnected); mDepthController = new DepthController(this); if (DesktopModeStatus.canEnterDesktopMode(this)) { - mDesktopVisibilityController = new DesktopVisibilityController(this); - mDesktopVisibilityController.registerSystemUiListener(); mSplitSelectStateController.initSplitFromDesktopController(this, overviewComponentObserver); } @@ -556,10 +551,6 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, mLauncherUnfoldAnimationController.onDestroy(); } - if (mDesktopVisibilityController != null) { - mDesktopVisibilityController.unregisterSystemUiListener(); - } - if (mSplitSelectStateController != null) { mSplitSelectStateController.onDestroy(); } @@ -610,7 +601,7 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, .append(" is missing."), QUICK_SWITCH_FROM_HOME_FALLBACK); } - taskToLaunch.launchTask(success -> { + taskToLaunch.launchWithoutAnimation(success -> { if (!success) { getStateManager().goToState(OVERVIEW); } else { @@ -701,9 +692,7 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, } addMultiWindowModeChangedListener(mDepthController); initUnfoldTransitionProgressProvider(); - if (FeatureFlags.CONTINUOUS_VIEW_TREE_CAPTURE.get()) { - mViewCapture = ViewCaptureFactory.getInstance(this).startCapture(getWindow()); - } + mViewCapture = ViewCaptureFactory.getInstance(this).startCapture(getWindow()); getWindow().addPrivateFlags(PRIVATE_FLAG_OPTIMIZE_MEASURE); QuickstepOnboardingPrefs.setup(this); View.setTraceLayoutSteps(TRACE_LAYOUTS); @@ -1013,10 +1002,11 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, @Override public void setResumed() { - if (!WALLPAPER_ACTIVITY.isEnabled(this) - && mDesktopVisibilityController != null - && mDesktopVisibilityController.areDesktopTasksVisible() - && !mDesktopVisibilityController.isRecentsGestureInProgress()) { + DesktopVisibilityController desktopVisibilityController = getDesktopVisibilityController(); + if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue() + && desktopVisibilityController != null + && desktopVisibilityController.areDesktopTasksVisible() + && !desktopVisibilityController.isRecentsGestureInProgress()) { // Return early to skip setting activity to appear as resumed // TODO: b/333533253 - Remove after flag rollout return; @@ -1156,8 +1146,9 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, } @Nullable + @Override public DesktopVisibilityController getDesktopVisibilityController() { - return mDesktopVisibilityController; + return mTISBindHelper.getDesktopVisibilityController(); } @Nullable @@ -1192,7 +1183,8 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, @Override public ActivityOptionsWrapper getActivityLaunchOptions(View v, @Nullable ItemInfo item) { - ActivityOptionsWrapper activityOptions = mAppTransitionManager.getActivityLaunchOptions(v); + ActivityOptionsWrapper activityOptions = mAppTransitionManager.getActivityLaunchOptions( + v, item != null ? item : (ItemInfo) v.getTag()); if (mLastTouchUpTime > 0) { activityOptions.options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_LAUNCHER, mLastTouchUpTime); @@ -1232,43 +1224,6 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, mSplitWithKeyboardShortcutController.enterStageSplit(leftOrTop); } - /** - * Return a new launch cookie for the activity launch if supported. - * - * @param info the item info for the launch - */ - public IBinder getLaunchCookie(ItemInfo info) { - if (info == null) { - return null; - } - switch (info.container) { - case Favorites.CONTAINER_DESKTOP: - case Favorites.CONTAINER_HOTSEAT: - case Favorites.CONTAINER_PRIVATESPACE: - // Fall through and continue it's on the workspace (we don't support swiping back - // to other containers like all apps or the hotseat predictions (which can change) - break; - default: - if (info.container >= 0) { - // Also allow swiping to folders - break; - } - // Reset any existing launch cookies associated with the cookie - return ObjectWrapper.wrap(NO_MATCHING_ID); - } - switch (info.itemType) { - case Favorites.ITEM_TYPE_APPLICATION: - case Favorites.ITEM_TYPE_DEEP_SHORTCUT: - case Favorites.ITEM_TYPE_APPWIDGET: - // Fall through and continue if it's an app, shortcut, or widget - break; - default: - // Reset any existing launch cookies associated with the cookie - return ObjectWrapper.wrap(NO_MATCHING_ID); - } - return ObjectWrapper.wrap(new Integer(info.id)); - } - @Override public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) { super.onDisplayInfoChanged(context, info, flags); @@ -1347,8 +1302,9 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, @Override public boolean areDesktopTasksVisible() { - if (mDesktopVisibilityController != null) { - return mDesktopVisibilityController.areDesktopTasksVisible(); + DesktopVisibilityController desktopVisibilityController = getDesktopVisibilityController(); + if (desktopVisibilityController != null) { + return desktopVisibilityController.areDesktopTasksVisible(); } return false; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java index fa80dc2776..030a7acb48 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java @@ -26,7 +26,6 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.Themes; import com.android.launcher3.views.ActivityContext; import com.android.quickstep.util.BaseDepthController; @@ -202,17 +201,6 @@ public class AllAppsState extends LauncherState { } @Override - public float[] getOverviewScaleAndOffset(Launcher launcher) { - if (!FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get()) { - return super.getOverviewScaleAndOffset(launcher); - } - // This handles the case of returning to the previous app from Overview -> All Apps gesture. - // This is the start scale/offset of overview that will be used for that transition. - // TODO (b/283336332): Translate in Y direction (ideally with overview resistance). - return new float[] {0.5f /* scale */, NO_OFFSET}; - } - - @Override public int getWorkspaceScrimColor(Launcher launcher) { return launcher.getDeviceProfile().isTablet ? launcher.getResources().getColor(R.color.widgets_picker_scrim) diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java index 1ba784bb6e..18d717f096 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java @@ -50,9 +50,11 @@ public class BackgroundAppState extends OverviewState { return super.getVerticalProgress(launcher); } RecentsView recentsView = launcher.getOverviewPanel(); - int transitionLength = LayoutUtils.getShelfTrackingDistance(launcher, + int transitionLength = LayoutUtils.getShelfTrackingDistance( + launcher, launcher.getDeviceProfile(), - recentsView.getPagedOrientationHandler()); + recentsView.getPagedOrientationHandler(), + recentsView.getSizeStrategy()); AllAppsTransitionController controller = launcher.getAllAppsController(); float scrollRange = Math.max(controller.getShiftRange(), 1); float progressDelta = (transitionLength / scrollRange); diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java index 6822f1b39c..b165cddfb2 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java @@ -209,7 +209,7 @@ public class OverviewState extends LauncherState { TaskView taskView = recentsView.getRunningTaskView(); if (taskView != null) { if (recentsView.isTaskViewFullyVisible(taskView)) { - taskView.launchTasks(); + taskView.launchWithAnimation(); } else { recentsView.snapToPage(recentsView.indexOfChild(taskView)); } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java index 11e0ed528c..1d9e49201d 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.AnimatorPlaybackController; 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.TaskUtils; 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 @@ public class NavBarToHomeTouchController implements TouchController, } 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/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java index d1aa4728e8..ff726e65d4 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java @@ -42,7 +42,6 @@ import com.android.internal.jank.Cuj; import com.android.launcher3.LauncherState; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.taskbar.LauncherTaskbarUIController; import com.android.launcher3.uioverrides.QuickstepLauncher; @@ -221,11 +220,6 @@ public class NoButtonNavbarToOverviewTouchController extends PortraitStatesTouch mCancelSplitRunnable.accept(animatorSet, duration); animatorSet.start(); } - if (FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() && - ((mFromState == NORMAL && mToState == ALL_APPS) - || (mFromState == ALL_APPS && mToState == NORMAL)) && isFling) { - mVibratorWrapper.vibrateForDragBump(); - } } private void onMotionPauseDetected() { diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java index 0da7b2da37..9164405f1a 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java @@ -129,7 +129,10 @@ public class NoButtonQuickSwitchTouchController implements TouchController, mRecentsView = mLauncher.getOverviewPanel(); mXRange = mLauncher.getDeviceProfile().widthPx / 2f; mYRange = LayoutUtils.getShelfTrackingDistance( - mLauncher, mLauncher.getDeviceProfile(), mRecentsView.getPagedOrientationHandler()); + mLauncher, + mLauncher.getDeviceProfile(), + mRecentsView.getPagedOrientationHandler(), + mRecentsView.getSizeStrategy()); mMaxYProgress = mLauncher.getDeviceProfile().heightPx / mYRange; mMotionPauseDetector = new MotionPauseDetector(mLauncher); mMotionPauseMinDisplacement = mLauncher.getResources().getDimension( diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java index b5914a1880..b562838091 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -29,7 +29,6 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.allapps.AllAppsTransitionController; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.AllAppsSwipeController; @@ -93,9 +92,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr @Override protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { if (fromState == ALL_APPS && !isDragTowardPositive) { - return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get() - ? mLauncher.getStateManager().getLastState() - : NORMAL; + return NORMAL; } else if (fromState == NORMAL && shouldOpenAllApps(isDragTowardPositive)) { return ALL_APPS; } @@ -145,8 +142,11 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr .createPlaybackController(); mLauncher.getStateManager().setCurrentUserControlledAnimation(mCurrentAnimation); RecentsView recentsView = mLauncher.getOverviewPanel(); - totalShift = LayoutUtils.getShelfTrackingDistance(mLauncher, - mLauncher.getDeviceProfile(), recentsView.getPagedOrientationHandler()); + totalShift = LayoutUtils.getShelfTrackingDistance( + mLauncher, + mLauncher.getDeviceProfile(), + recentsView.getPagedOrientationHandler(), + recentsView.getSizeStrategy()); } else { mCurrentAnimation = mLauncher.getStateManager() .createAnimationToNewWorkspace(mToState, config); diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 38d08e0d6e..a6d651c951 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -45,7 +45,6 @@ import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK; import static com.android.launcher3.util.VibratorWrapper.OVERVIEW_HAPTIC; import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs; -import static com.android.quickstep.GestureState.GestureEndTarget.ALL_APPS; 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; @@ -93,6 +92,7 @@ import android.view.WindowInsets; 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; @@ -153,7 +153,6 @@ import com.android.systemui.shared.system.SysUiStatsLog; 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; @@ -193,7 +192,6 @@ public abstract class AbsSwipeUpHandler< // Null if the recents animation hasn't started yet or has been canceled or finished. protected @Nullable RecentsAnimationController mRecentsAnimationController; - protected @Nullable RecentsAnimationController mDeferredCleanupRecentsAnimationController; protected RecentsAnimationTargets mRecentsAnimationTargets; protected @Nullable RECENTS_CONTAINER mContainer; protected @Nullable RECENTS_VIEW mRecentsView; @@ -265,8 +263,6 @@ public abstract class AbsSwipeUpHandler< getNextStateFlag("STATE_CURRENT_TASK_FINISHED"); private static final int STATE_FINISH_WITH_NO_END = getNextStateFlag("STATE_FINISH_WITH_NO_END"); - private static final int STATE_SETTLED_ON_ALL_APPS = - getNextStateFlag("STATE_SETTLED_ON_ALL_APPS"); private static final int LAUNCHER_UI_STATES = STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED | @@ -320,7 +316,6 @@ public abstract class AbsSwipeUpHandler< private boolean mGestureStarted; private boolean mLogDirectionUpOrLeft = true; private boolean mIsLikelyToStartNewTask; - private boolean mIsInAllAppsRegion; private final long mTouchTimeMs; private long mLauncherFrameDrawnTime; @@ -457,9 +452,6 @@ public abstract class AbsSwipeUpHandler< this::finishCurrentTransitionToHome); mStateCallback.runOnceAtState(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED, this::reset); - mStateCallback.runOnceAtState(STATE_SETTLED_ON_ALL_APPS | STATE_SCREENSHOT_CAPTURED - | STATE_GESTURE_COMPLETED, - this::finishCurrentTransitionToAllApps); mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED | STATE_LAUNCHER_DRAWN | STATE_SCALED_CONTROLLER_RECENTS @@ -540,14 +532,7 @@ public abstract class AbsSwipeUpHandler< HashMap<Integer, ThumbnailData> snapshots = mGestureState.consumeRecentsAnimationCanceledSnapshot(); if (snapshots != null) { - mRecentsView.switchToScreenshot(snapshots, () -> { - if (mRecentsAnimationController != null) { - mRecentsAnimationController.cleanupScreenshot(); - } else if (mDeferredCleanupRecentsAnimationController != null) { - mDeferredCleanupRecentsAnimationController.cleanupScreenshot(); - mDeferredCleanupRecentsAnimationController = null; - } - }); + mRecentsView.switchToScreenshot(snapshots, () -> {}); mRecentsView.onRecentsAnimationComplete(); } }); @@ -724,9 +709,7 @@ public abstract class AbsSwipeUpHandler< maybeUpdateRecentsAttachedState(true/* animate */, true/* moveRunningTask */); Optional.ofNullable(mContainerInterface.getTaskbarController()) .ifPresent(TaskbarUIController::startTranslationSpring); - if (!mIsInAllAppsRegion) { - performHapticFeedback(); - } + performHapticFeedback(); } @Override @@ -774,9 +757,7 @@ public abstract class AbsSwipeUpHandler< .findTask(mGestureState.getTopRunningTaskId()) : null; final boolean recentsAttachedToAppWindow; - if (mIsInAllAppsRegion) { - recentsAttachedToAppWindow = false; - } else if (mGestureState.getEndTarget() != null) { + if (mGestureState.getEndTarget() != null) { recentsAttachedToAppWindow = mGestureState.getEndTarget().recentsAttachedToAppWindow; } else if (mContinuingLastGesture && mRecentsView.getRunningTaskIndex() != mRecentsView.getNextPage()) { @@ -833,31 +814,6 @@ public abstract class AbsSwipeUpHandler< } } - /** - * Update whether user is currently dragging in a region that will trigger all apps. - */ - private void setIsInAllAppsRegion(boolean isInAllAppsRegion) { - if (mIsInAllAppsRegion == isInAllAppsRegion - || !mContainerInterface.allowAllAppsFromOverview()) { - return; - } - mIsInAllAppsRegion = isInAllAppsRegion; - - // Newly entering or exiting the zone - do haptic and animate recent tasks. - VibratorWrapper.INSTANCE.get(mContext).vibrate(OVERVIEW_HAPTIC); - maybeUpdateRecentsAttachedState(true); - - if (mContainer != null) { - mContainer.getAppsView().getSearchUiManager() - .prepareToFocusEditText(mIsInAllAppsRegion); - } - - // Draw active task below Launcher so that All Apps can appear over it. - runActionOnRemoteHandles(remoteTargetHandle -> - remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(isInAllAppsRegion)); - } - - private void buildAnimationController() { if (!canCreateNewOrUpdateExistingLauncherTransitionController()) { return; @@ -917,8 +873,6 @@ public abstract class AbsSwipeUpHandler< @UiThread @Override public void onCurrentShiftUpdated() { - float threshold = DeviceConfigWrapper.get().getAllAppsOverviewThreshold() / 100f; - setIsInAllAppsRegion(mCurrentShift.value >= threshold); updateSysUiFlags(mCurrentShift.value); applyScrollAndTransform(); @@ -1025,9 +979,6 @@ public abstract class AbsSwipeUpHandler< /* event= */ "cancelRecentsAnimation", /* gestureEvent= */ CANCEL_RECENTS_ANIMATION); mActivityInitListener.unregister("AbsSwipeUpHandler.onRecentsAnimationCanceled"); - // Cache the recents animation controller so we can defer its cleanup to after having - // properly cleaned up the screenshot without accidentally using it. - mDeferredCleanupRecentsAnimationController = mRecentsAnimationController; mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED); // Defer clearing the controller and the targets until after we've updated the state mRecentsAnimationController = null; @@ -1203,9 +1154,6 @@ public abstract class AbsSwipeUpHandler< } switch (endTarget) { - case ALL_APPS: - mStateCallback.setState(STATE_SETTLED_ON_ALL_APPS | STATE_CAPTURE_SCREENSHOT); - break; case HOME: mStateCallback.setState(STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT); // Notify the SysUI to use fade-in animation when entering PiP @@ -1308,8 +1256,8 @@ public abstract class AbsSwipeUpHandler< ? 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) { @@ -1324,9 +1272,6 @@ public abstract class AbsSwipeUpHandler< final boolean willGoToNewTask = isScrollingToNewTask() && Math.abs(velocity.x) > Math.abs(endVelocity); final boolean isSwipeUp = endVelocity < 0; - if (mIsInAllAppsRegion) { - return isSwipeUp ? ALL_APPS : LAST_TASK; - } if (!isSwipeUp) { final boolean isCenteredOnNewTask = mRecentsView != null && mRecentsView.getDestinationPage() != mRecentsView.getRunningTaskIndex(); @@ -1342,9 +1287,7 @@ public abstract class AbsSwipeUpHandler< // Fully gestural mode. final boolean isFlingX = Math.abs(velocity.x) > mContext.getResources() .getDimension(R.dimen.quickstep_fling_threshold_speed); - if (mIsInAllAppsRegion) { - return ALL_APPS; - } else if (isScrollingToNewTask && isFlingX) { + if (isScrollingToNewTask && isFlingX) { // Flinging towards new task takes precedence over mIsMotionPaused (which only // checks y-velocity). return NEW_TASK; @@ -1399,8 +1342,7 @@ public abstract class AbsSwipeUpHandler< .setUserIsNotGoingHome(endTarget != GestureState.GestureEndTarget.HOME); } - float endShift = endTarget == ALL_APPS ? mDragLengthFactor - : endTarget.isLauncher ? 1 : 0; + float endShift = endTarget.isLauncher ? 1 : 0; final float startShift; if (!isFling) { long expectedDuration = Math.abs(Math.round((endShift - currentShift) @@ -1481,8 +1423,8 @@ public abstract class AbsSwipeUpHandler< }; 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 @@ -2027,12 +1969,6 @@ public abstract class AbsSwipeUpHandler< reset(); } - @UiThread - private void finishCurrentTransitionToAllApps() { - finishCurrentTransitionToHome(); - reset(); - } - private void reset() { mStateCallback.setStateOnUiThread(STATE_HANDLER_INVALIDATED); if (mContainer != null) { @@ -2174,7 +2110,6 @@ public abstract class AbsSwipeUpHandler< private void updateThumbnail() { if (mGestureState.getEndTarget() == HOME || mGestureState.getEndTarget() == NEW_TASK - || mGestureState.getEndTarget() == ALL_APPS || mRecentsView == null) { // Capture the screenshot before finishing the transition to home or quickswitching to // ensure it's taken in the correct orientation, but no need to update the thumbnail. @@ -2314,8 +2249,8 @@ public abstract class AbsSwipeUpHandler< }); 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; @@ -2370,7 +2305,7 @@ public abstract class AbsSwipeUpHandler< ActiveGestureLog.INSTANCE.trackEvent(EXPECTING_TASK_APPEARED); } ActiveGestureLog.INSTANCE.addLog(nextTaskLog); - nextTask.launchTask(success -> { + nextTask.launchWithoutAnimation(true, success -> { resultCallback.accept(success); if (success) { if (hasTaskPreviouslyAppeared) { @@ -2383,7 +2318,7 @@ public abstract class AbsSwipeUpHandler< } } return Unit.INSTANCE; - }, true /* freezeTaskList */); + } /* freezeTaskList */); } else { mContainerInterface.onLaunchTaskFailed(); Toast.makeText(mContext, R.string.activity_not_available, LENGTH_SHORT).show(); diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java index 777761b0a3..bf3a662c4a 100644 --- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java +++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java @@ -74,9 +74,6 @@ public abstract class BaseContainerInterface<STATE_TYPE extends BaseState<STATE_ public abstract boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev); - /** @return whether to allow going to All Apps from Overview. */ - public abstract boolean allowAllAppsFromOverview(); - /** * Returns the color of the scrim behind overview when at rest in this state. * Return {@link Color#TRANSPARENT} for no scrim. @@ -131,7 +128,9 @@ public abstract class BaseContainerInterface<STATE_TYPE extends BaseState<STATE_ @Nullable public DesktopVisibilityController getDesktopVisibilityController() { - return null; + CONTAINER_TYPE container = getCreatedContainer(); + + return container == null ? null : container.getDesktopVisibilityController(); } /** diff --git a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt index 904ed69dc1..f610014a34 100644 --- a/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt +++ b/quickstep/src/com/android/quickstep/DeviceConfigWrapper.kt @@ -52,7 +52,11 @@ class DeviceConfigWrapper private constructor(propReader: PropReader) { ) val lpnhTimeoutMs = - propReader.get("LPNH_TIMEOUT_MS", 450, "Controls lpnh timeout in milliseconds") + propReader.get( + "LPNH_TIMEOUT_MS", + DEFAULT_LPNH_TIMEOUT_MS, + "Controls lpnh timeout in milliseconds" + ) val lpnhSlopPercentage = propReader.get("LPNH_SLOP_PERCENTAGE", 100, "Controls touch slop percentage for lpnh") @@ -138,13 +142,6 @@ class DeviceConfigWrapper private constructor(propReader: PropReader) { "Controls extra dp on the nav bar sides to trigger LPNH. Can be negative for a smaller touch region." ) - val allAppsOverviewThreshold = - propReader.get( - "ALL_APPS_OVERVIEW_THRESHOLD", - 180, - "Threshold to open All Apps from Overview" - ) - /** Dump config values. */ fun dump(prefix: String, writer: PrintWriter) { writer.println("$prefix DeviceConfigWrapper:") @@ -165,12 +162,13 @@ class DeviceConfigWrapper private constructor(propReader: PropReader) { writer.println("$prefix\tenableLpnhDeepPress=$enableLpnhDeepPress") writer.println("$prefix\tlpnhHapticHintDelay=$lpnhHapticHintDelay") writer.println("$prefix\tlpnhExtraTouchWidthDp=$lpnhExtraTouchWidthDp") - writer.println("$prefix\tallAppsOverviewThreshold=$allAppsOverviewThreshold") } companion object { @JvmStatic val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) } @JvmStatic fun get() = configHelper.config + + const val DEFAULT_LPNH_TIMEOUT_MS = 450 } } diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java index 94a4527504..df83eb2fdb 100644 --- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java +++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java @@ -133,11 +133,6 @@ public final class FallbackActivityInterface extends } @Override - public boolean allowAllAppsFromOverview() { - return false; - } - - @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 diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java index 81c9d4a674..9cc463a31d 100644 --- a/quickstep/src/com/android/quickstep/GestureState.java +++ b/quickstep/src/com/android/quickstep/GestureState.java @@ -179,7 +179,6 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL private RemoteAnimationTarget[] mLastAppearedTaskTargets; private Set<Integer> mPreviouslyAppearedTaskIds = new HashSet<>(); private int[] mLastStartedTaskId = new int[]{INVALID_TASK_ID, INVALID_TASK_ID}; - private RecentsAnimationController mRecentsAnimationController; private HashMap<Integer, ThumbnailData> mRecentsAnimationCanceledSnapshots; /** The time when the swipe up gesture is triggered. */ @@ -470,7 +469,6 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL @Override public void onRecentsAnimationStart(RecentsAnimationController controller, RecentsAnimationTargets targets) { - mRecentsAnimationController = controller; mStateCallback.setState(STATE_RECENTS_ANIMATION_STARTED); } @@ -480,10 +478,6 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL mStateCallback.setState(STATE_RECENTS_ANIMATION_CANCELED); mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED); if (mRecentsAnimationCanceledSnapshots != null) { - // Clean up the screenshot to finalize the recents animation cancel - if (mRecentsAnimationController != null) { - mRecentsAnimationController.cleanupScreenshot(); - } mRecentsAnimationCanceledSnapshots = null; } } @@ -522,7 +516,7 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL HashMap<Integer, ThumbnailData> consumeRecentsAnimationCanceledSnapshot() { if (mRecentsAnimationCanceledSnapshots != null) { HashMap<Integer, ThumbnailData> data = - new HashMap<Integer, ThumbnailData>(mRecentsAnimationCanceledSnapshots); + new HashMap<>(mRecentsAnimationCanceledSnapshots); mRecentsAnimationCanceledSnapshots = null; return data; } diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java index e9fe2f7b32..85312e4988 100644 --- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java +++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java @@ -18,7 +18,6 @@ package com.android.quickstep; import static com.android.app.animation.Interpolators.LINEAR; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.BACKGROUND_APP; -import static com.android.launcher3.LauncherState.FLOATING_SEARCH_BAR; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; @@ -40,9 +39,7 @@ import com.android.launcher3.LauncherAnimUtils; import com.android.launcher3.LauncherInitListener; import com.android.launcher3.LauncherState; import com.android.launcher3.anim.PendingAnimation; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statehandlers.DepthController; -import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.taskbar.LauncherTaskbarUIController; import com.android.launcher3.uioverrides.QuickstepLauncher; @@ -79,7 +76,7 @@ public final class LauncherActivityInterface extends && DisplayController.getNavigationMode(context) != NavigationMode.NO_BUTTON) { return dp.isSeascape() ? outRect.left : (dp.widthPx - outRect.right); } else { - return LayoutUtils.getShelfTrackingDistance(context, dp, orientationHandler); + return LayoutUtils.getShelfTrackingDistance(context, dp, orientationHandler, this); } } @@ -169,16 +166,6 @@ public final class LauncherActivityInterface extends @Nullable @Override - public DesktopVisibilityController getDesktopVisibilityController() { - QuickstepLauncher launcher = getCreatedContainer(); - if (launcher == null) { - return null; - } - return launcher.getDesktopVisibilityController(); - } - - @Nullable - @Override public LauncherTaskbarUIController getTaskbarController() { QuickstepLauncher launcher = getCreatedContainer(); if (launcher == null) { @@ -271,13 +258,6 @@ public final class LauncherActivityInterface extends } @Override - public boolean allowAllAppsFromOverview() { - return FeatureFlags.ENABLE_ALL_APPS_FROM_OVERVIEW.get() - // If floating search bar would not show in overview, don't allow all apps gesture. - && OVERVIEW.areElementsVisible(getCreatedContainer(), FLOATING_SEARCH_BAR); - } - - @Override public boolean isInLiveTileMode() { QuickstepLauncher launcher = getCreatedContainer(); diff --git a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java index b720382597..1124aac457 100644 --- a/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java +++ b/quickstep/src/com/android/quickstep/LauncherBackAnimationController.java @@ -27,7 +27,6 @@ import static com.android.launcher3.BaseActivity.PENDING_INVISIBLE_BY_WALLPAPER_ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.content.ComponentCallbacks; import android.content.res.Configuration; @@ -38,7 +37,6 @@ import android.graphics.RectF; import android.os.Handler; import android.os.RemoteException; import android.util.Log; -import android.util.Pair; import android.view.Choreographer; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; @@ -63,7 +61,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.taskbar.LauncherTaskbarUIController; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.widget.LauncherAppWidgetHostView; -import com.android.quickstep.util.RectFSpringAnim; +import com.android.quickstep.util.BackAnimState; import com.android.systemui.shared.system.QuickStepContract; import java.lang.ref.WeakReference; @@ -109,8 +107,6 @@ public class LauncherBackAnimationController { private RemoteAnimationTarget mLauncherTarget; private View mLauncherTargetView; private final SurfaceControl.Transaction mTransaction = new SurfaceControl.Transaction(); - private boolean mSpringAnimationInProgress = false; - private boolean mAnimatorSetInProgress = false; private float mBackProgress = 0; private boolean mBackInProgress = false; private OnBackInvokedCallbackStub mBackCallback; @@ -341,7 +337,9 @@ public class LauncherBackAnimationController { mTransaction .setColor(mScrimLayer, colorComponents) .setAlpha(mScrimLayer, mScrimAlpha) - .show(mScrimLayer); + .show(mScrimLayer) + // Ensure the scrim layer occludes opening task & wallpaper + .setLayer(mScrimLayer, 1000); } void removeScrimLayer() { @@ -446,15 +444,15 @@ public class LauncherBackAnimationController { mQuickstepTransitionManager.transferRectToTargetCoordinate( mBackTarget, mCurrentRect, true, resolveRectF); - Pair<RectFSpringAnim, AnimatorSet> pair = + BackAnimState backAnim = mQuickstepTransitionManager.createWallpaperOpenAnimations( new RemoteAnimationTarget[]{mBackTarget}, new RemoteAnimationTarget[0], - false /* fromUnlock */, + new RemoteAnimationTarget[0], resolveRectF, cornerRadius, mBackInProgress /* fromPredictiveBack */); - startTransitionAnimations(pair.first, pair.second); + startTransitionAnimations(backAnim); mLauncher.clearForceInvisibleFlag(INVISIBLE_ALL); customizeStatusBarAppearance(true); } @@ -469,8 +467,6 @@ public class LauncherBackAnimationController { mCurrentRect.setEmpty(); mStartRect.setEmpty(); mInitialTouchPos.set(0, 0); - mAnimatorSetInProgress = false; - mSpringAnimationInProgress = false; setLauncherTargetViewVisible(true); mLauncherTargetView = null; // We don't call customizeStatusBarAppearance here to prevent the status bar update with @@ -493,27 +489,8 @@ public class LauncherBackAnimationController { } } - private void startTransitionAnimations(RectFSpringAnim springAnim, AnimatorSet anim) { - mAnimatorSetInProgress = anim != null; - mSpringAnimationInProgress = springAnim != null; - if (springAnim != null) { - springAnim.addAnimatorListener( - new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mSpringAnimationInProgress = false; - tryFinishBackAnimation(); - } - } - ); - } - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mAnimatorSetInProgress = false; - tryFinishBackAnimation(); - } - }); + private void startTransitionAnimations(BackAnimState backAnim) { + backAnim.addOnAnimCompleteCallback(this::finishAnimation); if (mScrimLayer == null) { // Scrim hasn't been attached yet. Let's attach it. addScrimLayer(); @@ -533,7 +510,7 @@ public class LauncherBackAnimationController { } }); mScrimAlphaAnimator.setDuration(SCRIM_FADE_DURATION).start(); - anim.start(); + backAnim.start(); } private void loadResources() { @@ -566,12 +543,6 @@ public class LauncherBackAnimationController { mScrimAlpha = 0; } - private void tryFinishBackAnimation() { - if (!mSpringAnimationInProgress && !mAnimatorSetInProgress) { - finishAnimation(); - } - } - private void customizeStatusBarAppearance(boolean overridingStatusBarFlags) { if (mOverridingStatusBarFlags == overridingStatusBarFlags) { return; diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java index f653e60e4b..d2dcd7bb1e 100644 --- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java +++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java @@ -20,7 +20,6 @@ import static com.android.app.animation.Interpolators.LINEAR; import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation; import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.Utilities.mapBoundToRange; -import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION; import static com.android.launcher3.views.FloatingIconView.getFloatingIconView; @@ -42,7 +41,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.uioverrides.QuickstepLauncher; -import com.android.launcher3.util.ObjectWrapper; +import com.android.launcher3.util.StableViewInfo; import com.android.launcher3.views.ClipIconView; import com.android.launcher3.views.FloatingIconView; import com.android.launcher3.views.FloatingView; @@ -301,18 +300,7 @@ public class LauncherSwipeHandlerV2 extends AbsSwipeUpHandler< return null; } - // Find the associated item info for the launch cookie (if available), note that predicted - // apps actually have an id of -1, so use another default id here - int launchCookieItemId = NO_MATCHING_ID; - for (IBinder cookie : launchCookies) { - Integer itemId = ObjectWrapper.unwrap(cookie); - if (itemId != null) { - launchCookieItemId = itemId; - break; - } - } - - return mContainer.getFirstMatchForAppClose(launchCookieItemId, + return mContainer.getFirstMatchForAppClose(StableViewInfo.fromLaunchCookies(launchCookies), sourceTaskView.getFirstTask().key.getComponent().getPackageName(), UserHandle.of(sourceTaskView.getFirstTask().key.userId), false /* supportsAllAppsState */); diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt index 80ed5ae3ee..520bec35c7 100644 --- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt +++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.kt @@ -25,16 +25,25 @@ import android.util.Log import android.view.View import androidx.annotation.BinderThread import androidx.annotation.UiThread +import androidx.annotation.VisibleForTesting import com.android.internal.jank.Cuj +import com.android.launcher3.Flags.enableOverviewCommandHelperTimeout import com.android.launcher3.PagedView -import com.android.launcher3.config.FeatureFlags import com.android.launcher3.logger.LauncherAtom import com.android.launcher3.logging.StatsLogManager -import com.android.launcher3.logging.StatsLogManager.LauncherEvent.* +import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_3_BUTTON +import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_QUICK_SWITCH +import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT import com.android.launcher3.util.Executors import com.android.launcher3.util.RunnableList +import com.android.launcher3.util.coroutines.DispatcherProvider +import com.android.launcher3.util.coroutines.ProductionDispatchers import com.android.quickstep.OverviewCommandHelper.CommandInfo.CommandStatus -import com.android.quickstep.OverviewCommandHelper.CommandType.* +import com.android.quickstep.OverviewCommandHelper.CommandType.HIDE +import com.android.quickstep.OverviewCommandHelper.CommandType.HOME +import com.android.quickstep.OverviewCommandHelper.CommandType.KEYBOARD_INPUT +import com.android.quickstep.OverviewCommandHelper.CommandType.SHOW +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 @@ -43,13 +52,25 @@ import com.android.systemui.shared.recents.model.ThumbnailData import com.android.systemui.shared.system.InteractionJankMonitorWrapper import java.io.PrintWriter import java.util.concurrent.ConcurrentLinkedDeque +import kotlin.coroutines.resume +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.ensureActive +import kotlinx.coroutines.launch +import kotlinx.coroutines.suspendCancellableCoroutine +import kotlinx.coroutines.withTimeout /** Helper class to handle various atomic commands for switching between Overview. */ -class OverviewCommandHelper( +class OverviewCommandHelper +@JvmOverloads +constructor( private val touchInteractionService: TouchInteractionService, private val overviewComponentObserver: OverviewComponentObserver, - private val taskAnimationManager: TaskAnimationManager + private val taskAnimationManager: TaskAnimationManager, + private val dispatcherProvider: DispatcherProvider = ProductionDispatchers, ) { + private val coroutineScope = CoroutineScope(SupervisorJob() + dispatcherProvider.default) + private val commandQueue = ConcurrentLinkedDeque<CommandInfo>() /** @@ -59,14 +80,6 @@ class OverviewCommandHelper( */ 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 @@ -79,10 +92,10 @@ class OverviewCommandHelper( * dropped. */ @BinderThread - fun addCommand(type: CommandType) { + fun addCommand(type: CommandType): CommandInfo? { if (commandQueue.size >= MAX_QUEUE_SIZE) { - Log.d(TAG, "commands queue is full ($commandQueue). command not added: $type") - return + Log.d(TAG, "command not added: $type - queue is full ($commandQueue).") + return null } val command = CommandInfo(type) @@ -90,16 +103,25 @@ class OverviewCommandHelper( Log.d(TAG, "command added: $command") if (commandQueue.size == 1) { - Executors.MAIN_EXECUTOR.execute { executeNext() } + Log.d(TAG, "execute: $command - queue size: ${commandQueue.size}") + if (enableOverviewCommandHelperTimeout()) { + coroutineScope.launch(dispatcherProvider.main) { processNextCommand() } + } else { + Executors.MAIN_EXECUTOR.execute { processNextCommand() } + } + } else { + Log.d(TAG, "not executed: $command - queue size: ${commandQueue.size}") } + + return command } fun canStartHomeSafely(): Boolean = commandQueue.isEmpty() || commandQueue.first().type == HOME - /** Clear pending commands from the queue */ + /** Clear pending or completed commands from the queue */ fun clearPendingCommands() { Log.d(TAG, "clearing pending commands: $commandQueue") - commandQueue.clear() + commandQueue.removeAll { it.status != CommandStatus.PROCESSING } } /** @@ -108,7 +130,7 @@ class OverviewCommandHelper( * completion (returns false). */ @UiThread - private fun executeNext() { + private fun processNextCommand() { val command: CommandInfo = commandQueue.firstOrNull() ?: run { @@ -119,12 +141,22 @@ class OverviewCommandHelper( command.status = CommandStatus.PROCESSING Log.d(TAG, "executing command: $command") - val result = executeCommand(command) - Log.d(TAG, "command executed: $command with result: $result") - if (result) { - onCommandFinished(command) + if (enableOverviewCommandHelperTimeout()) { + coroutineScope.launch(dispatcherProvider.main) { + withTimeout(QUEUE_WAIT_DURATION_IN_MS) { + executeCommandSuspended(command) + ensureActive() + onCommandFinished(command) + } + } } else { - Log.d(TAG, "waiting for command callback: $command") + val result = executeCommand(command, onCallbackResult = { onCommandFinished(command) }) + Log.d(TAG, "command executed: $command with result: $result") + if (result) { + onCommandFinished(command) + } else { + Log.d(TAG, "waiting for command callback: $command") + } } } @@ -132,24 +164,42 @@ class OverviewCommandHelper( * Executes the task and returns true if next task can be executed. If false, then the next task * is deferred until [.scheduleNextTask] is called */ - private fun executeCommand(command: CommandInfo): Boolean { - if (waitForToggleCommandComplete && command.type == TOGGLE) { - Log.d(TAG, "executeCommand: $command - waiting for toggle command complete") - return true - } - + @VisibleForTesting + fun executeCommand(command: CommandInfo, onCallbackResult: () -> Unit): Boolean { val recentsView = visibleRecentsView Log.d(TAG, "executeCommand: $command - visibleRecentsView: $recentsView") return if (recentsView != null) { - executeWhenRecentsIsVisible(command, recentsView) + executeWhenRecentsIsVisible(command, recentsView, onCallbackResult) } else { - executeWhenRecentsIsNotVisible(command) + executeWhenRecentsIsNotVisible(command, onCallbackResult) } } + /** + * Executes the task and returns true if next task can be executed. If false, then the next task + * is deferred until [.scheduleNextTask] is called + */ + private suspend fun executeCommandSuspended(command: CommandInfo) = + suspendCancellableCoroutine { continuation -> + fun processResult(isCompleted: Boolean) { + Log.d(TAG, "command executed: $command with result: $isCompleted") + if (isCompleted) { + continuation.resume(Unit) + } else { + Log.d(TAG, "waiting for command callback: $command") + } + } + + val result = executeCommand(command, onCallbackResult = { processResult(true) }) + processResult(result) + + continuation.invokeOnCancellation { cancelCommand(command, it) } + } + private fun executeWhenRecentsIsVisible( command: CommandInfo, recentsView: RecentsView<*, *>, + onCallbackResult: () -> Unit, ): Boolean = when (command.type) { SHOW -> true // already visible @@ -161,7 +211,7 @@ class OverviewCommandHelper( keyboardTaskFocusIndex = PagedView.INVALID_PAGE val currentPage = recentsView.nextPage val taskView = recentsView.getTaskViewAt(currentPage) - launchTask(recentsView, taskView, command) + launchTask(recentsView, taskView, command, onCallbackResult) } } TOGGLE -> { @@ -171,7 +221,7 @@ class OverviewCommandHelper( } else { recentsView.nextTaskView ?: recentsView.runningTaskView } - launchTask(recentsView, taskView, command) + launchTask(recentsView, taskView, command, onCallbackResult) } HOME -> { recentsView.startHome() @@ -182,38 +232,38 @@ class OverviewCommandHelper( private fun launchTask( recents: RecentsView<*, *>, taskView: TaskView?, - command: CommandInfo + command: CommandInfo, + onCallbackResult: () -> Unit, ): Boolean { var callbackList: RunnableList? = null if (taskView != null) { - waitForToggleCommandComplete = true taskView.isEndQuickSwitchCuj = true - callbackList = taskView.launchTasks() + callbackList = taskView.launchWithAnimation() } if (callbackList != null) { callbackList.add { Log.d(TAG, "launching task callback: $command") - onCommandFinished(command) - waitForToggleCommandComplete = false + onCallbackResult() } Log.d(TAG, "launching task - waiting for callback: $command") return false } else { recents.startHome() - waitForToggleCommandComplete = false return true } } - private fun executeWhenRecentsIsNotVisible(command: CommandInfo): Boolean { + private fun executeWhenRecentsIsNotVisible( + command: CommandInfo, + onCallbackResult: () -> Unit, + ): Boolean { val recentsViewContainer = activityInterface.getCreatedContainer() as? RecentsViewContainer val recentsView: RecentsView<*, *>? = recentsViewContainer?.getOverviewPanel() val deviceProfile = recentsViewContainer?.getDeviceProfile() val uiController = activityInterface.getTaskbarController() val allowQuickSwitch = - FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH.get() && - uiController != null && + uiController != null && deviceProfile != null && (deviceProfile.isTablet || deviceProfile.isTwoPanels) @@ -263,7 +313,7 @@ class OverviewCommandHelper( Log.d(TAG, "switching to Overview state - onAnimationEnd: $command") super.onAnimationEnd(animation) onRecentsViewFocusUpdated(command) - onCommandFinished(command) + onCallbackResult() } } if (activityInterface.switchToRecentsIfVisible(animatorListener)) { @@ -280,16 +330,16 @@ class OverviewCommandHelper( val gestureState = touchInteractionService.createGestureState( GestureState.DEFAULT_STATE, - GestureState.TrackpadGestureType.NONE + GestureState.TrackpadGestureType.NONE, ) gestureState.isHandlingAtomicEvent = true val interactionHandler = touchInteractionService.swipeUpHandlerFactory.newHandler( gestureState, - command.createTime + command.createTime, ) interactionHandler.setGestureEndCallback { - onTransitionComplete(command, interactionHandler) + onTransitionComplete(command, interactionHandler, onCallbackResult) } interactionHandler.initWhenReady("OverviewCommandHelper: command.type=${command.type}") @@ -297,7 +347,7 @@ class OverviewCommandHelper( object : RecentsAnimationCallbacks.RecentsAnimationListener { override fun onRecentsAnimationStart( controller: RecentsAnimationController, - targets: RecentsAnimationTargets + targets: RecentsAnimationTargets, ) { Log.d(TAG, "recents animation started: $command") updateRecentsViewFocus(command) @@ -321,11 +371,6 @@ class OverviewCommandHelper( } } - // TODO(b/361768912): Dead code. Remove or update after this bug is fixed. - // if (visibleRecentsView != null) { - // visibleRecentsView.moveRunningTaskToFront(); - // } - if (taskAnimationManager.isRecentsAnimationRunning) { command.setAnimationCallbacks( taskAnimationManager.continueRecentsAnimation(gestureState) @@ -351,29 +396,40 @@ class OverviewCommandHelper( return false } - private fun onTransitionComplete(command: CommandInfo, handler: AbsSwipeUpHandler<*, *, *>) { + private fun onTransitionComplete( + command: CommandInfo, + handler: AbsSwipeUpHandler<*, *, *>, + onCommandResult: () -> Unit, + ) { Log.d(TAG, "switching via recents animation - onTransitionComplete: $command") command.removeListener(handler) Trace.endAsyncSection(TRANSITION_NAME, 0) onRecentsViewFocusUpdated(command) - onCommandFinished(command) + onCommandResult() } /** Called when the command finishes execution. */ private fun onCommandFinished(command: CommandInfo) { command.status = CommandStatus.COMPLETED - if (commandQueue.first() !== command) { + if (commandQueue.firstOrNull() !== command) { Log.d( TAG, "next task not scheduled. First pending command type " + - "is ${commandQueue.first()} - command type is: $command" + "is ${commandQueue.firstOrNull()} - command type is: $command", ) return } Log.d(TAG, "command executed successfully! $command") commandQueue.remove(command) - executeNext() + processNextCommand() + } + + private fun cancelCommand(command: CommandInfo, throwable: Throwable?) { + command.status = CommandStatus.CANCELED + Log.e(TAG, "command cancelled: $command - $throwable") + commandQueue.remove(command) + processNextCommand() } private fun updateRecentsViewFocus(command: CommandInfo) { @@ -444,14 +500,14 @@ class OverviewCommandHelper( pw.println(" pendingCommandType=${commandQueue.first().type}") } pw.println(" keyboardTaskFocusIndex=$keyboardTaskFocusIndex") - pw.println(" waitForToggleCommandComplete=$waitForToggleCommandComplete") } - private data class CommandInfo( + @VisibleForTesting + data class CommandInfo( val type: CommandType, var status: CommandStatus = CommandStatus.IDLE, val createTime: Long = SystemClock.elapsedRealtime(), - private var animationCallbacks: RecentsAnimationCallbacks? = null + private var animationCallbacks: RecentsAnimationCallbacks? = null, ) { fun setAnimationCallbacks(recentsAnimationCallbacks: RecentsAnimationCallbacks) { this.animationCallbacks = recentsAnimationCallbacks @@ -468,7 +524,8 @@ class OverviewCommandHelper( enum class CommandStatus { IDLE, PROCESSING, - COMPLETED + COMPLETED, + CANCELED, } } @@ -489,5 +546,6 @@ class OverviewCommandHelper( * should be enough. We'll toss in one more because we're kind hearted. */ private const val MAX_QUEUE_SIZE = 3 + private const val QUEUE_WAIT_DURATION_IN_MS = 5000L } } diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java index 6d5cb4b43b..9c60693e65 100644 --- a/quickstep/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/src/com/android/quickstep/RecentsActivity.java @@ -63,6 +63,7 @@ import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.desktop.DesktopRecentsTransitionController; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.statemanager.StateManager; import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory; import com.android.launcher3.statemanager.StateManager.StateHandler; @@ -525,4 +526,10 @@ public final class RecentsActivity extends StatefulActivity<RecentsState> implem public boolean isRecentsViewVisible() { return getStateManager().getState().isRecentsViewVisible(); } + + @Nullable + @Override + public DesktopVisibilityController getDesktopVisibilityController() { + return mTISBindHelper.getDesktopVisibilityController(); + } } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java index 7b9b5604a0..0c5806b13c 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java @@ -174,19 +174,7 @@ public class RecentsAnimationCallbacks implements }); } - @BinderThread - @Override - public boolean onSwitchToScreenshot(Runnable onFinished) { - Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { - for (RecentsAnimationListener listener : getListeners()) { - if (listener.onSwitchToScreenshot(onFinished)) return; - } - onFinished.run(); - }); - return true; - } - - private final void onAnimationFinished(RecentsAnimationController controller) { + private void onAnimationFinished(RecentsAnimationController controller) { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { ActiveGestureLog.INSTANCE.addLog( /* event= */ "RecentsAnimationCallbacks.onAnimationFinished", @@ -242,12 +230,5 @@ public class RecentsAnimationCallbacks implements * Callback made when a task started from the recents is ready for an app transition. */ default void onTasksAppeared(@NonNull RemoteAnimationTarget[] appearedTaskTarget) {} - - /** - * @return whether this will call onFinished or not (onFinished should only be called once). - */ - default boolean onSwitchToScreenshot(Runnable onFinished) { - return false; - } } } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java index adcf4ef6cd..190d5269ed 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java @@ -19,11 +19,9 @@ import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.FINISH_RECENTS_ANIMATION; -import android.content.Context; import android.os.Bundle; import android.os.RemoteException; import android.util.Log; -import android.view.IRecentsAnimationController; import android.view.SurfaceControl; import android.view.WindowManagerGlobal; import android.window.PictureInPictureSurfaceTransaction; @@ -34,11 +32,11 @@ import com.android.internal.jank.Cuj; import com.android.internal.os.IResultReceiver; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.RunnableList; -import com.android.quickstep.util.ActiveGestureErrorDetector; import com.android.quickstep.util.ActiveGestureLog; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InteractionJankMonitorWrapper; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; +import com.android.wm.shell.recents.IRecentsAnimationController; import java.io.PrintWriter; import java.util.function.Consumer; @@ -90,15 +88,6 @@ public class RecentsAnimationController { } } - /** - * Remove task remote animation target from - * {@link RecentsAnimationCallbacks#onTasksAppeared}}. - */ - @UiThread - public void removeTaskTarget(int targetTaskId) { - UI_HELPER_EXECUTOR.execute(() -> mController.removeTask(targetTaskId)); - } - @UiThread public void finishAnimationToHome() { finishController(true /* toRecents */, null, false /* sendUserLeaveHint */); @@ -173,19 +162,6 @@ public class RecentsAnimationController { } /** - * @see IRecentsAnimationController#cleanupScreenshot() - */ - @UiThread - public void cleanupScreenshot() { - UI_HELPER_EXECUTOR.execute(() -> { - ActiveGestureLog.INSTANCE.addLog( - "cleanupScreenshot", - ActiveGestureErrorDetector.GestureEvent.CLEANUP_SCREENSHOT); - mController.cleanupScreenshot(); - }); - } - - /** * @see RecentsAnimationControllerCompat#detachNavigationBarFromApp */ @UiThread @@ -194,14 +170,6 @@ public class RecentsAnimationController { } /** - * @see IRecentsAnimationController#animateNavigationBarToApp(long) - */ - @UiThread - public void animateNavigationBarToApp(long duration) { - UI_HELPER_EXECUTOR.execute(() -> mController.animateNavigationBarToApp(duration)); - } - - /** * @see IRecentsAnimationController#setWillFinishToHome(boolean) */ @UiThread diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index a01ceb2446..d073580fb5 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -56,6 +56,7 @@ import com.android.systemui.shared.system.TaskStackChangeListeners; import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Executor; import java.util.concurrent.Executors; import java.util.function.Consumer; @@ -76,7 +77,8 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener, private static final Executor RECENTS_MODEL_EXECUTOR = Executors.newSingleThreadExecutor( new SimpleThreadFactory("TaskThumbnailIconCache-", THREAD_PRIORITY_BACKGROUND)); - private final List<TaskVisualsChangeListener> mThumbnailChangeListeners = new ArrayList<>(); + private final ConcurrentLinkedQueue<TaskVisualsChangeListener> mThumbnailChangeListeners = + new ConcurrentLinkedQueue<>(); private final Context mContext; private final RecentTasksList mTaskList; @@ -239,8 +241,8 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener, public boolean onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) { mThumbnailCache.updateTaskSnapShot(taskId, snapshot); - for (int i = mThumbnailChangeListeners.size() - 1; i >= 0; i--) { - Task task = mThumbnailChangeListeners.get(i).onTaskThumbnailChanged(taskId, snapshot); + for (TaskVisualsChangeListener listener : mThumbnailChangeListeners) { + Task task = listener.onTaskThumbnailChanged(taskId, snapshot); if (task != null) { task.thumbnail = snapshot; } @@ -269,8 +271,8 @@ public class RecentsModel implements RecentTasksDataSource, IconChangeListener, @Override public void onAppIconChanged(String packageName, UserHandle user) { mIconCache.invalidateCacheEntries(packageName, user); - for (int i = mThumbnailChangeListeners.size() - 1; i >= 0; i--) { - mThumbnailChangeListeners.get(i).onTaskIconChanged(packageName, user); + for (TaskVisualsChangeListener listener : mThumbnailChangeListeners) { + listener.onTaskIconChanged(packageName, user); } } diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java index 1be60dee14..8adc11ac10 100644 --- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java +++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java @@ -68,7 +68,7 @@ public class RemoteTargetGluer { */ public RemoteTargetGluer(Context context, BaseContainerInterface sizingStrategy) { DesktopVisibilityController desktopVisibilityController = - LauncherActivityInterface.INSTANCE.getDesktopVisibilityController(); + sizingStrategy.getDesktopVisibilityController(); if (desktopVisibilityController != null) { int visibleTasksCount = desktopVisibilityController.getVisibleDesktopTasksCount(); if (visibleTasksCount > 0) { diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index dde16c83b1..f9b4dab5bf 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -43,8 +43,6 @@ import android.os.Message; import android.os.RemoteException; import android.os.UserHandle; import android.util.Log; -import android.view.IRecentsAnimationController; -import android.view.IRecentsAnimationRunner; import android.view.IRemoteAnimationRunner; import android.view.MotionEvent; import android.view.RemoteAnimationTarget; @@ -53,6 +51,7 @@ import android.window.IOnBackInvokedCallback; 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; @@ -89,10 +88,11 @@ import com.android.wm.shell.draganddrop.IDragAndDrop; import com.android.wm.shell.onehanded.IOneHanded; 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; @@ -1395,7 +1395,7 @@ public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable { 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 49ec5973e1..289a2c1feb 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -289,38 +289,10 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn true /*shown*/, null /* animatorHandler */); } if (mController != null) { - if (mLastAppearedTaskTargets != null) { - for (RemoteAnimationTarget lastTarget : mLastAppearedTaskTargets) { - for (RemoteAnimationTarget appearedTarget : appearedTaskTargets) { - if (lastTarget != null && - appearedTarget.taskId != lastTarget.taskId) { - mController.removeTaskTarget(lastTarget.taskId); - } - } - } - } mLastAppearedTaskTargets = appearedTaskTargets; mLastGestureState.updateLastAppearedTaskTargets(mLastAppearedTaskTargets); } } - - @Override - public boolean onSwitchToScreenshot(Runnable onFinished) { - if (!containerInterface.isInLiveTileMode() - || containerInterface.getCreatedContainer() == null) { - // No need to switch since tile is already a screenshot. - onFinished.run(); - } else { - final RecentsView recentsView = - containerInterface.getCreatedContainer().getOverviewPanel(); - if (recentsView != null) { - recentsView.switchToScreenshot(onFinished); - } else { - onFinished.run(); - } - } - return true; - } }); final long eventTime = gestureState.getSwipeUpStartTimeMs(); mCallbacks.addListener(gestureState); @@ -329,10 +301,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn final ActivityOptions options = ActivityOptions.makeBasic(); options.setPendingIntentBackgroundActivityStartMode( ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS); - // Use regular (non-transient) launch for all apps page to control IME. - if (!containerInterface.allowAllAppsFromOverview()) { - options.setTransientLaunch(); - } + options.setTransientLaunch(); options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime); // Notify taskbar that we should skip reacting to launcher visibility change to diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java index 9e6e2f3f04..785666f77e 100644 --- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java +++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java @@ -431,7 +431,7 @@ public interface TaskShortcutFactory { @Override public void onClick(View view) { - if (mTaskView.launchTaskAnimated() != null) { + if (mTaskView.launchAsStaticTile() != null) { SystemUiProxy.INSTANCE.get(mTarget.asContext()).startScreenPinning( mTaskView.getFirstTask().key.id); } diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java index 1a09691d9a..d8063ba9b9 100644 --- a/quickstep/src/com/android/quickstep/TaskViewUtils.java +++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java @@ -304,14 +304,6 @@ public final class TaskViewUtils { } } }); - } else { - // There is no transition animation for app launch from recent in live tile mode so - // we have to trigger the navigation bar animation from system here. - final RecentsAnimationController controller = - recentsView.getRecentsAnimationController(); - if (controller != null) { - controller.animateNavigationBarToApp(RECENTS_LAUNCH_DURATION); - } } topMostSimulators = remoteTargetHandles; } diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java index 4587bdd0a4..178636e474 100644 --- a/quickstep/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java @@ -15,7 +15,6 @@ */ package com.android.quickstep; -import static android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS; import static android.view.MotionEvent.ACTION_CANCEL; import static android.view.MotionEvent.ACTION_DOWN; import static android.view.MotionEvent.ACTION_MOVE; @@ -26,11 +25,9 @@ import static android.view.MotionEvent.ACTION_UP; import static com.android.launcher3.Flags.enableCursorHoverStates; import static com.android.launcher3.Flags.enableHandleDelayedGestureCallbacks; import static com.android.launcher3.Flags.useActivityOverlay; -import static com.android.launcher3.Launcher.INTENT_ACTION_ALL_APPS_TOGGLE; import static com.android.launcher3.LauncherPrefs.backedUpItem; import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent; import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe; -import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN; @@ -92,8 +89,8 @@ import com.android.launcher3.EncryptionType; import com.android.launcher3.Flags; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.anim.AnimatedFloat; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.provider.RestoreDbTask; +import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.taskbar.TaskbarManager; @@ -227,7 +224,6 @@ public class TouchInteractionService extends Service { @BinderThread @Override public void onTaskbarToggled() { - if (!FeatureFlags.ENABLE_KEYBOARD_TASKBAR_TOGGLE.get()) return; MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> { TaskbarActivityContext activityContext = tis.mTaskbarManager.getCurrentActivityContext(); @@ -379,6 +375,15 @@ public class TouchInteractionService extends Service { )); } + @BinderThread + @Override + public void appTransitionPending(boolean pending) { + MAIN_EXECUTOR.execute(() -> executeForTouchInteractionService(tis -> + executeForTaskbarManager( + taskbarManager -> taskbarManager.appTransitionPending(pending)) + )); + } + /** * Preloads the Overview activity. * <p> @@ -453,6 +458,18 @@ public class TouchInteractionService extends Service { return tis.mTaskbarManager; } + /** + * Returns the {@link DesktopVisibilityController} + * <p> + * Returns {@code null} if TouchInteractionService is not connected + */ + @Nullable + public DesktopVisibilityController getDesktopVisibilityController() { + TouchInteractionService tis = mTis.get(); + if (tis == null) return null; + return tis.mDesktopVisibilityController; + } + @VisibleForTesting public void injectFakeTrackpadForTesting() { TouchInteractionService tis = mTis.get(); @@ -628,6 +645,8 @@ public class TouchInteractionService extends Service { private NavigationMode mGestureStartNavMode = null; + private DesktopVisibilityController mDesktopVisibilityController; + @Override public void onCreate() { super.onCreate(); @@ -640,15 +659,15 @@ public class TouchInteractionService extends Service { mAllAppsActionManager = new AllAppsActionManager( this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent); mInputManager = getSystemService(InputManager.class); - if (ENABLE_TRACKPAD_GESTURE.get()) { - mInputManager.registerInputDeviceListener(mInputDeviceListener, - UI_HELPER_EXECUTOR.getHandler()); - int [] inputDevices = mInputManager.getInputDeviceIds(); - for (int inputDeviceId : inputDevices) { - mInputDeviceListener.onInputDeviceAdded(inputDeviceId); - } - } - mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager, mNavCallbacks); + mInputManager.registerInputDeviceListener(mInputDeviceListener, + UI_HELPER_EXECUTOR.getHandler()); + int [] inputDevices = mInputManager.getInputDeviceIds(); + for (int inputDeviceId : inputDevices) { + mInputDeviceListener.onInputDeviceAdded(inputDeviceId); + } + mDesktopVisibilityController = new DesktopVisibilityController(this); + mTaskbarManager = new TaskbarManager( + this, mAllAppsActionManager, mNavCallbacks, mDesktopVisibilityController); mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer(); // Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized. @@ -677,7 +696,7 @@ public class TouchInteractionService extends Service { if (mDeviceState.isButtonNavMode() && !mDeviceState.supportsAssistantGestureInButtonNav() - && (!ENABLE_TRACKPAD_GESTURE.get() || mTrackpadsConnected.isEmpty())) { + && (mTrackpadsConnected.isEmpty())) { return; } @@ -743,8 +762,8 @@ public class TouchInteractionService extends Service { private void onOverviewTargetChange(boolean isHomeAndOverviewSame) { mAllAppsActionManager.setHomeAndOverviewSame(isHomeAndOverviewSame); - StatefulActivity newOverviewActivity = mOverviewComponentObserver.getActivityInterface() - .getCreatedContainer(); + StatefulActivity<?> newOverviewActivity = + mOverviewComponentObserver.getActivityInterface().getCreatedContainer(); if (newOverviewActivity != null) { mTaskbarManager.setActivity(newOverviewActivity); } @@ -752,23 +771,14 @@ public class TouchInteractionService extends Service { } private PendingIntent createAllAppsPendingIntent() { - if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) { - return new PendingIntent(new IIntentSender.Stub() { - @Override - public void send(int code, Intent intent, String resolvedType, - IBinder allowlistToken, IIntentReceiver finishedReceiver, - String requiredPermission, Bundle options) { - MAIN_EXECUTOR.execute(() -> mTaskbarManager.toggleAllApps()); - } - }); - } else { - return PendingIntent.getActivity( - this, - GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS, - new Intent(mOverviewComponentObserver.getHomeIntent()) - .setAction(INTENT_ACTION_ALL_APPS_TOGGLE), - PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE); - } + return new PendingIntent(new IIntentSender.Stub() { + @Override + public void send(int code, Intent intent, String resolvedType, + IBinder allowlistToken, IIntentReceiver finishedReceiver, + String requiredPermission, Bundle options) { + MAIN_EXECUTOR.execute(() -> mTaskbarManager.toggleAllApps()); + } + }); } @UiThread @@ -808,6 +818,7 @@ public class TouchInteractionService extends Service { mTrackpadsConnected.clear(); mTaskbarManager.destroy(); + mDesktopVisibilityController.onDestroy(); sConnected = false; ScreenOnTracker.INSTANCE.get(this).removeListener(mScreenOnListener); @@ -1244,7 +1255,7 @@ public class TouchInteractionService extends Service { getBaseContext(), mDeviceState, mInputMonitorCompat); } - if (ENABLE_TRACKPAD_GESTURE.get() && mGestureState.isTrackpadGesture() + if (mGestureState.isTrackpadGesture() && canStartSystemGesture && !previousGestureState.isRecentsAnimationRunning()) { reasonString = newCompoundString(reasonPrefix) .append(SUBSTRING_PREFIX) @@ -1654,6 +1665,7 @@ public class TouchInteractionService extends Service { createdOverviewActivity.getDeviceProfile().dump(this, "", pw); } mTaskbarManager.dumpLogs("", pw); + mDesktopVisibilityController.dumpLogs("", pw); pw.println("AssistStateManager:"); AssistStateManager.INSTANCE.get(this).dump("\t", pw); SystemUiProxy.INSTANCE.get(this).dump(pw); diff --git a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java new file mode 100644 index 0000000000..08345b85f6 --- /dev/null +++ b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java @@ -0,0 +1,22 @@ +/* + * 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 dagger.Module; + +@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 0000000000..f2d571554d --- /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/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index f4a2738fef..e67a9bc1b6 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -253,6 +253,9 @@ public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsSta } setFreezeViewVisibility(true); + if (mContainer.getDesktopVisibilityController() != null) { + mContainer.getDesktopVisibilityController().onLauncherStateChanged(toState); + } } @Override diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java index 9284e138af..5ad55ae177 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java @@ -184,7 +184,7 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { if (!mHasPassedTaskbarNavThreshold && passedTaskbarNavThreshold && !mGestureState.isInExtendedSlopRegion()) { mHasPassedTaskbarNavThreshold = true; - mTaskbarActivityContext.onSwipeToUnstashTaskbar(); + mTaskbarActivityContext.onSwipeToUnstashTaskbar(true); } if (dY < 0) { @@ -287,7 +287,7 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { // start a single unstash timeout if hovering bottom edge under the hinted taskbar. if (!sUnstashHandler.hasMessagesOrCallbacks()) { sUnstashHandler.postDelayed(() -> { - mTaskbarActivityContext.onSwipeToUnstashTaskbar(); + mTaskbarActivityContext.onSwipeToUnstashTaskbar(false); mIsStashedTaskbarHovered = false; }, HOVER_TASKBAR_UNSTASH_TIMEOUT); } @@ -315,7 +315,7 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer { startStashedTaskbarHover(/* isHovered = */ true); } else if (mBottomEdgeBounds.contains(x, y)) { // If hover screen's bottom edge not below the stashed taskbar, unstash it. - mTaskbarActivityContext.onSwipeToUnstashTaskbar(); + mTaskbarActivityContext.onSwipeToUnstashTaskbar(false); } } diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java index 1bec97075a..f7f3157230 100644 --- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java +++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java @@ -62,6 +62,7 @@ import androidx.core.graphics.ColorUtils; import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; +import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatedFloat; @@ -103,6 +104,9 @@ public class AllSetActivity extends Activity { private final AnimatedFloat mSwipeProgress = new AnimatedFloat(this::onSwipeProgressUpdate); + private final InvariantDeviceProfile.OnIDPChangeListener mOnIDPChangeListener = + modelPropertiesChanged -> updateHint(); + private TISBindHelper mTISBindHelper; private BgDrawable mBackground; @@ -115,6 +119,8 @@ public class AllSetActivity extends Activity { private AnimatorPlaybackController mLauncherStartAnim = null; + private TextView mHintView; + @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -167,12 +173,9 @@ public class AllSetActivity extends Activity { } }); - TextView hint = findViewById(R.id.hint); - DeviceProfile dp = InvariantDeviceProfile.INSTANCE.get(this).getDeviceProfile(this); - if (!dp.isGestureMode) { - hint.setText(R.string.allset_button_hint); - } - hint.setAccessibilityDelegate(new SkipButtonAccessibilityDelegate()); + mHintView = findViewById(R.id.hint); + mHintView.setAccessibilityDelegate(new SkipButtonAccessibilityDelegate()); + updateHint(); mTISBindHelper = new TISBindHelper(this, this::onTISConnected); @@ -190,7 +193,21 @@ public class AllSetActivity extends Activity { LOTTIE_TERTIARY_COLOR_TOKEN, R.color.all_set_bg_tertiary), getTheme()); - startBackgroundAnimation(dp.isTablet); + startBackgroundAnimation(getDP().isTablet); + getIDP().addOnChangeListener(mOnIDPChangeListener); + } + + private InvariantDeviceProfile getIDP() { + return LauncherAppState.getInstance(this).getInvariantDeviceProfile(); + } + + private DeviceProfile getDP() { + return getIDP().getDeviceProfile(this); + } + + private void updateHint() { + mHintView.setText( + getDP().isGestureMode ? R.string.allset_hint : R.string.allset_button_hint); } private void runOnUiHelperThread(Runnable runnable) { @@ -202,7 +219,7 @@ public class AllSetActivity extends Activity { } private void startBackgroundAnimation(boolean forTablet) { - if (!Utilities.ATLEAST_S || mVibrator == null) { + if (mVibrator == null) { return; } boolean supportsThud = mVibrator.areAllPrimitivesSupported( @@ -311,6 +328,7 @@ public class AllSetActivity extends Activity { @Override protected void onDestroy() { super.onDestroy(); + getIDP().removeOnChangeListener(mOnIDPChangeListener); mTISBindHelper.onDestroy(); clearBinderOverride(); if (mBackgroundAnimatorListener != null) { diff --git a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java index 742b0fc7e8..7a86db37c7 100644 --- a/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java +++ b/quickstep/src/com/android/quickstep/interaction/AnimatedTaskView.java @@ -15,8 +15,6 @@ */ package com.android.quickstep.interaction; -import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL; - import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; @@ -175,11 +173,8 @@ public class AnimatedTaskView extends ConstraintLayout { void setFakeTaskViewFillColor(@ColorInt int colorResId) { mFullTaskView.setBackgroundColor(colorResId); - - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()){ - mTopTaskView.getBackground().setTint(colorResId); - mBottomTaskView.getBackground().setTint(colorResId); - } + mTopTaskView.getBackground().setTint(colorResId); + mBottomTaskView.getBackground().setTint(colorResId); } @Override diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java index 6757cd88cc..be7f8e5fc2 100644 --- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java @@ -15,7 +15,6 @@ */ package com.android.quickstep.interaction; -import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL; import static com.android.quickstep.interaction.TutorialController.TutorialType.BACK_NAVIGATION; import static com.android.quickstep.interaction.TutorialController.TutorialType.BACK_NAVIGATION_COMPLETE; @@ -40,35 +39,29 @@ final class BackGestureTutorialController extends TutorialController { BackGestureTutorialController(BackGestureTutorialFragment fragment, TutorialType tutorialType) { super(fragment, tutorialType); // Set the Lottie animation colors specifically for the Back gesture - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - LottieAnimationColorUtils.updateToArgbColors( - mAnimatedGestureDemonstration, - Map.of(".onSurfaceBack", fragment.mRootView.mColorOnSurfaceBack, - ".surfaceBack", fragment.mRootView.mColorSurfaceBack, - ".secondaryBack", fragment.mRootView.mColorSecondaryBack)); + LottieAnimationColorUtils.updateToArgbColors( + mAnimatedGestureDemonstration, + Map.of(".onSurfaceBack", fragment.mRootView.mColorOnSurfaceBack, + ".surfaceBack", fragment.mRootView.mColorSurfaceBack, + ".secondaryBack", fragment.mRootView.mColorSecondaryBack)); - LottieAnimationColorUtils.updateToArgbColors( - mCheckmarkAnimation, - Map.of(".checkmark", - Utilities.isDarkTheme(mContext) - ? fragment.mRootView.mColorOnSurfaceBack - : fragment.mRootView.mColorSecondaryBack, - ".checkmarkBackground", fragment.mRootView.mColorSurfaceBack)); - } + LottieAnimationColorUtils.updateToArgbColors( + mCheckmarkAnimation, + Map.of(".checkmark", + Utilities.isDarkTheme(mContext) + ? fragment.mRootView.mColorOnSurfaceBack + : fragment.mRootView.mColorSecondaryBack, + ".checkmarkBackground", fragment.mRootView.mColorSurfaceBack)); } @Override public int getIntroductionTitle() { - return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.string.back_gesture_tutorial_title - : R.string.back_gesture_intro_title; + return R.string.back_gesture_tutorial_title; } @Override public int getIntroductionSubtitle() { - return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.string.back_gesture_tutorial_subtitle - : R.string.back_gesture_intro_subtitle; + return R.string.back_gesture_tutorial_subtitle; } @Override @@ -85,9 +78,7 @@ final class BackGestureTutorialController extends TutorialController { public int getSuccessFeedbackSubtitle() { return mTutorialFragment.isAtFinalStep() ? R.string.back_gesture_feedback_complete_without_follow_up - : ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.string.back_gesture_feedback_complete_with_follow_up - : R.string.back_gesture_feedback_complete_with_overview_follow_up; + : R.string.back_gesture_feedback_complete_with_follow_up; } @Override @@ -128,20 +119,12 @@ final class BackGestureTutorialController extends TutorialController { @LayoutRes int getMockAppTaskCurrentPageLayoutResId() { - return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.layout.back_gesture_tutorial_background - : mTutorialFragment.isLargeScreen() - ? R.layout.gesture_tutorial_tablet_mock_conversation - : R.layout.gesture_tutorial_mock_conversation; + return R.layout.back_gesture_tutorial_background; } @LayoutRes int getMockAppTaskPreviousPageLayoutResId() { - return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.layout.back_gesture_tutorial_background - : mTutorialFragment.isLargeScreen() - ? R.layout.gesture_tutorial_tablet_mock_conversation_list - : R.layout.gesture_tutorial_mock_conversation_list; + return R.layout.back_gesture_tutorial_background; } @Override @@ -214,17 +197,13 @@ final class BackGestureTutorialController extends TutorialController { } private void handleBackAttempt(BackGestureResult result) { - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - resetViewsForBackGesture(); - } + resetViewsForBackGesture(); switch (result) { case BACK_COMPLETED_FROM_LEFT: case BACK_COMPLETED_FROM_RIGHT: mTutorialFragment.releaseFeedbackAnimation(); - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - mExitingAppView.setVisibility(View.GONE); - } + mExitingAppView.setVisibility(View.GONE); updateFakeAppTaskViewLayout(getMockAppTaskPreviousPageLayoutResId()); showSuccessFeedback(); break; diff --git a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java index 1b12be85df..700fbf8d03 100644 --- a/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java +++ b/quickstep/src/com/android/quickstep/interaction/EdgeBackGestureHandler.java @@ -15,8 +15,6 @@ */ package com.android.quickstep.interaction; -import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL; - import android.content.Context; import android.content.res.Resources; import android.graphics.Point; @@ -211,10 +209,8 @@ public class EdgeBackGestureHandler implements OnTouchListener { } } - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - mGestureCallback.onBackGestureProgress(ev.getX() - mDownPoint.x, - ev.getY() - mDownPoint.y, mEdgeBackPanel.getIsLeftPanel()); - } + mGestureCallback.onBackGestureProgress(ev.getX() - mDownPoint.x, + ev.getY() - mDownPoint.y, mEdgeBackPanel.getIsLeftPanel()); // forward touch mEdgeBackPanel.onMotionEvent(ev); diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java index acc9959a8f..bc5cc15328 100644 --- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java +++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java @@ -37,7 +37,6 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherPrefs; import com.android.launcher3.R; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.logging.StatsLogManager; import com.android.quickstep.TouchInteractionService.TISBinder; import com.android.quickstep.interaction.TutorialController.TutorialType; @@ -79,9 +78,7 @@ public class GestureSandboxActivity extends FragmentActivity { Bundle args = savedInstanceState == null ? getIntent().getExtras() : savedInstanceState; boolean gestureComplete = args != null && args.getBoolean(KEY_GESTURE_COMPLETE, false); - if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - && args != null - && args.getBoolean(KEY_USE_TUTORIAL_MENU, false)) { + if (args != null && args.getBoolean(KEY_USE_TUTORIAL_MENU, false)) { mTutorialSteps = null; TutorialType tutorialTypeOverride = (TutorialType) args.get(KEY_TUTORIAL_TYPE); mCurrentFragment = tutorialTypeOverride == null @@ -101,9 +98,7 @@ public class GestureSandboxActivity extends FragmentActivity { .add(R.id.gesture_tutorial_fragment_container, mCurrentFragment) .commit(); - if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - correctUserOrientation(); - } + correctUserOrientation(); mTISBindHelper = new TISBindHelper(this, this::onTISConnected); initWindowInsets(); @@ -115,9 +110,7 @@ public class GestureSandboxActivity extends FragmentActivity { super.onConfigurationChanged(newConfig); // Ensure the prompt to rotate the screen is updated - if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - correctUserOrientation(); - } + correctUserOrientation(); } private void initWindowInsets() { diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java index 1129e025c5..bf4eaf2f53 100644 --- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java @@ -15,8 +15,6 @@ */ package com.android.quickstep.interaction; -import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL; - import android.graphics.PointF; import com.android.launcher3.R; @@ -34,35 +32,29 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll super(fragment, tutorialType); // Set the Lottie animation colors specifically for the Home gesture - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - LottieAnimationColorUtils.updateToArgbColors( - mAnimatedGestureDemonstration, - Map.of(".onSurfaceHome", fragment.mRootView.mColorOnSurfaceHome, - ".surfaceHome", fragment.mRootView.mColorSurfaceHome, - ".secondaryHome", fragment.mRootView.mColorSecondaryHome)); - - LottieAnimationColorUtils.updateToArgbColors( - mCheckmarkAnimation, - Map.of(".checkmark", - Utilities.isDarkTheme(mContext) - ? fragment.mRootView.mColorOnSurfaceHome - : fragment.mRootView.mColorSecondaryHome, - ".checkmarkBackground", fragment.mRootView.mColorSurfaceHome)); - } + LottieAnimationColorUtils.updateToArgbColors( + mAnimatedGestureDemonstration, + Map.of(".onSurfaceHome", fragment.mRootView.mColorOnSurfaceHome, + ".surfaceHome", fragment.mRootView.mColorSurfaceHome, + ".secondaryHome", fragment.mRootView.mColorSecondaryHome)); + + LottieAnimationColorUtils.updateToArgbColors( + mCheckmarkAnimation, + Map.of(".checkmark", + Utilities.isDarkTheme(mContext) + ? fragment.mRootView.mColorOnSurfaceHome + : fragment.mRootView.mColorSecondaryHome, + ".checkmarkBackground", fragment.mRootView.mColorSurfaceHome)); } @Override public int getIntroductionTitle() { - return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.string.home_gesture_tutorial_title - : R.string.home_gesture_intro_title; + return R.string.home_gesture_tutorial_title; } @Override public int getIntroductionSubtitle() { - return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.string.home_gesture_tutorial_subtitle - : R.string.home_gesture_intro_subtitle; + return R.string.home_gesture_tutorial_subtitle; } @Override @@ -72,9 +64,7 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll @Override public int getSuccessFeedbackTitle() { - return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.string.home_gesture_tutorial_success - : R.string.gesture_tutorial_nice; + return R.string.home_gesture_tutorial_success; } @Override diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java index a04dd4456b..e45f8d868e 100644 --- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java @@ -16,7 +16,6 @@ package com.android.quickstep.interaction; import static com.android.app.animation.Interpolators.ACCELERATE; -import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -49,34 +48,28 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont super(fragment, tutorialType); // Set the Lottie animation colors specifically for the Overview gesture - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - LottieAnimationColorUtils.updateToArgbColors( - mAnimatedGestureDemonstration, - Map.of(".onSurfaceOverview", fragment.mRootView.mColorOnSurfaceOverview, - ".surfaceOverview", fragment.mRootView.mColorSurfaceOverview, - ".secondaryOverview", fragment.mRootView.mColorSecondaryOverview)); - - LottieAnimationColorUtils.updateToArgbColors( - mCheckmarkAnimation, - Map.of(".checkmark", - Utilities.isDarkTheme(mContext) - ? fragment.mRootView.mColorOnSurfaceOverview - : fragment.mRootView.mColorSecondaryOverview, - ".checkmarkBackground", fragment.mRootView.mColorSurfaceOverview)); - } + LottieAnimationColorUtils.updateToArgbColors( + mAnimatedGestureDemonstration, + Map.of(".onSurfaceOverview", fragment.mRootView.mColorOnSurfaceOverview, + ".surfaceOverview", fragment.mRootView.mColorSurfaceOverview, + ".secondaryOverview", fragment.mRootView.mColorSecondaryOverview)); + + LottieAnimationColorUtils.updateToArgbColors( + mCheckmarkAnimation, + Map.of(".checkmark", + Utilities.isDarkTheme(mContext) + ? fragment.mRootView.mColorOnSurfaceOverview + : fragment.mRootView.mColorSecondaryOverview, + ".checkmarkBackground", fragment.mRootView.mColorSurfaceOverview)); } @Override public int getIntroductionTitle() { - return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.string.overview_gesture_tutorial_title - : R.string.overview_gesture_intro_title; + return R.string.overview_gesture_tutorial_title; } @Override public int getIntroductionSubtitle() { - return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.string.overview_gesture_tutorial_subtitle - : R.string.overview_gesture_intro_subtitle; + return R.string.overview_gesture_tutorial_subtitle; } @Override @@ -86,9 +79,7 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont @Override public int getSuccessFeedbackTitle() { - return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.string.overview_gesture_tutorial_success - : R.string.gesture_tutorial_nice; + return R.string.overview_gesture_tutorial_success; } @Override @@ -168,10 +159,7 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont @Override protected int getMockPreviousAppTaskThumbnailColor() { - return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? mTutorialFragment.mRootView.mColorSurfaceContainer - : mContext.getResources().getColor( - R.color.gesture_tutorial_fake_previous_task_view_color); + return mTutorialFragment.mRootView.mColorSurfaceContainer; } @Override @@ -224,11 +212,8 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont case OVERVIEW_GESTURE_COMPLETED: setGestureCompleted(); mTutorialFragment.releaseFeedbackAnimation(); - animateTaskViewToOverview(ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()); + animateTaskViewToOverview(true); onMotionPaused(true /*arbitrary value*/); - if (!ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - showSuccessFeedback(); - } break; case HOME_OR_OVERVIEW_NOT_STARTED_WRONG_SWIPE_DIRECTION: case HOME_OR_OVERVIEW_CANCELLED: diff --git a/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java b/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java index affedb9497..d733267d37 100644 --- a/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java +++ b/quickstep/src/com/android/quickstep/interaction/RootSandboxLayout.java @@ -15,16 +15,12 @@ */ package com.android.quickstep.interaction; -import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL; - import android.content.Context; import android.content.res.TypedArray; import android.graphics.Color; import android.graphics.Insets; -import android.graphics.Rect; import android.util.AttributeSet; import android.view.MotionEvent; -import android.view.View; import android.view.WindowInsets; import android.widget.RelativeLayout; @@ -39,10 +35,6 @@ import com.android.launcher3.Utilities; /** Root layout that TutorialFragment uses to intercept motion events. */ public class RootSandboxLayout extends RelativeLayout { - private final Rect mTempStepIndicatorBounds = new Rect(); - private final Rect mTempInclusionBounds = new Rect(); - private final Rect mTempExclusionBounds = new Rect(); - @ColorInt final int mColorSurfaceContainer; @ColorInt final int mColorOnSurfaceHome; @ColorInt final int mColorSurfaceHome; @@ -54,11 +46,6 @@ public class RootSandboxLayout extends RelativeLayout { @ColorInt final int mColorSurfaceOverview; @ColorInt final int mColorSecondaryOverview; - private View mFeedbackView; - private View mTutorialStepView; - private View mSkipButton; - private View mDoneButton; - public RootSandboxLayout(Context context) { this(context, null); } @@ -123,56 +110,4 @@ public class RootSandboxLayout extends RelativeLayout { return getHeight() + insets.top + insets.bottom; } - - @Override - protected void onFinishInflate() { - super.onFinishInflate(); - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - return; - } - mFeedbackView = findViewById(R.id.gesture_tutorial_fragment_feedback_view); - mTutorialStepView = - mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_feedback_tutorial_step); - mSkipButton = mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_close_button); - mDoneButton = mFeedbackView.findViewById(R.id.gesture_tutorial_fragment_action_button); - - mFeedbackView.addOnLayoutChangeListener( - (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> { - if (mSkipButton.getVisibility() != VISIBLE - && mDoneButton.getVisibility() != VISIBLE) { - return; - } - // Either the skip or the done button is ever shown at once, never both. - boolean showingSkipButton = mSkipButton.getVisibility() == VISIBLE; - boolean isRTL = Utilities.isRtl(getContext().getResources()); - updateTutorialStepViewTranslation( - showingSkipButton ? mSkipButton : mDoneButton, - // Translate the step indicator away from whichever button is being - // shown. The skip button in on the left in LTR or on the right in RTL. - // The done button is on the right in LTR or left in RTL. - (showingSkipButton && !isRTL) || (!showingSkipButton && isRTL)); - }); - } - - private void updateTutorialStepViewTranslation( - @NonNull View anchorView, boolean translateToRight) { - mTempStepIndicatorBounds.set( - mTutorialStepView.getLeft(), - mTutorialStepView.getTop(), - mTutorialStepView.getRight(), - mTutorialStepView.getBottom()); - mTempInclusionBounds.set(0, 0, mFeedbackView.getWidth(), mFeedbackView.getHeight()); - mTempExclusionBounds.set( - anchorView.getLeft(), - anchorView.getTop(), - anchorView.getRight(), - anchorView.getBottom()); - - Utilities.translateOverlappingView( - mTutorialStepView, - mTempStepIndicatorBounds, - mTempInclusionBounds, - mTempExclusionBounds, - translateToRight ? Utilities.TRANSLATE_RIGHT : Utilities.TRANSLATE_LEFT); - } } diff --git a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java index ad13efbd42..e462706c98 100644 --- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java @@ -48,7 +48,6 @@ import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.AnimatorListeners; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; -import com.android.launcher3.config.FeatureFlags; import com.android.quickstep.GestureState; import com.android.quickstep.OverviewComponentObserver; import com.android.quickstep.RecentsAnimationDeviceState; @@ -127,9 +126,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController { void resetTaskViews() { mFakeHotseatView.setVisibility(View.INVISIBLE); mFakeIconView.setVisibility(View.INVISIBLE); - if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - mFakeIconView.getBackground().setTint(getFakeTaskViewColor()); - } + mFakeIconView.getBackground().setTint(getFakeTaskViewColor()); if (mTutorialFragment.getActivity() != null) { int height = mTutorialFragment.getRootView().getFullscreenHeight(); int width = mTutorialFragment.getRootView().getWidth(); @@ -138,9 +135,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController { mFakeTaskViewRadius = 0; mFakeTaskView.invalidateOutline(); mFakeTaskView.setVisibility(View.VISIBLE); - if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - mFakeTaskView.setBackgroundColor(getFakeTaskViewColor()); - } + mFakeTaskView.setBackgroundColor(getFakeTaskViewColor()); mFakeTaskView.setAlpha(1); mFakePreviousTaskView.setVisibility(View.INVISIBLE); mFakePreviousTaskView.setAlpha(1); @@ -390,12 +385,10 @@ abstract class SwipeUpGestureTutorialController extends TutorialController { false, /* isOpening */ mFakeIconView, mDp); mFakeIconView.setAlpha(1); - if (FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - int iconColor = ColorUtils.blendARGB( - getFakeTaskViewColor(), getHotseatIconColor(), progress); - mFakeIconView.getBackground().setTint(iconColor); - mFakeTaskView.setBackgroundColor(iconColor); - } + int iconColor = ColorUtils.blendARGB( + getFakeTaskViewColor(), getHotseatIconColor(), progress); + mFakeIconView.getBackground().setTint(iconColor); + mFakeTaskView.setBackgroundColor(iconColor); mFakeTaskView.setAlpha(getWindowAlpha(progress)); mFakePreviousTaskView.setAlpha(getWindowAlpha(progress)); } diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java index 54653fafd5..5028da4f6a 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java @@ -19,10 +19,7 @@ import static android.view.View.GONE; import static android.view.View.NO_ID; import static android.view.View.inflate; -import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL; - import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; @@ -33,7 +30,6 @@ import android.graphics.Color; import android.graphics.Matrix; import android.graphics.Outline; import android.graphics.Rect; -import android.graphics.drawable.AnimatedVectorDrawable; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.RippleDrawable; import android.util.Log; @@ -52,7 +48,6 @@ import androidx.annotation.CallSuper; import androidx.annotation.ColorInt; import androidx.annotation.DrawableRes; import androidx.annotation.LayoutRes; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.StringRes; import androidx.annotation.StyleRes; @@ -153,8 +148,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, mFakeHotseatView = rootView.findViewById(R.id.gesture_tutorial_fake_hotseat_view); mFakeIconView = rootView.findViewById(R.id.gesture_tutorial_fake_icon_view); mFakeTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_task_view); - mFakeTaskbarView = ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? null : rootView.findViewById(R.id.gesture_tutorial_fake_taskbar_view); + mFakeTaskbarView = null; mFakePreviousTaskView = rootView.findViewById(R.id.gesture_tutorial_fake_previous_task_view); mRippleView = rootView.findViewById(R.id.gesture_tutorial_ripple_view); @@ -165,32 +159,30 @@ abstract class TutorialController implements BackGestureAttemptCallback, mFingerDotView = rootView.findViewById(R.id.gesture_tutorial_finger_dot); mSkipTutorialDialog = createSkipTutorialDialog(); - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - mFullGestureDemonstration = rootView.findViewById(R.id.full_gesture_demonstration); - mCheckmarkAnimation = rootView.findViewById(R.id.checkmark_animation); - mAnimatedGestureDemonstration = rootView.findViewById( - R.id.gesture_demonstration_animations); - mExitingAppView = rootView.findViewById(R.id.exiting_app_back); - mScreenWidth = mTutorialFragment.getDeviceProfile().widthPx; - mScreenHeight = mTutorialFragment.getDeviceProfile().heightPx; - mExitingAppMargin = mContext.getResources().getDimensionPixelSize( - R.dimen.gesture_tutorial_back_gesture_exiting_app_margin); - mExitingAppStartingCornerRadius = QuickStepContract.getWindowCornerRadius(mContext); - mExitingAppEndingCornerRadius = mContext.getResources().getDimensionPixelSize( - R.dimen.gesture_tutorial_back_gesture_end_corner_radius); - mAnimatedGestureDemonstration.addLottieOnCompositionLoadedListener( - this::createScalingMatrix); - - mFeedbackTitleView.setText(getIntroductionTitle()); - mFeedbackSubtitleView.setText(getIntroductionSubtitle()); - mExitingAppView.setClipToOutline(true); - mExitingAppView.setOutlineProvider(new ViewOutlineProvider() { - @Override - public void getOutline(View view, Outline outline) { - outline.setRoundRect(mExitingAppRect, mExitingAppRadius); - } - }); - } + mFullGestureDemonstration = rootView.findViewById(R.id.full_gesture_demonstration); + mCheckmarkAnimation = rootView.findViewById(R.id.checkmark_animation); + mAnimatedGestureDemonstration = rootView.findViewById( + R.id.gesture_demonstration_animations); + mExitingAppView = rootView.findViewById(R.id.exiting_app_back); + mScreenWidth = mTutorialFragment.getDeviceProfile().widthPx; + mScreenHeight = mTutorialFragment.getDeviceProfile().heightPx; + mExitingAppMargin = mContext.getResources().getDimensionPixelSize( + R.dimen.gesture_tutorial_back_gesture_exiting_app_margin); + mExitingAppStartingCornerRadius = QuickStepContract.getWindowCornerRadius(mContext); + mExitingAppEndingCornerRadius = mContext.getResources().getDimensionPixelSize( + R.dimen.gesture_tutorial_back_gesture_end_corner_radius); + mAnimatedGestureDemonstration.addLottieOnCompositionLoadedListener( + this::createScalingMatrix); + + mFeedbackTitleView.setText(getIntroductionTitle()); + mFeedbackSubtitleView.setText(getIntroductionSubtitle()); + mExitingAppView.setClipToOutline(true); + mExitingAppView.setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(mExitingAppRect, mExitingAppRadius); + } + }); mTitleViewCallback = () -> mFeedbackTitleView.sendAccessibilityEvent( AccessibilityEvent.TYPE_VIEW_FOCUSED); @@ -261,19 +253,11 @@ abstract class TutorialController implements BackGestureAttemptCallback, @LayoutRes protected int getMockHotseatResId() { - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - return mTutorialFragment.isLargeScreen() - ? mTutorialFragment.isFoldable() - ? R.layout.redesigned_gesture_tutorial_foldable_mock_hotseat - : R.layout.redesigned_gesture_tutorial_tablet_mock_hotseat - : R.layout.redesigned_gesture_tutorial_mock_hotseat; - } else { - return mTutorialFragment.isLargeScreen() - ? mTutorialFragment.isFoldable() - ? R.layout.gesture_tutorial_foldable_mock_hotseat - : R.layout.gesture_tutorial_tablet_mock_hotseat - : R.layout.gesture_tutorial_mock_hotseat; - } + return mTutorialFragment.isLargeScreen() + ? mTutorialFragment.isFoldable() + ? R.layout.redesigned_gesture_tutorial_foldable_mock_hotseat + : R.layout.redesigned_gesture_tutorial_tablet_mock_hotseat + : R.layout.redesigned_gesture_tutorial_mock_hotseat; } @LayoutRes @@ -312,9 +296,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, @DrawableRes public int getMockAppIconResId() { - return ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.drawable.redesigned_hotseat_icon - : R.drawable.default_sandbox_app_icon; + return R.drawable.redesigned_hotseat_icon; } @DrawableRes @@ -374,11 +356,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, mFeedbackView.setTranslationY(0); return; } - Animator gestureAnimation = mTutorialFragment.getGestureAnimation(); - AnimatedVectorDrawable edgeAnimation = mTutorialFragment.getEdgeAnimation(); - if (gestureAnimation != null && edgeAnimation != null) { - playFeedbackAnimation(gestureAnimation, edgeAnimation, mShowFeedbackRunnable, true); - } + playFeedbackAnimation(); } /** @@ -442,12 +420,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, } mFeedbackTitleView.setText(titleResId); - mFeedbackSubtitleView.setText( - ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() || spokenSubtitleResId == NO_ID - ? mContext.getText(subtitleResId) - : Utilities.wrapForTts( - mContext.getText(subtitleResId), - mContext.getString(spokenSubtitleResId))); + mFeedbackSubtitleView.setText(subtitleResId); if (isGestureSuccessful) { if (mTutorialFragment.isAtFinalStep()) { showActionButton(); @@ -458,27 +431,16 @@ abstract class TutorialController implements BackGestureAttemptCallback, mFakeTaskViewCallback = null; } - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - showSuccessPage(); - } + showSuccessPage(); } mGestureCompleted = isGestureSuccessful; - - Animator gestureAnimation = mTutorialFragment.getGestureAnimation(); - AnimatedVectorDrawable edgeAnimation = mTutorialFragment.getEdgeAnimation(); - if (!isGestureSuccessful && gestureAnimation != null && edgeAnimation != null) { - playFeedbackAnimation( - gestureAnimation, - edgeAnimation, - mShowFeedbackRunnable, - useGestureAnimationDelay); - return; + if (!isGestureSuccessful) { + playFeedbackAnimation(); } else { mTutorialFragment.releaseFeedbackAnimation(); + mFeedbackViewCallback = mShowFeedbackRunnable; + mFeedbackView.post(mFeedbackViewCallback); } - mFeedbackViewCallback = mShowFeedbackRunnable; - - mFeedbackView.post(mFeedbackViewCallback); } private void showSuccessPage() { @@ -517,79 +479,17 @@ abstract class TutorialController implements BackGestureAttemptCallback, mFeedbackTitleView.removeCallbacks(mTitleViewCallback); } - private void playFeedbackAnimation( - @NonNull Animator gestureAnimation, - @NonNull AnimatedVectorDrawable edgeAnimation, - @NonNull Runnable onStartRunnable, - boolean useGestureAnimationDelay) { - - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - mFeedbackView.setVisibility(View.VISIBLE); - mAnimatedGestureDemonstration.setVisibility(View.VISIBLE); - mFullGestureDemonstration.setVisibility(View.VISIBLE); - mAnimatedGestureDemonstration.playAnimation(); - return; - } - - if (gestureAnimation.isRunning()) { - gestureAnimation.cancel(); - } - if (edgeAnimation.isRunning()) { - edgeAnimation.reset(); - } - gestureAnimation.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationStart(Animator animation) { - super.onAnimationStart(animation); - - mEdgeGestureVideoView.setVisibility(GONE); - if (edgeAnimation.isRunning()) { - edgeAnimation.stop(); - } - - if (!useGestureAnimationDelay) { - onStartRunnable.run(); - } - } - - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - - mEdgeGestureVideoView.setVisibility(View.VISIBLE); - edgeAnimation.start(); - - gestureAnimation.removeListener(this); - } - }); - - cancelQueuedGestureAnimation(); - if (useGestureAnimationDelay) { - mFeedbackViewCallback = onStartRunnable; - mFakeTaskViewCallback = gestureAnimation::start; - - mFeedbackView.post(mFeedbackViewCallback); - mFakeTaskView.postDelayed(mFakeTaskViewCallback, GESTURE_ANIMATION_DELAY_MS); - } else { - gestureAnimation.start(); - } + private void playFeedbackAnimation() { + mFeedbackView.setVisibility(View.VISIBLE); + mAnimatedGestureDemonstration.setVisibility(View.VISIBLE); + mFullGestureDemonstration.setVisibility(View.VISIBLE); + mAnimatedGestureDemonstration.playAnimation(); } void setRippleHotspot(float x, float y) { mRippleDrawable.setHotspot(x, y); } - void showRippleEffect(@Nullable Runnable onCompleteRunnable) { - mRippleDrawable.setState( - new int[] {android.R.attr.state_pressed, android.R.attr.state_enabled}); - mRippleView.postDelayed(() -> { - mRippleDrawable.setState(new int[] {}); - if (onCompleteRunnable != null) { - onCompleteRunnable.run(); - } - }, RIPPLE_VISIBLE_MS); - } - void onActionButtonClicked(View button) { mTutorialFragment.continueTutorial(); } @@ -601,24 +501,19 @@ abstract class TutorialController implements BackGestureAttemptCallback, updateDrawables(); updateLayout(); - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - mFeedbackTitleView.setTextAppearance(mContext, getTitleTextAppearance()); - mDoneButton.setTextAppearance(mContext, getDoneButtonTextAppearance()); - mDoneButton.getBackground().setTint(getDoneButtonColor()); - mCheckmarkAnimation.setAnimation(mTutorialFragment.isAtFinalStep() - ? R.raw.checkmark_animation_end - : R.raw.checkmark_animation_in_progress); - if (!isGestureCompleted()) { - mCheckmarkAnimation.setVisibility(GONE); - startGestureAnimation(); - if (mTutorialType == TutorialType.BACK_NAVIGATION) { - resetViewsForBackGesture(); - } - + mFeedbackTitleView.setTextAppearance(mContext, getTitleTextAppearance()); + mDoneButton.setTextAppearance(mContext, getDoneButtonTextAppearance()); + mDoneButton.getBackground().setTint(getDoneButtonColor()); + mCheckmarkAnimation.setAnimation(mTutorialFragment.isAtFinalStep() + ? R.raw.checkmark_animation_end + : R.raw.checkmark_animation_in_progress); + if (!isGestureCompleted()) { + mCheckmarkAnimation.setVisibility(GONE); + startGestureAnimation(); + if (mTutorialType == TutorialType.BACK_NAVIGATION) { + resetViewsForBackGesture(); } - } else { - hideFeedback(); - hideActionButton(); + } mGestureCompleted = false; @@ -654,13 +549,6 @@ abstract class TutorialController implements BackGestureAttemptCallback, : R.style.TextAppearance_GestureTutorial_Feedback_Subtext_Dark); } - void hideActionButton() { - mSkipButton.setVisibility(View.VISIBLE); - // Invisible to maintain the layout. - mDoneButton.setVisibility(View.INVISIBLE); - mDoneButton.setOnClickListener(null); - } - void showActionButton() { mSkipButton.setVisibility(GONE); mDoneButton.setVisibility(View.VISIBLE); @@ -711,10 +599,8 @@ abstract class TutorialController implements BackGestureAttemptCallback, } private void updateSubtext() { - if (!ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - mTutorialStepView.setTutorialProgress( - mTutorialFragment.getCurrentStep(), mTutorialFragment.getNumSteps()); - } + mTutorialStepView.setTutorialProgress( + mTutorialFragment.getCurrentStep(), mTutorialFragment.getNumSteps()); } private void updateHotseatChildViewColor(@Nullable View child) { @@ -727,9 +613,7 @@ abstract class TutorialController implements BackGestureAttemptCallback, mTutorialFragment.getRootView().setBackground(AppCompatResources.getDrawable( mContext, getMockWallpaperResId())); mTutorialFragment.updateFeedbackAnimation(); - mFakeLauncherView.setBackgroundColor(ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? getFakeLauncherColor() - : mContext.getColor(R.color.gesture_tutorial_fake_wallpaper_color)); + mFakeLauncherView.setBackgroundColor(getFakeLauncherColor()); updateFakeViewLayout(mFakeHotseatView, getMockHotseatResId()); mHotseatIconView = mFakeHotseatView.findViewById(R.id.hotseat_icon_1); mFakeTaskView.animate().alpha(1).setListener( @@ -738,19 +622,15 @@ abstract class TutorialController implements BackGestureAttemptCallback, mFakeIconView.setBackground(AppCompatResources.getDrawable( mContext, getMockAppIconResId())); - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - mExitingAppView.setBackgroundColor(getExitingAppColor()); - mFakeTaskView.setBackgroundColor(getFakeTaskViewColor()); - updateHotseatChildViewColor(mHotseatIconView); - updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_2)); - updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_3)); - updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_4)); - updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_5)); - updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_6)); - updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_search_bar)); - } else { - updateFakeViewLayout(mFakeTaskView, getMockAppTaskLayoutResId()); - } + mExitingAppView.setBackgroundColor(getExitingAppColor()); + mFakeTaskView.setBackgroundColor(getFakeTaskViewColor()); + updateHotseatChildViewColor(mHotseatIconView); + updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_2)); + updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_3)); + updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_4)); + updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_5)); + updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_icon_6)); + updateHotseatChildViewColor(mFakeHotseatView.findViewById(R.id.hotseat_search_bar)); } } diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java index 0fafb94d1e..2ff2c836ae 100644 --- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java +++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java @@ -17,7 +17,6 @@ package com.android.quickstep.interaction; import static android.view.View.NO_ID; -import static com.android.launcher3.config.FeatureFlags.ENABLE_NEW_GESTURE_NAV_TUTORIAL; import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_GESTURE_COMPLETE; import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_TUTORIAL_TYPE; import static com.android.quickstep.interaction.GestureSandboxActivity.KEY_USE_TUTORIAL_MENU; @@ -215,9 +214,7 @@ abstract class TutorialFragment extends GestureSandboxFragment implements OnTouc super.onCreateView(inflater, container, savedInstanceState); mRootView = (RootSandboxLayout) inflater.inflate( - ENABLE_NEW_GESTURE_NAV_TUTORIAL.get() - ? R.layout.redesigned_gesture_tutorial_fragment - : R.layout.gesture_tutorial_fragment, + R.layout.redesigned_gesture_tutorial_fragment, container, false); @@ -383,10 +380,7 @@ abstract class TutorialFragment extends GestureSandboxFragment implements OnTouc if (mTutorialController != null && !isGestureComplete()) { mTutorialController.hideFeedback(); } - - if (ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()) { - mTutorialController.pauseAndHideLottieAnimation(); - } + mTutorialController.pauseAndHideLottieAnimation(); // Note: Using logical-or to ensure both functions get called. return mEdgeBackGestureHandler.onTouch(view, motionEvent) diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java index 717f6c879b..995635fa6c 100644 --- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java +++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java @@ -43,16 +43,21 @@ import androidx.annotation.VisibleForTesting; 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 org.xmlpull.v1.XmlPullParserException; 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 @@ public class SettingsChangeLogger implements /** * 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 @@ public class SettingsChangeLogger implements 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); + + getPrefs(context).registerOnSharedPreferenceChangeListener(this); + getDevicePrefs(context).registerOnSharedPreferenceChangeListener(this); - SettingsCache mSettingsCache = SettingsCache.INSTANCE.get(context); - mSettingsCache.register(NOTIFICATION_BADGING_URI, - this::onNotificationDotsChanged); - onNotificationDotsChanged(mSettingsCache.getValue(NOTIFICATION_BADGING_URI)); + 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 class SettingsChangeLogger implements 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 ec04cb767d..658975c4a9 100644 --- a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt +++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt @@ -37,6 +37,7 @@ import android.widget.LinearLayout import androidx.annotation.VisibleForTesting import androidx.core.util.component1 import androidx.core.util.component2 +import androidx.core.view.updateLayoutParams import com.android.launcher3.DeviceProfile import com.android.launcher3.Flags import com.android.launcher3.LauncherAnimUtils @@ -242,7 +243,30 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler { lp.height = ViewGroup.LayoutParams.WRAP_CONTENT } - override fun getDwbLayoutTranslations( + override fun updateDwbBannerLayout( + taskViewWidth: Int, + taskViewHeight: Int, + isGroupedTaskView: Boolean, + deviceProfile: DeviceProfile, + snapshotViewWidth: Int, + snapshotViewHeight: Int, + banner: View + ) { + banner.pivotX = 0f + banner.pivotY = 0f + banner.rotation = degreesRotated + banner.updateLayoutParams<FrameLayout.LayoutParams> { + gravity = Gravity.TOP or if (banner.isLayoutRtl) Gravity.END else Gravity.START + width = + if (isGroupedTaskView) { + snapshotViewHeight + } else { + taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx + } + } + } + + override fun getDwbBannerTranslations( taskViewWidth: Int, taskViewHeight: Int, splitBounds: SplitBounds?, @@ -252,39 +276,25 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler { banner: View ): Pair<Float, Float> { val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams - val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL val translationX = banner.height.toFloat() - - val bannerParams = banner.layoutParams as FrameLayout.LayoutParams - bannerParams.gravity = Gravity.TOP or if (isRtl) Gravity.END else Gravity.START - banner.pivotX = 0f - banner.pivotY = 0f - banner.rotation = degreesRotated - - if (splitBounds == null) { - // Single, fullscreen case - bannerParams.width = taskViewHeight - snapshotParams.topMargin - return Pair(translationX, snapshotParams.topMargin.toFloat()) - } - - // Set correct width and translations val translationY: Float - if (desiredTaskId == splitBounds.leftTopTaskId) { - bannerParams.width = thumbnailViews[0].measuredHeight + if (splitBounds == null) { translationY = snapshotParams.topMargin.toFloat() } else { - bannerParams.width = thumbnailViews[1].measuredHeight - val topLeftTaskPlusDividerPercent = - if (splitBounds.appsStackedVertically) { - splitBounds.topTaskPercent + splitBounds.dividerHeightPercent - } else { - splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent - } - translationY = - snapshotParams.topMargin + - (taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent + if (desiredTaskId == splitBounds.leftTopTaskId) { + translationY = snapshotParams.topMargin.toFloat() + } else { + val topLeftTaskPlusDividerPercent = + if (splitBounds.appsStackedVertically) { + splitBounds.topTaskPercent + splitBounds.dividerHeightPercent + } else { + splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent + } + translationY = + snapshotParams.topMargin + + (taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent + } } - return Pair(translationX, translationY) } @@ -300,6 +310,7 @@ open class LandscapePagedViewHandler : RecentsPagedOrientationHandler { if (isRtl) displacement < 0 else displacement > 0 override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) 1 else -1 + /* -------------------- */ override fun getChildBounds( diff --git a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java index eeacee1cf6..cc022b202e 100644 --- a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java +++ b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java @@ -243,54 +243,54 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements } @Override - public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth, - int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile, - View[] thumbnailViews, int desiredTaskId, View banner) { - float translationX = 0; - float translationY = 0; + public void updateDwbBannerLayout(int taskViewWidth, int taskViewHeight, + boolean isGroupedTaskView, @NonNull DeviceProfile deviceProfile, + int snapshotViewWidth, int snapshotViewHeight, @NonNull View banner) { FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams(); banner.setPivotX(0); banner.setPivotY(0); banner.setRotation(getDegreesRotated()); - if (splitBounds == null) { - // Single, fullscreen case + if (isGroupedTaskView) { + bannerParams.gravity = + BOTTOM | (deviceProfile.isLeftRightSplit ? START : CENTER_HORIZONTAL); + bannerParams.width = snapshotViewWidth; + } else { bannerParams.width = MATCH_PARENT; bannerParams.gravity = BOTTOM | CENTER_HORIZONTAL; - return new Pair<>(translationX, translationY); - } - - bannerParams.gravity = - BOTTOM | (deviceProfile.isLeftRightSplit ? START : CENTER_HORIZONTAL); - - // Set correct width - if (desiredTaskId == splitBounds.leftTopTaskId) { - bannerParams.width = thumbnailViews[0].getMeasuredWidth(); - } else { - bannerParams.width = thumbnailViews[1].getMeasuredWidth(); } + banner.setLayoutParams(bannerParams); + } - // Set translations - if (deviceProfile.isLeftRightSplit) { - if (desiredTaskId == splitBounds.rightBottomTaskId) { - float leftTopTaskPercent = splitBounds.appsStackedVertically - ? splitBounds.topTaskPercent - : splitBounds.leftTaskPercent; - float dividerThicknessPercent = splitBounds.appsStackedVertically - ? splitBounds.dividerHeightPercent - : splitBounds.dividerWidthPercent; - translationX = ((taskViewWidth * leftTopTaskPercent) - + (taskViewWidth * dividerThicknessPercent)); - } - } else { - if (desiredTaskId == splitBounds.leftTopTaskId) { - FrameLayout.LayoutParams snapshotParams = - (FrameLayout.LayoutParams) thumbnailViews[0] - .getLayoutParams(); - float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically - ? (1f - splitBounds.topTaskPercent) - : (1f - splitBounds.leftTaskPercent); - translationY = -((taskViewHeight - snapshotParams.topMargin) - * bottomRightTaskPlusDividerPercent); + @NonNull + @Override + public Pair<Float, Float> getDwbBannerTranslations(int taskViewWidth, + int taskViewHeight, SplitBounds splitBounds, @NonNull DeviceProfile deviceProfile, + @NonNull View[] thumbnailViews, int desiredTaskId, @NonNull View banner) { + float translationX = 0; + float translationY = 0; + if (splitBounds != null) { + if (deviceProfile.isLeftRightSplit) { + if (desiredTaskId == splitBounds.rightBottomTaskId) { + float leftTopTaskPercent = splitBounds.appsStackedVertically + ? splitBounds.topTaskPercent + : splitBounds.leftTaskPercent; + float dividerThicknessPercent = splitBounds.appsStackedVertically + ? splitBounds.dividerHeightPercent + : splitBounds.dividerWidthPercent; + translationX = ((taskViewWidth * leftTopTaskPercent) + + (taskViewWidth * dividerThicknessPercent)); + } + } else { + if (desiredTaskId == splitBounds.leftTopTaskId) { + FrameLayout.LayoutParams snapshotParams = + (FrameLayout.LayoutParams) thumbnailViews[0] + .getLayoutParams(); + float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically + ? (1f - splitBounds.topTaskPercent) + : (1f - splitBounds.leftTaskPercent); + translationY = -((taskViewHeight - snapshotParams.topMargin) + * bottomRightTaskPlusDividerPercent); + } } } return new Pair<>(translationX, translationY); @@ -535,6 +535,18 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements int parentWidth, int parentHeight, SplitBounds splitBoundsConfig, DeviceProfile dp, boolean isRtl) { int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx; + + FrameLayout.LayoutParams primaryParams = + (FrameLayout.LayoutParams) primarySnapshot.getLayoutParams(); + FrameLayout.LayoutParams secondaryParams = + (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams(); + + // Reset margin and translations 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 ? splitBoundsConfig.dividerHeightPercent @@ -552,24 +564,14 @@ public class PortraitPagedViewHandler extends DefaultPagedViewHandler implements secondarySnapshot.setTranslationX(translationX); primarySnapshot.setTranslationX(0); } - secondarySnapshot.setTranslationY(spaceAboveSnapshot); - // Reset unused translations - primarySnapshot.setTranslationY(0); + secondarySnapshot.setTranslationY(spaceAboveSnapshot); } else { float finalDividerHeight = Math.round(totalThumbnailHeight * dividerScale); float translationY = taskViewSizes.first.y + spaceAboveSnapshot + finalDividerHeight; secondarySnapshot.setTranslationY(translationY); - FrameLayout.LayoutParams primaryParams = - (FrameLayout.LayoutParams) primarySnapshot.getLayoutParams(); - FrameLayout.LayoutParams secondaryParams = - (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams(); - secondaryParams.topMargin = 0; - primaryParams.topMargin = spaceAboveSnapshot; - - // Reset unused translations - primarySnapshot.setTranslationY(0); + // Reset unused translations. secondarySnapshot.setTranslationX(0); primarySnapshot.setTranslationX(0); } diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt index df4b03038f..06a0685d6c 100644 --- a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt +++ b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt @@ -199,6 +199,7 @@ interface RecentsPagedOrientationHandler : PagedOrientationHandler { parentWidth: Int, parentHeight: Int ): Pair<Point, Point> + // Overview TaskMenuView methods /** Sets layout params on a task's app icon. Only use this when app chip is disabled. */ fun setTaskIconParams( @@ -294,13 +295,24 @@ interface RecentsPagedOrientationHandler : PagedOrientationHandler { deviceProfile: DeviceProfile ) + /** Layout a Digital Wellbeing Banner on its parent. TaskView. */ + fun updateDwbBannerLayout( + taskViewWidth: Int, + taskViewHeight: Int, + isGroupedTaskView: Boolean, + deviceProfile: DeviceProfile, + snapshotViewWidth: Int, + snapshotViewHeight: Int, + banner: View + ) + /** - * Calculates the position where a Digital Wellbeing Banner should be placed on its parent + * Calculates the translations where a Digital Wellbeing Banner should be apply on its parent * TaskView. * * @return A Pair of Floats representing the proper x and y translations. */ - fun getDwbLayoutTranslations( + fun getDwbBannerTranslations( taskViewWidth: Int, taskViewHeight: Int, splitBounds: SplitConfigurationOptions.SplitBounds?, @@ -309,6 +321,7 @@ interface RecentsPagedOrientationHandler : PagedOrientationHandler { desiredTaskId: Int, banner: View ): Pair<Float, Float> + // The following are only used by TaskViewTouchHandler. /** @return Either VERTICAL or HORIZONTAL. */ diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt index 333359fdd8..a972e8c1ef 100644 --- a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt +++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt @@ -28,6 +28,7 @@ import android.view.View.MeasureSpec import android.widget.FrameLayout import androidx.core.util.component1 import androidx.core.util.component2 +import androidx.core.view.updateLayoutParams import com.android.launcher3.DeviceProfile import com.android.launcher3.Flags import com.android.launcher3.R @@ -125,7 +126,30 @@ class SeascapePagedViewHandler : LandscapePagedViewHandler() { } } - override fun getDwbLayoutTranslations( + override fun updateDwbBannerLayout( + taskViewWidth: Int, + taskViewHeight: Int, + isGroupedTaskView: Boolean, + deviceProfile: DeviceProfile, + snapshotViewWidth: Int, + snapshotViewHeight: Int, + banner: View + ) { + banner.pivotX = 0f + banner.pivotY = 0f + banner.rotation = degreesRotated + banner.updateLayoutParams<FrameLayout.LayoutParams> { + gravity = Gravity.BOTTOM or if (banner.isLayoutRtl) Gravity.END else Gravity.START + width = + if (isGroupedTaskView) { + snapshotViewHeight + } else { + taskViewHeight - deviceProfile.overviewTaskThumbnailTopMarginPx + } + } + } + + override fun getDwbBannerTranslations( taskViewWidth: Int, taskViewHeight: Int, splitBounds: SplitBounds?, @@ -135,39 +159,26 @@ class SeascapePagedViewHandler : LandscapePagedViewHandler() { banner: View ): Pair<Float, Float> { val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams - val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL - - val bannerParams = banner.layoutParams as FrameLayout.LayoutParams - bannerParams.gravity = Gravity.BOTTOM or if (isRtl) Gravity.END else Gravity.START - banner.pivotX = 0f - banner.pivotY = 0f - banner.rotation = degreesRotated - val translationX: Float = (taskViewWidth - banner.height).toFloat() - if (splitBounds == null) { - // Single, fullscreen case - bannerParams.width = taskViewHeight - snapshotParams.topMargin - return Pair(translationX, banner.height.toFloat()) - } - - // Set correct width and translations val translationY: Float - if (desiredTaskId == splitBounds.leftTopTaskId) { - bannerParams.width = thumbnailViews[0].measuredHeight - val bottomRightTaskPlusDividerPercent = - if (splitBounds.appsStackedVertically) { - 1f - splitBounds.topTaskPercent - } else { - 1f - splitBounds.leftTaskPercent - } - translationY = - banner.height - - (taskViewHeight - snapshotParams.topMargin) * bottomRightTaskPlusDividerPercent - } else { - bannerParams.width = thumbnailViews[1].measuredHeight + if (splitBounds == null) { translationY = banner.height.toFloat() + } else { + if (desiredTaskId == splitBounds.leftTopTaskId) { + val bottomRightTaskPlusDividerPercent = + if (splitBounds.appsStackedVertically) { + 1f - splitBounds.topTaskPercent + } else { + 1f - splitBounds.leftTaskPercent + } + translationY = + banner.height - + (taskViewHeight - snapshotParams.topMargin) * + bottomRightTaskPlusDividerPercent + } else { + translationY = banner.height.toFloat() + } } - return Pair(translationX, translationY) } @@ -339,6 +350,7 @@ class SeascapePagedViewHandler : LandscapePagedViewHandler() { if (isRtl) displacement > 0 else displacement < 0 override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) -1 else 1 + /* -------------------- */ override fun getSplitIconsPosition( diff --git a/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt index a141e89c23..a45d194a1c 100644 --- a/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt +++ b/quickstep/src/com/android/quickstep/recents/data/TaskVisualsChangedDelegate.kt @@ -23,6 +23,7 @@ import com.android.quickstep.recents.data.TaskVisualsChangedDelegate.TaskThumbna import com.android.quickstep.util.TaskVisualsChangeListener import com.android.systemui.shared.recents.model.Task import com.android.systemui.shared.recents.model.ThumbnailData +import java.util.concurrent.ConcurrentHashMap /** Delegates the checking of task visuals (thumbnails, high res changes, icons) */ interface TaskVisualsChangedDelegate : @@ -30,7 +31,7 @@ interface TaskVisualsChangedDelegate : /** Registers a callback for visuals relating to icons */ fun registerTaskIconChangedCallback( taskKey: Task.TaskKey, - taskIconChangedCallback: TaskIconChangedCallback + taskIconChangedCallback: TaskIconChangedCallback, ) /** Unregisters a callback for visuals relating to icons */ @@ -39,7 +40,7 @@ interface TaskVisualsChangedDelegate : /** Registers a callback for visuals relating to thumbnails */ fun registerTaskThumbnailChangedCallback( taskKey: Task.TaskKey, - taskThumbnailChangedCallback: TaskThumbnailChangedCallback + taskThumbnailChangedCallback: TaskThumbnailChangedCallback, ) /** Unregisters a callback for visuals relating to thumbnails */ @@ -66,31 +67,9 @@ class TaskVisualsChangedDelegateImpl( private val highResLoadingStateNotifier: HighResLoadingStateNotifier, ) : TaskVisualsChangedDelegate { private val taskIconChangedCallbacks = - mutableMapOf<Int, Pair<Task.TaskKey, TaskIconChangedCallback>>() + ConcurrentHashMap<Int, Pair<Task.TaskKey, TaskIconChangedCallback>>() private val taskThumbnailChangedCallbacks = - mutableMapOf<Int, Pair<Task.TaskKey, TaskThumbnailChangedCallback>>() - private var isListening = false - - @Synchronized - private fun onCallbackRegistered() { - if (isListening) return - - taskVisualsChangeNotifier.addThumbnailChangeListener(this) - highResLoadingStateNotifier.addCallback(this) - isListening = true - } - - @Synchronized - private fun onCallbackUnregistered() { - if (!isListening) return - - if (taskIconChangedCallbacks.size + taskThumbnailChangedCallbacks.size == 0) { - taskVisualsChangeNotifier.removeThumbnailChangeListener(this) - highResLoadingStateNotifier.removeCallback(this) - } - - isListening = false - } + ConcurrentHashMap<Int, Pair<Task.TaskKey, TaskThumbnailChangedCallback>>() override fun onTaskIconChanged(taskId: Int) { taskIconChangedCallbacks[taskId]?.let { (_, callback) -> callback.onTaskIconChanged() } @@ -119,27 +98,48 @@ class TaskVisualsChangedDelegateImpl( override fun registerTaskIconChangedCallback( taskKey: Task.TaskKey, - taskIconChangedCallback: TaskIconChangedCallback + taskIconChangedCallback: TaskIconChangedCallback, ) { - taskIconChangedCallbacks[taskKey.id] = taskKey to taskIconChangedCallback - onCallbackRegistered() + updateCallbacks { + taskIconChangedCallbacks[taskKey.id] = taskKey to taskIconChangedCallback + } } override fun unregisterTaskIconChangedCallback(taskKey: Task.TaskKey) { - taskIconChangedCallbacks.remove(taskKey.id) - onCallbackUnregistered() + updateCallbacks { taskIconChangedCallbacks.remove(taskKey.id) } } override fun registerTaskThumbnailChangedCallback( taskKey: Task.TaskKey, - taskThumbnailChangedCallback: TaskThumbnailChangedCallback + taskThumbnailChangedCallback: TaskThumbnailChangedCallback, ) { - taskThumbnailChangedCallbacks[taskKey.id] = taskKey to taskThumbnailChangedCallback - onCallbackRegistered() + updateCallbacks { + taskThumbnailChangedCallbacks[taskKey.id] = taskKey to taskThumbnailChangedCallback + } } override fun unregisterTaskThumbnailChangedCallback(taskKey: Task.TaskKey) { - taskThumbnailChangedCallbacks.remove(taskKey.id) - onCallbackUnregistered() + updateCallbacks { taskThumbnailChangedCallbacks.remove(taskKey.id) } + } + + @Synchronized + private fun updateCallbacks(callbackModifier: () -> Unit) { + val prevHasCallbacks = + taskIconChangedCallbacks.size + taskThumbnailChangedCallbacks.size > 0 + callbackModifier() + + val currHasCallbacks = + taskIconChangedCallbacks.size + taskThumbnailChangedCallbacks.size > 0 + + when { + prevHasCallbacks && !currHasCallbacks -> { + taskVisualsChangeNotifier.removeThumbnailChangeListener(this) + highResLoadingStateNotifier.removeCallback(this) + } + !prevHasCallbacks && currHasCallbacks -> { + taskVisualsChangeNotifier.addThumbnailChangeListener(this) + highResLoadingStateNotifier.addCallback(this) + } + } } } diff --git a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt index 1716f2e2dc..5cf68239b8 100644 --- a/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt +++ b/quickstep/src/com/android/quickstep/recents/viewmodel/RecentsViewModel.kt @@ -24,7 +24,7 @@ import kotlinx.coroutines.flow.first class RecentsViewModel( private val recentsTasksRepository: RecentTasksRepository, - private val recentsViewData: RecentsViewData + private val recentsViewData: RecentsViewData, ) { fun refreshAllTaskData() { recentsTasksRepository.getAllTaskData(true) @@ -58,7 +58,8 @@ class RecentsViewModel( recentsViewData.thumbnailSplashProgress.value = taskThumbnailSplashAlpha } - suspend fun waitForThumbnailsToUpdate(updatedThumbnails: Map<Int, ThumbnailData>) { + suspend fun waitForThumbnailsToUpdate(updatedThumbnails: Map<Int, ThumbnailData>?) { + if (updatedThumbnails.isNullOrEmpty()) return combine( updatedThumbnails.map { recentsTasksRepository.getThumbnailById(it.key).filter { thumbnailData -> diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java index c7c04ed91c..b583a4bd3f 100644 --- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java +++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java @@ -21,7 +21,6 @@ import static com.android.launcher3.Flags.enableGridOnlyOverview; import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY; import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION; -import android.animation.AnimatorSet; import android.animation.TimeInterpolator; import android.content.Context; import android.graphics.Matrix; @@ -34,18 +33,11 @@ import androidx.annotation.Nullable; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherState; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; -import com.android.launcher3.statemanager.StateManager; -import com.android.launcher3.statemanager.StatefulActivity; -import com.android.launcher3.states.StateAnimationConfig; -import com.android.launcher3.touch.AllAppsSwipeController; -import com.android.quickstep.DeviceConfigWrapper; import com.android.quickstep.orientation.RecentsPagedOrientationHandler; import com.android.quickstep.views.RecentsView; -import com.android.quickstep.views.RecentsViewContainer; /** * Controls an animation that can go beyond progress = 1, at which point resistance should be @@ -57,10 +49,8 @@ public class AnimatorControllerWithResistance { private enum RecentsResistanceParams { FROM_APP(0.75f, 0.5f, 1f, false), - FROM_APP_TO_ALL_APPS(1f, 0.6f, 0.8f, false), FROM_APP_TABLET(1f, 0.7f, 1f, true), FROM_APP_TABLET_GRID_ONLY(1f, 1f, 1f, true), - FROM_APP_TO_ALL_APPS_TABLET(1f, 0.5f, 0.5f, false), FROM_OVERVIEW(1f, 0.75f, 0.5f, false); RecentsResistanceParams(float scaleStartResist, float scaleMaxResist, @@ -157,46 +147,10 @@ public class AnimatorControllerWithResistance { RecentsParams params = new RecentsParams(context, recentsOrientedState, dp, scaleTarget, scaleProperty, translationTarget, translationProperty); PendingAnimation resistAnim = createRecentsResistanceAnim(params); - - // Apply All Apps animation during the resistance animation. - if (recentsOrientedState.getContainerInterface().allowAllAppsFromOverview()) { - RecentsViewContainer container = - recentsOrientedState.getContainerInterface().getCreatedContainer(); - if (container != null) { - RecentsView recentsView = container.getOverviewPanel(); - StateManager<LauncherState, StatefulActivity<LauncherState>> stateManager = - recentsView.getStateManager(); - if (stateManager.isInStableState(LauncherState.BACKGROUND_APP) - && stateManager.isInTransition()) { - - // Calculate the resistance progress threshold where All Apps will trigger. - float threshold = getAllAppsThreshold(context, recentsOrientedState, dp); - - StateAnimationConfig config = new StateAnimationConfig(); - AllAppsSwipeController.applyOverviewToAllAppsAnimConfig(dp, config, threshold); - AnimatorSet allAppsAnimator = stateManager.createAnimationToNewWorkspace( - LauncherState.ALL_APPS, config).getTarget(); - resistAnim.add(allAppsAnimator); - } - } - } - AnimatorPlaybackController resistanceController = resistAnim.createPlaybackController(); return new AnimatorControllerWithResistance(normalController, resistanceController); } - private static float getAllAppsThreshold(Context context, - RecentsOrientedState recentsOrientedState, DeviceProfile dp) { - int transitionDragLength = - recentsOrientedState.getContainerInterface().getSwipeUpDestinationAndLength( - dp, context, TEMP_RECT, - recentsOrientedState.getOrientationHandler()); - float dragLengthFactor = (float) dp.heightPx / transitionDragLength; - // -1s are because 0-1 is reserved for the normal transition. - float threshold = DeviceConfigWrapper.get().getAllAppsOverviewThreshold() / 100f; - return (threshold - 1) / (dragLengthFactor - 1); - } - /** * Creates the resistance animation for {@link #createForRecents}, or can be used separately * when starting from recents, i.e. {@link #createRecentsResistanceFromOverviewAnim}. @@ -305,17 +259,11 @@ public class AnimatorControllerWithResistance { this.translationTarget = translationTarget; this.translationProperty = translationProperty; if (dp.isTablet) { - resistanceParams = - recentsOrientedState.getContainerInterface().allowAllAppsFromOverview() - ? RecentsResistanceParams.FROM_APP_TO_ALL_APPS_TABLET - : enableGridOnlyOverview() - ? RecentsResistanceParams.FROM_APP_TABLET_GRID_ONLY - : RecentsResistanceParams.FROM_APP_TABLET; + resistanceParams = enableGridOnlyOverview() + ? RecentsResistanceParams.FROM_APP_TABLET_GRID_ONLY + : RecentsResistanceParams.FROM_APP_TABLET; } else { - resistanceParams = - recentsOrientedState.getContainerInterface().allowAllAppsFromOverview() - ? RecentsResistanceParams.FROM_APP_TO_ALL_APPS - : RecentsResistanceParams.FROM_APP; + resistanceParams = RecentsResistanceParams.FROM_APP; } } diff --git a/quickstep/src/com/android/quickstep/util/BackAnimState.kt b/quickstep/src/com/android/quickstep/util/BackAnimState.kt new file mode 100644 index 0000000000..9009eaa263 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/BackAnimState.kt @@ -0,0 +1,70 @@ +/* + * 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 android.animation.AnimatorSet +import android.content.Context +import com.android.launcher3.LauncherAnimationRunner.AnimationResult +import com.android.launcher3.anim.AnimatorListeners.forEndCallback +import com.android.launcher3.util.RunnableList + +/** Interface to represent animation for back to Launcher transition */ +interface BackAnimState { + + fun addOnAnimCompleteCallback(r: Runnable) + + fun applyToAnimationResult(result: AnimationResult, c: Context) + + fun start() +} + +class AnimatorBackState(private val springAnim: RectFSpringAnim?, private val anim: AnimatorSet?) : + BackAnimState { + + override fun addOnAnimCompleteCallback(r: Runnable) { + val springAnimWait = RunnableList() + springAnim?.addAnimatorListener(forEndCallback(springAnimWait::executeAllAndDestroy)) + ?: springAnimWait.executeAllAndDestroy() + + val animWait = RunnableList() + anim?.addListener( + forEndCallback(Runnable { springAnimWait.add(animWait::executeAllAndDestroy) }) + ) ?: springAnimWait.add(animWait::executeAllAndDestroy) + animWait.add(r) + } + + override fun applyToAnimationResult(result: AnimationResult, c: Context) { + result.setAnimation(anim, c) + } + + override fun start() { + anim?.start() + } +} + +class AlreadyStartedBackAnimState(private val onEndCallback: RunnableList) : BackAnimState { + + override fun addOnAnimCompleteCallback(r: Runnable) { + onEndCallback.add(r) + } + + override fun applyToAnimationResult(result: AnimationResult, c: Context) { + addOnAnimCompleteCallback(result::onAnimationFinished) + } + + override fun start() {} +} diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java index 26668c8da3..4c26761440 100644 --- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java +++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java @@ -31,7 +31,6 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.Hotseat; import com.android.launcher3.Workspace; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.HorizontalInsettableView; import com.android.quickstep.SystemUiProxy; @@ -80,17 +79,12 @@ public class LauncherUnfoldAnimationController implements OnDeviceProfileChangeL @UnfoldMain RotationChangeProvider rotationChangeProvider) { mLauncher = launcher; - if (FeatureFlags.PREEMPTIVE_UNFOLD_ANIMATION_START.get()) { - mPreemptiveProgressProvider = new PreemptiveUnfoldTransitionProgressProvider( - unfoldTransitionProgressProvider, launcher.getMainThreadHandler()); - mPreemptiveProgressProvider.init(); + mPreemptiveProgressProvider = new PreemptiveUnfoldTransitionProgressProvider( + unfoldTransitionProgressProvider, launcher.getMainThreadHandler()); + mPreemptiveProgressProvider.init(); - mProgressProvider = new ScopedUnfoldTransitionProgressProvider( - mPreemptiveProgressProvider); - } else { - mProgressProvider = new ScopedUnfoldTransitionProgressProvider( - unfoldTransitionProgressProvider); - } + mProgressProvider = new ScopedUnfoldTransitionProgressProvider( + mPreemptiveProgressProvider); unfoldTransitionProgressProvider.addCallback(mExternalTransitionStatusProvider); unfoldTransitionProgressProvider.addCallback( @@ -169,10 +163,6 @@ public class LauncherUnfoldAnimationController implements OnDeviceProfileChangeL @Override public void onDeviceProfileChanged(DeviceProfile dp) { - if (!FeatureFlags.PREEMPTIVE_UNFOLD_ANIMATION_START.get()) { - return; - } - if (mIsTablet != null && dp.isTablet != mIsTablet) { // We should preemptively start the animation only if: // - We changed to the unfolded screen diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java index b9338a32ac..a8460c9d7c 100644 --- a/quickstep/src/com/android/quickstep/util/LayoutUtils.java +++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java @@ -23,7 +23,7 @@ import android.view.ViewGroup; import com.android.launcher3.DeviceProfile; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.NavigationMode; -import com.android.quickstep.LauncherActivityInterface; +import com.android.quickstep.BaseContainerInterface; import com.android.quickstep.orientation.RecentsPagedOrientationHandler; public class LayoutUtils { @@ -41,11 +41,14 @@ public class LayoutUtils { return swipeHeight; } - public static int getShelfTrackingDistance(Context context, DeviceProfile dp, - RecentsPagedOrientationHandler orientationHandler) { + public static int getShelfTrackingDistance( + Context context, + DeviceProfile dp, + RecentsPagedOrientationHandler orientationHandler, + BaseContainerInterface<?, ?> baseContainerInterface) { // Track the bottom of the window. Rect taskSize = new Rect(); - LauncherActivityInterface.INSTANCE.calculateTaskSize(context, dp, taskSize, + baseContainerInterface.calculateTaskSize(context, dp, taskSize, orientationHandler); return orientationHandler.getDistanceToBottomOfRect(dp, taskSize); } diff --git a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt index cf083916a9..be1af64f02 100644 --- a/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt +++ b/quickstep/src/com/android/quickstep/util/RecentsViewUtils.kt @@ -28,9 +28,17 @@ import com.android.systemui.shared.recents.model.ThumbnailData * and extracted functions from RecentsView to facilitate the implementation of unit tests. */ class RecentsViewUtils { + /** Takes a screenshot of all [taskView] and return map of taskId to the screenshot */ + fun screenshotTasks( + taskView: TaskView, + recentsAnimationController: RecentsAnimationController, + ): Map<Int, ThumbnailData> = + taskView.taskContainers.associate { + it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id) + } /** - * Sort task groups to move desktop tasks to the end of the list. + * Sorts task groups to move desktop tasks to the end of the list. * * @param tasks List of group tasks to be sorted. * @return Sorted list of GroupTasks to be used in the RecentsView. @@ -40,6 +48,7 @@ class RecentsViewUtils { return otherTasks + desktopTasks } + /** Returns the expected index of the focus task. */ fun getFocusedTaskIndex(taskGroups: List<GroupTask>): Int { // The focused task index is placed after the desktop tasks views. return if (enableLargeDesktopWindowingTile()) { @@ -49,33 +58,77 @@ class RecentsViewUtils { } } - /** - * Counts [numChildren] that are [DesktopTaskView] instances. - * - * @param numChildren Quantity of children to transverse - * @param getTaskViewAt Function that provides a TaskView given an index - */ - fun getDesktopTaskViewCount(numChildren: Int, getTaskViewAt: (Int) -> TaskView?): Int = - (0 until numChildren).count { getTaskViewAt(it) is DesktopTaskView } + /** Counts [TaskView]s that are [DesktopTaskView] instances. */ + fun getDesktopTaskViewCount(taskViews: Iterable<TaskView>): Int = + taskViews.count { it is DesktopTaskView } + + /** Returns a list of all large TaskView Ids from [TaskView]s */ + fun getLargeTaskViewIds(taskViews: Iterable<TaskView>): List<Int> = + taskViews.filter { it.isLargeTile }.map { it.taskViewId } /** * Returns the first TaskView that should be displayed as a large tile. * - * @param numChildren Quantity of children to transverse - * @param getTaskViewAt Function that provides a TaskView given an index + * @param taskViews List of [TaskView]s */ - fun getFirstLargeTaskView(numChildren: Int, getTaskViewAt: (Int) -> TaskView?): TaskView? { - return (0 until numChildren).firstNotNullOfOrNull { index -> - val taskView = getTaskViewAt(index) - if (taskView?.isLargeTile == true) taskView else null + fun getFirstLargeTaskView(taskViews: Iterable<TaskView>): TaskView? = + taskViews.firstOrNull { it.isLargeTile } + + /** Returns the last TaskView that should be displayed as a large tile. */ + fun getLastLargeTaskView(taskViews: Iterable<TaskView>): TaskView? = + taskViews.lastOrNull { it.isLargeTile } + + /** Returns the first [TaskView], with some tasks possibly hidden in the carousel. */ + fun getFirstTaskViewInCarousel( + nonRunningTaskCategoryHidden: Boolean, + taskViews: Iterable<TaskView>, + runningTaskView: TaskView?, + ): TaskView? = + taskViews.firstOrNull { + it.isVisibleInCarousel(runningTaskView, nonRunningTaskCategoryHidden) } - } - fun screenshotTasks( - taskView: TaskView, - recentsAnimationController: RecentsAnimationController - ): Map<Int, ThumbnailData> = - taskView.taskContainers.associate { - it.task.key.id to recentsAnimationController.screenshotTask(it.task.key.id) + /** Returns the last [TaskView], with some tasks possibly hidden in the carousel. */ + fun getLastTaskViewInCarousel( + nonRunningTaskCategoryHidden: Boolean, + taskViews: Iterable<TaskView>, + runningTaskView: TaskView?, + ): TaskView? = + taskViews.lastOrNull { + it.isVisibleInCarousel(runningTaskView, nonRunningTaskCategoryHidden) } + + /** Returns the current list of [TaskView] children. */ + fun getTaskViews(taskViewCount: Int, requireTaskViewAt: (Int) -> TaskView): Iterable<TaskView> = + (0 until taskViewCount).map(requireTaskViewAt) + + /** Apply attachAlpha to all [TaskView] accordingly to different conditions. */ + fun applyAttachAlpha( + taskViews: Iterable<TaskView>, + runningTaskView: TaskView?, + runningTaskTileHidden: Boolean, + nonRunningTaskCategoryHidden: Boolean, + ) { + taskViews.forEach { taskView -> + val isVisible = + if (taskView == runningTaskView) !runningTaskTileHidden + else taskView.isVisibleInCarousel(runningTaskView, nonRunningTaskCategoryHidden) + taskView.attachAlpha = if (isVisible) 1f else 0f + } + } + + private fun TaskView.isVisibleInCarousel( + runningTaskView: TaskView?, + nonRunningTaskCategoryHidden: Boolean, + ): Boolean = + if (!nonRunningTaskCategoryHidden) true + else if (runningTaskView == null) true else getCategory() == runningTaskView.getCategory() + + private fun TaskView.getCategory(): TaskViewCategory = + if (this is DesktopTaskView) TaskViewCategory.DESKTOP else TaskViewCategory.FULL_SCREEN + + private enum class TaskViewCategory { + FULL_SCREEN, + DESKTOP, + } } diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt index fa5a67a7e6..256e29e79a 100644 --- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt +++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt @@ -731,16 +731,19 @@ class SplitAnimationController(val splitSelectStateController: SplitSelectStateC val mainRootCandidate = splitRoots.first // Will contain changes (1) and (2) in diagram above val leafRoots: List<Change> = splitRoots.second + // Don't rely on DP.isLeftRightSplit because if launcher is portrait apps could still + // launch in landscape if system auto-rotate is enabled and phone is held horizontally + val isLeftRightSplit = leafRoots.all { it.endAbsBounds.top == 0 } // Find the place where our left/top app window meets the divider (used for the // launcher side animation) val leftTopApp = leafRoots.single { change -> - (dp.isLeftRightSplit && change.endAbsBounds.left == 0) || - (!dp.isLeftRightSplit && change.endAbsBounds.top == 0) + (isLeftRightSplit && change.endAbsBounds.left == 0) || + (!isLeftRightSplit && change.endAbsBounds.top == 0) } val dividerPos = - if (dp.isLeftRightSplit) leftTopApp.endAbsBounds.right + if (isLeftRightSplit) leftTopApp.endAbsBounds.right else leftTopApp.endAbsBounds.bottom // Create a new floating view in Launcher, positioned above the launching icon diff --git a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java index 304b8f47eb..f3b984b81e 100644 --- a/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java +++ b/quickstep/src/com/android/quickstep/util/SystemWindowManagerProxy.java @@ -15,6 +15,7 @@ */ package com.android.quickstep.util; +import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM; import static android.view.Display.DEFAULT_DISPLAY; import android.content.Context; @@ -30,7 +31,8 @@ import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.util.WindowBounds; import com.android.launcher3.util.window.CachedDisplayInfo; import com.android.launcher3.util.window.WindowManagerProxy; -import com.android.quickstep.LauncherActivityInterface; +import com.android.quickstep.SystemUiProxy; +import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import java.util.List; import java.util.Set; @@ -40,8 +42,17 @@ import java.util.Set; */ public class SystemWindowManagerProxy extends WindowManagerProxy { + private final TISBindHelper mTISBindHelper; + public SystemWindowManagerProxy(Context context) { super(true); + mTISBindHelper = new TISBindHelper(context, binder -> {}); + } + + @Override + public void close() { + super.close(); + mTISBindHelper.onDestroy(); } @Override @@ -53,11 +64,29 @@ public class SystemWindowManagerProxy extends WindowManagerProxy { @Override public boolean isInDesktopMode() { DesktopVisibilityController desktopController = - LauncherActivityInterface.INSTANCE.getDesktopVisibilityController(); + mTISBindHelper.getDesktopVisibilityController(); return desktopController != null && desktopController.areDesktopTasksVisible(); } @Override + public boolean showLockedTaskbarOnHome(Context displayInfoContext) { + if (!DesktopModeStatus.canEnterDesktopMode(displayInfoContext)) { + return false; + } + if (!DesktopModeStatus.enterDesktopByDefaultOnFreeformDisplay(displayInfoContext)) { + return false; + } + final boolean isFreeformDisplay = displayInfoContext.getResources().getConfiguration() + .windowConfiguration.getWindowingMode() == WINDOWING_MODE_FREEFORM; + return isFreeformDisplay; + } + + @Override + public boolean isHomeVisible(Context context) { + return SystemUiProxy.INSTANCE.get(context).getHomeVisibilityState().isHomeVisible(); + } + + @Override public int getRotation(Context displayInfoContext) { return displayInfoContext.getResources().getConfiguration().windowConfiguration .getRotation(); diff --git a/quickstep/src/com/android/quickstep/util/TISBindHelper.java b/quickstep/src/com/android/quickstep/util/TISBindHelper.java index 9a010429d3..b57360410e 100644 --- a/quickstep/src/com/android/quickstep/util/TISBindHelper.java +++ b/quickstep/src/com/android/quickstep/util/TISBindHelper.java @@ -25,6 +25,7 @@ import android.util.Log; import androidx.annotation.Nullable; +import com.android.launcher3.statehandlers.DesktopVisibilityController; import com.android.launcher3.taskbar.TaskbarManager; import com.android.quickstep.OverviewCommandHelper; import com.android.quickstep.TouchInteractionService; @@ -108,6 +109,11 @@ public class TISBindHelper implements ServiceConnection { return mBinder == null ? null : mBinder.getTaskbarManager(); } + @Nullable + public DesktopVisibilityController getDesktopVisibilityController() { + return mBinder == null ? null : mBinder.getDesktopVisibilityController(); + } + /** * Sets flag whether a predictive back-to-home animation is in progress */ diff --git a/quickstep/src/com/android/quickstep/util/TaskGridNavHelper.java b/quickstep/src/com/android/quickstep/util/TaskGridNavHelper.java index 98d363ef5c..498078b423 100644 --- a/quickstep/src/com/android/quickstep/util/TaskGridNavHelper.java +++ b/quickstep/src/com/android/quickstep/util/TaskGridNavHelper.java @@ -22,13 +22,13 @@ import androidx.annotation.IntDef; import com.android.launcher3.util.IntArray; import java.lang.annotation.Retention; +import java.util.List; /** * Helper class for navigating RecentsView grid tasks via arrow keys and tab. */ public class TaskGridNavHelper { public static final int CLEAR_ALL_PLACEHOLDER_ID = -1; - public static final int INVALID_FOCUSED_TASK_ID = -1; public static final int DIRECTION_UP = 0; public static final int DIRECTION_DOWN = 1; @@ -43,25 +43,25 @@ public class TaskGridNavHelper { private final IntArray mOriginalTopRowIds; private IntArray mTopRowIds; private IntArray mBottomRowIds; - private final int mFocusedTaskId; - public TaskGridNavHelper(IntArray topIds, IntArray bottomIds, int focusedTaskId) { - mFocusedTaskId = focusedTaskId; + public TaskGridNavHelper(IntArray topIds, IntArray bottomIds, + List<Integer> largeTileIds) { mOriginalTopRowIds = topIds.clone(); - generateTaskViewIdGrid(topIds, bottomIds); + generateTaskViewIdGrid(topIds, bottomIds, largeTileIds); } - private void generateTaskViewIdGrid(IntArray topRowIdArray, IntArray bottomRowIdArray) { - boolean hasFocusedTask = mFocusedTaskId != INVALID_FOCUSED_TASK_ID; - int maxSize = - Math.max(topRowIdArray.size(), bottomRowIdArray.size()) + (hasFocusedTask ? 1 : 0); - int minSize = - Math.min(topRowIdArray.size(), bottomRowIdArray.size()) + (hasFocusedTask ? 1 : 0); - - // Add the focused task to the beginning of both arrays if it exists. - if (hasFocusedTask) { - topRowIdArray.add(0, mFocusedTaskId); - bottomRowIdArray.add(0, mFocusedTaskId); + private void generateTaskViewIdGrid(IntArray topRowIdArray, IntArray bottomRowIdArray, + List<Integer> largeTileIds) { + + int maxSize = Math.max(topRowIdArray.size(), bottomRowIdArray.size()) + + largeTileIds.size(); + int minSize = Math.min(topRowIdArray.size(), bottomRowIdArray.size()) + + largeTileIds.size(); + + // Add Large tile task views first at the beginning + for (int i = 0; i < largeTileIds.size(); i++) { + topRowIdArray.add(i, largeTileIds.get(i)); + bottomRowIdArray.add(i, largeTileIds.get(i)); } // Fill in the shorter array with the ids from the longer one. diff --git a/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt b/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt index 09563f5527..915c9e5305 100644 --- a/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt +++ b/quickstep/src/com/android/quickstep/util/unfold/LauncherUnfoldTransitionController.kt @@ -22,7 +22,6 @@ import com.android.launcher3.Alarm import com.android.launcher3.DeviceProfile import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener import com.android.launcher3.anim.PendingAnimation -import com.android.launcher3.config.FeatureFlags import com.android.launcher3.uioverrides.QuickstepLauncher import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener @@ -30,7 +29,7 @@ import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionPr /** Controls animations that are happening during unfolding foldable devices */ class LauncherUnfoldTransitionController( private val launcher: QuickstepLauncher, - private val progressProvider: ProxyUnfoldTransitionProvider + private val progressProvider: ProxyUnfoldTransitionProvider, ) : OnDeviceProfileChangeListener, ActivityLifecycleCallbacksAdapter, TransitionProgressListener { private var isTablet: Boolean? = null @@ -57,10 +56,6 @@ class LauncherUnfoldTransitionController( } override fun onDeviceProfileChanged(dp: DeviceProfile) { - if (!FeatureFlags.PREEMPTIVE_UNFOLD_ANIMATION_START.get()) { - return - } - if (isTablet != null && dp.isTablet != isTablet) { // We should preemptively start the animation only if: // - We changed to the unfolded screen @@ -93,7 +88,7 @@ class LauncherUnfoldTransitionController( provider = this, factory = this::onPrepareUnfoldAnimation, duration = - 1000L // The expected duration for the animation. Then only comes to play if we have + 1000L, // The expected duration for the animation. Then only comes to play if we have // to run the animation ourselves in case sysui misses the end signal ) timeoutAlarm.cancelAlarm() @@ -119,7 +114,7 @@ class LauncherUnfoldTransitionController( launcher, isVertical, dp.displayInfo.currentSize, - anim + anim, ) } diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt index 41add5414d..6db0923563 100644 --- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt +++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt @@ -262,7 +262,7 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu } Log.d( TAG, - "launchTaskAnimated - launchTaskWithDesktopController: ${taskIds.contentToString()}, withRemoteTransition: $animated" + "launchTaskWithDesktopController: ${taskIds.contentToString()}, withRemoteTransition: $animated" ) // Callbacks get run from recentsView for case when recents animation already running @@ -270,11 +270,12 @@ class DesktopTaskView @JvmOverloads constructor(context: Context, attrs: Attribu return endCallback } - override fun launchTaskAnimated() = launchTaskWithDesktopController(animated = true) + override fun launchAsStaticTile() = launchTaskWithDesktopController(animated = true) - override fun launchTask(callback: (launched: Boolean) -> Unit, isQuickSwitch: Boolean) { - launchTaskWithDesktopController(animated = false)?.add { callback(true) } ?: callback(false) - } + override fun launchWithoutAnimation( + isQuickSwitch: Boolean, + callback: (launched: Boolean) -> Unit + ) = launchTaskWithDesktopController(animated = false)?.add { callback(true) } ?: callback(false) // Desktop tile can't be in split screen override fun confirmSecondSplitSelectApp(): Boolean = false diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt index 0ab36c9d72..7b97c23bbc 100644 --- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt +++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.kt @@ -15,8 +15,10 @@ */ package com.android.quickstep.views +import android.annotation.SuppressLint import android.app.ActivityOptions import android.content.ActivityNotFoundException +import android.content.Context import android.content.Intent import android.content.pm.LauncherApps import android.content.pm.LauncherApps.AppUsageLimit @@ -27,46 +29,59 @@ import android.icu.util.Measure import android.icu.util.MeasureUnit import android.os.UserHandle import android.provider.Settings +import android.util.AttributeSet import android.util.Log import android.view.View -import android.view.ViewGroup.MarginLayoutParams import android.view.ViewOutlineProvider import android.view.accessibility.AccessibilityNodeInfo -import android.widget.FrameLayout import android.widget.TextView import androidx.annotation.StringRes +import androidx.annotation.VisibleForTesting import androidx.core.util.component1 import androidx.core.util.component2 -import androidx.core.view.updateLayoutParams +import androidx.core.view.isVisible import com.android.launcher3.R import com.android.launcher3.Utilities import com.android.launcher3.util.Executors import com.android.launcher3.util.SplitConfigurationOptions +import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT +import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED +import com.android.launcher3.util.SplitConfigurationOptions.StagePosition import com.android.quickstep.TaskUtils import com.android.systemui.shared.recents.model.Task import java.time.Duration import java.util.Locale -class DigitalWellBeingToast( - private val container: RecentsViewContainer, - private val taskView: TaskView -) { - private val launcherApps: LauncherApps? = - container.asContext().getSystemService(LauncherApps::class.java) +@SuppressLint("AppCompatCustomView") +class DigitalWellBeingToast +@JvmOverloads +constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, + defStyleRes: Int = 0 +) : TextView(context, attrs, defStyleAttr, defStyleRes) { + private val recentsViewContainer = + RecentsViewContainer.containerFromContext<RecentsViewContainer>(context) + + private val launcherApps: LauncherApps? = context.getSystemService(LauncherApps::class.java) private val bannerHeight = - container - .asContext() - .resources - .getDimensionPixelSize(R.dimen.digital_wellbeing_toast_height) + context.resources.getDimensionPixelSize(R.dimen.digital_wellbeing_toast_height) private lateinit var task: Task + private lateinit var taskView: TaskView + private lateinit var snapshotView: View + @StagePosition private var stagePosition = STAGE_POSITION_UNDEFINED private var appRemainingTimeMs: Long = 0 - private var banner: View? = null - private var oldBannerOutlineProvider: ViewOutlineProvider? = null private var splitOffsetTranslationY = 0f - private var splitOffsetTranslationX = 0f + set(value) { + if (field != value) { + field = value + updateTranslationY() + } + } private var isDestroyed = false @@ -76,65 +91,63 @@ class DigitalWellBeingToast( set(value) { if (field != value) { field = value - banner?.let { - updateTranslationY() - it.invalidateOutline() - } + updateTranslationY() } } + init { + setOnClickListener(::openAppUsageSettings) + outlineProvider = + object : ViewOutlineProvider() { + override fun getOutline(view: View, outline: Outline) { + BACKGROUND.getOutline(view, outline) + val verticalTranslation = splitOffsetTranslationY - translationY + outline.offset(0, Math.round(verticalTranslation)) + } + } + clipToOutline = true + } + private fun setNoLimit() { + isVisible = false hasLimit = false - taskView.contentDescription = task.titleDescription - replaceBanner(null) appRemainingTimeMs = -1 + setContentDescription(appUsageLimitTimeMs = -1, appRemainingTimeMs = -1) } private fun setLimit(appUsageLimitTimeMs: Long, appRemainingTimeMs: Long) { - this.appRemainingTimeMs = appRemainingTimeMs + isVisible = true hasLimit = true - val toast = - container.viewCache - .getView<TextView>( - R.layout.digital_wellbeing_toast, - container.asContext(), - taskView - ) - .apply { - text = - Utilities.prefixTextWithIcon( - container.asContext(), - R.drawable.ic_hourglass_top, - getBannerText() - ) - setOnClickListener(::openAppUsageSettings) - } - replaceBanner(toast) + this.appRemainingTimeMs = appRemainingTimeMs + setContentDescription(appUsageLimitTimeMs, appRemainingTimeMs) + text = Utilities.prefixTextWithIcon(context, R.drawable.ic_hourglass_top, getBannerText()) + } - taskView.contentDescription = + private fun setContentDescription(appUsageLimitTimeMs: Long, appRemainingTimeMs: Long) { + val contentDescription = getContentDescriptionForTask(task, appUsageLimitTimeMs, appRemainingTimeMs) + snapshotView.contentDescription = contentDescription } - fun initialize(task: Task) { + fun initialize() { check(!isDestroyed) { "Cannot re-initialize a destroyed toast" } - this.task = task + setupTranslations() Executors.ORDERED_BG_EXECUTOR.execute { var usageLimit: AppUsageLimit? = null try { usageLimit = launcherApps?.getAppUsageLimit( - this.task.topComponent.packageName, - UserHandle.of(this.task.key.userId) + task.topComponent.packageName, + UserHandle.of(task.key.userId) ) } catch (e: Exception) { Log.e(TAG, "Error initializing digital well being toast", e) } val appUsageLimitTimeMs = usageLimit?.totalUsageLimit ?: -1 val appRemainingTimeMs = usageLimit?.usageRemaining ?: -1 + taskView.post { - if (isDestroyed) { - return@post - } + if (isDestroyed) return@post if (appUsageLimitTimeMs < 0 || appRemainingTimeMs < 0) { setNoLimit() } else { @@ -144,20 +157,36 @@ class DigitalWellBeingToast( } } - /** Mark the DWB toast as destroyed and remove banner from TaskView. */ + /** Bind the DWB toast to its dependencies. */ + fun bind( + task: Task, + taskView: TaskView, + snapshotView: View, + @StagePosition stagePosition: Int + ) { + this.task = task + this.taskView = taskView + this.snapshotView = snapshotView + this.stagePosition = stagePosition + isDestroyed = false + } + + /** Mark the DWB toast as destroyed and hide it. */ fun destroy() { + isVisible = false isDestroyed = true - taskView.post { replaceBanner(null) } } private fun getSplitBannerConfig(): SplitBannerConfig { val splitBounds = splitBounds return when { - splitBounds == null || !container.deviceProfile.isTablet || taskView.isLargeTile -> - SplitBannerConfig.SPLIT_BANNER_FULLSCREEN + splitBounds == null || + !recentsViewContainer.deviceProfile.isTablet || + taskView.isLargeTile -> SplitBannerConfig.SPLIT_BANNER_FULLSCREEN // For portrait grid only height of task changes, not width. So we keep the text the // same - !container.deviceProfile.isLeftRightSplit -> SplitBannerConfig.SPLIT_GRID_BANNER_LARGE + !recentsViewContainer.deviceProfile.isLeftRightSplit -> + SplitBannerConfig.SPLIT_GRID_BANNER_LARGE // For landscape grid, for 30% width we only show icon, otherwise show icon and time task.key.id == splitBounds.leftTopTaskId -> if (splitBounds.leftTaskPercent < THRESHOLD_LEFT_ICON_ONLY) @@ -193,8 +222,7 @@ class DigitalWellBeingToast( MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE) .formatMeasures(Measure(minutes, MeasureUnit.MINUTE)) // Use a specific string for usage less than one minute but non-zero. - duration > Duration.ZERO -> - container.asContext().getString(durationLessThanOneMinuteStringId) + duration > Duration.ZERO -> context.getString(durationLessThanOneMinuteStringId) // Otherwise, return 0-minute string. else -> MeasureFormat.getInstance(Locale.getDefault(), MeasureFormat.FormatWidth.WIDE) @@ -208,6 +236,7 @@ class DigitalWellBeingToast( * [.SPLIT_BANNER_FULLSCREEN] */ @JvmOverloads + @VisibleForTesting fun getBannerText( remainingTime: Long = appRemainingTimeMs, forContentDesc: Boolean = false @@ -226,7 +255,7 @@ class DigitalWellBeingToast( val splitBannerConfig = getSplitBannerConfig() return when { forContentDesc || splitBannerConfig == SplitBannerConfig.SPLIT_BANNER_FULLSCREEN -> - container.asContext().getString(R.string.time_left_for_app, readableDuration) + context.getString(R.string.time_left_for_app, readableDuration) // show no text splitBannerConfig == SplitBannerConfig.SPLIT_GRID_BANNER_SMALL -> "" // SPLIT_GRID_BANNER_LARGE only show time @@ -241,7 +270,7 @@ class DigitalWellBeingToast( .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK) try { val options = ActivityOptions.makeScaleUpAnimation(view, 0, 0, view.width, view.height) - container.asContext().startActivity(intent, options.toBundle()) + context.startActivity(intent, options.toBundle()) // TODO: add WW logging on the app usage settings click. } catch (e: ActivityNotFoundException) { @@ -259,99 +288,77 @@ class DigitalWellBeingToast( appRemainingTimeMs: Long ): String? = if (appUsageLimitTimeMs >= 0 && appRemainingTimeMs >= 0) - container - .asContext() - .getString( - R.string.task_contents_description_with_remaining_time, - task.titleDescription, - getBannerText(appRemainingTimeMs, true /* forContentDesc */) - ) + context.getString( + R.string.task_contents_description_with_remaining_time, + task.titleDescription, + getBannerText(appRemainingTimeMs, true /* forContentDesc */) + ) else task.titleDescription - private fun replaceBanner(view: View?) { - resetOldBanner() - setBanner(view) - } - - private fun resetOldBanner() { - val banner = banner ?: return - banner.outlineProvider = oldBannerOutlineProvider - taskView.removeView(banner) - banner.setOnClickListener(null) - container.viewCache.recycleView(R.layout.digital_wellbeing_toast, banner) - } - - private fun setBanner(banner: View?) { - this.banner = banner - if (banner != null && taskView.recentsView != null) { - setupAndAddBanner() - setBannerOutline() + fun setupLayout() { + val snapshotWidth: Int + val snapshotHeight: Int + val splitBounds = splitBounds + if (splitBounds == null) { + snapshotWidth = taskView.layoutParams.width + snapshotHeight = + taskView.layoutParams.height - + recentsViewContainer.deviceProfile.overviewTaskThumbnailTopMarginPx + } else { + val groupedTaskSize = + taskView.pagedOrientationHandler.getGroupedTaskViewSizes( + recentsViewContainer.deviceProfile, + splitBounds, + taskView.layoutParams.width, + taskView.layoutParams.height + ) + if (stagePosition == STAGE_POSITION_TOP_OR_LEFT) { + snapshotWidth = groupedTaskSize.first.x + snapshotHeight = groupedTaskSize.first.y + } else { + snapshotWidth = groupedTaskSize.second.x + snapshotHeight = groupedTaskSize.second.y + } } + taskView.pagedOrientationHandler.updateDwbBannerLayout( + taskView.layoutParams.width, + taskView.layoutParams.height, + taskView is GroupedTaskView, + recentsViewContainer.deviceProfile, + snapshotWidth, + snapshotHeight, + this + ) } - private fun setupAndAddBanner() { - val banner = banner ?: return - banner.updateLayoutParams<FrameLayout.LayoutParams> { - bottomMargin = - (taskView.firstSnapshotView.layoutParams as MarginLayoutParams).bottomMargin - } + private fun setupTranslations() { val (translationX, translationY) = - taskView.pagedOrientationHandler.getDwbLayoutTranslations( - taskView.measuredWidth, - taskView.measuredHeight, + taskView.pagedOrientationHandler.getDwbBannerTranslations( + taskView.layoutParams.width, + taskView.layoutParams.height, splitBounds, - container.deviceProfile, + recentsViewContainer.deviceProfile, taskView.snapshotViews, task.key.id, - banner + this ) - splitOffsetTranslationX = translationX - splitOffsetTranslationY = translationY - updateTranslationY() - updateTranslationX() - taskView.addView(banner) - } - - private fun setBannerOutline() { - val banner = banner ?: return - // TODO(b\273367585) to investigate why mBanner.getOutlineProvider() can be null - val oldBannerOutlineProvider = - if (banner.outlineProvider != null) banner.outlineProvider - else ViewOutlineProvider.BACKGROUND - this.oldBannerOutlineProvider = oldBannerOutlineProvider - - banner.outlineProvider = - object : ViewOutlineProvider() { - override fun getOutline(view: View, outline: Outline) { - oldBannerOutlineProvider.getOutline(view, outline) - val verticalTranslation = -view.translationY + splitOffsetTranslationY - outline.offset(0, Math.round(verticalTranslation)) - } - } - banner.clipToOutline = true + this.translationX = translationX + this.splitOffsetTranslationY = translationY } private fun updateTranslationY() { - banner?.translationY = bannerOffsetPercentage * bannerHeight + splitOffsetTranslationY - } - - private fun updateTranslationX() { - banner?.translationX = splitOffsetTranslationX + translationY = bannerOffsetPercentage * bannerHeight + splitOffsetTranslationY + invalidateOutline() } - fun setBannerColorTint(color: Int, amount: Float) { - val banner = banner ?: return + fun setColorTint(color: Int, amount: Float) { if (amount == 0f) { - banner.setLayerType(View.LAYER_TYPE_NONE, null) + setLayerType(View.LAYER_TYPE_NONE, null) } val layerPaint = Paint() layerPaint.setColorFilter(Utilities.makeColorTintingColorFilter(color, amount)) - banner.setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint) - banner.setLayerPaint(layerPaint) - } - - fun setBannerVisibility(visibility: Int) { - banner?.visibility = visibility + setLayerType(View.LAYER_TYPE_HARDWARE, layerPaint) + setLayerPaint(layerPaint) } private fun getAccessibilityActionId(): Int = @@ -361,9 +368,8 @@ class DigitalWellBeingToast( fun getDWBAccessibilityAction(): AccessibilityNodeInfo.AccessibilityAction? { if (!hasLimit) return null - val context = container.asContext() val label = - if ((taskView.containsMultipleTasks())) + if (taskView.containsMultipleTasks()) context.getString( R.string.split_app_usage_settings, TaskUtils.getTitle(context, task) diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java index 4ea77532bc..f17be05d42 100644 --- a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java +++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java @@ -32,7 +32,6 @@ import androidx.annotation.Nullable; 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 @@ final class FloatingWidgetBackgroundView extends View { /** 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 ba4d78694c..3fd1a6bb60 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt @@ -115,6 +115,7 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu R.id.snapshot, R.id.icon, R.id.show_windows, + R.id.digital_wellbeing_toast, STAGE_POSITION_TOP_OR_LEFT, taskOverlayFactory ), @@ -123,6 +124,7 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu R.id.bottomright_snapshot, R.id.bottomRight_icon, R.id.show_windows_right, + R.id.bottomRight_digital_wellbeing_toast, STAGE_POSITION_BOTTOM_OR_RIGHT, taskOverlayFactory ) @@ -211,16 +213,12 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu splitBoundsConfig = splitBounds taskContainers.forEach { it.digitalWellBeingToast?.splitBounds = splitBoundsConfig - it.digitalWellBeingToast?.initialize(it.task) + it.digitalWellBeingToast?.initialize() } invalidate() } - override fun launchTaskAnimated(): RunnableList? { - if (taskContainers.isEmpty()) { - Log.d(TAG, "launchTaskAnimated - task is not bound") - return null - } + override fun launchAsStaticTile(): RunnableList? { val recentsView = recentsView ?: return null val endCallback = RunnableList() // Callbacks run from remote animation when recents animation not currently running @@ -239,8 +237,11 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu return endCallback } - override fun launchTask(callback: (launched: Boolean) -> Unit, isQuickSwitch: Boolean) { - launchTaskInternal(isQuickSwitch, false, callback /*launchingExistingTaskview*/) + override fun launchWithoutAnimation( + isQuickSwitch: Boolean, + callback: (launched: Boolean) -> Unit + ) { + launchTaskInternal(isQuickSwitch, launchingExistingTaskView = false, callback) } /** @@ -264,7 +265,10 @@ class GroupedTaskView @JvmOverloads constructor(context: Context, attrs: Attribu isQuickSwitch, snapPosition ) - Log.d(TAG, "launchTaskInternal - launchExistingSplitPair: ${taskIds.contentToString()}") + Log.d( + TAG, + "launchTaskInternal - launchExistingSplitPair: ${taskIds.contentToString()}, launchingExistingTaskView: $launchingExistingTaskView" + ) } } diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java index d20d0a5781..73edb9e8fa 100644 --- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java +++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java @@ -16,6 +16,7 @@ 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; @@ -26,7 +27,6 @@ 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; @@ -268,7 +268,8 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher 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 +292,8 @@ public class LauncherRecentsView extends RecentsView<QuickstepLauncher, Launcher } } 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 226ecf5063..f502e31de6 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -343,7 +343,7 @@ public abstract class RecentsView< }; 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; @@ -635,13 +635,16 @@ public abstract class RecentsView< @Override public void onTaskRemoved(int taskId) { if (!mHandleTaskStackChanges) { + Log.d(TAG, "onTaskRemoved: " + taskId + ", not handling task stack changes"); return; } TaskView taskView = getTaskViewByTaskId(taskId); if (taskView == null) { + Log.d(TAG, "onTaskRemoved: " + taskId + ", no associated TaskView"); return; } + Log.d(TAG, "onTaskRemoved: " + taskId); Task.TaskKey taskKey = taskView.getFirstTask().key; UI_HELPER_EXECUTOR.execute(new CancellableTask<>( () -> PackageManagerWrapper.getInstance() @@ -678,6 +681,7 @@ public abstract class RecentsView< protected int mRunningTaskViewId = -1; private int mTaskViewIdCount; protected boolean mRunningTaskTileHidden; + private boolean mNonRunningTaskCategoryHidden; @Nullable private Task[] mTmpRunningTasks; protected int mFocusedTaskViewId = INVALID_TASK_ID; @@ -838,8 +842,7 @@ public abstract class RecentsView< private final RecentsViewModel mRecentsViewModel; private final RecentsViewModelHelper mHelper; - - private final RecentsViewUtils mRecentsViewUtils = new RecentsViewUtils(); + private final RecentsViewUtils mUtils = new RecentsViewUtils(); public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, BaseContainerInterface sizeStrategy) { @@ -1100,14 +1103,13 @@ public abstract class RecentsView< @Override public void onTaskIconChanged(@NonNull String pkg, @NonNull UserHandle user) { - for (int i = 0; i < getTaskViewCount(); i++) { - TaskView tv = requireTaskViewAt(i); - Task task = tv.getFirstTask(); + for (TaskView taskView : getTaskViews()) { + Task task = taskView.getFirstTask(); if (pkg.equals(task.key.getPackageName()) && task.key.userId == user.getIdentifier()) { task.icon = null; - if (tv.getTaskContainers().stream().anyMatch( + if (taskView.getTaskContainers().stream().anyMatch( container -> container.getIconView().getDrawable() != null)) { - tv.onTaskListVisibilityChanged(true /* visible */); + taskView.onTaskListVisibilityChanged(true /* visible */); } } } @@ -1496,8 +1498,7 @@ public abstract class RecentsView< return null; } - for (int i = 0; i < getTaskViewCount(); i++) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { if (taskView.containsTaskId(taskId)) { return taskView; } @@ -1518,8 +1519,7 @@ public abstract class RecentsView< int[] taskIdsCopy = Arrays.copyOf(taskIds, taskIds.length); Arrays.sort(taskIdsCopy); - for (int i = 0; i < getTaskViewCount(); i++) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { int[] taskViewIdsCopy = taskView.getTaskIds(); Arrays.sort(taskViewIdsCopy); if (Arrays.equals(taskIdsCopy, taskViewIdsCopy)) { @@ -1555,9 +1555,7 @@ public abstract class RecentsView< */ public void setTaskBorderEnabled(boolean enabled) { mBorderEnabled = enabled; - int taskCount = getTaskViewCount(); - for (int i = 0; i < taskCount; i++) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { taskView.setBorderEnabled(enabled); } mClearAllButton.setBorderEnabled(enabled); @@ -1624,9 +1622,7 @@ public abstract class RecentsView< super.onTouchEvent(ev); if (showAsGrid()) { - int taskCount = getTaskViewCount(); - for (int i = 0; i < taskCount; i++) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { if (isTaskViewVisible(taskView) && taskView.offerTouchToChildren(ev)) { // Keep consuming events to pass to delegate return true; @@ -1880,7 +1876,7 @@ public abstract class RecentsView< // Move Desktop Tasks to the end of the list if (enableLargeDesktopWindowingTile()) { - taskGroups = mRecentsViewUtils.sortDesktopTasksToFront(taskGroups); + taskGroups = mUtils.sortDesktopTasksToFront(taskGroups); } // Add views as children based on whether it's grouped or single task. Looping through @@ -1936,7 +1932,7 @@ public abstract class RecentsView< // Keep same previous focused task TaskView newFocusedTaskView = getTaskViewByTaskIds(focusedTaskIds); // If the list changed, maybe the focused task doesn't exist anymore - int newFocusedTaskViewIndex = mRecentsViewUtils.getFocusedTaskIndex(taskGroups); + int newFocusedTaskViewIndex = mUtils.getFocusedTaskIndex(taskGroups); if (newFocusedTaskView == null && getTaskViewCount() > newFocusedTaskViewIndex) { newFocusedTaskView = getTaskViewAt(newFocusedTaskViewIndex); } @@ -2027,15 +2023,13 @@ public abstract class RecentsView< } private void removeTasksViewsAndClearAllButton() { - // This handles an edge case where applyLoadPlan happens during a gesture when the - // only Task is one with excludeFromRecents, in which case we should not remove it. - final int stubRunningTaskIndex = isGestureActive() ? getRunningTaskIndex() : -1; - - for (int i = getTaskViewCount() - 1; i >= 0; i--) { - if (i == stubRunningTaskIndex) { + for (TaskView taskView : getTaskViews()) { + if (isGestureActive() && taskView.isRunningTask()) { + // This handles an edge case where applyLoadPlan happens during a gesture when the + // only Task is one with excludeFromRecents, in which case we should not remove it. continue; } - removeView(requireTaskViewAt(i)); + removeView(taskView); } if (getTaskViewCount() == 0 && indexOfChild(mClearAllButton) != -1) { removeView(mClearAllButton); @@ -2056,7 +2050,7 @@ public abstract class RecentsView< * @return Number of children that are instances of DesktopTaskView */ private int getDesktopTaskViewCount() { - return mRecentsViewUtils.getDesktopTaskViewCount(getChildCount(), this::getTaskViewAt); + return mUtils.getDesktopTaskViewCount(getTaskViews()); } /** @@ -2079,8 +2073,7 @@ public abstract class RecentsView< } public void resetTaskVisuals() { - for (int i = getTaskViewCount() - 1; i >= 0; i--) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { if (Arrays.stream(taskView.getTaskIds()).noneMatch( taskId -> taskId == mIgnoreResetTaskId)) { taskView.resetViewTransforms(); @@ -2102,14 +2095,10 @@ public abstract class RecentsView< simulator.fullScreenProgress.value = 0; simulator.recentsViewScale.value = 1; }); - // Similar to setRunningTaskHidden below, reapply the state before runningTaskView is - // null. - if (!mRunningTaskShowScreenshot) { - setRunningTaskViewShowScreenshot(mRunningTaskShowScreenshot); - } - if (mRunningTaskTileHidden) { - setRunningTaskHidden(mRunningTaskTileHidden); - } + // Reapply runningTask related attributes as they might have been reset by + // resetViewTransforms(). + setRunningTaskViewShowScreenshot(mRunningTaskShowScreenshot); + applyAttachAlpha(); updateCurveProperties(); // Update the set of visible task's data @@ -2123,9 +2112,8 @@ public abstract class RecentsView< if (enableRefactorTaskThumbnail()) { mRecentsViewModel.updateFullscreenProgress(mFullscreenProgress); } - int taskCount = getTaskViewCount(); - for (int i = 0; i < taskCount; i++) { - requireTaskViewAt(i).setFullscreenProgress(mFullscreenProgress); + for (TaskView taskView : getTaskViews()) { + taskView.setFullscreenProgress(mFullscreenProgress); } mClearAllButton.setFullscreenProgress(fullscreenProgress); @@ -2138,6 +2126,7 @@ public abstract class RecentsView< boolean handleTaskStackChanges = mOverviewStateEnabled && isAttachedToWindow() && getWindowVisibility() == VISIBLE; if (handleTaskStackChanges != mHandleTaskStackChanges) { + Log.d(TAG, "updateTaskStackListenerState: " + handleTaskStackChanges); mHandleTaskStackChanges = handleTaskStackChanges; if (handleTaskStackChanges) { reloadIfNeeded(); @@ -2270,8 +2259,7 @@ public abstract class RecentsView< ? mLastComputedCarouselTaskSize.right - mLastComputedTaskSize.right : mLastComputedCarouselTaskSize.left - mLastComputedTaskSize.left; } - for (int i = 0; i < taskCount; i++) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { taskView.updateTaskSize(mLastComputedTaskSize, mLastComputedGridTaskSize, mLastComputedCarouselTaskSize); taskView.setNonGridTranslationX(accumulatedTranslationX); @@ -2659,18 +2647,13 @@ public abstract class RecentsView< return getTaskViewFromTaskViewId(mFocusedTaskViewId); } - private @Nullable TaskView getFirstLargeTaskView() { - return mRecentsViewUtils.getFirstLargeTaskView(getChildCount(), this::getTaskViewAt); - } - @Nullable private TaskView getTaskViewFromTaskViewId(int taskViewId) { if (taskViewId == -1) { return null; } - for (int i = 0; i < getTaskViewCount(); i++) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { if (taskView.getTaskViewId() == taskViewId) { return taskView; } @@ -2731,9 +2714,12 @@ public abstract class RecentsView< if (!mModel.isTaskListValid(mTaskListChangeId)) { mTaskListChangeId = mModel.getTasks(this::applyLoadPlan, RecentsFilterState .getFilter(mFilterState.getPackageNameToFilter())); + Log.d(TAG, "reloadIfNeeded - getTasks: " + mTaskListChangeId); if (enableRefactorTaskThumbnail()) { mRecentsViewModel.refreshAllTaskData(); } + } else { + Log.d(TAG, "reloadIfNeeded - task list still valid: " + mTaskListChangeId); } } @@ -2756,7 +2742,10 @@ public abstract class RecentsView< showCurrentTask(mActiveGestureRunningTasks); setEnableFreeScroll(false); setEnableDrawingLiveTile(false); - setRunningTaskHidden(!shouldUpdateRunningTaskAlpha()); + setRunningTaskHidden(true); + if (enableLargeDesktopWindowingTile()) { + setNonRunningTaskCategoryHidden(true); + } setTaskIconScaledDown(true); } @@ -2816,8 +2805,8 @@ public abstract class RecentsView< } private void updateChildTaskOrientations() { - for (int i = 0; i < getTaskViewCount(); i++) { - requireTaskViewAt(i).setOrientationState(mOrientationState); + for (TaskView taskView : getTaskViews()) { + taskView.setOrientationState(mOrientationState); } boolean shouldRotateMenuForFakeRotation = !mOrientationState.isRecentsActivityRotationAllowed(); @@ -2895,6 +2884,9 @@ public abstract class RecentsView< setEnableDrawingLiveTile(mCurrentGestureEndTarget == GestureState.GestureEndTarget.RECENTS); Log.d(TAG, "onGestureAnimationEnd - mEnableDrawingLiveTile: " + mEnableDrawingLiveTile); setRunningTaskHidden(false); + if (enableLargeDesktopWindowingTile()) { + setNonRunningTaskCategoryHidden(false); + } animateUpTaskIconScale(); animateActionsViewIn(); @@ -3050,13 +3042,27 @@ public abstract class RecentsView< if (runningTask == null) { return; } - runningTask.setStableAlpha(isHidden ? 0 : mContentAlpha); + applyAttachAlpha(); if (!isHidden) { AccessibilityManagerCompat.sendCustomAccessibilityEvent( runningTask, AccessibilityEvent.TYPE_VIEW_FOCUSED, null); } } + /** + * Hides the tasks that has a different category (Fullscreen/Desktop) from the running task. + */ + public void setNonRunningTaskCategoryHidden(boolean isHidden) { + mNonRunningTaskCategoryHidden = isHidden; + updateMinAndMaxScrollX(); + applyAttachAlpha(); + } + + private void applyAttachAlpha() { + mUtils.applyAttachAlpha(getTaskViews(), getRunningTaskView(), mRunningTaskTileHidden, + mNonRunningTaskCategoryHidden); + } + private void setRunningTaskViewShowScreenshot(boolean showScreenshot) { setRunningTaskViewShowScreenshot(showScreenshot, /*updatedThumbnails=*/null); } @@ -3076,9 +3082,8 @@ public abstract class RecentsView< public void setTaskIconScaledDown(boolean isScaledDown) { if (mTaskIconScaledDown != isScaledDown) { mTaskIconScaledDown = isScaledDown; - int taskCount = getTaskViewCount(); - for (int i = 0; i < taskCount; i++) { - requireTaskViewAt(i).setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1); + for (TaskView taskView : getTaskViews()) { + taskView.setIconScaleAndDim(mTaskIconScaledDown ? 0 : 1); } } } @@ -3091,9 +3096,7 @@ public abstract class RecentsView< public void animateUpTaskIconScale() { mTaskIconScaledDown = false; - int taskCount = getTaskViewCount(); - for (int i = 0; i < taskCount; i++) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { taskView.animateIconScaleAndDimIntoView(); } } @@ -3388,9 +3391,8 @@ public abstract class RecentsView< private void setGridProgress(float gridProgress) { mGridProgress = gridProgress; - int taskCount = getTaskViewCount(); - for (int i = 0; i < taskCount; i++) { - requireTaskViewAt(i).setGridProgress(gridProgress); + for (TaskView taskView : getTaskViews()) { + taskView.setGridProgress(gridProgress); } mClearAllButton.setGridProgress(gridProgress); } @@ -3400,14 +3402,10 @@ public abstract class RecentsView< mRecentsViewModel.updateThumbnailSplashProgress(taskThumbnailSplashAlpha); return; } - int taskCount = getTaskViewCount(); - if (taskCount == 0) { - return; - } mTaskThumbnailSplashAlpha = taskThumbnailSplashAlpha; - for (int i = 0; i < taskCount; i++) { - requireTaskViewAt(i).setTaskThumbnailSplashAlpha(taskThumbnailSplashAlpha); + for (TaskView taskView : getTaskViews()) { + taskView.setTaskThumbnailSplashAlpha(taskThumbnailSplashAlpha); } } @@ -3630,8 +3628,7 @@ public abstract class RecentsView< nextFocusedTaskFromTop = !mTopRowIdSet.isEmpty() && mTopRowIdSet.size() >= (taskCount - 1) / 2f; // Pick the next focused task from the preferred row. - for (int i = 0; i < taskCount; i++) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { if (taskView == dismissedTaskView || taskView.isLargeTile()) { continue; } @@ -3759,8 +3756,7 @@ public abstract class RecentsView< END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET + (taskCount - 1) * halfAdditionalDismissTranslationOffset, END_DISMISS_TRANSLATION_INTERPOLATION_OFFSET, 1); - for (int i = 0; i < taskCount; i++) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { anim.setFloat(taskView, TaskView.GRID_END_TRANSLATION_X, longGridRowWidthDiff, clampToProgress(LINEAR, dismissTranslationInterpolationEnd, 1)); dismissTranslationInterpolationEnd = Utilities.boundToRange( @@ -4220,9 +4216,8 @@ public abstract class RecentsView< return new IntArray(0); } IntArray topArray = new IntArray(mTopRowIdSet.size()); - int taskViewCount = getTaskViewCount(); - for (int i = 0; i < taskViewCount; i++) { - int taskViewId = requireTaskViewAt(i).getTaskViewId(); + for (TaskView taskView : getTaskViews()) { + int taskViewId = taskView.getTaskViewId(); if (mTopRowIdSet.contains(taskViewId)) { topArray.add(taskViewId); } @@ -4239,9 +4234,7 @@ public abstract class RecentsView< return new IntArray(0); } IntArray bottomArray = new IntArray(bottomRowIdArraySize); - int taskViewCount = getTaskViewCount(); - for (int i = 0; i < taskViewCount; i++) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { int taskViewId = taskView.getTaskViewId(); if (!mTopRowIdSet.contains(taskViewId) && !taskView.isLargeTile()) { bottomArray.add(taskViewId); @@ -4301,9 +4294,8 @@ public abstract class RecentsView< } PendingAnimation anim = new PendingAnimation(duration); - int count = getTaskViewCount(); - for (int i = 0; i < count; i++) { - addDismissedTaskAnimations(requireTaskViewAt(i), duration, anim); + for (TaskView taskView : getTaskViews()) { + addDismissedTaskAnimations(taskView, duration, anim); } mPendingAnimation = anim; @@ -4349,9 +4341,8 @@ public abstract class RecentsView< } // Init task grid nav helper with top/bottom id arrays. - // TODO(b/361070854): Add keyboard navigation for all large tiles. TaskGridNavHelper taskGridNavHelper = new TaskGridNavHelper(getTopRowIdArray(), - getBottomRowIdArray(), mFocusedTaskViewId); + getBottomRowIdArray(), mUtils.getLargeTaskViewIds(getTaskViews())); // Get current page's task view ID. TaskView currentPageTaskView = getCurrentPageTaskView(); @@ -4382,8 +4373,10 @@ public abstract class RecentsView< private void dismissTask(int taskId) { TaskView taskView = getTaskViewByTaskId(taskId); if (taskView == null) { + Log.d(TAG, "dismissTask: " + taskId + ", no associated TaskView"); return; } + Log.d(TAG, "dismissTask: " + taskId); dismissTask(taskView, true /* animate */, false /* removeTask */); } @@ -4467,13 +4460,8 @@ public abstract class RecentsView< alpha = Utilities.boundToRange(alpha, 0, 1); mContentAlpha = alpha; - TaskView runningTaskView = getRunningTaskView(); - for (int i = getTaskViewCount() - 1; i >= 0; i--) { - TaskView child = requireTaskViewAt(i); - if (runningTaskView != null && mRunningTaskTileHidden && child == runningTaskView) { - continue; - } - child.setStableAlpha(alpha); + for (TaskView taskView : getTaskViews()) { + taskView.setStableAlpha(alpha); } mClearAllButton.setContentAlpha(mContentAlpha); int alphaInt = Math.round(alpha * 255); @@ -4582,6 +4570,13 @@ public abstract class RecentsView< return Objects.requireNonNull(getTaskViewAt(index)); } + /** + * Returns the current list of [TaskView] children. + */ + private Iterable<TaskView> getTaskViews() { + return mUtils.getTaskViews(getTaskViewCount(), this::requireTaskViewAt); + } + public void setOnEmptyMessageUpdatedListener(OnEmptyMessageUpdatedListener listener) { mOnEmptyMessageUpdatedListener = listener; } @@ -4886,9 +4881,9 @@ public abstract class RecentsView< protected void setTaskViewsResistanceTranslation(float translation) { mTaskViewsSecondaryTranslation = translation; - for (int i = 0; i < getTaskViewCount(); i++) { - TaskView task = requireTaskViewAt(i); - task.getTaskResistanceTranslationProperty().set(task, translation / getScaleY()); + for (TaskView taskView : getTaskViews()) { + taskView.getTaskResistanceTranslationProperty().set(taskView, + translation / getScaleY()); } runActionOnRemoteHandles( remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator() @@ -4896,23 +4891,21 @@ public abstract class RecentsView< } private void updateTaskViewsSnapshotRadius() { - for (int i = 0; i < getTaskViewCount(); i++) { - requireTaskViewAt(i).updateSnapshotRadius(); + for (TaskView taskView : getTaskViews()) { + taskView.updateSnapshotRadius(); } } protected void setTaskViewsPrimarySplitTranslation(float translation) { mTaskViewsPrimarySplitTranslation = translation; - for (int i = 0; i < getTaskViewCount(); i++) { - TaskView task = requireTaskViewAt(i); - task.getPrimarySplitTranslationProperty().set(task, translation); + for (TaskView taskView : getTaskViews()) { + taskView.getPrimarySplitTranslationProperty().set(taskView, translation); } } protected void setTaskViewsSecondarySplitTranslation(float translation) { mTaskViewsSecondarySplitTranslation = translation; - for (int i = 0; i < getTaskViewCount(); i++) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { if (taskView == mSplitHiddenTaskView && !taskView.containsMultipleTasks()) { continue; } @@ -5485,7 +5478,7 @@ public abstract class RecentsView< finishRecentsAnimation(false /* toRecents */, null); onTaskLaunchAnimationEnd(true /* success */); } else { - taskView.launchTask(this::onTaskLaunchAnimationEnd); + taskView.launchWithoutAnimation(this::onTaskLaunchAnimationEnd); } mContainer.getStatsLogManager().logger().withItemInfo(taskView.getFirstItemInfo()) .log(LAUNCHER_TASK_LAUNCH_SWIPE_DOWN); @@ -5810,26 +5803,42 @@ public abstract class RecentsView< } private int getFirstViewIndex() { - TaskView firstTaskView = mShowAsGridLastOnLayout ? getFirstLargeTaskView() : null; - return firstTaskView != null ? indexOfChild(firstTaskView) : 0; + final TaskView firstView; + if (mShowAsGridLastOnLayout) { + // For grid Overivew, it always start if a large tile (focused task or desktop task) if + // they exist, otherwise it start with the first task. + TaskView firstLargeTaskView = mUtils.getFirstLargeTaskView(getTaskViews()); + if (firstLargeTaskView != null) { + firstView = firstLargeTaskView; + } else { + firstView = getTaskViewAt(0); + } + } else { + firstView = mUtils.getFirstTaskViewInCarousel(mNonRunningTaskCategoryHidden, + getTaskViews(), getRunningTaskView()); + } + return indexOfChild(firstView); } private int getLastViewIndex() { + final View lastView; if (!mDisallowScrollToClearAll) { - return indexOfChild(mClearAllButton); - } - - if (!mShowAsGridLastOnLayout) { - return getTaskViewCount() - 1; - } - - TaskView lastGridTaskView = getLastGridTaskView(); - if (lastGridTaskView != null) { - return indexOfChild(lastGridTaskView); + // When ClearAllButton is present, it always end with ClearAllButton. + lastView = mClearAllButton; + } else if (mShowAsGridLastOnLayout) { + // When ClearAllButton is absent, for the grid Overview, it always end with a grid task + // if they exist, otherwise it ends with a large tile (focused task or desktop task). + TaskView lastGridTaskView = getLastGridTaskView(); + if (lastGridTaskView != null) { + lastView = lastGridTaskView; + } else { + lastView = mUtils.getLastLargeTaskView(getTaskViews()); + } + } else { + lastView = mUtils.getLastTaskViewInCarousel(mNonRunningTaskCategoryHidden, + getTaskViews(), getRunningTaskView()); } - - // Returns focus task if there are no grid tasks. - return indexOfChild(getFirstLargeTaskView()); + return indexOfChild(lastView); } /** @@ -6079,9 +6088,7 @@ public abstract class RecentsView< private void updateEnabledOverlays() { TaskView focusedTaskView = getFocusedTaskView(); - int taskCount = getTaskViewCount(); - for (int i = 0; i < taskCount; i++) { - TaskView taskView = requireTaskViewAt(i); + for (TaskView taskView : getTaskViews()) { if (taskView == focusedTaskView) { continue; } @@ -6155,7 +6162,7 @@ public abstract class RecentsView< return; } - Map<Integer, ThumbnailData> updatedThumbnails = mRecentsViewUtils.screenshotTasks(taskView, + Map<Integer, ThumbnailData> updatedThumbnails = mUtils.screenshotTasks(taskView, mRecentsAnimationController); if (enableRefactorTaskThumbnail()) { mHelper.switchToScreenshot(taskView, updatedThumbnails, onFinishRunnable); @@ -6253,8 +6260,8 @@ public abstract class RecentsView< mRecentsViewModel.setTintAmount(tintAmount); } - for (int i = 0; i < getTaskViewCount(); i++) { - requireTaskViewAt(i).setColorTint(mColorTint, mTintingColor); + for (TaskView taskView : getTaskViews()) { + taskView.setColorTint(mColorTint, mTintingColor); } Drawable scrimBg = mContainer.getScrimView().getBackground(); diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java index 060c71e446..8f194442d0 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java +++ b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java @@ -26,8 +26,11 @@ import android.view.MotionEvent; import android.view.View; import android.view.Window; +import androidx.annotation.Nullable; + 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; @@ -198,4 +201,7 @@ public interface RecentsViewContainer extends ActivityContext { .setOrientationHandler(orientationForLogging)) .build()); } + + @Nullable + DesktopVisibilityController getDesktopVisibilityController(); } diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt index 4604b7022b..f22c672147 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt +++ b/quickstep/src/com/android/quickstep/views/RecentsViewModelHelper.kt @@ -49,9 +49,7 @@ class RecentsViewModelHelper(private val recentsViewModel: RecentsViewModel) { recentsViewModel.setRunningTaskShowScreenshot(true) viewAttachedScope.launch { recentsViewModel.waitForRunningTaskShowScreenshotToUpdate() - if (updatedThumbnails != null) { - recentsViewModel.waitForThumbnailsToUpdate(updatedThumbnails) - } + recentsViewModel.waitForThumbnailsToUpdate(updatedThumbnails) ViewUtils.postFrameDrawn(taskView, onFinishRunnable) } } diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt index af32ba2565..13c4f78487 100644 --- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt +++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt @@ -146,6 +146,7 @@ class TaskContainer( } fun bind() { + digitalWellBeingToast?.bind(task, taskView, snapshotView, stagePosition) if (enableRefactorTaskThumbnail()) { bindThumbnailView() } else { @@ -171,4 +172,19 @@ class TaskContainer( thumbnailViewDeprecated.setOverlayEnabled(enabled) } } + + fun addChildForAccessibility(outChildren: ArrayList<View>) { + addAccessibleChildToList(iconView.asView(), outChildren) + addAccessibleChildToList(snapshotView, outChildren) + showWindowsView?.let { addAccessibleChildToList(it, outChildren) } + digitalWellBeingToast?.let { addAccessibleChildToList(it, outChildren) } + } + + private fun addAccessibleChildToList(view: View, outChildren: ArrayList<View>) { + if (view.includeForAccessibility()) { + outChildren.add(view) + } else { + view.addChildrenForAccessibility(outChildren) + } + } } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt index d2cdfa2bef..2ed6ae66c8 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.kt +++ b/quickstep/src/com/android/quickstep/views/TaskView.kt @@ -46,7 +46,6 @@ import androidx.annotation.VisibleForTesting import androidx.core.view.updateLayoutParams import com.android.app.animation.Interpolators import com.android.launcher3.Flags.enableCursorHoverStates -import com.android.launcher3.Flags.enableFocusOutline import com.android.launcher3.Flags.enableGridOnlyOverview import com.android.launcher3.Flags.enableHoverOfChildElementsInTaskview import com.android.launcher3.Flags.enableLargeDesktopWindowingTile @@ -55,7 +54,6 @@ import com.android.launcher3.Flags.enableRefactorTaskThumbnail import com.android.launcher3.R import com.android.launcher3.Utilities import com.android.launcher3.anim.AnimatedFloat -import com.android.launcher3.config.FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH import com.android.launcher3.logging.StatsLogManager.LauncherEvent import com.android.launcher3.model.data.ItemInfo import com.android.launcher3.testing.TestLogging @@ -84,7 +82,6 @@ import com.android.quickstep.TaskViewUtils import com.android.quickstep.orientation.RecentsPagedOrientationHandler import com.android.quickstep.recents.di.RecentsDependencies import com.android.quickstep.recents.di.get -import com.android.quickstep.task.thumbnail.TaskThumbnailView import com.android.quickstep.task.viewmodel.TaskViewModel import com.android.quickstep.util.ActiveGestureErrorDetector import com.android.quickstep.util.ActiveGestureLog @@ -201,14 +198,14 @@ constructor( get() = pagedOrientationHandler.getPrimaryValue( SPLIT_SELECT_TRANSLATION_X, - SPLIT_SELECT_TRANSLATION_Y + SPLIT_SELECT_TRANSLATION_Y, ) protected val secondarySplitTranslationProperty: FloatProperty<TaskView> get() = pagedOrientationHandler.getSecondaryValue( SPLIT_SELECT_TRANSLATION_X, - SPLIT_SELECT_TRANSLATION_Y + SPLIT_SELECT_TRANSLATION_Y, ) protected val primaryDismissTranslationProperty: FloatProperty<TaskView> @@ -223,21 +220,21 @@ constructor( get() = pagedOrientationHandler.getPrimaryValue( TASK_OFFSET_TRANSLATION_X, - TASK_OFFSET_TRANSLATION_Y + TASK_OFFSET_TRANSLATION_Y, ) protected val secondaryTaskOffsetTranslationProperty: FloatProperty<TaskView> get() = pagedOrientationHandler.getSecondaryValue( TASK_OFFSET_TRANSLATION_X, - TASK_OFFSET_TRANSLATION_Y + TASK_OFFSET_TRANSLATION_Y, ) protected val taskResistanceTranslationProperty: FloatProperty<TaskView> get() = pagedOrientationHandler.getSecondaryValue( TASK_RESISTANCE_TRANSLATION_X, - TASK_RESISTANCE_TRANSLATION_Y + TASK_RESISTANCE_TRANSLATION_Y, ) private val tempCoordinates = FloatArray(2) @@ -399,7 +396,7 @@ constructor( } get() = taskViewAlpha.get(ALPHA_INDEX_STABLE).value - protected var attachAlpha + var attachAlpha set(value) { taskViewAlpha.get(ALPHA_INDEX_ATTACH).value = value } @@ -435,7 +432,7 @@ constructor( field = value Log.d( TAG, - "${taskIds.contentToString()} - setting border animator visibility to: $field" + "${taskIds.contentToString()} - setting border animator visibility to: $field", ) hoverBorderAnimator?.setBorderVisibility(visible = field, animated = true) } @@ -455,7 +452,7 @@ constructor( FOCUS_TRANSITION, FOCUS_TRANSITION_INDEX_COUNT, { x: Float, y: Float -> x * y }, - 1f + 1f, ) private val focusTransitionFullscreen = focusTransitionPropertyFactory.get(FOCUS_TRANSITION_INDEX_FULLSCREEN) @@ -486,27 +483,23 @@ constructor( taskViewModel = RecentsDependencies.get(this, "TaskViewType" to type) } - val keyboardFocusHighlightEnabled = - (ENABLE_KEYBOARD_QUICK_SWITCH.get() || enableFocusOutline()) val cursorHoverStatesEnabled = enableCursorHoverStates() - setWillNotDraw(!keyboardFocusHighlightEnabled && !cursorHoverStatesEnabled) + setWillNotDraw(!cursorHoverStatesEnabled) context.obtainStyledAttributes(attrs, R.styleable.TaskView, defStyleAttr, defStyleRes).use { this.focusBorderAnimator = focusBorderAnimator - ?: if (keyboardFocusHighlightEnabled) - createSimpleBorderAnimator( - currentFullscreenParams.cornerRadius.toInt(), - context.resources.getDimensionPixelSize( - R.dimen.keyboard_quick_switch_border_width - ), - { bounds: Rect -> getThumbnailBounds(bounds) }, - this, - it.getColor( - R.styleable.TaskView_focusBorderColor, - BorderAnimator.DEFAULT_BORDER_COLOR - ) - ) - else null + ?: createSimpleBorderAnimator( + currentFullscreenParams.cornerRadius.toInt(), + context.resources.getDimensionPixelSize( + R.dimen.keyboard_quick_switch_border_width + ), + { bounds: Rect -> getThumbnailBounds(bounds) }, + this, + it.getColor( + R.styleable.TaskView_focusBorderColor, + BorderAnimator.DEFAULT_BORDER_COLOR, + ), + ) this.hoverBorderAnimator = hoverBorderAnimator ?: if (cursorHoverStatesEnabled) @@ -519,8 +512,8 @@ constructor( this, it.getColor( R.styleable.TaskView_hoverBorderColor, - BorderAnimator.DEFAULT_BORDER_COLOR - ) + BorderAnimator.DEFAULT_BORDER_COLOR, + ), ) else null } @@ -612,6 +605,7 @@ constructor( override fun onRecycle() { resetPersistentViewTransforms() + attachAlpha = 1f // Clear any references to the thumbnail (it will be re-read either from the cache or the // system on next bind) if (!enableRefactorTaskThumbnail()) { @@ -634,7 +628,7 @@ constructor( addAction( AccessibilityAction( R.id.action_close, - context.getText(R.string.accessibility_close) + context.getText(R.string.accessibility_close), ) ) @@ -658,7 +652,7 @@ constructor( 1, it.taskViewCount - it.indexOfChild(this@TaskView) - 1, 1, - false + false, ) } } @@ -702,8 +696,9 @@ constructor( R.id.snapshot, R.id.icon, R.id.show_windows, + R.id.digital_wellbeing_toast, STAGE_POSITION_UNDEFINED, - taskOverlayFactory + taskOverlayFactory, ) ) taskContainers.forEach { it.bind() } @@ -715,6 +710,7 @@ constructor( @IdRes thumbnailViewId: Int, @IdRes iconViewId: Int, @IdRes showWindowViewId: Int, + @IdRes digitalWellbeingBannerId: Int, @StagePosition stagePosition: Int, taskOverlayFactory: TaskOverlayFactory, ): TaskContainer { @@ -730,6 +726,7 @@ constructor( thumbnailViewDeprecated } val iconView = getOrInflateIconView(iconViewId) + val digitalWellBeingToast = findViewById<DigitalWellBeingToast>(digitalWellbeingBannerId)!! return TaskContainer( this, task, @@ -737,9 +734,9 @@ constructor( iconView, TransformingTouchDelegate(iconView.asView()), stagePosition, - DigitalWellBeingToast(container, this), + digitalWellBeingToast, findViewById(showWindowViewId)!!, - taskOverlayFactory + taskOverlayFactory, ) } @@ -775,7 +772,7 @@ constructor( protected open fun setThumbnailOrientation(orientationState: RecentsOrientedState) { taskContainers.forEach { it.overlay.updateOrientationState(orientationState) - it.digitalWellBeingToast?.initialize(it.task) + it.digitalWellBeingToast?.initialize() } } @@ -827,10 +824,8 @@ constructor( } else { nonGridScale = 1f boxTranslationY = 0f - expectedWidth = if (enableOverviewIconMenu()) taskWidth else LayoutParams.MATCH_PARENT - expectedHeight = - if (enableOverviewIconMenu()) taskHeight + thumbnailPadding - else LayoutParams.MATCH_PARENT + expectedWidth = taskWidth + expectedHeight = taskHeight + thumbnailPadding } this.nonGridScale = nonGridScale this.boxTranslationY = boxTranslationY @@ -847,6 +842,7 @@ constructor( taskContainers[0].snapshotView.updateLayoutParams<LayoutParams> { topMargin = container.deviceProfile.overviewTaskThumbnailTopMarginPx } + taskContainers.forEach { it.digitalWellBeingToast?.setupLayout() } } /** Returns the thumbnail's bounds, optionally relative to the screen. */ @@ -858,7 +854,7 @@ constructor( if (relativeToDragLayer) { container.dragLayer.getDescendantRectRelativeToSelf( it.snapshotView, - thumbnailBounds + thumbnailBounds, ) } else { thumbnailBounds.set(it.snapshotView) @@ -939,7 +935,7 @@ constructor( if (enableOverviewIconMenu()) { setText(taskContainer.iconView, taskContainer.task.title) } - taskContainer.digitalWellBeingToast?.initialize(taskContainer.task) + taskContainer.digitalWellBeingToast?.initialize() } protected open fun onIconUnloaded(taskContainer: TaskContainer) { @@ -977,7 +973,7 @@ constructor( @JvmOverloads open fun setShouldShowScreenshot( shouldShowScreenshot: Boolean, - thumbnailDatas: Map<Int, ThumbnailData?>? = null + thumbnailDatas: Map<Int, ThumbnailData?>? = null, ) { if (this.shouldShowScreenshot == shouldShowScreenshot) return this.shouldShowScreenshot = shouldShowScreenshot @@ -1001,7 +997,7 @@ constructor( return } val callbackList = - launchTasks()?.apply { + launchWithAnimation()?.apply { add { Log.d("b/310064698", "${taskIds.contentToString()} - onClick - launchCompleted") } @@ -1013,16 +1009,110 @@ constructor( .log(LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP) } + /** Launch of the current task (both live and inactive tasks) with an animation. */ + fun launchWithAnimation(): RunnableList? { + return if (isRunningTask && recentsView?.remoteTargetHandles != null) { + launchAsLiveTile() + } else { + launchAsStaticTile() + } + } + + private fun launchAsLiveTile(): RunnableList? { + val recentsView = recentsView ?: return null + val remoteTargetHandles = recentsView.remoteTargetHandles + if (!isClickableAsLiveTile) { + Log.e( + TAG, + "launchAsLiveTile - TaskView is not clickable as a live tile; returning to home: ${taskIds.contentToString()}", + ) + return null + } + isClickableAsLiveTile = false + val targets = + if (remoteTargetHandles.size == 1) { + remoteTargetHandles[0].transformParams.targetSet + } else { + val apps = + remoteTargetHandles.flatMap { it.transformParams.targetSet.apps.asIterable() } + val wallpapers = + remoteTargetHandles.flatMap { + it.transformParams.targetSet.wallpapers.asIterable() + } + RemoteAnimationTargets( + apps.toTypedArray(), + wallpapers.toTypedArray(), + remoteTargetHandles[0].transformParams.targetSet.nonApps, + remoteTargetHandles[0].transformParams.targetSet.targetMode, + ) + } + if (targets == null) { + // If the recents animation is cancelled somehow between the parent if block and + // here, try to launch the task as a non live tile task. + val runnableList = launchAsStaticTile() + if (runnableList == null) { + Log.e( + TAG, + "launchAsLiveTile - Recents animation cancelled and cannot launch task as non-live tile; returning to home: ${taskIds.contentToString()}", + ) + } + isClickableAsLiveTile = true + return runnableList + } + TestLogging.recordEvent( + TestProtocol.SEQUENCE_MAIN, + "composeRecentsLaunchAnimator", + taskIds.contentToString(), + ) + val runnableList = RunnableList() + with(AnimatorSet()) { + TaskViewUtils.composeRecentsLaunchAnimator( + this, + this@TaskView, + targets.apps, + targets.wallpapers, + targets.nonApps, + true /* launcherClosing */, + recentsView.stateManager, + recentsView, + recentsView.depthController, + ) + addListener( + object : AnimatorListenerAdapter() { + override fun onAnimationEnd(animator: Animator) { + if (taskContainers.any { it.task.key.displayId != rootViewDisplayId }) { + launchAsStaticTile() + } + isClickableAsLiveTile = true + runEndCallback() + } + + override fun onAnimationCancel(animation: Animator) { + runEndCallback() + } + + private fun runEndCallback() { + runnableList.executeAllAndDestroy() + } + } + ) + start() + } + Log.d(TAG, "launchAsLiveTile - composeRecentsLaunchAnimator: ${taskIds.contentToString()}") + recentsView.onTaskLaunchedInLiveTileMode() + return runnableList + } + /** * Starts the task associated with this view and animates the startup. * * @return CompletionStage to indicate the animation completion or null if the launch failed. */ - open fun launchTaskAnimated(): RunnableList? { + open fun launchAsStaticTile(): RunnableList? { TestLogging.recordEvent( TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", - taskIds.contentToString() + taskIds.contentToString(), ) val opts = container.getActivityLaunchOptions(this, null).apply { @@ -1034,13 +1124,16 @@ constructor( ) { Log.d( TAG, - "launchTaskAnimated - startActivityFromRecents: ${taskIds.contentToString()}" + "launchAsStaticTile - startActivityFromRecents: ${taskIds.contentToString()}", ) ActiveGestureLog.INSTANCE.trackEvent( ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED ) val recentsView = recentsView ?: return null - if (recentsView.runningTaskViewId != -1) { + if ( + recentsView.runningTaskViewId != -1 && + recentsView.mRecentsAnimationController != null + ) { recentsView.onTaskLaunchedInLiveTileMode() // Return a fresh callback in the live tile case, so that it's not accidentally @@ -1055,22 +1148,21 @@ constructor( recentsView.addSideTaskLaunchCallback(opts.onEndCallback) return opts.onEndCallback } else { - notifyTaskLaunchFailed() + notifyTaskLaunchFailed("launchAsStaticTile") return null } } /** Starts the task associated with this view without any animation */ - fun launchTask(callback: (launched: Boolean) -> Unit) { - launchTask(callback, isQuickSwitch = false) - } - - /** Starts the task associated with this view without any animation */ - open fun launchTask(callback: (launched: Boolean) -> Unit, isQuickSwitch: Boolean) { + @JvmOverloads + open fun launchWithoutAnimation( + isQuickSwitch: Boolean = false, + callback: (launched: Boolean) -> Unit, + ) { TestLogging.recordEvent( TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", - taskIds.contentToString() + taskIds.contentToString(), ) val firstContainer = taskContainers[0] val failureListener = TaskRemovedDuringLaunchListener(context.applicationContext) @@ -1079,7 +1171,7 @@ constructor( // gesture launcher is in the background state, vs other launches which are in // the actual overview state failureListener.register(container, firstContainer.task.key.id) { - notifyTaskLaunchFailed() + notifyTaskLaunchFailed("launchWithoutAnimation") recentsView?.let { // Disable animations for now, as it is an edge case and the app usually // covers launcher and also any state transition animation also gets @@ -1101,7 +1193,7 @@ constructor( 0, 0, Executors.MAIN_EXECUTOR.handler, - { callback(true) } + { callback(true) }, ) { failureListener.onTransitionFinished() } @@ -1123,103 +1215,20 @@ constructor( // otherwise, wait for the animation start callback from the activity options // above Executors.MAIN_EXECUTOR.post { - notifyTaskLaunchFailed() + notifyTaskLaunchFailed("launchTask") callback(false) } } - Log.d(TAG, "launchTask - startActivityFromRecents: ${taskIds.contentToString()}") - } - } - - /** Launch of the current task (both live and inactive tasks) with an animation. */ - fun launchTasks(): RunnableList? { - val recentsView = recentsView ?: return null - val remoteTargetHandles = recentsView.mRemoteTargetHandles - if (!isRunningTask || remoteTargetHandles == null) { - return launchTaskAnimated() - } - if (!isClickableAsLiveTile) { - Log.e(TAG, "TaskView is not clickable as a live tile; returning to home.") - return null - } - isClickableAsLiveTile = false - val targets = - if (remoteTargetHandles.size == 1) { - remoteTargetHandles[0].transformParams.targetSet - } else { - val apps = - remoteTargetHandles.flatMap { it.transformParams.targetSet.apps.asIterable() } - val wallpapers = - remoteTargetHandles.flatMap { - it.transformParams.targetSet.wallpapers.asIterable() - } - RemoteAnimationTargets( - apps.toTypedArray(), - wallpapers.toTypedArray(), - remoteTargetHandles[0].transformParams.targetSet.nonApps, - remoteTargetHandles[0].transformParams.targetSet.targetMode - ) - } - if (targets == null) { - // If the recents animation is cancelled somehow between the parent if block and - // here, try to launch the task as a non live tile task. - val runnableList = launchTaskAnimated() - if (runnableList == null) { - Log.e( - TAG, - "Recents animation cancelled and cannot launch task as non-live tile" + - "; returning to home" - ) - } - isClickableAsLiveTile = true - return runnableList - } - TestLogging.recordEvent( - TestProtocol.SEQUENCE_MAIN, - "composeRecentsLaunchAnimator", - taskIds.contentToString() - ) - val runnableList = RunnableList() - with(AnimatorSet()) { - TaskViewUtils.composeRecentsLaunchAnimator( - this, - this@TaskView, - targets.apps, - targets.wallpapers, - targets.nonApps, - true /* launcherClosing */, - recentsView.stateManager, - recentsView, - recentsView.depthController - ) - addListener( - object : AnimatorListenerAdapter() { - override fun onAnimationEnd(animator: Animator) { - if (taskContainers.any { it.task.key.displayId != rootViewDisplayId }) { - launchTaskAnimated() - } - isClickableAsLiveTile = true - runEndCallback() - } - - override fun onAnimationCancel(animation: Animator) { - runEndCallback() - } - - private fun runEndCallback() { - runnableList.executeAllAndDestroy() - } - } + Log.d( + TAG, + "launchWithoutAnimation - startActivityFromRecents: ${taskIds.contentToString()}", ) - start() } - Log.d(TAG, "launchTasks - composeRecentsLaunchAnimator: ${taskIds.contentToString()}") - recentsView.onTaskLaunchedInLiveTileMode() - return runnableList } - private fun notifyTaskLaunchFailed() { - val sb = StringBuilder("Failed to launch task \n") + private fun notifyTaskLaunchFailed(launchMethod: String) { + val sb = + StringBuilder("$launchMethod - Failed to launch task: ${taskIds.contentToString()}\n") taskContainers.forEach { sb.append("(task=${it.task.key.baseIntent} userId=${it.task.key.userId})\n") } @@ -1231,7 +1240,7 @@ constructor( recentsView?.initiateSplitSelect( this, splitPositionOption.stagePosition, - SplitConfigurationOptions.getLogEventForPosition(splitPositionOption.stagePosition) + SplitConfigurationOptions.getLogEventForPosition(splitPositionOption.stagePosition), ) } @@ -1254,7 +1263,7 @@ constructor( container.splitAnimationThumbnail, /* intent */ null, /* user */ null, - container.itemInfo + container.itemInfo, ) } @@ -1359,13 +1368,13 @@ constructor( this[0] = viewHalfWidth this[1] = viewHalfHeight }, - false + false, ) transformingTouchDelegate.setBounds( (tempCenterCoordinates[0] - viewHalfWidth).toInt(), (tempCenterCoordinates[1] - viewHalfHeight).toInt(), (tempCenterCoordinates[0] + viewHalfWidth).toInt(), - (tempCenterCoordinates[1] + viewHalfHeight).toInt() + (tempCenterCoordinates[1] + viewHalfHeight).toInt(), ) } @@ -1375,7 +1384,7 @@ constructor( it.showWindowsView?.let { showWindowsView -> updateFilterCallback( showWindowsView, - getFilterUpdateCallback(it.task.key.packageName) + getFilterUpdateCallback(it.task.key.packageName), ) } } @@ -1444,7 +1453,7 @@ constructor( it.thumbnailViewDeprecated.dimAlpha = amount } it.iconView.setIconColorTint(tintColor, amount) - it.digitalWellBeingToast?.setBannerColorTint(tintColor, amount) + it.digitalWellBeingToast?.setColorTint(tintColor, amount) } } @@ -1458,7 +1467,7 @@ constructor( taskContainers.forEach { if (visibility == VISIBLE || it.task.key.id == taskId) { it.snapshotView.visibility = visibility - it.digitalWellBeingToast?.setBannerVisibility(visibility) + it.digitalWellBeingToast?.visibility = visibility it.showWindowsView?.visibility = visibility it.overlay.setVisibility(visibility) } @@ -1578,10 +1587,7 @@ constructor( resetViewTransforms() } - fun getTaskContainerForTaskThumbnailView(taskThumbnailView: TaskThumbnailView): TaskContainer? = - taskContainers.firstOrNull { it.thumbnailView == taskThumbnailView } - - open fun resetViewTransforms() { + fun resetViewTransforms() { // fullscreenTranslation and accumulatedTranslation should not be reset, as // resetViewTransforms is called during QuickSwitch scrolling. dismissTranslationX = 0f @@ -1597,7 +1603,6 @@ constructor( } dismissScale = 1f translationZ = 0f - attachAlpha = 1f setIconScaleAndDim(1f) setColorTint(0f, 0) } @@ -1662,6 +1667,12 @@ constructor( return thumbnailBounds.contains(x.toInt(), y.toInt()) } + override fun addChildrenForAccessibility(outChildren: ArrayList<View>) { + (if (isLayoutRtl) taskContainers.reversed() else taskContainers).forEach { + it.addChildForAccessibility(outChildren) + } + } + companion object { private const val TAG = "TaskView" const val FLAG_UPDATE_ICON = 1 @@ -1689,7 +1700,7 @@ constructor( Interpolators.clampToProgress( Interpolators.FAST_OUT_SLOW_IN, 1f - FOCUS_TRANSITION_THRESHOLD, - 1f + 1f, )!! private val SYSTEM_GESTURE_EXCLUSION_RECT = listOf(Rect()) diff --git a/quickstep/testing/com/android/launcher3/taskbar/bubbles/testing/FakeBubbleViewFactory.kt b/quickstep/testing/com/android/launcher3/taskbar/bubbles/testing/FakeBubbleViewFactory.kt new file mode 100644 index 0000000000..37a07c3647 --- /dev/null +++ b/quickstep/testing/com/android/launcher3/taskbar/bubbles/testing/FakeBubbleViewFactory.kt @@ -0,0 +1,78 @@ +/* + * 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.testing + +import android.app.Notification +import android.content.Context +import android.graphics.Bitmap +import android.graphics.Canvas +import android.graphics.Color +import android.graphics.Paint +import android.util.PathParser +import android.view.LayoutInflater +import android.view.ViewGroup +import com.android.launcher3.R +import com.android.launcher3.taskbar.bubbles.BubbleBarBubble +import com.android.launcher3.taskbar.bubbles.BubbleView +import com.android.wm.shell.shared.bubbles.BubbleInfo + +object FakeBubbleViewFactory { + + /** Inflates a [BubbleView] and adds it to the [parent] view if it is present. */ + fun createBubble( + context: Context, + key: String, + parent: ViewGroup?, + iconSize: Int = 50, + iconColor: Int, + badgeColor: Int = Color.RED, + dotColor: Int = Color.BLUE, + suppressNotification: Boolean = false, + ): BubbleView { + val inflater = LayoutInflater.from(context) + // BubbleView uses launcher's badge to icon ratio and expects the badge image to already + // have the right size + val badgeToIconRatio = 0.444f + val badgeRadius = iconSize * badgeToIconRatio / 2 + val icon = createCircleBitmap(radius = iconSize / 2, color = iconColor) + val badge = createCircleBitmap(radius = badgeRadius.toInt(), color = badgeColor) + + val flags = + if (suppressNotification) Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION else 0 + val bubbleInfo = + BubbleInfo(key, flags, null, null, 0, context.packageName, null, null, false, true) + val bubbleView = inflater.inflate(R.layout.bubblebar_item_view, parent, false) as BubbleView + val dotPath = + PathParser.createPathFromPathData( + context.resources.getString(com.android.internal.R.string.config_icon_mask) + ) + val bubble = + BubbleBarBubble(bubbleInfo, bubbleView, badge, icon, dotColor, dotPath, "test app") + bubbleView.setBubble(bubble) + return bubbleView + } + + private fun createCircleBitmap(radius: Int, color: Int): Bitmap { + val bitmap = Bitmap.createBitmap(radius * 2, radius * 2, Bitmap.Config.ARGB_8888) + val canvas = Canvas(bitmap) + canvas.drawARGB(0, 0, 0, 0) + val paint = Paint() + paint.color = color + canvas.drawCircle(radius.toFloat(), radius.toFloat(), radius.toFloat(), paint) + return bitmap + } +} diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewScreenshotTest.kt new file mode 100644 index 0000000000..e4b8069b7f --- /dev/null +++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewScreenshotTest.kt @@ -0,0 +1,141 @@ +/* + * 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.content.Context +import android.graphics.Color +import android.platform.test.rule.ScreenRecordRule +import android.view.View +import android.widget.FrameLayout +import android.widget.FrameLayout.LayoutParams.MATCH_PARENT +import android.widget.FrameLayout.LayoutParams.WRAP_CONTENT +import androidx.activity.ComponentActivity +import androidx.test.core.app.ApplicationProvider +import com.android.launcher3.R +import com.android.launcher3.taskbar.bubbles.testing.FakeBubbleViewFactory +import com.google.android.apps.nexuslauncher.imagecomparison.goldenpathmanager.ViewScreenshotGoldenPathManager +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters +import platform.test.screenshot.DeviceEmulationSpec +import platform.test.screenshot.Displays +import platform.test.screenshot.ViewScreenshotTestRule +import platform.test.screenshot.getEmulatedDevicePathConfig + +/** Screenshot tests for [BubbleBarView]. */ +@RunWith(ParameterizedAndroidJunit4::class) +@ScreenRecordRule.ScreenRecord +class BubbleBarViewScreenshotTest(emulationSpec: DeviceEmulationSpec) { + + private val context = ApplicationProvider.getApplicationContext<Context>() + private lateinit var bubbleBarView: BubbleBarView + + companion object { + @Parameters(name = "{0}") + @JvmStatic + fun getTestSpecs() = + DeviceEmulationSpec.forDisplays( + Displays.Phone, + isDarkTheme = false, + isLandscape = false, + ) + } + + @get:Rule + val screenshotRule = + ViewScreenshotTestRule( + emulationSpec, + ViewScreenshotGoldenPathManager(getEmulatedDevicePathConfig(emulationSpec)), + ) + + @Test + fun bubbleBarView_collapsed_oneBubble() { + screenshotRule.screenshotTest("bubbleBarView_collapsed_oneBubble") { activity -> + activity.actionBar?.hide() + setupBubbleBarView() + bubbleBarView.addBubble(createBubble("key1", Color.GREEN)) + val container = FrameLayout(context) + val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + container.layoutParams = lp + container.addView(bubbleBarView) + container + } + } + + @Test + fun bubbleBarView_collapsed_twoBubbles() { + screenshotRule.screenshotTest("bubbleBarView_collapsed_twoBubbles") { activity -> + activity.actionBar?.hide() + setupBubbleBarView() + bubbleBarView.addBubble(createBubble("key1", Color.GREEN)) + bubbleBarView.addBubble(createBubble("key2", Color.CYAN)) + val container = FrameLayout(context) + val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + container.layoutParams = lp + container.addView(bubbleBarView) + container + } + } + + @Test + fun bubbleBarView_expanded_threeBubbles() { + // if we're still expanding, wait with taking a screenshot + val shouldWait: (ComponentActivity, View) -> Boolean = { _, _ -> bubbleBarView.isExpanding } + screenshotRule.screenshotTest( + "bubbleBarView_expanded_threeBubbles", + checkView = shouldWait, + ) { activity -> + activity.actionBar?.hide() + setupBubbleBarView() + bubbleBarView.addBubble(createBubble("key1", Color.GREEN)) + bubbleBarView.addBubble(createBubble("key2", Color.CYAN)) + bubbleBarView.addBubble(createBubble("key3", Color.MAGENTA)) + val container = FrameLayout(context) + val lp = FrameLayout.LayoutParams(MATCH_PARENT, MATCH_PARENT) + container.layoutParams = lp + container.addView(bubbleBarView) + bubbleBarView.isExpanded = true + container + } + } + + private fun setupBubbleBarView() { + bubbleBarView = BubbleBarView(context) + val lp = FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT) + bubbleBarView.layoutParams = lp + val paddingTop = + context.resources.getDimensionPixelSize(R.dimen.bubblebar_pointer_visible_size) + bubbleBarView.setPadding(0, paddingTop, 0, 0) + bubbleBarView.visibility = View.VISIBLE + bubbleBarView.alpha = 1f + } + + private fun createBubble(key: String, color: Int): BubbleView { + val bubbleView = + FakeBubbleViewFactory.createBubble( + context, + key, + parent = bubbleBarView, + iconColor = color, + ) + bubbleView.showDotIfNeeded(1f) + bubbleBarView.setSelectedBubble(bubbleView) + return bubbleView + } +} diff --git a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt index eb459ff953..47f393ffc1 100644 --- a/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt +++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/BubbleViewScreenshotTest.kt @@ -15,17 +15,10 @@ */ package com.android.launcher3.taskbar.bubbles -import android.app.Notification import android.content.Context -import android.graphics.Bitmap -import android.graphics.Canvas import android.graphics.Color -import android.graphics.Paint -import android.util.PathParser -import android.view.LayoutInflater import androidx.test.core.app.ApplicationProvider -import com.android.launcher3.R -import com.android.wm.shell.shared.bubbles.BubbleInfo +import com.android.launcher3.taskbar.bubbles.testing.FakeBubbleViewFactory import com.google.android.apps.nexuslauncher.imagecomparison.goldenpathmanager.ViewScreenshotGoldenPathManager import org.junit.Rule import org.junit.Test @@ -50,7 +43,7 @@ class BubbleViewScreenshotTest(emulationSpec: DeviceEmulationSpec) { DeviceEmulationSpec.forDisplays( Displays.Phone, isDarkTheme = false, - isLandscape = false + isLandscape = false, ) } @@ -58,7 +51,7 @@ class BubbleViewScreenshotTest(emulationSpec: DeviceEmulationSpec) { val screenshotRule = ViewScreenshotTestRule( emulationSpec, - ViewScreenshotGoldenPathManager(getEmulatedDevicePathConfig(emulationSpec)) + ViewScreenshotGoldenPathManager(getEmulatedDevicePathConfig(emulationSpec)), ) @Test @@ -86,39 +79,16 @@ class BubbleViewScreenshotTest(emulationSpec: DeviceEmulationSpec) { } private fun setupBubbleView(suppressNotification: Boolean = false): BubbleView { - val inflater = LayoutInflater.from(context) - - val iconSize = 100 - // BubbleView uses launcher's badge to icon ratio and expects the badge image to already - // have the right size - val badgeToIconRatio = 0.444f - val badgeRadius = iconSize * badgeToIconRatio / 2 - val icon = createCircleBitmap(radius = iconSize / 2, color = Color.LTGRAY) - val badge = createCircleBitmap(radius = badgeRadius.toInt(), color = Color.RED) - - val flags = - if (suppressNotification) Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION else 0 - val bubbleInfo = - BubbleInfo("key", flags, null, null, 0, context.packageName, null, null, false, true) - val bubbleView = inflater.inflate(R.layout.bubblebar_item_view, null) as BubbleView - val dotPath = - PathParser.createPathFromPathData( - context.resources.getString(com.android.internal.R.string.config_icon_mask) + val bubbleView = + FakeBubbleViewFactory.createBubble( + context, + key = "key", + parent = null, + iconSize = 100, + iconColor = Color.LTGRAY, + suppressNotification = suppressNotification, ) - val bubble = - BubbleBarBubble(bubbleInfo, bubbleView, badge, icon, Color.BLUE, dotPath, "test app") - bubbleView.setBubble(bubble) bubbleView.showDotIfNeeded(1f) return bubbleView } - - private fun createCircleBitmap(radius: Int, color: Int): Bitmap { - val bitmap = Bitmap.createBitmap(radius * 2, radius * 2, Bitmap.Config.ARGB_8888) - val canvas = Canvas(bitmap) - canvas.drawARGB(0, 0, 0, 0) - val paint = Paint() - paint.color = color - canvas.drawCircle(radius.toFloat(), radius.toFloat(), radius.toFloat(), paint) - return bitmap - } } 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 new file mode 100644 index 0000000000..537a755c21 --- /dev/null +++ b/quickstep/tests/multivalentScreenshotTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutViewScreenshotTest.kt @@ -0,0 +1,159 @@ +/* + * 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.flyout + +import android.content.Context +import android.graphics.Color +import android.graphics.drawable.ColorDrawable +import androidx.test.core.app.ApplicationProvider +import com.google.android.apps.nexuslauncher.imagecomparison.goldenpathmanager.ViewScreenshotGoldenPathManager +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import platform.test.runner.parameterized.ParameterizedAndroidJunit4 +import platform.test.runner.parameterized.Parameters +import platform.test.screenshot.DeviceEmulationSpec +import platform.test.screenshot.Displays +import platform.test.screenshot.ViewScreenshotTestRule +import platform.test.screenshot.getEmulatedDevicePathConfig + +/** Screenshot tests for [BubbleBarFlyoutView]. */ +@RunWith(ParameterizedAndroidJunit4::class) +class BubbleBarFlyoutViewScreenshotTest(emulationSpec: DeviceEmulationSpec) { + + private val context = ApplicationProvider.getApplicationContext<Context>() + + companion object { + @Parameters(name = "{0}") + @JvmStatic + fun getTestSpecs() = + DeviceEmulationSpec.forDisplays( + Displays.Phone, + isDarkTheme = false, + isLandscape = false, + ) + } + + @get:Rule + val screenshotRule = + ViewScreenshotTestRule( + emulationSpec, + ViewScreenshotGoldenPathManager(getEmulatedDevicePathConfig(emulationSpec)), + ) + + @Test + fun bubbleBarFlyoutView_noAvatar_onRight() { + screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar_onRight") { activity -> + activity.actionBar?.hide() + val flyout = BubbleBarFlyoutView(context, onLeft = false) + flyout.setData( + BubbleBarFlyoutMessage( + senderAvatar = null, + senderName = "sender", + message = "message", + isGroupChat = false, + ) + ) + flyout + } + } + + @Test + fun bubbleBarFlyoutView_noAvatar_onLeft() { + screenshotRule.screenshotTest("bubbleBarFlyoutView_noAvatar_onLeft") { activity -> + activity.actionBar?.hide() + 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), + senderName = "sender", + message = "message", + isGroupChat = true, + ) + ) + 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/TaskbarNavButtonControllerTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java index 399aea612d..02d62186b1 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 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.doReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; @@ -33,11 +34,13 @@ import android.view.inputmethod.Flags; 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 @@ public class TaskbarNavButtonControllerTest { @Mock SystemUiProxy mockSystemUiProxy; + + @Mock + ContextualEduStatsManager mockContextualEduStatsManager; + @Mock TouchInteractionService mockService; @Mock @@ -100,6 +107,7 @@ public class TaskbarNavButtonControllerTest { mockService, mCallbacks, mockSystemUiProxy, + mockContextualEduStatsManager, mockHandler, mockAssistUtils); } @@ -111,6 +119,13 @@ public class TaskbarNavButtonControllerTest { } @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 @@ public class TaskbarNavButtonControllerTest { } @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/bubbles/flyout/BubbleBarFlyoutControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt new file mode 100644 index 0000000000..a58ce08209 --- /dev/null +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt @@ -0,0 +1,97 @@ +/* + * 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.flyout + +import android.content.Context +import android.view.Gravity +import android.widget.FrameLayout +import android.widget.TextView +import androidx.test.core.app.ApplicationProvider +import androidx.test.ext.junit.runners.AndroidJUnit4 +import androidx.test.filters.SmallTest +import com.android.launcher3.R +import com.google.common.truth.Truth.assertThat +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith + +/** Unit tests for [BubbleBarFlyoutController] */ +@SmallTest +@RunWith(AndroidJUnit4::class) +class BubbleBarFlyoutControllerTest { + + private lateinit var flyoutController: BubbleBarFlyoutController + private lateinit var flyoutContainer: FrameLayout + private val context = ApplicationProvider.getApplicationContext<Context>() + private val flyoutMessage = + BubbleBarFlyoutMessage(senderAvatar = null, "sender name", "message", isGroupChat = false) + private var onLeft = true + + @Before + fun setUp() { + flyoutContainer = FrameLayout(context) + val positioner = + object : BubbleBarFlyoutPositioner { + override val isOnLeft: Boolean + get() = onLeft + + override val targetTy: Float + get() = 50f + } + flyoutController = BubbleBarFlyoutController(flyoutContainer, positioner) + } + + @Test + fun flyoutPosition_left() { + flyoutController.setUpFlyout(flyoutMessage) + assertThat(flyoutContainer.childCount).isEqualTo(1) + val flyout = flyoutContainer.getChildAt(0) + val lp = flyout.layoutParams as FrameLayout.LayoutParams + assertThat(lp.gravity).isEqualTo(Gravity.BOTTOM or Gravity.LEFT) + assertThat(flyout.translationY).isEqualTo(50f) + } + + @Test + fun flyoutPosition_right() { + onLeft = false + flyoutController.setUpFlyout(flyoutMessage) + assertThat(flyoutContainer.childCount).isEqualTo(1) + val flyout = flyoutContainer.getChildAt(0) + val lp = flyout.layoutParams as FrameLayout.LayoutParams + assertThat(lp.gravity).isEqualTo(Gravity.BOTTOM or Gravity.RIGHT) + assertThat(flyout.translationY).isEqualTo(50f) + } + + @Test + fun flyoutMessage() { + flyoutController.setUpFlyout(flyoutMessage) + assertThat(flyoutContainer.childCount).isEqualTo(1) + val flyout = flyoutContainer.getChildAt(0) + val sender = flyout.findViewById<TextView>(R.id.bubble_flyout_name) + assertThat(sender.text).isEqualTo("sender name") + val message = flyout.findViewById<TextView>(R.id.bubble_flyout_text) + assertThat(message.text).isEqualTo("message") + } + + @Test + fun hideFlyout_removedFromContainer() { + flyoutController.setUpFlyout(flyoutMessage) + assertThat(flyoutContainer.childCount).isEqualTo(1) + flyoutController.hideFlyout() + assertThat(flyoutContainer.childCount).isEqualTo(0) + } +} diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt index 262d8da668..d4a3b3aee9 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt @@ -16,6 +16,7 @@ package com.android.launcher3.taskbar.bubbles.stashing +import android.animation.AnimatorSet import android.animation.AnimatorTestRule import android.content.Context import android.view.View @@ -31,6 +32,7 @@ import com.android.launcher3.taskbar.TaskbarInsetsController import com.android.launcher3.taskbar.bubbles.BubbleBarView import com.android.launcher3.taskbar.bubbles.BubbleBarViewController import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController +import com.android.launcher3.taskbar.bubbles.BubbleView import com.android.launcher3.util.MultiValueAlpha import com.android.wm.shell.shared.animation.PhysicsAnimator import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils @@ -54,13 +56,13 @@ class TransientBubbleStashControllerTest { companion object { const val TASKBAR_BOTTOM_SPACE = 5 - const val BUBBLE_BAR_WIDTH = 200f - const val BUBBLE_BAR_HEIGHT = 100f + const val BUBBLE_BAR_WIDTH = 200 + const val BUBBLE_BAR_HEIGHT = 100 const val HOTSEAT_TRANSLATION_Y = -45f const val TASK_BAR_TRANSLATION_Y = -TASKBAR_BOTTOM_SPACE const val HANDLE_VIEW_WIDTH = 150 const val HANDLE_VIEW_HEIGHT = 4 - const val BUBBLE_BAR_STASHED_TRANSLATION_Y = -2.5f + const val BUBBLE_BAR_STASHED_TRANSLATION_Y = -4.5f } @get:Rule val animatorTestRule: AnimatorTestRule = AnimatorTestRule(this) @@ -76,10 +78,14 @@ class TransientBubbleStashControllerTest { private val context = ApplicationProvider.getApplicationContext<Context>() private lateinit var bubbleBarView: BubbleBarView private lateinit var stashedHandleView: StashedHandleView + private lateinit var bubbleView: BubbleView private lateinit var barTranslationY: AnimatedFloat private lateinit var barScaleX: AnimatedFloat private lateinit var barScaleY: AnimatedFloat private lateinit var barAlpha: MultiValueAlpha + private lateinit var bubbleOffsetY: AnimatedFloat + private lateinit var bubbleAlpha: AnimatedFloat + private lateinit var backgroundAlpha: AnimatedFloat private lateinit var stashedHandleAlpha: MultiValueAlpha private lateinit var stashedHandleScale: AnimatedFloat private lateinit var stashedHandleTranslationY: AnimatedFloat @@ -102,7 +108,7 @@ class TransientBubbleStashControllerTest { taskbarInsetsController, bubbleBarViewController, bubbleStashedHandleViewController, - ImmediateAction() + ImmediateAction(), ) } @@ -158,11 +164,13 @@ class TransientBubbleStashControllerTest { mTransientBubbleStashController.isStashed = false whenever(bubbleBarViewController.isHiddenForNoBubbles).thenReturn(false) + val bubbleInitialTranslation = bubbleView.translationY + // When stash getInstrumentation().runOnMainSync { mTransientBubbleStashController.updateStashedAndExpandedState( stash = true, - expand = false + expand = false, ) } @@ -178,9 +186,13 @@ class TransientBubbleStashControllerTest { assertThat(bubbleBarView.alpha).isEqualTo(0f) assertThat(bubbleBarView.scaleX).isEqualTo(mTransientBubbleStashController.getStashScaleX()) assertThat(bubbleBarView.scaleY).isEqualTo(mTransientBubbleStashController.getStashScaleY()) + assertThat(bubbleBarView.background.alpha).isEqualTo(255) // Handle view is visible assertThat(stashedHandleView.translationY).isEqualTo(0) assertThat(stashedHandleView.alpha).isEqualTo(1) + // Bubble view is reset + assertThat(bubbleView.translationY).isEqualTo(bubbleInitialTranslation) + assertThat(bubbleView.alpha).isEqualTo(1f) } @Test @@ -271,7 +283,7 @@ class TransientBubbleStashControllerTest { val height = mTransientBubbleStashController.getTouchableHeight() // Then bubble bar height is returned - assertThat(height).isEqualTo(BUBBLE_BAR_HEIGHT.toInt()) + assertThat(height).isEqualTo(BUBBLE_BAR_HEIGHT) } private fun advanceTimeBy(advanceMs: Long) { @@ -282,31 +294,46 @@ class TransientBubbleStashControllerTest { private fun setUpBubbleBarView() { getInstrumentation().runOnMainSync { bubbleBarView = BubbleBarView(context) - bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0) + bubbleBarView.layoutParams = + FrameLayout.LayoutParams(BUBBLE_BAR_WIDTH, BUBBLE_BAR_HEIGHT) + bubbleView = BubbleView(context) + bubbleBarView.addBubble(bubbleView) + bubbleBarView.layout(0, 0, BUBBLE_BAR_WIDTH, BUBBLE_BAR_HEIGHT) } } private fun setUpStashedHandleView() { getInstrumentation().runOnMainSync { stashedHandleView = StashedHandleView(context) - stashedHandleView.layoutParams = FrameLayout.LayoutParams(0, 0) + stashedHandleView.layoutParams = + FrameLayout.LayoutParams(HANDLE_VIEW_WIDTH, HANDLE_VIEW_HEIGHT) } } private fun setUpBubbleBarController() { barTranslationY = AnimatedFloat(Runnable { bubbleBarView.translationY = barTranslationY.value }) + bubbleOffsetY = AnimatedFloat { value -> bubbleBarView.setBubbleOffsetY(value) } barScaleX = AnimatedFloat { value -> bubbleBarView.scaleX = value } barScaleY = AnimatedFloat { value -> bubbleBarView.scaleY = value } barAlpha = MultiValueAlpha(bubbleBarView, 1 /* num alpha channels */) + bubbleAlpha = AnimatedFloat { value -> bubbleBarView.setBubbleAlpha(value) } + backgroundAlpha = AnimatedFloat { value -> bubbleBarView.setBackgroundAlpha(value) } whenever(bubbleBarViewController.hasBubbles()).thenReturn(true) whenever(bubbleBarViewController.bubbleBarTranslationY).thenReturn(barTranslationY) - whenever(bubbleBarViewController.bubbleBarScaleX).thenReturn(barScaleX) - whenever(bubbleBarViewController.bubbleBarScaleY).thenReturn(barScaleY) + whenever(bubbleBarViewController.bubbleOffsetY).thenReturn(bubbleOffsetY) + whenever(bubbleBarViewController.bubbleBarBackgroundScaleX).thenReturn(barScaleX) + whenever(bubbleBarViewController.bubbleBarBackgroundScaleY).thenReturn(barScaleY) whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(barAlpha) - whenever(bubbleBarViewController.bubbleBarCollapsedWidth).thenReturn(BUBBLE_BAR_WIDTH) - whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT) + whenever(bubbleBarViewController.bubbleBarBubbleAlpha).thenReturn(bubbleAlpha) + whenever(bubbleBarViewController.bubbleBarBackgroundAlpha).thenReturn(backgroundAlpha) + whenever(bubbleBarViewController.bubbleBarCollapsedWidth) + .thenReturn(BUBBLE_BAR_WIDTH.toFloat()) + whenever(bubbleBarViewController.bubbleBarCollapsedHeight) + .thenReturn(BUBBLE_BAR_HEIGHT.toFloat()) + whenever(bubbleBarViewController.createRevealAnimatorForStashChange(any())) + .thenReturn(AnimatorSet()) } private fun setUpBubbleStashedHandleViewController() { diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt index bbcf566e06..cb5e464dde 100644 --- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt +++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/rules/TaskbarUnitTestRule.kt @@ -26,6 +26,7 @@ import android.provider.Settings.Secure.USER_SETUP_COMPLETE import androidx.test.platform.app.InstrumentationRegistry import androidx.test.rule.ServiceTestRule import com.android.launcher3.LauncherAppState +import com.android.launcher3.statehandlers.DesktopVisibilityController import com.android.launcher3.taskbar.TaskbarActivityContext import com.android.launcher3.taskbar.TaskbarManager import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks @@ -143,6 +144,7 @@ class TaskbarUnitTestRule( PendingIntent(IIntentSender.Default()) }, object : TaskbarNavButtonCallbacks {}, + DesktopVisibilityController(context), ) { override fun recreateTaskbar() { super.recreateTaskbar() diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt new file mode 100644 index 0000000000..0ae710f866 --- /dev/null +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/OverviewCommandHelperTest.kt @@ -0,0 +1,179 @@ +/* + * 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 android.platform.test.flag.junit.SetFlagsRule +import androidx.test.filters.SmallTest +import com.android.launcher3.Flags +import com.android.launcher3.util.LauncherMultivalentJUnit +import com.android.launcher3.util.TestDispatcherProvider +import com.android.launcher3.util.rule.setFlags +import com.android.quickstep.OverviewCommandHelper.CommandInfo +import com.android.quickstep.OverviewCommandHelper.CommandInfo.CommandStatus +import com.android.quickstep.OverviewCommandHelper.CommandType +import com.google.common.truth.Truth.assertThat +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.test.StandardTestDispatcher +import kotlinx.coroutines.test.TestScope +import kotlinx.coroutines.test.advanceTimeBy +import kotlinx.coroutines.test.runCurrent +import kotlinx.coroutines.test.runTest +import org.junit.Before +import org.junit.Rule +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mockito.doAnswer +import org.mockito.Mockito.spy +import org.mockito.Mockito.`when` +import org.mockito.kotlin.any +import org.mockito.kotlin.mock + +@SmallTest +@RunWith(LauncherMultivalentJUnit::class) +@OptIn(ExperimentalCoroutinesApi::class) +class OverviewCommandHelperTest { + @get:Rule val setFlagsRule: SetFlagsRule = SetFlagsRule() + + private lateinit var sut: OverviewCommandHelper + private val dispatcher = StandardTestDispatcher() + private val testScope = TestScope(dispatcher) + + private var pendingCallbacksWithDelays = mutableListOf<Long>() + + @Suppress("UNCHECKED_CAST") + @Before + fun setup() { + setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_OVERVIEW_COMMAND_HELPER_TIMEOUT) + + sut = + spy( + OverviewCommandHelper( + touchInteractionService = mock(), + overviewComponentObserver = mock(), + taskAnimationManager = mock(), + dispatcherProvider = TestDispatcherProvider(dispatcher) + ) + ) + + doAnswer { invocation -> + val pendingCallback = invocation.arguments[1] as () -> Unit + + val delayInMillis = pendingCallbacksWithDelays.removeFirstOrNull() + if (delayInMillis != null) { + runBlocking { + testScope.backgroundScope.launch { + delay(delayInMillis) + pendingCallback.invoke() + } + } + } + delayInMillis == null // if no callback to execute, returns success + } + .`when`(sut) + .executeCommand(any<CommandInfo>(), any()) + } + + private fun addCallbackDelay(delayInMillis: Long = 0) { + pendingCallbacksWithDelays.add(delayInMillis) + } + + @Test + fun whenFirstCommandIsAdded_executeCommandImmediately() = + testScope.runTest { + // Add command to queue + val commandInfo: CommandInfo = sut.addCommand(CommandType.HOME)!! + assertThat(commandInfo.status).isEqualTo(CommandStatus.IDLE) + runCurrent() + assertThat(commandInfo.status).isEqualTo(CommandStatus.COMPLETED) + } + + @Test + fun whenFirstCommandIsAdded_executeCommandImmediately_WithCallbackDelay() = + testScope.runTest { + addCallbackDelay(100) + + // Add command to queue + val commandType = CommandType.HOME + val commandInfo: CommandInfo = sut.addCommand(commandType)!! + assertThat(commandInfo.status).isEqualTo(CommandStatus.IDLE) + + runCurrent() + assertThat(commandInfo.status).isEqualTo(CommandStatus.PROCESSING) + + advanceTimeBy(200L) + assertThat(commandInfo.status).isEqualTo(CommandStatus.COMPLETED) + } + + @Test + fun whenFirstCommandIsPendingCallback_NextCommandWillWait() = + testScope.runTest { + // Add command to queue + addCallbackDelay(100) + val commandType1 = CommandType.HOME + val commandInfo1: CommandInfo = sut.addCommand(commandType1)!! + assertThat(commandInfo1.status).isEqualTo(CommandStatus.IDLE) + + addCallbackDelay(100) + val commandType2 = CommandType.SHOW + val commandInfo2: CommandInfo = sut.addCommand(commandType2)!! + assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE) + + runCurrent() + assertThat(commandInfo1.status).isEqualTo(CommandStatus.PROCESSING) + assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE) + + advanceTimeBy(101L) + assertThat(commandInfo1.status).isEqualTo(CommandStatus.COMPLETED) + assertThat(commandInfo2.status).isEqualTo(CommandStatus.PROCESSING) + + advanceTimeBy(101L) + assertThat(commandInfo2.status).isEqualTo(CommandStatus.COMPLETED) + } + + @Test + fun whenCommandTakesTooLong_TriggerTimeout_AndExecuteNextCommand() = + testScope.runTest { + // Add command to queue + addCallbackDelay(QUEUE_TIMEOUT) + val commandType1 = CommandType.HOME + val commandInfo1: CommandInfo = sut.addCommand(commandType1)!! + assertThat(commandInfo1.status).isEqualTo(CommandStatus.IDLE) + + addCallbackDelay(100) + val commandType2 = CommandType.SHOW + val commandInfo2: CommandInfo = sut.addCommand(commandType2)!! + assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE) + + runCurrent() + assertThat(commandInfo1.status).isEqualTo(CommandStatus.PROCESSING) + assertThat(commandInfo2.status).isEqualTo(CommandStatus.IDLE) + + advanceTimeBy(QUEUE_TIMEOUT) + assertThat(commandInfo1.status).isEqualTo(CommandStatus.CANCELED) + assertThat(commandInfo2.status).isEqualTo(CommandStatus.PROCESSING) + + advanceTimeBy(101) + assertThat(commandInfo2.status).isEqualTo(CommandStatus.COMPLETED) + } + + private companion object { + const val QUEUE_TIMEOUT = 5001L + } +} diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java index 80b9489048..c18f60476b 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java @@ -25,6 +25,7 @@ import static android.view.MotionEvent.ACTION_UP; import static androidx.test.core.app.ApplicationProvider.getApplicationContext; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; +import static com.android.quickstep.DeviceConfigWrapper.DEFAULT_LPNH_TIMEOUT_MS; import static com.google.common.truth.Truth.assertThat; @@ -39,7 +40,6 @@ import static org.mockito.Mockito.when; import android.os.SystemClock; import android.view.MotionEvent; -import android.view.ViewConfiguration; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; @@ -142,7 +142,7 @@ public class NavHandleLongPressInputConsumerTest { @Test public void testLongPressTriggered() { mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN)); - SystemClock.sleep(ViewConfiguration.getLongPressTimeout()); + SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE); @@ -156,7 +156,7 @@ public class NavHandleLongPressInputConsumerTest { mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN)); mUnderTest.onMotionEvent(generateCenteredMotionEventWithYOffset(ACTION_MOVE, -(TOUCH_SLOP - 1))); - SystemClock.sleep(ViewConfiguration.getLongPressTimeout()); + SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE); @@ -170,7 +170,7 @@ public class NavHandleLongPressInputConsumerTest { mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN)); mUnderTest.onMotionEvent(generateMotionEvent(ACTION_MOVE, mScreenWidth / 2f - (TOUCH_SLOP - 1), 0)); - SystemClock.sleep(ViewConfiguration.getLongPressTimeout()); + SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE); @@ -189,7 +189,7 @@ public class NavHandleLongPressInputConsumerTest { mUnderTest.onMotionEvent(generateMotionEvent(ACTION_MOVE, mScreenWidth / 2f - (TOUCH_SLOP - 1), 0)); // We have entered the second stage, so the normal timeout shouldn't trigger. - SystemClock.sleep(ViewConfiguration.getLongPressTimeout()); + SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE); @@ -200,7 +200,7 @@ public class NavHandleLongPressInputConsumerTest { // After an extended time, the long press should trigger. float extendedDurationMultiplier = (DeviceConfigWrapper.get().getTwoStageDurationPercentage() / 100f); - SystemClock.sleep((long) (ViewConfiguration.getLongPressTimeout() + SystemClock.sleep((long) (DEFAULT_LPNH_TIMEOUT_MS * (extendedDurationMultiplier - 1))); // -1 because we already waited 1x InstrumentationRegistry.getInstrumentation().waitForIdleSync(); @@ -221,7 +221,7 @@ public class NavHandleLongPressInputConsumerTest { mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN)); // We have not entered the second stage, so the normal timeout should trigger. - SystemClock.sleep(ViewConfiguration.getLongPressTimeout()); + SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE); @@ -236,7 +236,7 @@ public class NavHandleLongPressInputConsumerTest { @Test public void testLongPressAbortedByTouchUp() { mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN)); - SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10); + SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS - 10); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE); @@ -256,7 +256,7 @@ public class NavHandleLongPressInputConsumerTest { @Test public void testLongPressAbortedByTouchCancel() { mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN)); - SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10); + SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS - 10); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE); @@ -276,7 +276,7 @@ public class NavHandleLongPressInputConsumerTest { @Test public void testLongPressAbortedByTouchSlopPassedVertically() { mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN)); - SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10); + SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS - 10); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE); @@ -297,7 +297,7 @@ public class NavHandleLongPressInputConsumerTest { @Test public void testLongPressAbortedByTouchSlopPassedHorizontally() { mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN)); - SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10); + SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS - 10); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE); @@ -326,7 +326,7 @@ public class NavHandleLongPressInputConsumerTest { mUnderTest.onMotionEvent(generateCenteredMotionEventWithYOffset(ACTION_MOVE, -(TOUCH_SLOP - 1))); // Normal duration shouldn't trigger. - SystemClock.sleep(ViewConfiguration.getLongPressTimeout()); + SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE); @@ -338,7 +338,7 @@ public class NavHandleLongPressInputConsumerTest { // Wait past the extended long press timeout, to be sure it wouldn't have triggered. float extendedDurationMultiplier = (DeviceConfigWrapper.get().getTwoStageDurationPercentage() / 100f); - SystemClock.sleep((long) (ViewConfiguration.getLongPressTimeout() + SystemClock.sleep((long) (DEFAULT_LPNH_TIMEOUT_MS * (extendedDurationMultiplier - 1))); // -1 because we already waited 1x InstrumentationRegistry.getInstrumentation().waitForIdleSync(); @@ -363,7 +363,7 @@ public class NavHandleLongPressInputConsumerTest { mUnderTest.onMotionEvent(generateMotionEvent(ACTION_MOVE, mScreenWidth / 2f - (TOUCH_SLOP - 1), 0)); // Normal duration shouldn't trigger. - SystemClock.sleep(ViewConfiguration.getLongPressTimeout()); + SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE); @@ -375,7 +375,7 @@ public class NavHandleLongPressInputConsumerTest { // Wait past the extended long press timeout, to be sure it wouldn't have triggered. float extendedDurationMultiplier = (DeviceConfigWrapper.get().getTwoStageDurationPercentage() / 100f); - SystemClock.sleep((long) (ViewConfiguration.getLongPressTimeout() + SystemClock.sleep((long) (DEFAULT_LPNH_TIMEOUT_MS * (extendedDurationMultiplier - 1))); // -1 because we already waited 1x InstrumentationRegistry.getInstrumentation().waitForIdleSync(); @@ -393,7 +393,7 @@ public class NavHandleLongPressInputConsumerTest { public void testTouchOutsideNavHandleIgnored() { // Touch the far left side of the screen. (y=0 is top of navbar region, picked arbitrarily) mUnderTest.onMotionEvent(generateMotionEvent(ACTION_DOWN, 0, 0)); - SystemClock.sleep(ViewConfiguration.getLongPressTimeout()); + SystemClock.sleep(DEFAULT_LPNH_TIMEOUT_MS); InstrumentationRegistry.getInstrumentation().waitForIdleSync(); // Should be ignored because the x position was not centered in the navbar region. 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 d2479bc926..0a607744d0 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt @@ -34,9 +34,7 @@ import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVI 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.google.android.apps.nexuslauncher.PrefKey.KEY_ENABLE_MINUS_ONE -import com.google.android.apps.nexuslauncher.PrefKey.OVERVIEW_SUGGESTED_ACTIONS -import com.google.android.apps.nexuslauncher.PrefKey.SMARTSPACE_ON_HOME_SCREEN +import com.android.launcher3.util.DaggerSingletonTracker import com.google.common.truth.Truth.assertThat import org.junit.After import org.junit.Before @@ -65,6 +63,7 @@ class SettingsChangeLoggerTest { @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 @@ -82,7 +81,7 @@ class SettingsChangeLoggerTest { // 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 @@ -93,7 +92,7 @@ class SettingsChangeLoggerTest { @Test fun loggingPrefs_correctDefaultValue() { - val systemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager) + val systemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager, mTracker) assertThat(systemUnderTest.loggingPrefs[ALLOW_ROTATION_PREFERENCE_KEY]!!.defaultValue) .isFalse() @@ -120,7 +119,7 @@ class SettingsChangeLoggerTest { 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 @@ -141,7 +140,14 @@ class SettingsChangeLoggerTest { .isTrue() assertThat(capturedEvents.any { it.id == LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED.id }) .isTrue() - // LAUNCHER_GOOGLE_APP_SWIPE_LEFT_ENABLED - assertThat(capturedEvents.any { it.id == 617 }).isTrue() + assertThat(capturedEvents.any { it.id == LAUNCHER_GOOGLE_APP_SWIPE_LEFT_ENABLED }).isTrue() + } + + companion object { + private const val KEY_ENABLE_MINUS_ONE = "pref_enable_minus_one" + private const val OVERVIEW_SUGGESTED_ACTIONS = "pref_overview_action_suggestions" + private const val SMARTSPACE_ON_HOME_SCREEN = "pref_smartspace_home_screen" + + private const val LAUNCHER_GOOGLE_APP_SWIPE_LEFT_ENABLED = 617 } } diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt index fe67313329..33d96a8c16 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/viewmodel/RecentsViewModelTest.kt @@ -70,6 +70,55 @@ class RecentsViewModelTest { assertThat(thumbnailDataFlow2.first()).isNull() } + @Test + fun updatesRunningTaskShowScreenshot() = runTest { + systemUnderTest.setRunningTaskShowScreenshot(true) + systemUnderTest.waitForRunningTaskShowScreenshotToUpdate() + } + + @Test + fun waitForThumbnailsToUpdate() = runTest { + // Given taskRepository with visible 2 tasks containing thumbnailData + val thumbnailData1 = createThumbnailData().apply { snapshotId = 1 } + val thumbnailData2 = createThumbnailData().apply { snapshotId = 2 } + tasksRepository.seedTasks(tasks) + tasksRepository.seedThumbnailData(mapOf(1 to thumbnailData1, 2 to thumbnailData2)) + systemUnderTest.updateVisibleTasks(listOf(1, 2)) + + val thumbnailDataFlow1 = tasksRepository.getThumbnailById(1) + val thumbnailDataFlow2 = tasksRepository.getThumbnailById(2) + + // Then getThumbnailById should initially contains correct thumbnailData + assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1) + assertThat(thumbnailDataFlow2.first()).isEqualTo(thumbnailData2) + + // When thumbnailData is updated in taskRepository + tasksRepository.seedThumbnailData( + mapOf(1 to thumbnailData1, 2 to createThumbnailData().apply { snapshotId = 3 }) + ) + // setVisibleTasks forces FakeTasksRepository to update the flows returned by + // getThumbnailById + tasksRepository.setVisibleTasks(listOf(1, 2)) + + // Then wait for thumbnailData should complete, and the previous getThumbnailById flow + // should return updated values + systemUnderTest.waitForThumbnailsToUpdate( + mapOf(2 to createThumbnailData().apply { snapshotId = 3 }) + ) + assertThat(thumbnailDataFlow1.first()).isEqualTo(thumbnailData1) + assertThat(thumbnailDataFlow2.first()?.snapshotId).isEqualTo(3) + } + + @Test + fun waitForThumbnailsToUpdate_emptyMap() = runTest { + systemUnderTest.waitForThumbnailsToUpdate(emptyMap()) + } + + @Test + fun waitForThumbnailsToUpdate_null() = runTest { + systemUnderTest.waitForThumbnailsToUpdate(null) + } + private fun createTaskWithId(taskId: Int) = Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000)).apply { colorBackground = Color.argb(taskId, taskId, taskId, taskId) diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.java deleted file mode 100644 index 7ef4910ce5..0000000000 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.java +++ /dev/null @@ -1,510 +0,0 @@ -/* - * Copyright (C) 2023 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 static com.android.quickstep.util.TaskGridNavHelper.CLEAR_ALL_PLACEHOLDER_ID; -import static com.android.quickstep.util.TaskGridNavHelper.INVALID_FOCUSED_TASK_ID; - -import static org.junit.Assert.assertEquals; - -import com.android.launcher3.util.IntArray; - -import org.junit.Test; - -public class TaskGridNavHelperTest { - - @Test - public void equalLengthRows_noFocused_onTop_pressDown_goesToBottom() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 1; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_DOWN; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 2, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onTop_pressUp_goesToBottom() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 1; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_UP; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 2, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onBottom_pressDown_goesToTop() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 2; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_DOWN; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 1, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onBottom_pressUp_goesToTop() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 2; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_UP; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 1, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onTop_pressLeft_goesLeft() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 1; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 3, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onBottom_pressLeft_goesLeft() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 2; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 4, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onTop_secondItem_pressRight_goesRight() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 3; - int delta = -1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 1, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onBottom_secondItem_pressRight_goesRight() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 4; - int delta = -1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 2, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onTop_pressRight_cycleToClearAll() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 1; - int delta = -1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onBottom_pressRight_cycleToClearAll() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 2; - int delta = -1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onTop_lastItem_pressLeft_toClearAll() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 5; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onBottom_lastItem_pressLeft_toClearAll() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 6; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onClearAll_pressLeft_cycleToFirst() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 1, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onClearAll_pressRight_toLastInBottom() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID; - int delta = -1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 6, nextGridPage); - } - - @Test - public void equalLengthRows_withFocused_onFocused_pressLeft_toTop() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int focusedTaskId = 99; - int currentPageTaskViewId = focusedTaskId; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, focusedTaskId); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 1, nextGridPage); - } - - @Test - public void equalLengthRows_withFocused_onFocused_pressUp_stayOnFocused() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int focusedTaskId = 99; - int currentPageTaskViewId = focusedTaskId; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_UP; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, focusedTaskId); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", focusedTaskId, nextGridPage); - } - - @Test - public void equalLengthRows_withFocused_onFocused_pressDown_stayOnFocused() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int focusedTaskId = 99; - int currentPageTaskViewId = focusedTaskId; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_DOWN; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, focusedTaskId); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", focusedTaskId, nextGridPage); - } - - @Test - public void equalLengthRows_withFocused_onFocused_pressRight_cycleToClearAll() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int focusedTaskId = 99; - int currentPageTaskViewId = focusedTaskId; - int delta = -1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, focusedTaskId); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", CLEAR_ALL_PLACEHOLDER_ID, nextGridPage); - } - - @Test - public void equalLengthRows_withFocused_onClearAll_pressLeft_cycleToFocusedTask() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int focusedTaskId = 99; - int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, focusedTaskId); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", focusedTaskId, nextGridPage); - } - - @Test - public void longerTopRow_noFocused_atEndTopBeyondBottom_pressDown_stayTop() { - IntArray topIds = IntArray.wrap(1, 3, 5, 7); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 7; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_DOWN; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 7, nextGridPage); - } - - @Test - public void longerTopRow_noFocused_atEndTopBeyondBottom_pressUp_stayTop() { - IntArray topIds = IntArray.wrap(1, 3, 5, 7); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 7; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_UP; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 7, nextGridPage); - } - - @Test - public void longerTopRow_noFocused_atEndBottom_pressLeft_goToTop() { - IntArray topIds = IntArray.wrap(1, 3, 5, 7); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 6; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_LEFT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 7, nextGridPage); - } - - @Test - public void longerTopRow_noFocused_atClearAll_pressRight_goToLonger() { - IntArray topIds = IntArray.wrap(1, 3, 5, 7); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID; - int delta = -1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 7, nextGridPage); - } - - @Test - public void longerBottomRow_noFocused_atClearAll_pressRight_goToLonger() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6, 7); - int currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID; - int delta = -1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_RIGHT; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 7, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onTop_pressTab_goesToBottom() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 1; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_TAB; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 2, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onBottom_pressTab_goesToNextTop() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 2; - int delta = 1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_TAB; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 3, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onTop_pressTabWithShift_goesToPreviousBottom() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 3; - int delta = -1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_TAB; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 2, nextGridPage); - } - - @Test - public void equalLengthRows_noFocused_onBottom_pressTabWithShift_goesToTop() { - IntArray topIds = IntArray.wrap(1, 3, 5); - IntArray bottomIds = IntArray.wrap(2, 4, 6); - int currentPageTaskViewId = 2; - int delta = -1; - @TaskGridNavHelper.TASK_NAV_DIRECTION int direction = TaskGridNavHelper.DIRECTION_TAB; - boolean cycle = true; - TaskGridNavHelper taskGridNavHelper = - new TaskGridNavHelper(topIds, bottomIds, INVALID_FOCUSED_TASK_ID); - - int nextGridPage = - taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, cycle); - - assertEquals("Wrong next page returned.", 1, nextGridPage); - } -} diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.kt new file mode 100644 index 0000000000..7aab75f590 --- /dev/null +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.kt @@ -0,0 +1,638 @@ +/* + * Copyright (C) 2023 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 com.android.launcher3.util.IntArray +import com.android.quickstep.util.TaskGridNavHelper.CLEAR_ALL_PLACEHOLDER_ID +import com.android.quickstep.util.TaskGridNavHelper.DIRECTION_DOWN +import com.android.quickstep.util.TaskGridNavHelper.DIRECTION_LEFT +import com.android.quickstep.util.TaskGridNavHelper.DIRECTION_RIGHT +import com.android.quickstep.util.TaskGridNavHelper.DIRECTION_TAB +import com.android.quickstep.util.TaskGridNavHelper.DIRECTION_UP +import com.google.common.truth.Truth.assertThat +import org.junit.Test + +class TaskGridNavHelperTest { + + /* + 5 3 1 + CLEAR_ALL ↓ + 6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onTop_pressDown_goesToBottom() { + assertThat(getNextGridPage(currentPageTaskViewId = 1, DIRECTION_DOWN, delta = 1)) + .isEqualTo(2) + } + + /* ↑----→ + 5 3 1 | + CLEAR_ALL | + 6 4 2←---| + */ + @Test + fun equalLengthRows_noFocused_onTop_pressUp_goesToBottom() { + assertThat(getNextGridPage(currentPageTaskViewId = 1, DIRECTION_UP, delta = 1)).isEqualTo(2) + } + + /* ↓----↑ + 5 3 1 | + CLEAR_ALL | + 6 4 2 | + ↓----→ + */ + @Test + fun equalLengthRows_noFocused_onBottom_pressDown_goesToTop() { + assertThat(getNextGridPage(currentPageTaskViewId = 2, DIRECTION_DOWN, delta = 1)) + .isEqualTo(1) + } + + /* + 5 3 1 + CLEAR_ALL ↑ + 6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onBottom_pressUp_goesToTop() { + assertThat(getNextGridPage(currentPageTaskViewId = 2, DIRECTION_UP, delta = 1)).isEqualTo(1) + } + + /* + 5 3<--1 + CLEAR_ALL + 6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onTop_pressLeft_goesLeft() { + assertThat(getNextGridPage(currentPageTaskViewId = 1, DIRECTION_LEFT, delta = 1)) + .isEqualTo(3) + } + + /* + 5 3 1 + CLEAR_ALL + 6 4<--2 + */ + @Test + fun equalLengthRows_noFocused_onBottom_pressLeft_goesLeft() { + assertThat(getNextGridPage(currentPageTaskViewId = 2, DIRECTION_LEFT, delta = 1)) + .isEqualTo(4) + } + + /* + 5 3-->1 + CLEAR_ALL + 6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onTop_secondItem_pressRight_goesRight() { + assertThat(getNextGridPage(currentPageTaskViewId = 3, DIRECTION_RIGHT, delta = -1)) + .isEqualTo(1) + } + + /* + 5 3 1 + CLEAR_ALL + 6 4-->2 + */ + @Test + fun equalLengthRows_noFocused_onBottom_secondItem_pressRight_goesRight() { + assertThat(getNextGridPage(currentPageTaskViewId = 4, DIRECTION_RIGHT, delta = -1)) + .isEqualTo(2) + } + + /* + ↓------------------← + | | + ↓ 5 3 1---→ + CLEAR_ALL + 6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onTop_pressRight_cycleToClearAll() { + assertThat(getNextGridPage(currentPageTaskViewId = 1, DIRECTION_RIGHT, delta = -1)) + .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID) + } + + /* + ↓------------------← + | ↑ + ↓ 5 3 1 | + CLEAR_ALL ↑ + 6 4 2---→ + */ + @Test + fun equalLengthRows_noFocused_onBottom_pressRight_cycleToClearAll() { + assertThat(getNextGridPage(currentPageTaskViewId = 2, DIRECTION_RIGHT, delta = -1)) + .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID) + } + + /* + ←----5 3 1 + ↓ + CLEAR_ALL + 6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onTop_lastItem_pressLeft_toClearAll() { + assertThat(getNextGridPage(currentPageTaskViewId = 5, DIRECTION_LEFT, delta = 1)) + .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID) + } + + /* + 5 3 1 + CLEAR_ALL + ↑ + ←---6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onBottom_lastItem_pressLeft_toClearAll() { + assertThat(getNextGridPage(currentPageTaskViewId = 6, DIRECTION_LEFT, delta = 1)) + .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID) + } + + /* + |→-----------------------| + | ↓ + ↑ 5 3 1 + ←------CLEAR_ALL + + 6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onClearAll_pressLeft_cycleToFirst() { + assertThat( + getNextGridPage( + currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID, + DIRECTION_LEFT, + delta = 1, + ) + ) + .isEqualTo(1) + } + + /* + 5 3 1 + CLEAR_ALL--↓ + | + |--→6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onClearAll_pressRight_toLastInBottom() { + assertThat( + getNextGridPage( + currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID, + DIRECTION_RIGHT, + delta = -1, + ) + ) + .isEqualTo(6) + } + + /* + 5 3 1←--- + ↑ + CLEAR_ALL ←--FOCUSED_TASK + 6 4 2 + */ + @Test + fun equalLengthRows_withFocused_onFocused_pressLeft_toTop() { + assertThat( + getNextGridPage( + currentPageTaskViewId = FOCUSED_TASK_ID, + DIRECTION_LEFT, + delta = 1, + largeTileIds = listOf(FOCUSED_TASK_ID), + ) + ) + .isEqualTo(1) + } + + /* + 5 3 1 + ←--↑ + CLEAR_ALL ↓-→FOCUSED_TASK + 6 4 2 + */ + @Test + fun equalLengthRows_withFocused_onFocused_pressUp_stayOnFocused() { + assertThat( + getNextGridPage( + currentPageTaskViewId = FOCUSED_TASK_ID, + DIRECTION_UP, + delta = 1, + largeTileIds = listOf(FOCUSED_TASK_ID), + ) + ) + .isEqualTo(FOCUSED_TASK_ID) + } + + /* + 5 3 1 + CLEAR_ALL ↑--→FOCUSED_TASK + ↑←--↓ + 6 4 2 + */ + + @Test + fun equalLengthRows_withFocused_onFocused_pressDown_stayOnFocused() { + + assertThat( + getNextGridPage( + currentPageTaskViewId = FOCUSED_TASK_ID, + DIRECTION_DOWN, + delta = 1, + largeTileIds = listOf(FOCUSED_TASK_ID), + ) + ) + .isEqualTo(FOCUSED_TASK_ID) + } + + /* + ↓-------------------------------←| + | ↑ + ↓ 5 3 1 | + CLEAR_ALL FOCUSED_TASK--→ + 6 4 2 + */ + @Test + fun equalLengthRows_withFocused_onFocused_pressRight_cycleToClearAll() { + + assertThat( + getNextGridPage( + currentPageTaskViewId = FOCUSED_TASK_ID, + DIRECTION_RIGHT, + delta = -1, + largeTileIds = listOf(FOCUSED_TASK_ID), + ) + ) + .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID) + } + + /* + |→---------------------------| + | | + ↑ 5 3 1 ↓ + ←------CLEAR_ALL FOCUSED_TASK + + 6 4 2 + */ + @Test + fun equalLengthRows_withFocused_onClearAll_pressLeft_cycleToFocusedTask() { + + assertThat( + getNextGridPage( + currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID, + DIRECTION_LEFT, + delta = 1, + largeTileIds = listOf(FOCUSED_TASK_ID), + ) + ) + .isEqualTo(FOCUSED_TASK_ID) + } + + /* + 7←-↑ 5 3 1 + ↓--→ + CLEAR_ALL + 6 4 2 + */ + @Test + fun longerTopRow_noFocused_atEndTopBeyondBottom_pressDown_stayTop() { + assertThat( + getNextGridPage( + currentPageTaskViewId = 7, + DIRECTION_DOWN, + delta = 1, + topIds = IntArray.wrap(1, 3, 5, 7), + ) + ) + .isEqualTo(7) + } + + /* + ←--↑ + ↓-→7 5 3 1 + CLEAR_ALL + 6 4 2 + */ + @Test + fun longerTopRow_noFocused_atEndTopBeyondBottom_pressUp_stayTop() { + assertThat( + getNextGridPage( + /* topIds = */ currentPageTaskViewId = 7, + DIRECTION_UP, + delta = 1, + topIds = IntArray.wrap(1, 3, 5, 7), + ) + ) + .isEqualTo(7) + } + + /* + 7 5 3 1 + CLEAR_ALL ↑ + ←----6 4 2 + */ + @Test + fun longerTopRow_noFocused_atEndBottom_pressLeft_goToTop() { + assertThat( + getNextGridPage( + /* topIds = */ currentPageTaskViewId = 6, + DIRECTION_LEFT, + delta = 1, + topIds = IntArray.wrap(1, 3, 5, 7), + ) + ) + .isEqualTo(7) + } + + /* + 7 5 3 1 + ↑ + CLEAR_ALL-----→ + 6 4 2 + */ + @Test + fun longerTopRow_noFocused_atClearAll_pressRight_goToLonger() { + assertThat( + getNextGridPage( + /* topIds = */ currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID, + DIRECTION_RIGHT, + delta = -1, + topIds = IntArray.wrap(1, 3, 5, 7), + ) + ) + .isEqualTo(7) + } + + /* + 5 3 1 + CLEAR_ALL-----→ + ↓ + 7 6 4 2 + */ + @Test + fun longerBottomRow_noFocused_atClearAll_pressRight_goToLonger() { + assertThat( + getNextGridPage( + currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID, + DIRECTION_RIGHT, + delta = -1, + bottomIds = IntArray.wrap(2, 4, 6, 7), + ) + ) + .isEqualTo(7) + } + + /* + 5 3 1 + CLEAR_ALL ↓ + 6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onTop_pressTab_goesToBottom() { + assertThat(getNextGridPage(currentPageTaskViewId = 1, DIRECTION_TAB, delta = 1)) + .isEqualTo(2) + } + + /* + 5 3 1 + CLEAR_ALL ↑ + ←---↑ + 6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onBottom_pressTab_goesToNextTop() { + assertThat(getNextGridPage(currentPageTaskViewId = 2, DIRECTION_TAB, delta = 1)) + .isEqualTo(3) + } + + /* + 5 3 1 + CLEAR_ALL ↓ + ----→ + ↓ + 6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onTop_pressTabWithShift_goesToPreviousBottom() { + assertThat(getNextGridPage(currentPageTaskViewId = 3, DIRECTION_TAB, delta = -1)) + .isEqualTo(2) + } + + /* + 5 3 1 + CLEAR_ALL ↑ + 6 4 2 + */ + @Test + fun equalLengthRows_noFocused_onBottom_pressTabWithShift_goesToTop() { + assertThat(getNextGridPage(currentPageTaskViewId = 2, DIRECTION_TAB, delta = -1)) + .isEqualTo(1) + } + + /* + 5 3 1 + CLEAR_ALL FOCUSED_TASK←--DESKTOP + 6 4 2 + */ + @Test + fun withLargeTile_pressLeftFromDesktopTask_goesToFocusedTask() { + assertThat( + getNextGridPage( + currentPageTaskViewId = DESKTOP_TASK_ID, + DIRECTION_LEFT, + delta = 1, + largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID), + ) + ) + .isEqualTo(FOCUSED_TASK_ID) + } + + /* + 5 3 1 + CLEAR_ALL FOCUSED_TASK--→DESKTOP + 6 4 2 + */ + @Test + fun withLargeTile_pressRightFromFocusedTask_goesToDesktopTask() { + assertThat( + getNextGridPage( + currentPageTaskViewId = FOCUSED_TASK_ID, + DIRECTION_RIGHT, + delta = -1, + largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID), + ) + ) + .isEqualTo(DESKTOP_TASK_ID) + } + + /* + ↓-----------------------------------------←| + | | + ↓ 5 3 1 ↑ + CLEAR_ALL FOCUSED_TASK DESKTOP--→ + 6 4 2 + */ + @Test + fun withLargeTile_pressRightFromDesktopTask_goesToClearAll() { + assertThat( + getNextGridPage( + currentPageTaskViewId = DESKTOP_TASK_ID, + DIRECTION_RIGHT, + delta = -1, + largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID), + ) + ) + .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID) + } + + /* + |→-------------------------------------------| + | | + ↑ 5 3 1 ↓ + ←------CLEAR_ALL FOCUSED_TASK DESKTOP + + 6 4 2 + */ + @Test + fun withLargeTile_pressLeftFromClearAll_goesToDesktopTask() { + assertThat( + getNextGridPage( + currentPageTaskViewId = CLEAR_ALL_PLACEHOLDER_ID, + DIRECTION_LEFT, + delta = 1, + largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID), + ) + ) + .isEqualTo(DESKTOP_TASK_ID) + } + + /* + 5 3 1 + CLEAR_ALL FOCUSED_TASK DESKTOP + ↑ + 6 4 2→----↑ + */ + @Test + fun withLargeTile_pressRightFromBottom_goesToLargeTile() { + assertThat( + getNextGridPage( + currentPageTaskViewId = 2, + DIRECTION_RIGHT, + delta = -1, + largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID), + ) + ) + .isEqualTo(FOCUSED_TASK_ID) + } + + /* + 5 3 1→----| + ↓ + CLEAR_ALL FOCUSED_TASK DESKTOP + 6 4 2 + */ + @Test + fun withLargeTile_pressRightFromTop_goesToLargeTile() { + assertThat( + getNextGridPage( + currentPageTaskViewId = 1, + DIRECTION_RIGHT, + delta = -1, + largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID), + ) + ) + .isEqualTo(FOCUSED_TASK_ID) + } + + /* + 5 3 1 + + CLEAR_ALL FOCUSED_TASK←---DESKTOP + 6 4 2 + */ + @Test + fun withLargeTile_pressTabFromDeskTop_goesToFocusedTask() { + assertThat( + getNextGridPage( + currentPageTaskViewId = DESKTOP_TASK_ID, + DIRECTION_TAB, + delta = 1, + largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID), + ) + ) + .isEqualTo(FOCUSED_TASK_ID) + } + + /* + CLEAR_ALL FOCUSED_TASK DESKTOP + ↓ + 2←----↓ + */ + @Test + fun withLargeTile_pressLeftFromLargeTile_goesToBottom() { + assertThat( + getNextGridPage( + currentPageTaskViewId = FOCUSED_TASK_ID, + DIRECTION_LEFT, + delta = 1, + topIds = IntArray(), + bottomIds = IntArray.wrap(2), + largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID), + ) + ) + .isEqualTo(2) + } + + /* + ↓-----------------------------------------←| + | | + ↓ 5 3 1 ↑ + CLEAR_ALL FOCUSED_TASK DESKTOP--→ + 6 4 2 + */ + @Test + fun withLargeTile_pressShiftTabFromDeskTop_goesToClearAll() { + assertThat( + getNextGridPage( + currentPageTaskViewId = DESKTOP_TASK_ID, + DIRECTION_TAB, + delta = -1, + largeTileIds = listOf(DESKTOP_TASK_ID, FOCUSED_TASK_ID), + ) + ) + .isEqualTo(CLEAR_ALL_PLACEHOLDER_ID) + } + + private fun getNextGridPage( + currentPageTaskViewId: Int, + direction: Int, + delta: Int, + topIds: IntArray = IntArray.wrap(1, 3, 5), + bottomIds: IntArray = IntArray.wrap(2, 4, 6), + largeTileIds: List<Int> = emptyList(), + ): Int { + val taskGridNavHelper = TaskGridNavHelper(topIds, bottomIds, largeTileIds) + return taskGridNavHelper.getNextGridPage(currentPageTaskViewId, delta, direction, true) + } + + private companion object { + const val FOCUSED_TASK_ID = 99 + const val DESKTOP_TASK_ID = 100 + } +} diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt index 88ffeeaf99..b67bc5a952 100644 --- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt +++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt @@ -31,7 +31,6 @@ import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDIC import com.android.launcher3.model.data.AppInfo import com.android.launcher3.model.data.ItemInfo import com.android.launcher3.model.data.TaskItemInfo -import com.android.launcher3.statehandlers.DesktopVisibilityController import com.android.quickstep.RecentsModel import com.android.quickstep.RecentsModel.RecentTasksChangedListener import com.android.quickstep.TaskIconCache @@ -66,9 +65,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { // Update canShowRunningAndRecentAppsAtInit before setUp() is called for each test. canShowRunningAndRecentAppsAtInit = description.methodName !in - listOf( - "canShowRunningAndRecentAppsAtInitIsFalse_getTasksNeverCalled", - ) + listOf("canShowRunningAndRecentAppsAtInitIsFalse_getTasksNeverCalled") } } @@ -76,7 +73,6 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { @Mock private lateinit var mockRecentsModel: RecentsModel @Mock private lateinit var mockContext: Context @Mock private lateinit var mockResources: Resources - @Mock private lateinit var mockDesktopVisibilityController: DesktopVisibilityController private var taskListChangeId: Int = 1 @@ -100,13 +96,11 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { recentTasksChangedListener = null it } - recentAppsController = - TaskbarRecentAppsController(mockContext, mockRecentsModel) { - mockDesktopVisibilityController - } + recentAppsController = TaskbarRecentAppsController(mockContext, mockRecentsModel) recentAppsController.canShowRunningApps = canShowRunningAndRecentAppsAtInit recentAppsController.canShowRecentApps = canShowRunningAndRecentAppsAtInit recentAppsController.init(taskbarControllers) + taskbarControllers.onPostInit() recentTasksChangedListener = if (canShowRunningAndRecentAppsAtInit) { @@ -133,7 +127,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2), runningTasks = listOf(createTask(1, RUNNING_APP_PACKAGE_1)), - recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) + recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2), ) verify(mockRecentsModel, never()).getTasks(any<Consumer<List<GroupTask>>>()) } @@ -147,7 +141,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2), runningTasks = listOf(createTask(1, RUNNING_APP_PACKAGE_1)), - recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) + recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2), ) // Verify that getTasks() was not called again after the init(). verify(mockRecentsModel, times(1)).getTasks(any<Consumer<List<GroupTask>>>()) @@ -162,7 +156,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = hotseatPackages, runningTasks = emptyList(), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) assertThat(newHotseatItems.map { it?.targetPackage }) .containsExactlyElementsIn(hotseatPackages) @@ -177,7 +171,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = hotseatPackages, runningTasks = emptyList(), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) assertThat(newHotseatItems.map { it?.targetPackage }) .containsExactlyElementsIn(hotseatPackages) @@ -191,7 +185,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1), runningTasks = emptyList(), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) val expectedPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2) assertThat(newHotseatItems.map { it?.targetPackage }) @@ -206,7 +200,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2), runningTasks = listOf(createTask(id = 1, HOTSEAT_PACKAGE_1)), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) assertThat(newHotseatItems).hasLength(2) @@ -226,9 +220,9 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { runningTasks = listOf( createTask(id = 1, HOTSEAT_PACKAGE_1), - createTask(id = 2, HOTSEAT_PACKAGE_1) + createTask(id = 2, HOTSEAT_PACKAGE_1), ), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) // First task is in Hotseat Items @@ -251,7 +245,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1), runningTasks = emptyList(), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) val expectedPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2) assertThat(newHotseatItems.map { it?.targetPackage }) @@ -267,9 +261,9 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { runningTasks = listOf( createTask(id = 1, RUNNING_APP_PACKAGE_1), - createTask(id = 2, RUNNING_APP_PACKAGE_2) + createTask(id = 2, RUNNING_APP_PACKAGE_2), ), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) assertThat(recentAppsController.shownTasks).isEmpty() } @@ -281,7 +275,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2, PREDICTED_PACKAGE_1), runningTasks = emptyList(), - recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) + recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2), ) assertThat(recentAppsController.shownTasks).isEmpty() } @@ -294,9 +288,9 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { runningTasks = listOf( createTask(id = 1, RUNNING_APP_PACKAGE_1), - createTask(id = 2, RUNNING_APP_PACKAGE_2) + createTask(id = 2, RUNNING_APP_PACKAGE_2), ), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) assertThat(recentAppsController.shownTasks).isEmpty() assertThat(recentAppsController.minimizedTaskIds).isEmpty() @@ -308,7 +302,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = emptyList(), - recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) + recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2), ) assertThat(recentAppsController.shownTasks).isEmpty() } @@ -321,7 +315,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task1, task2), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) val shownTasks = recentAppsController.shownTasks.map { it.task1 } assertThat(shownTasks).containsExactlyElementsIn(listOf(task1, task2)) @@ -335,7 +329,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task1, task2), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) assertThat(recentAppsController.runningTaskIds).isEmpty() assertThat(recentAppsController.minimizedTaskIds).isEmpty() @@ -349,7 +343,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task1, task2), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) assertThat(recentAppsController.runningTaskIds).containsExactlyElementsIn(listOf(1, 2)) assertThat(recentAppsController.minimizedTaskIds).isEmpty() @@ -362,12 +356,12 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { listOf( createTask(id = 1, HOTSEAT_PACKAGE_1), createTask(id = 2, RUNNING_APP_PACKAGE_1), - createTask(id = 3, RUNNING_APP_PACKAGE_2) + createTask(id = 3, RUNNING_APP_PACKAGE_2), ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2), runningTasks = runningTasks, - recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) + recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2), ) assertThat(recentAppsController.runningTaskIds).containsExactlyElementsIn(listOf(1, 2, 3)) assertThat(recentAppsController.minimizedTaskIds).isEmpty() @@ -383,7 +377,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = runningTasks, - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) assertThat(recentAppsController.runningTaskIds).containsExactly(1, 2, 3) assertThat(recentAppsController.minimizedTaskIds).containsExactly(3) @@ -397,7 +391,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task1, task2), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) assertThat(recentAppsController.runningTaskIds).containsExactlyElementsIn(listOf(1, 2)) } @@ -410,13 +404,13 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task1, task2), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task2, task1), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) val shownTasks = recentAppsController.shownTasks.map { it.task1 } @@ -431,13 +425,13 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task1, task2), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task2, task1), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) val shownTasks = recentAppsController.shownTasks.map { it.task1 } @@ -452,17 +446,17 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(RUNNING_APP_PACKAGE_1), runningTasks = listOf(task1, task2), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) updateRecentTasks( // Trigger a recent-tasks change before calling updateHotseatItems() runningTasks = listOf(task2, task1), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = listOf(RUNNING_APP_PACKAGE_1), runningTasks = listOf(task2, task1), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) val newHotseatItems = recentAppsController.shownHotseatItems @@ -479,12 +473,12 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = emptyList(), - recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3) + recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3), ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = emptyList(), - recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3, RECENT_PACKAGE_1) + recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3, RECENT_PACKAGE_1), ) val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } // Most recent packages, minus the currently running one (RECENT_PACKAGE_1). @@ -500,12 +494,12 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task1, task2), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task2, task1, task3), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } val expectedOrder = @@ -519,12 +513,12 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = emptyList(), - recentTaskPackages = listOf(RECENT_PACKAGE_3, RECENT_PACKAGE_2) + recentTaskPackages = listOf(RECENT_PACKAGE_3, RECENT_PACKAGE_2), ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = emptyList(), - recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3, RECENT_PACKAGE_1) + recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3, RECENT_PACKAGE_1), ) val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } // Most recent packages, minus the currently running one (RECENT_PACKAGE_1). @@ -540,12 +534,12 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task1, task2, task3), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task2, task1), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } assertThat(shownPackages).isEqualTo(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)) @@ -557,12 +551,12 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = emptyList(), - recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3) + recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3), ) prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = emptyList(), - recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3) + recentTaskPackages = listOf(RECENT_PACKAGE_2, RECENT_PACKAGE_3), ) val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } // Most recent packages, minus the currently running one (RECENT_PACKAGE_3). @@ -579,7 +573,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(runningTask1, runningTask2), - recentTaskPackages = recentTaskPackages + recentTaskPackages = recentTaskPackages, ) setInDesktopMode(true) @@ -597,7 +591,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(runningTask1, runningTask2), - recentTaskPackages = recentTaskPackages + recentTaskPackages = recentTaskPackages, ) setInDesktopMode(false) recentTasksChangedListener!!.onRecentTasksChanged() @@ -613,7 +607,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = emptyList(), - recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3) + recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2, RECENT_PACKAGE_3), ) val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames } // RECENT_PACKAGE_3 is the top task (visible to user) so should be excluded. @@ -629,7 +623,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(runningTask1, runningTask2), - recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) + recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2), ) val shownPackages = recentAppsController.shownTasks.map { it.packageNames } // Only 2 recent tasks shown: Desktop Tile + 1 Recent Task @@ -645,7 +639,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = emptyList(), - recentTaskPackages = listOf(RECENT_SPLIT_PACKAGES_1, RECENT_PACKAGE_1, RECENT_PACKAGE_2) + recentTaskPackages = listOf(RECENT_SPLIT_PACKAGES_1, RECENT_PACKAGE_1, RECENT_PACKAGE_2), ) val shownPackages = recentAppsController.shownTasks.map { it.packageNames } // Only 2 recent tasks shown: Pair + 1 Recent Task @@ -661,14 +655,14 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = emptyList(), - recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) + recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2), ) verify(taskbarViewController, times(1)).commitRunningAppsToUI() // Call onRecentTasksChanged() again with the same tasks, verify it's a no-op. prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = emptyList(), - recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2) + recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2), ) verify(taskbarViewController, times(1)).commitRunningAppsToUI() } @@ -681,14 +675,14 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(runningTask1, runningTask2), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) verify(taskbarViewController, times(1)).commitRunningAppsToUI() // Call onRecentTasksChanged() again with the same tasks, verify it's a no-op. prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(runningTask1, runningTask2), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) verify(taskbarViewController, times(1)).commitRunningAppsToUI() } @@ -702,7 +696,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task1Minimized, task2Visible), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) verify(taskbarViewController, times(1)).commitRunningAppsToUI() @@ -710,7 +704,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = emptyList(), runningTasks = listOf(task1Minimized, task2Minimized), - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) verify(taskbarViewController, times(2)).commitRunningAppsToUI() @@ -726,7 +720,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = hotseatPackages, runningTasks = originalTasks, - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) verify(taskbarViewController, times(1)).commitRunningAppsToUI() @@ -734,7 +728,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { prepareHotseatAndRunningAndRecentApps( hotseatPackages = hotseatPackages, runningTasks = newTasks, - recentTaskPackages = emptyList() + recentTaskPackages = emptyList(), ) verify(taskbarViewController, times(2)).commitRunningAppsToUI() @@ -751,10 +745,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { return recentAppsController.shownHotseatItems.toTypedArray() } - private fun updateRecentTasks( - runningTasks: List<Task>, - recentTaskPackages: List<String>, - ) { + private fun updateRecentTasks(runningTasks: List<Task>, recentTaskPackages: List<String>) { val recentTasks = createRecentTasksFromPackageNames(recentTaskPackages) val allTasks = ArrayList<GroupTask>().apply { @@ -790,7 +781,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { private fun createTestAppInfo( packageName: String = "testPackageName", - className: String = "testClassName" + className: String = "testClassName", ) = AppInfo(ComponentName(packageName, className), className /* title */, userHandle, Intent()) private fun createRecentTasksFromPackageNames(packageNames: List<String>): List<GroupTask> { @@ -800,7 +791,7 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { GroupTask( createTask(100, splitPackages[0]), createTask(101, splitPackages[1]), - /* splitBounds = */ null + /* splitBounds = */ null, ) } else { // Use the number at the end of the test packageName as the id. @@ -818,14 +809,15 @@ class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() { Intent().apply { `package` = packageName }, ComponentName(packageName, "TestActivity"), userHandle.identifier, - 0 + 0, ) ) .apply { this.isVisible = isVisible } } private fun setInDesktopMode(inDesktopMode: Boolean) { - whenever(mockDesktopVisibilityController.areDesktopTasksVisible()).thenReturn(inDesktopMode) + whenever(taskbarControllers.taskbarDesktopModeController.areDesktopTasksVisible) + .thenReturn(inDesktopMode) } private val GroupTask.packageNames: List<String> diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java index 2e456a7fcd..28589291fd 100644 --- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java +++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java @@ -248,7 +248,6 @@ public class FallbackRecentsTest { } @Test - @ScreenRecordRule.ScreenRecord // b/355042336 public void testOverview() throws IOException { startAppFast(getAppPackageName()); startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR)); diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java index 2087016388..9bc1c5981e 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java +++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java @@ -15,20 +15,18 @@ */ package com.android.quickstep; -import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL; -import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT; - import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.content.Intent; import android.platform.test.annotations.PlatinumTest; +import com.android.launcher3.tapl.Overview; import com.android.launcher3.tapl.OverviewTask.OverviewSplitTask; import com.android.launcher3.tapl.OverviewTaskMenu; import com.android.launcher3.ui.AbstractLauncherUiTest; import com.android.launcher3.uioverrides.QuickstepLauncher; -import com.android.launcher3.util.rule.TestStabilityRule; +import com.android.quickstep.util.SplitScreenTestUtils; import org.junit.Test; @@ -70,39 +68,17 @@ public class TaplOverviewIconTest extends AbstractLauncherUiTest<QuickstepLaunch @Test public void testSplitTaskTapBothIconMenus() { - createAndLaunchASplitPair(); + Overview overview = SplitScreenTestUtils.createAndLaunchASplitPairInOverview(mLauncher); - OverviewTaskMenu taskMenu = - mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu(); + OverviewTaskMenu taskMenu = overview.getCurrentTask().tapMenu(); assertTrue("App info item not appearing in expanded task menu.", taskMenu.hasMenuItem("App info")); taskMenu.touchOutsideTaskMenuToDismiss(); - OverviewTaskMenu splitMenu = - mLauncher.goHome().switchToOverview().getCurrentTask().tapMenu( + OverviewTaskMenu splitMenu = overview.getCurrentTask().tapMenu( OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT); assertTrue("App info item not appearing in expanded split task's menu.", splitMenu.hasMenuItem("App info")); splitMenu.touchOutsideTaskMenuToDismiss(); } - - private void createAndLaunchASplitPair() { - clearAllRecentTasks(); - - startTestActivity(2); - startTestActivity(3); - - if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) { - mLauncher.goHome().switchToOverview().getOverviewActions() - .clickSplit() - .getTestActivityTask(2) - .open(); - } else { - mLauncher.goHome().switchToOverview().getCurrentTask() - .tapMenu() - .tapSplitMenuItem() - .getCurrentTask() - .open(); - } - } -} +}
\ No newline at end of file diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java index 23a29f7840..800fd4aa93 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java +++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java @@ -21,6 +21,7 @@ import static com.android.launcher3.LauncherState.NORMAL; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeFalse; import android.util.Log; @@ -117,7 +118,6 @@ public class TaplPrivateSpaceTest extends AbstractQuickStepTest { } @Test - @ScreenRecordRule.ScreenRecord // b/334946529 public void testUserInstalledAppIsShownAboveDivider() throws IOException { // Ensure that the App is not installed in main user otherwise, it may not be found in // PS container. @@ -142,7 +142,6 @@ public class TaplPrivateSpaceTest extends AbstractQuickStepTest { } @Test - @ScreenRecordRule.ScreenRecord // b/334946529 public void testPrivateSpaceAppLongPressUninstallMenu() throws IOException { // Ensure that the App is not installed in main user otherwise, it may not be found in // PS container. @@ -166,8 +165,9 @@ public class TaplPrivateSpaceTest extends AbstractQuickStepTest { } @Test - @ScreenRecordRule.ScreenRecord // b/334946529 + @ScreenRecordRule.ScreenRecord // b/355466672 public void testPrivateSpaceLockingBehaviour() throws IOException { + assumeFalse(mLauncher.isTablet()); // b/367258373 // Scroll to the bottom of All Apps executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader()); HomeAllApps homeAllApps = mLauncher.getAllApps(); diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java index c419cd2f76..a16811efaf 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsPersistentTaskbar.java @@ -23,7 +23,6 @@ import androidx.test.runner.AndroidJUnit4; import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch; import org.junit.Assert; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -31,8 +30,6 @@ import org.junit.runner.RunWith; @RunWith(AndroidJUnit4.class) public class TaplTestsPersistentTaskbar extends AbstractTaplTestsTaskbar { - //TODO(b/359277238): fix falling tests - @Ignore @Test @NavigationModeSwitch public void testTaskbarFillsWidth() { diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java index 84b9a869ef..113b8a437f 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java @@ -350,7 +350,6 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { @Test @TaskbarModeSwitch - @ScreenRecord // b/358607191 public void testQuickSwitchToPreviousAppForTablet() throws Exception { assumeTrue(mLauncher.isTablet()); startTestActivity(2); @@ -478,7 +477,8 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { // assertTrue("Launcher internal state didn't remain in Overview", // isInState(() -> LauncherState.OVERVIEW)); // overview.getCurrentTask().dismiss(); -// executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple dismissals", +// executeOnLauncher(launcher -> assertTrue("Grid did not rebalance after multiple +// dismissals", // (Math.abs(getTopRowTaskCountForTablet(launcher) - getBottomRowTaskCountForTablet( // launcher)) <= 1))); @@ -515,8 +515,6 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { isInState(() -> LauncherState.NORMAL)); } - //TODO(b/359277238): fix falling tests - @Ignore @Test @PortraitLandscape @TaskbarModeSwitch @@ -579,7 +577,7 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { public void testExcludeFromRecents() throws Exception { startExcludeFromRecentsTestActivity(); OverviewTask currentTask = getAndAssertLaunchedApp().switchToOverview().getCurrentTask(); - // TODO(b/326565120): the expected content description shouldn't be null but for now there + // TODO(b/342627272): the expected content description shouldn't be null but for now there // is a bug that causes it to sometimes be for excludeForRecents tasks. assertTrue("Can't find ExcludeFromRecentsTestActivity after entering Overview from it", currentTask.containsContentDescription("ExcludeFromRecents") @@ -589,7 +587,8 @@ public class TaplTestsQuickstep extends AbstractQuickStepTest { if (overview.hasTasks()) { currentTask = overview.getCurrentTask(); assertFalse("Found ExcludeFromRecentsTestActivity after entering Overview from Home", - currentTask.containsContentDescription("ExcludeFromRecents") + currentTask.containsContentDescription( + "ExcludeFromRecents") || currentTask.containsContentDescription(null)); } else { // Presumably the test started with 0 tasks and remains that way after going home. diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java index 733ea4e2cf..daa4ec327a 100644 --- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java +++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java @@ -17,8 +17,6 @@ package com.android.quickstep; import static com.android.launcher3.config.FeatureFlags.enableSplitContextually; -import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL; -import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -33,7 +31,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.launcher3.tapl.Overview; import com.android.launcher3.tapl.Taskbar; import com.android.launcher3.tapl.TaskbarAppIcon; -import com.android.launcher3.util.rule.TestStabilityRule; +import com.android.quickstep.util.SplitScreenTestUtils; import com.android.wm.shell.Flags; import org.junit.After; @@ -110,9 +108,8 @@ public class TaplTestsSplitscreen extends AbstractQuickStepTest { assumeTrue("App pairs feature is currently not enabled, no test needed", Flags.enableAppPairs()); - createAndLaunchASplitPair(); + Overview overview = SplitScreenTestUtils.createAndLaunchASplitPairInOverview(mLauncher); - Overview overview = mLauncher.goHome().switchToOverview(); if (mLauncher.isGridOnlyOverviewEnabled() || !mLauncher.isTablet()) { assertTrue("Save app pair menu item is missing", overview.getCurrentTask() @@ -156,24 +153,4 @@ public class TaplTestsSplitscreen extends AbstractQuickStepTest { TaskbarAppIcon firstApp = taskbar.getAppIcon(firstAppName); firstApp.launchIntoSplitScreen(); } - - private void createAndLaunchASplitPair() { - clearAllRecentTasks(); - - startTestActivity(2); - startTestActivity(3); - - if (mLauncher.isTablet() && !mLauncher.isGridOnlyOverviewEnabled()) { - mLauncher.goHome().switchToOverview().getOverviewActions() - .clickSplit() - .getTestActivityTask(2) - .open(); - } else { - mLauncher.goHome().switchToOverview().getCurrentTask() - .tapMenu() - .tapSplitMenuItem() - .getCurrentTask() - .open(); - } - } } diff --git a/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt index 4d10f0f51e..cb59f7dfda 100644 --- a/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt +++ b/quickstep/tests/src/com/android/quickstep/taskbar/controllers/TaskbarPinningControllerTest.kt @@ -55,7 +55,6 @@ class TaskbarPinningControllerTest : TaskbarBaseTestCase() { private val taskbarDragLayer = mock<TaskbarDragLayer>() private val taskbarSharedState = mock<TaskbarSharedState>() private var isInDesktopMode = false - private val isInDesktopModeProvider = { isInDesktopMode } private val launcherPrefs = mock<LauncherPrefs> { on { get(TASKBAR_PINNING) } doReturn false @@ -71,8 +70,9 @@ class TaskbarPinningControllerTest : TaskbarBaseTestCase() { whenever(taskbarActivityContext.launcherPrefs).thenReturn(launcherPrefs) whenever(taskbarActivityContext.dragLayer).thenReturn(taskbarDragLayer) whenever(taskbarActivityContext.statsLogManager).thenReturn(statsLogManager) - pinningController = - spy(TaskbarPinningController(taskbarActivityContext, isInDesktopModeProvider)) + whenever(taskbarControllers.taskbarDesktopModeController.areDesktopTasksVisible) + .thenAnswer { _ -> isInDesktopMode } + pinningController = spy(TaskbarPinningController(taskbarActivityContext)) pinningController.init(taskbarControllers, taskbarSharedState) } diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt b/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt new file mode 100644 index 0000000000..82361aabb8 --- /dev/null +++ b/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt @@ -0,0 +1,60 @@ +/* + * 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.test.uiautomator.By +import com.android.launcher3.tapl.LauncherInstrumentation +import com.android.launcher3.tapl.Overview +import com.android.launcher3.tapl.OverviewTask +import com.android.launcher3.ui.AbstractLauncherUiTest + +object SplitScreenTestUtils { + + /** Creates 2 tasks and makes a split mode pair. Also asserts the accessibility labels. */ + @JvmStatic + fun createAndLaunchASplitPairInOverview(launcher: LauncherInstrumentation): Overview { + clearAllRecentTasks(launcher) + + AbstractLauncherUiTest.startTestActivity(2) + AbstractLauncherUiTest.startTestActivity(3) + + val overView = launcher.goHome().switchToOverview() + if (launcher.isTablet && !launcher.isGridOnlyOverviewEnabled) { + overView.overviewActions.clickSplit().getTestActivityTask(2).open() + } else { + overView.currentTask.tapMenu().tapSplitMenuItem().currentTask.open() + } + + val overviewWithSplitPair = launcher.goHome().switchToOverview() + val currentTask = overviewWithSplitPair.currentTask + currentTask.containsContentDescription( + By.pkg(AbstractLauncherUiTest.getAppPackageName()).text("TestActivity3").toString(), + OverviewTask.OverviewSplitTask.SPLIT_TOP_OR_LEFT + ) + currentTask.containsContentDescription( + By.pkg(AbstractLauncherUiTest.getAppPackageName()).text("TestActivity2").toString(), + OverviewTask.OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT + ) + return overviewWithSplitPair + } + + private fun clearAllRecentTasks(launcher: LauncherInstrumentation) { + if (launcher.recentTasks.isNotEmpty()) { + launcher.goHome().switchToOverview().dismissAllTasks() + } + } +} diff --git a/res/color-night-v31/popup_color_background.xml b/res/color-night-v31/popup_color_background.xml deleted file mode 100644 index 13ceaa09e7..0000000000 --- a/res/color-night-v31/popup_color_background.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2023 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. ---> -<selector xmlns:android="http://schemas.android.com/apk/res/android" > - <item - android:color="@android:color/system_neutral1_900" - android:lStar="12" /> -</selector> diff --git a/res/color-v31/popup_color_background.xml b/res/color-v31/popup_color_background.xml deleted file mode 100644 index 99155d8972..0000000000 --- a/res/color-v31/popup_color_background.xml +++ /dev/null @@ -1,20 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2023 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. ---> -<selector xmlns:android="http://schemas.android.com/apk/res/android" > - <item - android:color="@android:color/system_neutral1_50" - android:lStar="94" /> -</selector> diff --git a/res/color/popup_color_background.xml b/res/color/popup_color_background.xml deleted file mode 100644 index e87e77231c..0000000000 --- a/res/color/popup_color_background.xml +++ /dev/null @@ -1,18 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2023 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. ---> -<selector xmlns:android="http://schemas.android.com/apk/res/android" > - <item android:color="?attr/popupColorBackground" /> -</selector> diff --git a/res/drawable-sw720dp/ic_transient_taskbar_all_apps_button.xml b/res/drawable-sw720dp/ic_transient_taskbar_all_apps_button.xml deleted file mode 100644 index 47f2a5d73a..0000000000 --- a/res/drawable-sw720dp/ic_transient_taskbar_all_apps_button.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2023 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="52dp" - android:height="52dp" - android:viewportWidth="52" - android:viewportHeight="52"> - <path - android:pathData="M15.5,19C14.538,19 13.715,18.65 13.033,17.968C12.35,17.285 12,16.462 12,15.5C12,14.538 12.35,13.715 13.033,13.033C13.715,12.35 14.538,12 15.5,12C16.462,12 17.285,12.35 17.968,13.033C18.65,13.715 19,14.538 19,15.5C19,16.462 18.65,17.285 17.968,17.968C17.285,18.65 16.462,19 15.5,19Z" - android:fillColor="#40484B"/> - <path - android:pathData="M26,19C25.038,19 24.215,18.65 23.532,17.968C22.85,17.285 22.5,16.462 22.5,15.5C22.5,14.538 22.85,13.715 23.532,13.033C24.215,12.35 25.038,12 26,12C26.962,12 27.785,12.35 28.468,13.033C29.15,13.715 29.5,14.538 29.5,15.5C29.5,16.462 29.15,17.285 28.468,17.968C27.785,18.65 26.962,19 26,19Z" - android:fillColor="#40484B"/> - <path - android:pathData="M36.5,19C35.537,19 34.715,18.65 34.033,17.968C33.35,17.285 33,16.462 33,15.5C33,14.538 33.35,13.715 34.033,13.033C34.715,12.35 35.537,12 36.5,12C37.463,12 38.285,12.35 38.967,13.033C39.65,13.715 40,14.538 40,15.5C40,16.462 39.65,17.285 38.967,17.968C38.285,18.65 37.463,19 36.5,19Z" - android:fillColor="#40484B"/> - <path - android:pathData="M15.5,29.5C14.538,29.5 13.715,29.15 13.033,28.468C12.35,27.785 12,26.962 12,26C12,25.038 12.35,24.215 13.033,23.532C13.715,22.85 14.538,22.5 15.5,22.5C16.462,22.5 17.285,22.85 17.968,23.532C18.65,24.215 19,25.038 19,26C19,26.962 18.65,27.785 17.968,28.468C17.285,29.15 16.462,29.5 15.5,29.5Z" - android:fillColor="#40484B"/> - <path - android:pathData="M26,29.5C25.038,29.5 24.215,29.15 23.532,28.468C22.85,27.785 22.5,26.962 22.5,26C22.5,25.038 22.85,24.215 23.532,23.532C24.215,22.85 25.038,22.5 26,22.5C26.962,22.5 27.785,22.85 28.468,23.532C29.15,24.215 29.5,25.038 29.5,26C29.5,26.962 29.15,27.785 28.468,28.468C27.785,29.15 26.962,29.5 26,29.5Z" - android:fillColor="#40484B"/> - <path - android:pathData="M36.5,29.5C35.537,29.5 34.715,29.15 34.033,28.468C33.35,27.785 33,26.962 33,26C33,25.038 33.35,24.215 34.033,23.532C34.715,22.85 35.537,22.5 36.5,22.5C37.463,22.5 38.285,22.85 38.967,23.532C39.65,24.215 40,25.038 40,26C40,26.962 39.65,27.785 38.967,28.468C38.285,29.15 37.463,29.5 36.5,29.5Z" - android:fillColor="#40484B"/> - <path - android:pathData="M15.5,40C14.538,40 13.715,39.65 13.033,38.967C12.35,38.285 12,37.463 12,36.5C12,35.537 12.35,34.715 13.033,34.033C13.715,33.35 14.538,33 15.5,33C16.462,33 17.285,33.35 17.968,34.033C18.65,34.715 19,35.537 19,36.5C19,37.463 18.65,38.285 17.968,38.967C17.285,39.65 16.462,40 15.5,40Z" - android:fillColor="#40484B"/> - <path - android:pathData="M26,40C25.038,40 24.215,39.65 23.532,38.967C22.85,38.285 22.5,37.463 22.5,36.5C22.5,35.537 22.85,34.715 23.532,34.033C24.215,33.35 25.038,33 26,33C26.962,33 27.785,33.35 28.468,34.033C29.15,34.715 29.5,35.537 29.5,36.5C29.5,37.463 29.15,38.285 28.468,38.967C27.785,39.65 26.962,40 26,40Z" - android:fillColor="#40484B"/> - <path - android:pathData="M36.5,40C35.537,40 34.715,39.65 34.033,38.967C33.35,38.285 33,37.463 33,36.5C33,35.537 33.35,34.715 34.033,34.033C34.715,33.35 35.537,33 36.5,33C37.463,33 38.285,33.35 38.967,34.033C39.65,34.715 40,35.537 40,36.5C40,37.463 39.65,38.285 38.967,38.967C38.285,39.65 37.463,40 36.5,40Z" - android:fillColor="#40484B"/> -</vector> diff --git a/res/drawable/ic_taskbar_all_apps_button.xml b/res/drawable/ic_taskbar_all_apps_button.xml deleted file mode 100644 index 82fbbea617..0000000000 --- a/res/drawable/ic_taskbar_all_apps_button.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2023 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="44dp" - android:height="44dp" - android:viewportWidth="44" - android:viewportHeight="44"> - <path - android:pathData="M13,16C12.175,16 11.47,15.7 10.885,15.115C10.3,14.53 10,13.825 10,13C10,12.175 10.3,11.47 10.885,10.885C11.47,10.3 12.175,10 13,10C13.825,10 14.53,10.3 15.115,10.885C15.7,11.47 16,12.175 16,13C16,13.825 15.7,14.53 15.115,15.115C14.53,15.7 13.825,16 13,16Z" - android:fillColor="#40484B"/> - <path - android:pathData="M22,16C21.175,16 20.47,15.7 19.885,15.115C19.3,14.53 19,13.825 19,13C19,12.175 19.3,11.47 19.885,10.885C20.47,10.3 21.175,10 22,10C22.825,10 23.53,10.3 24.115,10.885C24.7,11.47 25,12.175 25,13C25,13.825 24.7,14.53 24.115,15.115C23.53,15.7 22.825,16 22,16Z" - android:fillColor="#40484B"/> - <path - android:pathData="M31,16C30.175,16 29.47,15.7 28.885,15.115C28.3,14.53 28,13.825 28,13C28,12.175 28.3,11.47 28.885,10.885C29.47,10.3 30.175,10 31,10C31.825,10 32.53,10.3 33.115,10.885C33.7,11.47 34,12.175 34,13C34,13.825 33.7,14.53 33.115,15.115C32.53,15.7 31.825,16 31,16Z" - android:fillColor="#40484B"/> - <path - android:pathData="M13,25C12.175,25 11.47,24.7 10.885,24.115C10.3,23.53 10,22.825 10,22C10,21.175 10.3,20.47 10.885,19.885C11.47,19.3 12.175,19 13,19C13.825,19 14.53,19.3 15.115,19.885C15.7,20.47 16,21.175 16,22C16,22.825 15.7,23.53 15.115,24.115C14.53,24.7 13.825,25 13,25Z" - android:fillColor="#40484B"/> - <path - android:pathData="M22,25C21.175,25 20.47,24.7 19.885,24.115C19.3,23.53 19,22.825 19,22C19,21.175 19.3,20.47 19.885,19.885C20.47,19.3 21.175,19 22,19C22.825,19 23.53,19.3 24.115,19.885C24.7,20.47 25,21.175 25,22C25,22.825 24.7,23.53 24.115,24.115C23.53,24.7 22.825,25 22,25Z" - android:fillColor="#40484B"/> - <path - android:pathData="M31,25C30.175,25 29.47,24.7 28.885,24.115C28.3,23.53 28,22.825 28,22C28,21.175 28.3,20.47 28.885,19.885C29.47,19.3 30.175,19 31,19C31.825,19 32.53,19.3 33.115,19.885C33.7,20.47 34,21.175 34,22C34,22.825 33.7,23.53 33.115,24.115C32.53,24.7 31.825,25 31,25Z" - android:fillColor="#40484B"/> - <path - android:pathData="M13,34C12.175,34 11.47,33.7 10.885,33.115C10.3,32.53 10,31.825 10,31C10,30.175 10.3,29.47 10.885,28.885C11.47,28.3 12.175,28 13,28C13.825,28 14.53,28.3 15.115,28.885C15.7,29.47 16,30.175 16,31C16,31.825 15.7,32.53 15.115,33.115C14.53,33.7 13.825,34 13,34Z" - android:fillColor="#40484B"/> - <path - android:pathData="M22,34C21.175,34 20.47,33.7 19.885,33.115C19.3,32.53 19,31.825 19,31C19,30.175 19.3,29.47 19.885,28.885C20.47,28.3 21.175,28 22,28C22.825,28 23.53,28.3 24.115,28.885C24.7,29.47 25,30.175 25,31C25,31.825 24.7,32.53 24.115,33.115C23.53,33.7 22.825,34 22,34Z" - android:fillColor="#40484B"/> - <path - android:pathData="M31,34C30.175,34 29.47,33.7 28.885,33.115C28.3,32.53 28,31.825 28,31C28,30.175 28.3,29.47 28.885,28.885C29.47,28.3 30.175,28 31,28C31.825,28 32.53,28.3 33.115,28.885C33.7,29.47 34,30.175 34,31C34,31.825 33.7,32.53 33.115,33.115C32.53,33.7 31.825,34 31,34Z" - android:fillColor="#40484B"/> -</vector> diff --git a/res/drawable/ic_transient_taskbar_all_apps_button.xml b/res/drawable/ic_transient_taskbar_all_apps_button.xml deleted file mode 100644 index 6e740aed4f..0000000000 --- a/res/drawable/ic_transient_taskbar_all_apps_button.xml +++ /dev/null @@ -1,48 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2023 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:viewportWidth="48" - android:viewportHeight="48"> - <path - android:pathData="M13.5,17C12.538,17 11.715,16.65 11.033,15.967C10.35,15.285 10,14.462 10,13.5C10,12.538 10.35,11.715 11.033,11.033C11.715,10.35 12.538,10 13.5,10C14.462,10 15.285,10.35 15.967,11.033C16.65,11.715 17,12.538 17,13.5C17,14.462 16.65,15.285 15.967,15.967C15.285,16.65 14.462,17 13.5,17Z" - android:fillColor="#40484B"/> - <path - android:pathData="M24,17C23.038,17 22.215,16.65 21.532,15.967C20.85,15.285 20.5,14.462 20.5,13.5C20.5,12.538 20.85,11.715 21.532,11.033C22.215,10.35 23.038,10 24,10C24.962,10 25.785,10.35 26.468,11.033C27.15,11.715 27.5,12.538 27.5,13.5C27.5,14.462 27.15,15.285 26.468,15.967C25.785,16.65 24.962,17 24,17Z" - android:fillColor="#40484B"/> - <path - android:pathData="M34.5,17C33.537,17 32.715,16.65 32.033,15.967C31.35,15.285 31,14.462 31,13.5C31,12.538 31.35,11.715 32.033,11.033C32.715,10.35 33.537,10 34.5,10C35.463,10 36.285,10.35 36.967,11.033C37.65,11.715 38,12.538 38,13.5C38,14.462 37.65,15.285 36.967,15.967C36.285,16.65 35.463,17 34.5,17Z" - android:fillColor="#40484B"/> - <path - android:pathData="M13.5,27.5C12.538,27.5 11.715,27.15 11.033,26.468C10.35,25.785 10,24.962 10,24C10,23.038 10.35,22.215 11.033,21.532C11.715,20.85 12.538,20.5 13.5,20.5C14.462,20.5 15.285,20.85 15.967,21.532C16.65,22.215 17,23.038 17,24C17,24.962 16.65,25.785 15.967,26.468C15.285,27.15 14.462,27.5 13.5,27.5Z" - android:fillColor="#40484B"/> - <path - android:pathData="M24,27.5C23.038,27.5 22.215,27.15 21.532,26.468C20.85,25.785 20.5,24.962 20.5,24C20.5,23.038 20.85,22.215 21.532,21.532C22.215,20.85 23.038,20.5 24,20.5C24.962,20.5 25.785,20.85 26.468,21.532C27.15,22.215 27.5,23.038 27.5,24C27.5,24.962 27.15,25.785 26.468,26.468C25.785,27.15 24.962,27.5 24,27.5Z" - android:fillColor="#40484B"/> - <path - android:pathData="M34.5,27.5C33.537,27.5 32.715,27.15 32.033,26.468C31.35,25.785 31,24.962 31,24C31,23.038 31.35,22.215 32.033,21.532C32.715,20.85 33.537,20.5 34.5,20.5C35.463,20.5 36.285,20.85 36.967,21.532C37.65,22.215 38,23.038 38,24C38,24.962 37.65,25.785 36.967,26.468C36.285,27.15 35.463,27.5 34.5,27.5Z" - android:fillColor="#40484B"/> - <path - android:pathData="M13.5,38C12.538,38 11.715,37.65 11.033,36.967C10.35,36.285 10,35.463 10,34.5C10,33.537 10.35,32.715 11.033,32.033C11.715,31.35 12.538,31 13.5,31C14.462,31 15.285,31.35 15.967,32.033C16.65,32.715 17,33.537 17,34.5C17,35.463 16.65,36.285 15.967,36.967C15.285,37.65 14.462,38 13.5,38Z" - android:fillColor="#40484B"/> - <path - android:pathData="M24,38C23.038,38 22.215,37.65 21.532,36.967C20.85,36.285 20.5,35.463 20.5,34.5C20.5,33.537 20.85,32.715 21.532,32.033C22.215,31.35 23.038,31 24,31C24.962,31 25.785,31.35 26.468,32.033C27.15,32.715 27.5,33.537 27.5,34.5C27.5,35.463 27.15,36.285 26.468,36.967C25.785,37.65 24.962,38 24,38Z" - android:fillColor="#40484B"/> - <path - android:pathData="M34.5,38C33.537,38 32.715,37.65 32.033,36.967C31.35,36.285 31,35.463 31,34.5C31,33.537 31.35,32.715 32.033,32.033C32.715,31.35 33.537,31 34.5,31C35.463,31 36.285,31.35 36.967,32.033C37.65,32.715 38,33.537 38,34.5C38,35.463 37.65,36.285 36.967,36.967C36.285,37.65 35.463,38 34.5,38Z" - android:fillColor="#40484B"/> -</vector> diff --git a/res/drawable/popup_background.xml b/res/drawable/popup_background.xml index 6eedecb6ca..4ddd228c68 100644 --- a/res/drawable/popup_background.xml +++ b/res/drawable/popup_background.xml @@ -15,6 +15,6 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> - <solid android:color="?attr/popupColorBackground"/> + <solid android:color="?attr/materialColorSurfaceContainer"/> <corners android:radius="@dimen/dialogCornerRadius"/> </shape>
\ No newline at end of file diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml index d9f2072533..f62384c048 100644 --- a/res/values-hr/strings.xml +++ b/res/values-hr/strings.xml @@ -189,7 +189,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-km/strings.xml b/res/values-km/strings.xml index 3c9135bb2a..ebd68f78e7 100644 --- a/res/values-km/strings.xml +++ b/res/values-km/strings.xml @@ -117,7 +117,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-nb/strings.xml b/res/values-nb/strings.xml index 2a6611f3b2..e2be4ffe74 100644 --- a/res/values-nb/strings.xml +++ b/res/values-nb/strings.xml @@ -31,7 +31,7 @@ <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> - <string name="save_app_pair" msgid="5647523853662686243">"Lagre apptilkoblingen"</string> + <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> <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Åpne enheten for å bruke denne apptilkoblingen"</string> diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 6151b5fb93..57c9bc7a8f 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -25,7 +25,6 @@ <attr name="popupColorPrimary" format="color" /> <attr name="popupColorSecondary" format="color" /> <attr name="popupColorTertiary" format="color" /> - <attr name="popupColorBackground" format="color" /> <attr name="popupTextColor" format="color" /> <attr name="popupShadeFirst" format="color" /> <attr name="popupShadeSecond" format="color" /> diff --git a/res/values/config.xml b/res/values/config.xml index 507ce9a39e..701e64a4b4 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -67,7 +67,6 @@ <string name="main_process_initializer_class" translatable="false"></string> <string name="app_launch_tracker_class" translatable="false"></string> <string name="test_information_handler_class" translatable="false"></string> - <string name="launcher_activity_logic_class" translatable="false"></string> <string name="model_delegate_class" translatable="false"></string> <string name="window_manager_proxy_class" translatable="false"></string> <string name="secondary_display_predictions_class" translatable="false"></string> diff --git a/res/values/styles.xml b/res/values/styles.xml index 2d7808b7e2..728c523542 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -90,7 +90,6 @@ <item name="popupColorPrimary">@color/popup_color_primary_light</item> <item name="popupColorSecondary">@color/popup_color_secondary_light</item> <item name="popupColorTertiary">@color/popup_color_tertiary_light</item> - <item name="popupColorBackground">#EFEDED</item> <item name="popupTextColor">@color/system_on_surface_light</item> <item name="popupShadeFirst">@color/popup_shade_first_light</item> <item name="popupShadeSecond">@color/popup_shade_second_light</item> @@ -165,7 +164,6 @@ <item name="popupColorPrimary">@color/popup_color_primary_dark</item> <item name="popupColorSecondary">@color/popup_color_secondary_dark</item> <item name="popupColorTertiary">@color/popup_color_tertiary_dark</item> - <item name="popupColorBackground">#1F2020</item> <item name="popupTextColor">@color/system_on_surface_dark</item> <item name="popupNotificationDotColor">@color/popup_notification_dot_dark</item> <item name="popupShadeFirst">@color/popup_shade_first_dark</item> diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java index d3ee364e99..76c0f90e74 100644 --- a/src/com/android/launcher3/AbstractFloatingView.java +++ b/src/com/android/launcher3/AbstractFloatingView.java @@ -74,7 +74,8 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch TYPE_TASKBAR_ALL_APPS, TYPE_ADD_TO_HOME_CONFIRMATION, TYPE_TASKBAR_OVERLAY_PROXY, - TYPE_TASKBAR_PINNING_POPUP + TYPE_TASKBAR_PINNING_POPUP, + TYPE_PIN_IME_POPUP }) @Retention(RetentionPolicy.SOURCE) public @interface FloatingViewType {} diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java index ef56246136..b51e850c04 100644 --- a/src/com/android/launcher3/AppWidgetResizeFrame.java +++ b/src/com/android/launcher3/AppWidgetResizeFrame.java @@ -37,8 +37,6 @@ import com.android.launcher3.accessibility.DragViewStateAnnouncer; import com.android.launcher3.celllayout.CellLayoutLayoutParams; import com.android.launcher3.celllayout.CellPosMapper.CellPos; import com.android.launcher3.config.FeatureFlags; -import com.android.launcher3.debug.TestEvent; -import com.android.launcher3.debug.TestEventEmitter; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.keyboard.ViewGroupFocusHelper; import com.android.launcher3.logging.InstanceId; @@ -223,9 +221,6 @@ public class AppWidgetResizeFrame extends AbstractFloatingView implements View.O dl.addView(frame); frame.mIsOpen = true; frame.post(() -> frame.snapToWidget(false)); - TestEventEmitter.INSTANCE.get(widget.getContext()).sendEvent( - TestEvent.RESIZE_FRAME_SHOWING - ); } private void setCornerRadiusFromWidget() { diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index 8ae6d735f8..cc5baea07e 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -25,7 +25,6 @@ import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_LANDS import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_PORTRAIT; import static com.android.launcher3.Utilities.dpiFromPx; import static com.android.launcher3.Utilities.pxFromSp; -import static com.android.launcher3.config.FeatureFlags.ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH; import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR; import static com.android.launcher3.icons.GraphicsUtils.getShapePath; import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR; @@ -503,7 +502,7 @@ public class DeviceProfile { bottomSheetCloseDuration = res.getInteger(R.integer.config_bottomSheetCloseDuration); if (isTablet) { bottomSheetWorkspaceScale = workspaceContentScale; - if (isMultiDisplay && !ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH.get()) { + if (isMultiDisplay) { // TODO(b/259893832): Revert to use maxWallpaperScale to calculate bottomSheetDepth // when screen recorder bug is fixed. if (enableScalingRevealHomeAnimation()) { diff --git a/src/com/android/launcher3/DropTargetHandler.kt b/src/com/android/launcher3/DropTargetHandler.kt index e022159d15..f1029b1f2b 100644 --- a/src/com/android/launcher3/DropTargetHandler.kt +++ b/src/com/android/launcher3/DropTargetHandler.kt @@ -35,8 +35,7 @@ class DropTargetHandler(launcher: Launcher) { target?.let { deferred.mPackageName = it.packageName mLauncher.addEventCallback(EVENT_RESUMED) { deferred.onLauncherResume() } - } - ?: deferred.sendFailure() + } ?: deferred.sendFailure() } } } @@ -47,19 +46,10 @@ class DropTargetHandler(launcher: Launcher) { mLauncher.appWidgetHolder.startConfigActivity( mLauncher, widgetId, - ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET + ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET, ) } - fun dismissPrediction( - announcement: CharSequence, - onActionClicked: Runnable, - onDismiss: Runnable? - ) { - mLauncher.dragLayer.announceForAccessibility(announcement) - Snackbar.show(mLauncher, R.string.item_removed, R.string.undo, onDismiss, onActionClicked) - } - fun getViewUnderDrag(info: ItemInfo): View? { return if ( info is LauncherAppWidgetInfo && @@ -95,7 +85,7 @@ class DropTargetHandler(launcher: Launcher) { R.string.item_removed, R.string.undo, mLauncher.modelWriter::commitDelete, - onUndoClicked + onUndoClicked, ) } diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java index 6622e1157f..17084bb531 100644 --- a/src/com/android/launcher3/FastScrollRecyclerView.java +++ b/src/com/android/launcher3/FastScrollRecyclerView.java @@ -60,6 +60,7 @@ public abstract class FastScrollRecyclerView extends RecyclerView { mScrollbar = scrollbar; mScrollbar.setRecyclerView(this); mScrollbar.setFastScrollerLocation(location); + scrollToTop(); onUpdateScrollbar(0); } diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 0d4ebe0a78..024dde477f 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -33,15 +33,34 @@ import android.view.ViewDebug; import android.view.ViewGroup; import android.widget.FrameLayout; +import androidx.annotation.IntDef; + import com.android.launcher3.util.HorizontalInsettableView; +import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.launcher3.util.MultiTranslateDelegate; +import com.android.launcher3.util.MultiValueAlpha; import com.android.launcher3.views.ActivityContext; +import java.io.PrintWriter; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + /** * View class that represents the bottom row of the home screen. */ public class Hotseat extends CellLayout implements Insettable { + public static final int ALPHA_CHANNEL_TASKBAR_ALIGNMENT = 0; + public static final int ALPHA_CHANNEL_PREVIEW_RENDERER = 1; + public static final int ALPHA_CHANNEL_TASKBAR_STASH = 2; + public static final int ALPHA_CHANNEL_CHANNELS_COUNT = 3; + + @Retention(RetentionPolicy.RUNTIME) + @IntDef({ALPHA_CHANNEL_TASKBAR_ALIGNMENT, ALPHA_CHANNEL_PREVIEW_RENDERER, + ALPHA_CHANNEL_TASKBAR_STASH}) + public @interface HotseatQsbAlphaId { + } + // Ratio of empty space, qsb should take up to appear visually centered. public static final float QSB_CENTER_FACTOR = .325f; private static final int BUBBLE_BAR_ADJUSTMENT_ANIMATION_DURATION_MS = 250; @@ -50,6 +69,8 @@ public class Hotseat extends CellLayout implements Insettable { private boolean mHasVerticalHotseat; private Workspace<?> mWorkspace; private boolean mSendTouchToWorkspace; + private final MultiValueAlpha mIconsAlphaChannels; + private final MultiValueAlpha mQsbAlphaChannels; private final View mQsb; @@ -63,9 +84,11 @@ public class Hotseat extends CellLayout implements Insettable { public Hotseat(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); - mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false); addView(mQsb); + mIconsAlphaChannels = new MultiValueAlpha(getShortcutsAndWidgets(), + ALPHA_CHANNEL_CHANNELS_COUNT); + mQsbAlphaChannels = new MultiValueAlpha(mQsb, ALPHA_CHANNEL_CHANNELS_COUNT); } /** @@ -270,21 +293,27 @@ public class Hotseat extends CellLayout implements Insettable { } /** - * Sets the alpha value of just our ShortcutAndWidgetContainer. + * Sets the alpha value of the specified alpha channel of just our ShortcutAndWidgetContainer. */ - public void setIconsAlpha(float alpha) { - getShortcutsAndWidgets().setAlpha(alpha); + public void setIconsAlpha(float alpha, @HotseatQsbAlphaId int channelId) { + getIconsAlpha(channelId).setValue(alpha); } /** * Sets the alpha value of just our QSB. */ - public void setQsbAlpha(float alpha) { - mQsb.setAlpha(alpha); + public void setQsbAlpha(float alpha, @HotseatQsbAlphaId int channelId) { + getQsbAlpha(channelId).setValue(alpha); + } + + /** Returns the alpha channel for ShortcutAndWidgetContainer */ + public MultiProperty getIconsAlpha(@HotseatQsbAlphaId int channelId) { + return mIconsAlphaChannels.get(channelId); } - public float getIconsAlpha() { - return getShortcutsAndWidgets().getAlpha(); + /** Returns the alpha channel for Qsb */ + public MultiProperty getQsbAlpha(@HotseatQsbAlphaId int channelId) { + return mQsbAlphaChannels.get(channelId); } /** @@ -294,4 +323,24 @@ public class Hotseat extends CellLayout implements Insettable { return mQsb; } + /** Dumps the Hotseat internal state */ + public void dump(String prefix, PrintWriter writer) { + writer.println(prefix + "Hotseat:"); + mIconsAlphaChannels.dump( + prefix + "\t", + writer, + "mIconsAlphaChannels", + "ALPHA_CHANNEL_TASKBAR_ALIGNMENT", + "ALPHA_CHANNEL_PREVIEW_RENDERER", + "ALPHA_CHANNEL_TASKBAR_STASH"); + mQsbAlphaChannels.dump( + prefix + "\t", + writer, + "mQsbAlphaChannels", + "ALPHA_CHANNEL_TASKBAR_ALIGNMENT", + "ALPHA_CHANNEL_PREVIEW_RENDERER", + "ALPHA_CHANNEL_TASKBAR_STASH" + ); + } + } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index bafb528dd1..b0ec9b0573 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -76,7 +76,6 @@ import static com.android.launcher3.logging.KeyboardStateManager.KeyboardState.S import static com.android.launcher3.logging.StatsLogManager.EventEnum; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_ENTRY; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_EXIT; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ONRESUME; @@ -241,6 +240,7 @@ import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.ScreenOnTracker; import com.android.launcher3.util.ScreenOnTracker.ScreenOnListener; import com.android.launcher3.util.SettingsCache; +import com.android.launcher3.util.StableViewInfo; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.Themes; import com.android.launcher3.util.Thunk; @@ -448,12 +448,10 @@ public class Launcher extends StatefulActivity<LauncherState> .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 class Launcher extends StatefulActivity<LauncherState> 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 @@ -1250,9 +1241,7 @@ public class Launcher extends StatefulActivity<LauncherState> * Returns {@link EventEnum} that should be logged when Launcher enters into AllApps state. */ protected Optional<EventEnum> getAllAppsEntryEvent() { - return Optional.of(FeatureFlags.ENABLE_DEVICE_SEARCH.get() - ? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH - : LAUNCHER_ALLAPPS_ENTRY); + return Optional.of(LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH); } @Override @@ -2424,17 +2413,16 @@ public class Launcher extends StatefulActivity<LauncherState> * Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close * animation. * - * @param preferredItemId The id of the preferred item to match to if it exists, - * or ItemInfo#NO_MATCHING_ID if you want to not match by item id + * @param svi The StableViewInfo of the preferred item to match to if it exists or null * @param packageName The package name of the app to match. * @param user The user of the app to match. * @param supportsAllAppsState If true and we are in All Apps state, looks for view in All Apps. * Else we only looks on the workspace. */ - public @Nullable View getFirstMatchForAppClose(int preferredItemId, String packageName, + public @Nullable View getFirstMatchForAppClose( + @Nullable StableViewInfo svi, String packageName, UserHandle user, boolean supportsAllAppsState) { - final Predicate<ItemInfo> preferredItem = info -> - info != null && info.id == preferredItemId; + final Predicate<ItemInfo> preferredItem = svi == null ? i -> false : svi::matches; final Predicate<ItemInfo> packageAndUserAndApp = info -> info != null && info.itemType == ITEM_TYPE_APPLICATION @@ -2525,6 +2513,9 @@ public class Launcher extends StatefulActivity<LauncherState> final int itemCount = container.getChildCount(); for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) { View item = container.getChildAt(itemIdx); + if (item.getVisibility() != View.VISIBLE) { + continue; + } if (item instanceof ViewGroup viewGroup) { View view = mapOverViewGroup(viewGroup, op); if (view != null) { @@ -2579,10 +2570,8 @@ public class Launcher extends StatefulActivity<LauncherState> 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); } /** @@ -2675,6 +2664,7 @@ public class Launcher extends StatefulActivity<LauncherState> } writer.println(prefix + " Hotseat"); + mHotseat.dump(prefix, writer); ViewGroup layout = mHotseat.getShortcutsAndWidgets(); for (int j = 0; j < layout.getChildCount(); j++) { Object tag = layout.getChildAt(j).getTag(); @@ -3036,6 +3026,7 @@ public class Launcher extends StatefulActivity<LauncherState> return mPopupDataProvider.getDotInfoForItem(info); } + @NonNull public LauncherOverlayManager getOverlayManager() { return mOverlayManager; } diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java index 8969b60534..4c82e5676f 100644 --- a/src/com/android/launcher3/LauncherApplication.java +++ b/src/com/android/launcher3/LauncherApplication.java @@ -18,6 +18,7 @@ package com.android.launcher3; 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 class LauncherApplication extends Application { public void onCreate() { super.onCreate(); MainProcessInitializer.initialize(this); - mAppComponent = DaggerLauncherAppComponent.builder().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/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt index d57f8a0dbe..496d517e9a 100644 --- a/src/com/android/launcher3/ModelCallbacks.kt +++ b/src/com/android/launcher3/ModelCallbacks.kt @@ -61,7 +61,7 @@ class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { 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 @@ class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { 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 @@ class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { 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 @@ class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { // 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 @@ class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { val snackbar = AbstractFloatingView.getOpenView<AbstractFloatingView>( launcher, - AbstractFloatingView.TYPE_SNACKBAR + AbstractFloatingView.TYPE_SNACKBAR, ) snackbar?.post { snackbar.close(true) } } @@ -191,7 +189,7 @@ class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { 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 @@ class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { val info = PendingAddWidgetInfo( widgetsListBaseEntry.mWidgets[0].widgetInfo, - LauncherSettings.Favorites.CONTAINER_DESKTOP + LauncherSettings.Favorites.CONTAINER_DESKTOP, ) launcher.addPendingItem( info, @@ -320,14 +318,14 @@ class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { 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 @@ class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks { 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/MotionEventsUtils.java b/src/com/android/launcher3/MotionEventsUtils.java index 3228ec6942..fb244b07f3 100644 --- a/src/com/android/launcher3/MotionEventsUtils.java +++ b/src/com/android/launcher3/MotionEventsUtils.java @@ -18,8 +18,6 @@ package com.android.launcher3; import static android.view.MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE; -import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE; - import android.annotation.TargetApi; import android.os.Build; import android.view.MotionEvent; @@ -35,14 +33,12 @@ public class MotionEventsUtils { @TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public static boolean isTrackpadScroll(MotionEvent event) { - return ENABLE_TRACKPAD_GESTURE.get() - && event.getClassification() == CLASSIFICATION_TWO_FINGER_SWIPE; + return event.getClassification() == CLASSIFICATION_TWO_FINGER_SWIPE; } @TargetApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) public static boolean isTrackpadMultiFingerSwipe(MotionEvent event) { - return ENABLE_TRACKPAD_GESTURE.get() - && event.getClassification() == CLASSIFICATION_MULTI_FINGER_SWIPE; + return event.getClassification() == CLASSIFICATION_MULTI_FINGER_SWIPE; } public static boolean isTrackpadThreeFingerSwipe(MotionEvent event) { diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 365fbd3919..0ec3b79071 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1463,6 +1463,15 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou mEdgeGlowLeft.onFlingVelocity(velocity); mEdgeGlowRight.onFlingVelocity(velocity); } + + // Detect if user tries to swipe to -1 page but gets disallowed by checking if there was + // left-over values in mEdgeGlowLeft (or mEdgeGlowRight in RLT). + final int layoutDir = getLayoutDirection(); + if ((mEdgeGlowLeft.getDistance() > 0 && layoutDir == LAYOUT_DIRECTION_LTR) + || (mEdgeGlowRight.getDistance() > 0 && layoutDir == LAYOUT_DIRECTION_RTL)) { + onDisallowSwipeToMinusOnePage(); + } + mEdgeGlowLeft.onRelease(ev); mEdgeGlowRight.onRelease(ev); // End any intermediate reordering states @@ -1487,6 +1496,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou return true; } + protected void onDisallowSwipeToMinusOnePage() {} + protected void onNotSnappingToPageInFreeScroll() { } /** diff --git a/src/com/android/launcher3/SecondaryDropTarget.java b/src/com/android/launcher3/SecondaryDropTarget.java index 0a4fb73a86..8d1e61f9ba 100644 --- a/src/com/android/launcher3/SecondaryDropTarget.java +++ b/src/com/android/launcher3/SecondaryDropTarget.java @@ -7,7 +7,6 @@ import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate. import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.INVALID; import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.RECONFIGURE; import static com.android.launcher3.accessibility.LauncherAccessibilityDelegate.UNINSTALL; -import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DISMISS_PREDICTION_UNDO; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_DONT_SUGGEST; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_DROPPED_ON_UNINSTALL; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ITEM_UNINSTALL_CANCELLED; @@ -36,7 +35,6 @@ import android.widget.Toast; import androidx.annotation.Nullable; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragOptions; import com.android.launcher3.logging.FileLog; import com.android.launcher3.logging.InstanceId; @@ -242,8 +240,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList @Override public void completeDrop(final DragObject d) { - ComponentName target = performDropAction(getViewUnderDrag(d.dragInfo), d.dragInfo, - d.logInstanceId); + ComponentName target = performDropAction(getViewUnderDrag(d.dragInfo), d.dragInfo); mDropTargetHandler.onSecondaryTargetCompleteDrop(target, d); } @@ -275,7 +272,7 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList * Performs the drop action and returns the target component for the dragObject or null if * the action was not performed. */ - protected ComponentName performDropAction(View view, ItemInfo info, InstanceId instanceId) { + protected ComponentName performDropAction(View view, ItemInfo info) { if (mCurrentAccessibilityAction == RECONFIGURE) { int widgetId = getReconfigurableWidgetId(view); if (widgetId != INVALID_APPWIDGET_ID) { @@ -283,21 +280,6 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList } return null; } - if (mCurrentAccessibilityAction == DISMISS_PREDICTION) { - if (FeatureFlags.ENABLE_DISMISS_PREDICTION_UNDO.get()) { - CharSequence announcement = getContext().getString(R.string.item_removed); - mDropTargetHandler - .dismissPrediction(announcement, () -> { - }, () -> { - mStatsLogManager.logger() - .withInstanceId(instanceId) - .withItemInfo(info) - .log(LAUNCHER_DISMISS_PREDICTION_UNDO); - }); - } - return null; - } - return performUninstall(getContext(), getUninstallTarget(getContext(), info), info); } @@ -332,9 +314,8 @@ public class SecondaryDropTarget extends ButtonDropTarget implements OnAlarmList @Override public void onAccessibilityDrop(View view, ItemInfo item) { - InstanceId instanceId = new InstanceIdSequence().newInstanceId(); - doLog(instanceId, item); - performDropAction(view, item, instanceId); + doLog(new InstanceIdSequence().newInstanceId(), item); + performDropAction(view, item); } /** diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index fde701424f..f8ac48a7df 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -122,9 +122,6 @@ public final class Utilities { 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/Workspace.java b/src/com/android/launcher3/Workspace.java index 255260e8af..0e9c8610e6 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1123,6 +1123,11 @@ public class Workspace<T extends View & PageIndicator> extends PagedView<T> return super.onTouchEvent(ev); } + @Override + protected void onDisallowSwipeToMinusOnePage() { + mLauncher.getOverlayManager().onDisallowSwipeToMinusOnePage(); + } + /** * Called directly from a CellLayout (not by the framework), after we've been added as a * listener via setOnInterceptTouchEventListener(). This allows us to tell the CellLayout diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java index cc4724c558..10947683bb 100644 --- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java @@ -22,8 +22,6 @@ import static com.android.launcher3.allapps.ActivityAllAppsContainerView.Adapter import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER; import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_DISABLED_CARD; import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_WORK_EDU_CARD; -import static com.android.launcher3.config.FeatureFlags.ALL_APPS_GONE_VISIBILITY; -import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_COUNT; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_PERSONAL_TAB; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_TAP_ON_WORK_TAB; @@ -679,18 +677,13 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> @NonNull AllAppsRecyclerView mainRecyclerView, @Nullable AllAppsRecyclerView workRecyclerView, @NonNull AllAppsRecyclerViewPool recycledViewPool) { - if (!ENABLE_ALL_APPS_RV_PREINFLATION.get()) { - return; - } final boolean hasWorkProfile = workRecyclerView != null; recycledViewPool.setHasWorkProfile(hasWorkProfile); mainRecyclerView.setRecycledViewPool(recycledViewPool); if (workRecyclerView != null) { workRecyclerView.setRecycledViewPool(recycledViewPool); } - if (ALL_APPS_GONE_VISIBILITY.get()) { - mainRecyclerView.updatePoolSize(hasWorkProfile); - } + mainRecyclerView.updatePoolSize(hasWorkProfile); } private void replaceAppsRVContainer(boolean showTabs) { @@ -735,9 +728,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> removeCustomRules(rvContainer); removeCustomRules(getSearchRecyclerView()); - if (!isSearchSupported()) { - layoutWithoutSearchContainer(rvContainer, showTabs); - } else if (isSearchBarFloating()) { + if (isSearchBarFloating()) { alignParentTop(rvContainer, showTabs); alignParentTop(getSearchRecyclerView(), /* tabs= */ false); } else { @@ -768,9 +759,7 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> }); removeCustomRules(mHeader); - if (!isSearchSupported()) { - layoutWithoutSearchContainer(mHeader, false /* includeTabsMargin */); - } else if (isSearchBarFloating()) { + if (isSearchBarFloating()) { alignParentTop(mHeader, false /* includeTabsMargin */); } else { layoutBelowSearchContainer(mHeader, false /* includeTabsMargin */); @@ -925,23 +914,6 @@ public class ActivityAllAppsContainerView<T extends Context & ActivityContext> mMainAdapterProvider); } - // TODO(b/216683257): Remove when Taskbar All Apps supports search. - protected boolean isSearchSupported() { - return true; - } - - private void layoutWithoutSearchContainer(View v, boolean includeTabsMargin) { - if (!(v.getLayoutParams() instanceof RelativeLayout.LayoutParams)) { - return; - } - - RelativeLayout.LayoutParams layoutParams = (LayoutParams) v.getLayoutParams(); - layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP); - layoutParams.topMargin = getContext().getResources().getDimensionPixelSize(includeTabsMargin - ? R.dimen.all_apps_header_pill_height - : R.dimen.all_apps_header_top_margin); - } - public boolean isInAllApps() { // TODO: Make this abstract return true; diff --git a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java index 911612ff19..77a0fe331d 100644 --- a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java +++ b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java @@ -15,6 +15,8 @@ */ package com.android.launcher3.allapps; +import static android.view.HapticFeedbackConstants.CLOCK_TICK; + import androidx.recyclerview.widget.LinearSmoothScroller; import androidx.recyclerview.widget.RecyclerView.ViewHolder; @@ -71,6 +73,7 @@ public class AllAppsFastScrollHelper { @Override protected int getVerticalSnapPreference() { + mRv.performHapticFeedback(CLOCK_TICK); return SNAP_TO_ANY; } diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java index ae45a35328..4e1e95011b 100644 --- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java +++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java @@ -18,8 +18,6 @@ package com.android.launcher3.allapps; import static androidx.constraintlayout.widget.ConstraintSet.MATCH_CONSTRAINT; import static androidx.constraintlayout.widget.ConstraintSet.WRAP_CONTENT; -import static com.android.launcher3.config.FeatureFlags.ALL_APPS_GONE_VISIBILITY; -import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION; import static com.android.launcher3.logger.LauncherAtom.ContainerInfo; import static com.android.launcher3.logger.LauncherAtom.SearchResultContainer; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_PERSONAL_SCROLLED_DOWN; @@ -124,13 +122,11 @@ public class AllAppsRecyclerView extends FastScrollRecyclerView { // all apps. int maxPoolSizeForAppIcons = grid.getMaxAllAppsRowCount() * grid.numShownAllAppsColumns; - if (ALL_APPS_GONE_VISIBILITY.get() && ENABLE_ALL_APPS_RV_PREINFLATION.get()) { - // If we set all apps' hidden visibility to GONE and enable pre-inflation, we want to - // preinflate one page of all apps icons plus [PREINFLATE_ICONS_ROW_COUNT] rows + - // [EXTRA_ICONS_COUNT]. Thus we need to bump the max pool size of app icons accordingly. - maxPoolSizeForAppIcons += - PREINFLATE_ICONS_ROW_COUNT * grid.numShownAllAppsColumns + EXTRA_ICONS_COUNT; - } + // If we set all apps' hidden visibility to GONE and enable pre-inflation, we want to + // preinflate one page of all apps icons plus [PREINFLATE_ICONS_ROW_COUNT] rows + + // [EXTRA_ICONS_COUNT]. Thus we need to bump the max pool size of app icons accordingly. + maxPoolSizeForAppIcons += + PREINFLATE_ICONS_ROW_COUNT * grid.numShownAllAppsColumns + EXTRA_ICONS_COUNT; if (hasWorkProfile) { maxPoolSizeForAppIcons *= 2; } diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java index a4f130a63d..29b9e7761d 100644 --- a/src/com/android/launcher3/allapps/AllAppsStore.java +++ b/src/com/android/launcher3/allapps/AllAppsStore.java @@ -15,7 +15,6 @@ */ package com.android.launcher3.allapps; -import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_RV_PREINFLATION; import static com.android.launcher3.model.data.AppInfo.COMPONENT_KEY_COMPARATOR; import static com.android.launcher3.model.data.AppInfo.EMPTY_ARRAY; import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SHOW_DOWNLOAD_PROGRESS_MASK; @@ -109,7 +108,7 @@ public class AllAppsStore<T extends Context & ActivityContext> { mPackageUserKeytoUidMap = map; // Preinflate all apps RV when apps has changed, which can happen after unlocking screen, // rotating screen, or downloading/upgrading apps. - if (shouldPreinflate && ENABLE_ALL_APPS_RV_PREINFLATION.get()) { + if (shouldPreinflate) { mAllAppsRecyclerViewPool.preInflateAllAppsViewHolders(mContext); } } diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java index 1b0ad04e89..c6852e015c 100644 --- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java +++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java @@ -37,7 +37,6 @@ import static com.android.launcher3.util.SystemUiController.UI_STATE_ALL_APPS; import android.animation.Animator; import android.animation.ObjectAnimator; -import android.animation.ValueAnimator; import android.util.FloatProperty; import android.view.HapticFeedbackConstants; import android.view.View; @@ -52,11 +51,9 @@ import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.R; -import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatedFloat; import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.PropertySetter; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.statemanager.StateManager.StateHandler; import com.android.launcher3.states.StateAnimationConfig; import com.android.launcher3.touch.AllAppsSwipeController; @@ -359,22 +356,6 @@ public class AllAppsTransitionController }); } - if (FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get() && config.isUserControlled() - && Utilities.ATLEAST_S) { - if (toState == ALL_APPS) { - builder.addOnFrameListener( - new VibrationAnimatorUpdateListener(this, mVibratorWrapper, - SWIPE_DRAG_COMMIT_THRESHOLD, 1)); - } else { - builder.addOnFrameListener( - new VibrationAnimatorUpdateListener(this, mVibratorWrapper, - 0, SWIPE_DRAG_COMMIT_THRESHOLD)); - } - builder.addEndListener((unused) -> { - mVibratorWrapper.cancelVibrate(); - }); - } - float targetProgress = toState.getVerticalProgress(mLauncher); if (Float.compare(mProgress, targetProgress) == 0) { setAlphas(toState, config, builder); @@ -391,8 +372,7 @@ public class AllAppsTransitionController setAlphas(toState, config, builder); // This controls both haptics for tapping on QSB and going to all apps. - if (ALL_APPS.equals(toState) && mLauncher.isInState(NORMAL) && - !FeatureFlags.ENABLE_PREMIUM_HAPTICS_ALL_APPS.get()) { + if (ALL_APPS.equals(toState) && mLauncher.isInState(NORMAL)) { mLauncher.getAppsView().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); } @@ -432,8 +412,7 @@ public class AllAppsTransitionController mAppsView = appsView; mAppsView.setScrimView(scrimView); - mAppsViewAlpha = new MultiValueAlpha(mAppsView, APPS_VIEW_INDEX_COUNT, - FeatureFlags.ALL_APPS_GONE_VISIBILITY.get() ? View.GONE : View.INVISIBLE); + mAppsViewAlpha = new MultiValueAlpha(mAppsView, APPS_VIEW_INDEX_COUNT, View.GONE); mAppsViewAlpha.setUpdateVisibility(true); mAppsViewTranslationY = new MultiPropertyFactory<>( mAppsView, VIEW_TRANSLATE_Y, APPS_VIEW_INDEX_COUNT, Float::sum); @@ -445,45 +424,4 @@ public class AllAppsTransitionController public void setShiftRange(float shiftRange) { mShiftRange = shiftRange; } - - /** - * This VibrationAnimatorUpdateListener class takes in four parameters, a controller, start - * threshold, end threshold, and a Vibrator wrapper. We use the progress given by the controller - * as it gives an accurate progress that dictates where the vibrator should vibrate. - * Note: once the user begins a gesture and does the commit haptic, there should not be anymore - * haptics played for that gesture. - */ - private static class VibrationAnimatorUpdateListener implements - ValueAnimator.AnimatorUpdateListener { - private final VibratorWrapper mVibratorWrapper; - private final AllAppsTransitionController mController; - private final float mStartThreshold; - private final float mEndThreshold; - private boolean mHasCommitted; - - VibrationAnimatorUpdateListener(AllAppsTransitionController controller, - VibratorWrapper vibratorWrapper, float startThreshold, - float endThreshold) { - mController = controller; - mVibratorWrapper = vibratorWrapper; - mStartThreshold = startThreshold; - mEndThreshold = endThreshold; - } - - @Override - public void onAnimationUpdate(ValueAnimator animation) { - if (mHasCommitted) { - return; - } - float currentProgress = - AllAppsTransitionController.ALL_APPS_PROGRESS.get(mController); - if (currentProgress > mStartThreshold && currentProgress < mEndThreshold) { - mVibratorWrapper.vibrateForDragTexture(); - } else if (!(currentProgress == 0 || currentProgress == 1)) { - // This check guards against committing at the location of the start of the gesture - mVibratorWrapper.vibrateForDragCommit(); - mHasCommitted = true; - } - } - } } diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java index a2bd5dda12..ac06ab40e0 100644 --- a/src/com/android/launcher3/allapps/FloatingHeaderView.java +++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java @@ -34,7 +34,6 @@ import com.android.launcher3.Flags; import com.android.launcher3.Insettable; import com.android.launcher3.R; import com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.PluginManagerWrapper; import com.android.launcher3.views.ActivityContext; import com.android.systemui.plugins.AllAppsRow; @@ -220,15 +219,12 @@ public class FloatingHeaderView extends LinearLayout implements @Override public View getFocusedChild() { - if (FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { - for (FloatingHeaderRow row : mAllRows) { - if (row.hasVisibleContent() && row.isVisible()) { - return row.getFocusedChild(); - } + for (FloatingHeaderRow row : mAllRows) { + if (row.hasVisibleContent() && row.isVisible()) { + return row.getFocusedChild(); } - return null; } - return super.getFocusedChild(); + return null; } void setup(AllAppsRecyclerView mainRV, AllAppsRecyclerView workRV, SearchRecyclerView searchRV, diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java index ec45415afa..de3bb9efe1 100644 --- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java +++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java @@ -22,8 +22,6 @@ import android.text.TextWatcher; import android.text.style.SuggestionSpan; import android.util.Log; import android.view.KeyEvent; -import android.view.View; -import android.view.View.OnFocusChangeListener; import android.view.inputmethod.EditorInfo; import android.widget.TextView; import android.widget.TextView.OnEditorActionListener; @@ -31,7 +29,6 @@ import android.widget.TextView.OnEditorActionListener; import com.android.launcher3.ExtendedEditText; import com.android.launcher3.Utilities; import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem; -import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.search.SearchAlgorithm; import com.android.launcher3.search.SearchCallback; import com.android.launcher3.views.ActivityContext; @@ -40,8 +37,7 @@ import com.android.launcher3.views.ActivityContext; * An interface to a search box that AllApps can command. */ public class AllAppsSearchBarController - implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener, - OnFocusChangeListener { + implements TextWatcher, OnEditorActionListener, ExtendedEditText.OnBackKeyListener { private static final String TAG = "AllAppsSearchBarController"; protected ActivityContext mLauncher; @@ -69,7 +65,6 @@ public class AllAppsSearchBarController mInput.addTextChangedListener(this); mInput.setOnEditorActionListener(this); mInput.setOnBackKeyListener(this); - mInput.addOnFocusChangeListener(this); mSearchAlgorithm = searchAlgorithm; } @@ -142,13 +137,6 @@ public class AllAppsSearchBarController return false; } - @Override - public void onFocusChange(View view, boolean hasFocus) { - if (!hasFocus && !FeatureFlags.ENABLE_DEVICE_SEARCH.get()) { - mInput.hideKeyboard(); - } - } - /** * Resets the search bar state. */ @@ -157,7 +145,6 @@ public class AllAppsSearchBarController mInput.reset(); mInput.clearFocus(); mQuery = null; - mInput.removeOnFocusChangeListener(this); } /** diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java index d0596fac9e..8fe1b34077 100644 --- a/src/com/android/launcher3/config/FeatureFlags.java +++ b/src/com/android/launcher3/config/FeatureFlags.java @@ -62,18 +62,7 @@ public final class FeatureFlags { * and set a default value for the flag. This will be the default value on Debug builds. * <p> */ - // TODO(Block 2): Clean up flags - public static final BooleanFlag ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH = getDebugFlag(270395073, - "ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH", DISABLED, - "Allow bottom sheet depth to be smaller than 1 for multi-display devices."); - // TODO(Block 3): Clean up flags - public static final BooleanFlag ENABLE_DISMISS_PREDICTION_UNDO = getDebugFlag(270394476, - "ENABLE_DISMISS_PREDICTION_UNDO", DISABLED, - "Show an 'Undo' snackbar when users dismiss a predicted hotseat item"); - public static final BooleanFlag CONTINUOUS_VIEW_TREE_CAPTURE = getDebugFlag(270395171, - "CONTINUOUS_VIEW_TREE_CAPTURE", ENABLED, "Capture View tree every frame"); - public static final BooleanFlag ENABLE_WORKSPACE_LOADING_OPTIMIZATION = getDebugFlag(251502424, "ENABLE_WORKSPACE_LOADING_OPTIMIZATION", DISABLED, "load the current workspace screen visible to the user before the rest rather than " @@ -84,32 +73,7 @@ public final class FeatureFlags { "changes the timing of the loading and binding of delegate items during " + "data preparation for loading the home screen"); - // TODO(Block 4): Cleanup flags - public static final BooleanFlag ENABLE_ALL_APPS_FROM_OVERVIEW = - getDebugFlag(275132633, "ENABLE_ALL_APPS_FROM_OVERVIEW", DISABLED, - "Allow entering All Apps from Overview (e.g. long swipe up from app)"); - - public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag( - 270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED, - "Enable option to show keyboard when going to all-apps"); - - // TODO(Block 5): Clean up flags - public static final BooleanFlag ENABLE_TWOLINE_DEVICESEARCH = getDebugFlag(201388851, - "ENABLE_TWOLINE_DEVICESEARCH", DISABLED, - "Enable two line label for icons with labels on device search."); - - public static final BooleanFlag ENABLE_ICON_IN_TEXT_HEADER = getDebugFlag(270395143, - "ENABLE_ICON_IN_TEXT_HEADER", DISABLED, "Show icon in textheader"); - - public static final BooleanFlag ENABLE_PREMIUM_HAPTICS_ALL_APPS = getDebugFlag(270396358, - "ENABLE_PREMIUM_HAPTICS_ALL_APPS", DISABLED, - "Enables haptics opening/closing All apps"); - // TODO(Block 6): Clean up flags - public static final BooleanFlag ENABLE_ALL_APPS_SEARCH_IN_TASKBAR = getDebugFlag(270393900, - "ENABLE_ALL_APPS_SEARCH_IN_TASKBAR", ENABLED, - "Enables Search box in Taskbar All Apps."); - public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag(270395140, "SECONDARY_DRAG_N_DROP_TO_PIN", DISABLED, "Enable dragging and dropping to pin apps within secondary display"); @@ -125,10 +89,6 @@ public final class FeatureFlags { public static final BooleanFlag FOLDABLE_SINGLE_PAGE = getDebugFlag(270395274, "FOLDABLE_SINGLE_PAGE", DISABLED, "Use a single page for the workspace"); - public static final BooleanFlag ENABLE_PARAMETRIZE_REORDER = getDebugFlag(289420844, - "ENABLE_PARAMETRIZE_REORDER", DISABLED, - "Enables generating the reorder using a set of parameters"); - // TODO(Block 12): Clean up flags public static final BooleanFlag ENABLE_MULTI_INSTANCE = getDebugFlag(270396680, "ENABLE_MULTI_INSTANCE", DISABLED, @@ -175,32 +135,11 @@ public final class FeatureFlags { public static final BooleanFlag PROMISE_APPS_IN_ALL_APPS = getDebugFlag(270390012, "PROMISE_APPS_IN_ALL_APPS", DISABLED, "Add promise icon in all-apps"); - public static final BooleanFlag KEYGUARD_ANIMATION = getDebugFlag(270390904, - "KEYGUARD_ANIMATION", DISABLED, - "Enable animation for keyguard going away on wallpaper"); - - public static final BooleanFlag ENABLE_DEVICE_SEARCH = getReleaseFlag(270390907, - "ENABLE_DEVICE_SEARCH", ENABLED, "Allows on device search in all apps"); - - public static final BooleanFlag ENABLE_HIDE_HEADER = getReleaseFlag(270390930, - "ENABLE_HIDE_HEADER", ENABLED, "Hide header on keyboard before typing in all apps"); - // Aconfig migration complete for ENABLE_EXPANDING_PAUSE_WORK_BUTTON. public static final BooleanFlag ENABLE_EXPANDING_PAUSE_WORK_BUTTON = getDebugFlag(270390779, "ENABLE_EXPANDING_PAUSE_WORK_BUTTON", DISABLED, "Expand and collapse pause work button while scrolling"); - // Aconfig migration complete for ENABLE_TWOLINE_ALLAPPS. - public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937, - "ENABLE_TWOLINE_ALLAPPS", DISABLED, "Enables two line label inside all apps."); - - public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693, - "IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps"); - - public static final BooleanFlag FOLDER_NAME_MAJORITY_RANKING = getDebugFlag(270391638, - "FOLDER_NAME_MAJORITY_RANKING", ENABLED, - "Suggests folder names based on majority based ranking."); - public static final BooleanFlag INJECT_FALLBACK_APP_CORPUS_RESULTS = getReleaseFlag(270391706, "INJECT_FALLBACK_APP_CORPUS_RESULTS", DISABLED, "Inject fallback app corpus result when AiAi fails to return it."); @@ -225,27 +164,7 @@ public final class FeatureFlags { return ENABLE_APP_PAIRS.get() || com.android.wm.shell.Flags.enableAppPairs(); } - // TODO(Block 19): Clean up flags - public static final BooleanFlag SCROLL_TOP_TO_RESET = getReleaseFlag(270395177, - "SCROLL_TOP_TO_RESET", ENABLED, - "Bring up IME and focus on input when scroll to top if 'Always show keyboard'" - + " is enabled or in prefix state"); - - public static final BooleanFlag ENABLE_SEARCH_UNINSTALLED_APPS = getReleaseFlag(270395269, - "ENABLE_SEARCH_UNINSTALLED_APPS", ENABLED, "Search uninstalled app results."); - // TODO(Block 20): Clean up flags - public static final BooleanFlag ENABLE_SCRIM_FOR_APP_LAUNCH = getDebugFlag(270393276, - "ENABLE_SCRIM_FOR_APP_LAUNCH", DISABLED, "Enables scrim during app launch animation."); - - public static final BooleanFlag ENABLE_BACK_SWIPE_HOME_ANIMATION = getDebugFlag(270393426, - "ENABLE_BACK_SWIPE_HOME_ANIMATION", ENABLED, - "Enables home animation to icon when user swipes back."); - - public static final BooleanFlag ENABLE_DYNAMIC_TASKBAR_THRESHOLDS = getDebugFlag(294252473, - "ENABLE_DYNAMIC_TASKBAR_THRESHOLDS", ENABLED, - "Enables taskbar thresholds that scale based on screen size."); - // Aconfig migration complete for ENABLE_HOME_TRANSITION_LISTENER. public static final BooleanFlag ENABLE_HOME_TRANSITION_LISTENER = getDebugFlag(306053414, "ENABLE_HOME_TRANSITION_LISTENER", DISABLED, @@ -264,18 +183,7 @@ public final class FeatureFlags { "ENABLE_WIDGET_TRANSITION_FOR_RESIZING", DISABLED, "Enable widget transition animation when resizing the widgets"); - public static final BooleanFlag PREEMPTIVE_UNFOLD_ANIMATION_START = getDebugFlag(270397209, - "PREEMPTIVE_UNFOLD_ANIMATION_START", ENABLED, - "Enables starting the unfold animation preemptively when unfolding, without" - + "waiting for SystemUI and then merging the SystemUI progress whenever we " - + "start receiving the events"); - // TODO(Block 25): Clean up flags - public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257, - "ENABLE_NEW_GESTURE_NAV_TUTORIAL", ENABLED, - "Enable the redesigned gesture navigation tutorial"); - - // TODO(Block 26): Clean up flags public static final BooleanFlag ENABLE_WIDGET_HOST_IN_BACKGROUND = getDebugFlag(270394384, "ENABLE_WIDGET_HOST_IN_BACKGROUND", ENABLED, "Enable background widget updates listening for widget holder"); @@ -300,10 +208,6 @@ public final class FeatureFlags { "SEPARATE_RECENTS_ACTIVITY", DISABLED, "Uses a separate recents activity instead of using the integrated recents+Launcher UI"); - public static final BooleanFlag ENABLE_ENFORCED_ROUNDED_CORNERS = getReleaseFlag(270393258, - "ENABLE_ENFORCED_ROUNDED_CORNERS", ENABLED, - "Enforce rounded corners on all App Widgets"); - public static final BooleanFlag USE_LOCAL_ICON_OVERRIDES = getDebugFlag(270394973, "USE_LOCAL_ICON_OVERRIDES", ENABLED, "Use inbuilt monochrome icons if app doesn't provide one"); @@ -317,20 +221,15 @@ public final class FeatureFlags { com.android.wm.shell.Flags.enableSplitContextual(); } - public static final BooleanFlag ENABLE_TRACKPAD_GESTURE = getDebugFlag(271010401, - "ENABLE_TRACKPAD_GESTURE", ENABLED, "Enables trackpad gesture."); - // TODO(Block 29): Clean up flags + // Aconfig migration complete for ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT. public static final BooleanFlag ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT = getDebugFlag(270393897, "ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT", DISABLED, "Enables displaying the all apps button in the hotseat."); - public static final BooleanFlag ENABLE_KEYBOARD_QUICK_SWITCH = getDebugFlag(270396844, - "ENABLE_KEYBOARD_QUICK_SWITCH", ENABLED, "Enables keyboard quick switching"); - - public static final BooleanFlag ENABLE_KEYBOARD_TASKBAR_TOGGLE = getDebugFlag(281726846, - "ENABLE_KEYBOARD_TASKBAR_TOGGLE", ENABLED, - "Enables keyboard taskbar stash toggling"); + public static boolean enableAllAppsButtonInHotseat() { + return ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get() || Flags.enableAllAppsButtonInHotseat(); + } // TODO(Block 30): Clean up flags public static final BooleanFlag USE_SEARCH_REQUEST_TIMEOUT_OVERRIDES = getDebugFlag(270395010, @@ -349,14 +248,6 @@ public final class FeatureFlags { return ENABLE_RESPONSIVE_WORKSPACE.get() || Flags.enableResponsiveWorkspace(); } - // TODO(Block 33): Clean up flags - public static final BooleanFlag ENABLE_ALL_APPS_RV_PREINFLATION = getDebugFlag(288161355, - "ENABLE_ALL_APPS_RV_PREINFLATION", ENABLED, - "Enables preinflating all apps icons to avoid scrolling jank."); - public static final BooleanFlag ALL_APPS_GONE_VISIBILITY = getDebugFlag(291651514, - "ALL_APPS_GONE_VISIBILITY", ENABLED, - "Set all apps container view's hidden visibility to GONE instead of INVISIBLE."); - public static BooleanFlag getDebugFlag( int bugId, String key, BooleanFlag flagState, String description) { return flagState; diff --git a/src/com/android/launcher3/dagger/ActivityContextScope.java b/src/com/android/launcher3/dagger/ActivityContextScope.java new file mode 100644 index 0000000000..887f15cacf --- /dev/null +++ b/src/com/android/launcher3/dagger/ActivityContextScope.java @@ -0,0 +1,32 @@ +/* + * 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.dagger; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Scope; + +/** + * Scope annotation for singletons associated with Launcher activity context. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Scope +public @interface ActivityContextScope { +} diff --git a/src/com/android/launcher3/dagger/ApplicationContext.java b/src/com/android/launcher3/dagger/ApplicationContext.java new file mode 100644 index 0000000000..9a5b08b51b --- /dev/null +++ b/src/com/android/launcher3/dagger/ApplicationContext.java @@ -0,0 +1,32 @@ +/* + * 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.dagger; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Qualifier; + +/** + * Qualifier for Launcher application context. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Qualifier +public @interface ApplicationContext { +} diff --git a/src/com/android/launcher3/dagger/LauncherAppSingleton.java b/src/com/android/launcher3/dagger/LauncherAppSingleton.java new file mode 100644 index 0000000000..92c00b6d85 --- /dev/null +++ b/src/com/android/launcher3/dagger/LauncherAppSingleton.java @@ -0,0 +1,32 @@ +/* + * 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.dagger; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +import javax.inject.Scope; + +/** + * Scope annotation for singleton items within the LauncherAppComponent. + */ +@Documented +@Retention(RetentionPolicy.RUNTIME) +@Scope +public @interface LauncherAppSingleton { +} diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java index 3488c95333..0a50e8bc9e 100644 --- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java +++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java @@ -16,6 +16,12 @@ package com.android.launcher3.dagger; +import android.content.Context; + +import com.android.launcher3.util.DaggerSingletonTracker; + +import dagger.BindsInstance; + /** * Launcher base component for Dagger injection. * @@ -25,8 +31,10 @@ package com.android.launcher3.dagger; * 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); LauncherBaseAppComponent build(); } } diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java index dc8694d2f6..531cdfd38e 100644 --- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java +++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java @@ -16,11 +16,13 @@ package com.android.launcher3.graphics; import static com.android.launcher3.LauncherPrefs.THEMED_ICONS; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR; import static com.android.launcher3.util.Themes.isThemedIconEnabled; import android.content.ContentProvider; import android.content.ContentValues; +import android.content.Context; import android.content.pm.PackageManager; import android.database.Cursor; import android.database.MatrixCursor; @@ -32,14 +34,22 @@ import android.os.IBinder; import android.os.IBinder.DeathRecipient; import android.os.Message; import android.os.Messenger; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.InvariantDeviceProfile.GridOption; +import com.android.launcher3.LauncherAppState; +import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherPrefs; +import com.android.launcher3.model.BgDataModel; import com.android.launcher3.util.Executors; +import com.android.launcher3.util.Preconditions; +import com.android.systemui.shared.Flags; + +import java.util.concurrent.ExecutionException; /** * Exposes various launcher grid options and allows the caller to change them. @@ -80,8 +90,10 @@ public class GridCustomizationsProvider extends ContentProvider { private static final String KEY_SURFACE_PACKAGE = "surface_package"; private static final String KEY_CALLBACK = "callback"; public static final String KEY_HIDE_BOTTOM_ROW = "hide_bottom_row"; + public static final String KEY_GRID_NAME = "grid_name"; private static final int MESSAGE_ID_UPDATE_PREVIEW = 1337; + private static final int MESSAGE_ID_UPDATE_GRID = 7414; /** * Here we use the IBinder and the screen ID as the key of the active previews. @@ -141,14 +153,20 @@ public class GridCustomizationsProvider extends ContentProvider { @Override public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { - switch (uri.getPath()) { + String path = uri.getPath(); + Context context = getContext(); + if (path == null || context == null) { + return 0; + } + switch (path) { case KEY_DEFAULT_GRID: { String gridName = values.getAsString(KEY_NAME); - InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(getContext()); + InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context); // Verify that this is a valid grid option GridOption match = null; - for (GridOption option : idp.parseAllGridOptions(getContext())) { - if (option.name.equals(gridName)) { + for (GridOption option : idp.parseAllGridOptions(context)) { + String name = option.name; + if (name != null && name.equals(gridName)) { match = option; break; } @@ -157,15 +175,23 @@ public class GridCustomizationsProvider extends ContentProvider { return 0; } - idp.setCurrentGrid(getContext(), gridName); - getContext().getContentResolver().notifyChange(uri, null); + idp.setCurrentGrid(context, gridName); + if (Flags.newCustomizationPickerUi()) { + try { + // Wait for device profile to be fully reloaded and applied to the launcher + loadModelSync(context); + } catch (ExecutionException | InterruptedException e) { + Log.e(TAG, "Fail to load model", e); + } + } + context.getContentResolver().notifyChange(uri, null); return 1; } case ICON_THEMED: case SET_ICON_THEMED: { - LauncherPrefs.get(getContext()) + LauncherPrefs.get(context) .put(THEMED_ICONS, values.getAsBoolean(BOOLEAN_VALUE)); - getContext().getContentResolver().notifyChange(uri, null); + context.getContentResolver().notifyChange(uri, null); return 1; } default: @@ -173,6 +199,23 @@ public class GridCustomizationsProvider extends ContentProvider { } } + /** + * Loads the model in memory synchronously + */ + private void loadModelSync(Context context) throws ExecutionException, InterruptedException { + Preconditions.assertNonUiThread(); + BgDataModel.Callbacks emptyCallbacks = new BgDataModel.Callbacks() { }; + LauncherModel launcherModel = LauncherAppState.getInstance(context).getModel(); + MAIN_EXECUTOR.submit( + () -> launcherModel.addCallbacksAndLoad(emptyCallbacks) + ).get(); + + Executors.MODEL_EXECUTOR.submit(() -> { }).get(); + MAIN_EXECUTOR.submit( + () -> launcherModel.removeCallbacks(emptyCallbacks) + ).get(); + } + @Override public Bundle call(String method, String arg, Bundle extras) { if (getContext().checkPermission("android.permission.BIND_WALLPAPER", @@ -224,7 +267,7 @@ public class GridCustomizationsProvider extends ContentProvider { } observer.destroyed = true; observer.renderer.getHostToken().unlinkToDeath(observer, 0); - Executors.MAIN_EXECUTOR.execute(observer.renderer::destroy); + MAIN_EXECUTOR.execute(observer.renderer::destroy); PreviewLifecycleObserver cached = mActivePreviews.get(observer.getIdentifier()); if (cached == observer) { mActivePreviews.remove(observer.getIdentifier()); @@ -245,11 +288,22 @@ public class GridCustomizationsProvider extends ContentProvider { if (destroyed) { return true; } - if (message.what == MESSAGE_ID_UPDATE_PREVIEW) { - renderer.hideBottomRow(message.getData().getBoolean(KEY_HIDE_BOTTOM_ROW)); - } else { - destroyObserver(this); + + switch (message.what) { + case MESSAGE_ID_UPDATE_PREVIEW: + renderer.hideBottomRow(message.getData().getBoolean(KEY_HIDE_BOTTOM_ROW)); + break; + case MESSAGE_ID_UPDATE_GRID: + String gridName = message.getData().getString(KEY_GRID_NAME); + if (!TextUtils.isEmpty(gridName)) { + renderer.updateGrid(gridName); + } + break; + default: + destroyObserver(this); + break; } + return true; } diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java index 24089557aa..40c0cc65c9 100644 --- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java +++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java @@ -23,6 +23,7 @@ import static android.view.View.VISIBLE; import static com.android.launcher3.BubbleTextView.DISPLAY_TASKBAR; import static com.android.launcher3.BubbleTextView.DISPLAY_WORKSPACE; import static com.android.launcher3.DeviceProfile.DEFAULT_SCALE; +import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_PREVIEW_RENDERER; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET; import static com.android.launcher3.model.ModelUtils.filterCurrentWorkspaceItems; @@ -68,7 +69,6 @@ import com.android.launcher3.InvariantDeviceProfile; 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; @@ -206,15 +206,12 @@ public class LauncherPreviewRenderer extends ContextWrapper 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); } @@ -320,12 +317,12 @@ public class LauncherPreviewRenderer extends ContextWrapper mUiHandler.post(() -> { if (mDp.isTaskbarPresent) { // hotseat icons on bottom - mHotseat.setIconsAlpha(hide ? 0 : 1); + mHotseat.setIconsAlpha(hide ? 0 : 1, ALPHA_CHANNEL_PREVIEW_RENDERER); if (mDp.isQsbInline) { - mHotseat.setQsbAlpha(hide ? 0 : 1); + mHotseat.setQsbAlpha(hide ? 0 : 1, ALPHA_CHANNEL_PREVIEW_RENDERER); } } else { - mHotseat.setQsbAlpha(hide ? 0 : 1); + mHotseat.setQsbAlpha(hide ? 0 : 1, ALPHA_CHANNEL_PREVIEW_RENDERER); } }); } diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java index addd0727e8..56c4ca4b37 100644 --- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java +++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java @@ -38,6 +38,7 @@ import android.view.SurfaceControlViewHost; import android.view.SurfaceControlViewHost.SurfacePackage; import android.view.View; import android.view.animation.AccelerateDecelerateInterpolator; +import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -61,6 +62,7 @@ import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.Themes; import com.android.launcher3.widget.LocalColorExtractor; +import com.android.systemui.shared.Flags; import java.util.ArrayList; import java.util.Map; @@ -96,6 +98,7 @@ public class PreviewSurfaceRenderer { private boolean mDestroyed = false; private LauncherPreviewRenderer mRenderer; private boolean mHideQsb; + @Nullable private FrameLayout mViewRoot = null; public PreviewSurfaceRenderer(Context context, Bundle bundle) throws Exception { mContext = context; @@ -194,6 +197,19 @@ public class PreviewSurfaceRenderer { } /** + * Update the grid of the launcher preview + * + * @param gridName Name of the grid, e.g. normal, practical + */ + public void updateGrid(@NonNull String gridName) { + if (gridName.equals(mGridName)) { + return; + } + mGridName = gridName; + loadAsync(); + } + + /** * Hides the components in the bottom row. * * @param hide True to hide and false to show. @@ -302,11 +318,41 @@ public class PreviewSurfaceRenderer { view.setPivotY(0); view.setTranslationX((mWidth - scale * view.getWidth()) / 2); view.setTranslationY((mHeight - scale * view.getHeight()) / 2); - view.setAlpha(0); - view.animate().alpha(1) - .setInterpolator(new AccelerateDecelerateInterpolator()) - .setDuration(FADE_IN_ANIMATION_DURATION) - .start(); - mSurfaceControlViewHost.setView(view, view.getMeasuredWidth(), view.getMeasuredHeight()); + if (!Flags.newCustomizationPickerUi()) { + view.setAlpha(0); + view.animate().alpha(1) + .setInterpolator(new AccelerateDecelerateInterpolator()) + .setDuration(FADE_IN_ANIMATION_DURATION) + .start(); + mSurfaceControlViewHost.setView( + view, + view.getMeasuredWidth(), + view.getMeasuredHeight() + ); + return; + } + + if (mViewRoot == null) { + mViewRoot = new FrameLayout(inflationContext); + FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams( + FrameLayout.LayoutParams.WRAP_CONTENT, // Width + FrameLayout.LayoutParams.WRAP_CONTENT // Height + ); + mViewRoot.setLayoutParams(layoutParams); + mViewRoot.addView(view); + mViewRoot.setAlpha(0); + mViewRoot.animate().alpha(1) + .setInterpolator(new AccelerateDecelerateInterpolator()) + .setDuration(FADE_IN_ANIMATION_DURATION) + .start(); + mSurfaceControlViewHost.setView( + mViewRoot, + view.getMeasuredWidth(), + view.getMeasuredHeight() + ); + } else { + mViewRoot.removeAllViews(); + mViewRoot.addView(view); + } } } diff --git a/src/com/android/launcher3/graphics/SysUiScrim.java b/src/com/android/launcher3/graphics/SysUiScrim.java index 260d490926..077ddfc665 100644 --- a/src/com/android/launcher3/graphics/SysUiScrim.java +++ b/src/com/android/launcher3/graphics/SysUiScrim.java @@ -18,8 +18,6 @@ package com.android.launcher3.graphics; import static android.graphics.Paint.DITHER_FLAG; import static android.graphics.Paint.FILTER_BITMAP_FLAG; -import static com.android.launcher3.config.FeatureFlags.KEYGUARD_ANIMATION; - import android.animation.ObjectAnimator; import android.graphics.Bitmap; import android.graphics.Canvas; @@ -111,7 +109,7 @@ public class SysUiScrim implements View.OnAttachStateChangeListener { new int[]{0x00FFFFFF, 0x2FFFFFFF}, new float[]{0f, 1f}); - if (!KEYGUARD_ANIMATION.get() && !mHideSysUiScrim) { + if (!mHideSysUiScrim) { view.addOnAttachStateChangeListener(this); } } diff --git a/src/com/android/launcher3/icons/ComponentWithLabel.java b/src/com/android/launcher3/icons/ComponentWithLabel.java deleted file mode 100644 index 30575fcbe5..0000000000 --- a/src/com/android/launcher3/icons/ComponentWithLabel.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2018 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.icons; - -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.PackageManager; -import android.os.UserHandle; - -import androidx.annotation.NonNull; - -import com.android.launcher3.icons.cache.CachingLogic; - -public interface ComponentWithLabel { - - ComponentName getComponent(); - - UserHandle getUser(); - - CharSequence getLabel(PackageManager pm); - - - class ComponentCachingLogic<T extends ComponentWithLabel> implements CachingLogic<T> { - - private final PackageManager mPackageManager; - private final boolean mAddToMemCache; - - public ComponentCachingLogic(Context context, boolean addToMemCache) { - mPackageManager = context.getPackageManager(); - mAddToMemCache = addToMemCache; - } - - @Override - @NonNull - public ComponentName getComponent(@NonNull T object) { - return object.getComponent(); - } - - @NonNull - @Override - public UserHandle getUser(@NonNull T object) { - return object.getUser(); - } - - @NonNull - @Override - public CharSequence getLabel(@NonNull T object) { - return object.getLabel(mPackageManager); - } - - @NonNull - @Override - public BitmapInfo loadIcon(@NonNull Context context, @NonNull T object) { - return BitmapInfo.LOW_RES_INFO; - } - - @Override - public boolean addToMemCache() { - return mAddToMemCache; - } - } -} diff --git a/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java b/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java deleted file mode 100644 index 0a52dd7191..0000000000 --- a/src/com/android/launcher3/icons/ComponentWithLabelAndIcon.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.android.launcher3.icons; - -import android.content.Context; -import android.graphics.drawable.Drawable; - -import androidx.annotation.NonNull; - -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.icons.BaseIconFactory.IconOptions; - -/** - * Extension of ComponentWithLabel to also support loading icons - */ -public interface ComponentWithLabelAndIcon extends ComponentWithLabel { - - /** - * Provide an icon for this object - */ - Drawable getFullResIcon(IconCache cache); - - class ComponentWithIconCachingLogic extends ComponentCachingLogic<ComponentWithLabelAndIcon> { - - public ComponentWithIconCachingLogic(Context context, boolean addToMemCache) { - super(context, addToMemCache); - } - - @NonNull - @Override - public BitmapInfo loadIcon(@NonNull Context context, - @NonNull ComponentWithLabelAndIcon object) { - Drawable d = object.getFullResIcon(LauncherAppState.getInstance(context) - .getIconCache()); - if (d == null) { - return super.loadIcon(context, object); - } - try (LauncherIcons li = LauncherIcons.obtain(context)) { - return li.createBadgedIconBitmap(d, new IconOptions().setUser(object.getUser())); - } - } - } -} diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 44e448eea1..587dc2731a 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -54,9 +54,10 @@ import androidx.core.util.Pair; import com.android.launcher3.Flags; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.Utilities; -import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; import com.android.launcher3.icons.cache.BaseIconCache; +import com.android.launcher3.icons.cache.CachedObjectCachingLogic; import com.android.launcher3.icons.cache.CachingLogic; +import com.android.launcher3.icons.cache.LauncherActivityCachingLogic; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.IconRequestInfo; @@ -102,7 +103,6 @@ public class IconCache extends BaseIconCache { private final LauncherApps mLauncherApps; private final UserCache mUserManager; private final InstantAppResolver mInstantAppResolver; - private final IconProvider mIconProvider; private final CancellableTask mCancelledTask; private final SparseArray<BitmapInfo> mWidgetCategoryBitmapInfos; @@ -112,14 +112,14 @@ public class IconCache extends BaseIconCache { public IconCache(Context context, InvariantDeviceProfile idp, String dbFileName, IconProvider iconProvider) { super(context, dbFileName, MODEL_EXECUTOR.getLooper(), - idp.fillResIconDpi, idp.iconBitmapSize, true /* inMemoryCache */); - mComponentWithLabelCachingLogic = new ComponentCachingLogic(context, false); - mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.newInstance(context); + idp.fillResIconDpi, idp.iconBitmapSize, true /* inMemoryCache */, iconProvider); + mComponentWithLabelCachingLogic = new CachedObjectCachingLogic( + context, false /* loadIcons */, false /* addToMemCache */); + mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.INSTANCE; mShortcutCachingLogic = new ShortcutCachingLogic(); mLauncherApps = mContext.getSystemService(LauncherApps.class); mUserManager = UserCache.INSTANCE.get(mContext); mInstantAppResolver = InstantAppResolver.newInstance(mContext); - mIconProvider = iconProvider; mWidgetCategoryBitmapInfos = new SparseArray<>(); mCancelledTask = new CancellableTask(() -> null, MAIN_EXECUTOR, c -> { }); @@ -337,6 +337,9 @@ public class IconCache extends BaseIconCache { } } + /** + * Loads and returns the icon for the provided object without adding it to memCache + */ public synchronized String getTitleNoCache(ComponentWithLabel info) { CacheEntry entry = cacheLocked(info.getComponent(), info.getUser(), () -> info, mComponentWithLabelCachingLogic, false /* usePackageIcon */, @@ -629,12 +632,6 @@ public class IconCache extends BaseIconCache { info.getAppLabel()); } - @Override - @NonNull - protected String getIconSystemState(String packageName) { - return mIconProvider.getSystemStateForPackage(mSystemState, packageName); - } - /** * Interface for receiving itemInfo with high-res icon. */ diff --git a/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java deleted file mode 100644 index de2269c43d..0000000000 --- a/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (C) 2018 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.icons; - -import android.content.ComponentName; -import android.content.Context; -import android.content.pm.LauncherActivityInfo; -import android.os.Build; -import android.os.UserHandle; - -import androidx.annotation.NonNull; - -import com.android.launcher3.Flags; -import com.android.launcher3.LauncherAppState; -import com.android.launcher3.R; -import com.android.launcher3.icons.BaseIconFactory.IconOptions; -import com.android.launcher3.icons.cache.CachingLogic; -import com.android.launcher3.util.ResourceBasedOverride; - -/** - * Caching logic for LauncherActivityInfo. - */ -public class LauncherActivityCachingLogic - implements CachingLogic<LauncherActivityInfo>, ResourceBasedOverride { - - /** - * Creates and returns a new instance - */ - public static LauncherActivityCachingLogic newInstance(Context context) { - return Overrides.getObject(LauncherActivityCachingLogic.class, context, - R.string.launcher_activity_logic_class); - } - - @NonNull - @Override - public ComponentName getComponent(@NonNull LauncherActivityInfo object) { - return object.getComponentName(); - } - - @NonNull - @Override - public UserHandle getUser(@NonNull LauncherActivityInfo object) { - return object.getUser(); - } - - @NonNull - @Override - public CharSequence getLabel(@NonNull LauncherActivityInfo object) { - return object.getLabel(); - } - - @NonNull - @Override - public BitmapInfo loadIcon(@NonNull Context context, @NonNull LauncherActivityInfo object) { - try (LauncherIcons li = LauncherIcons.obtain(context)) { - IconOptions iconOptions = new IconOptions().setUser(object.getUser()); - iconOptions.mIsArchived = Flags.useNewIconForArchivedApps() - && Build.VERSION.SDK_INT >= 35 - && object.getActivityInfo().isArchived; - return li.createBadgedIconBitmap( - LauncherAppState.getInstance(context) - .getIconProvider() - .getIcon(object, li.mFillResIconDpi), - iconOptions - ); - } - } -} diff --git a/src/com/android/launcher3/icons/Legacy.kt b/src/com/android/launcher3/icons/Legacy.kt new file mode 100644 index 0000000000..3bf3bb2539 --- /dev/null +++ b/src/com/android/launcher3/icons/Legacy.kt @@ -0,0 +1,31 @@ +/* + * 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.icons + +import com.android.launcher3.icons.cache.CachedObject + +/** + * This files contains some definitions used during refactoring to avoid breaking changes. + * + * TODO(b/366237794) remove this file once refactoring is complete + */ + +/** Temporary interface to allow easier refactoring */ +interface ComponentWithLabel : CachedObject<IconCache> + +/** Temporary interface to allow easier refactoring */ +interface ComponentWithLabelAndIcon : ComponentWithLabel diff --git a/src/com/android/launcher3/icons/ShortcutCachingLogic.java b/src/com/android/launcher3/icons/ShortcutCachingLogic.java index f40eda6c2d..7bb39e1230 100644 --- a/src/com/android/launcher3/icons/ShortcutCachingLogic.java +++ b/src/com/android/launcher3/icons/ShortcutCachingLogic.java @@ -33,6 +33,7 @@ import androidx.annotation.Nullable; import com.android.launcher3.LauncherAppState; import com.android.launcher3.icons.BaseIconFactory.IconOptions; +import com.android.launcher3.icons.cache.BaseIconCache; import com.android.launcher3.icons.cache.CachingLogic; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.Themes; @@ -72,7 +73,8 @@ public class ShortcutCachingLogic implements CachingLogic<ShortcutInfo> { @NonNull @Override - public BitmapInfo loadIcon(@NonNull Context context, @NonNull ShortcutInfo info) { + public BitmapInfo loadIcon(@NonNull Context context, @NonNull BaseIconCache cache, + @NonNull ShortcutInfo info) { try (LauncherIcons li = LauncherIcons.obtain(context)) { Drawable unbadgedDrawable = ShortcutCachingLogic.getIcon( context, info, LauncherAppState.getIDP(context).fillResIconDpi); diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index 64ebbf3833..1f60f132df 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -223,7 +223,8 @@ public class AllAppsList { if (DEBUG) { Log.w(TAG, "updatePromiseInstallInfo: removing app due to install" + " failure and appInfo not startable." - + " package=" + appInfo.getTargetPackage()); + + " package=" + appInfo.getTargetPackage() + + ", user=" + user); } removeApp(i); } @@ -319,7 +320,8 @@ public class AllAppsList { if (!findActivity(matches, applicationInfo.componentName)) { if (DEBUG) { Log.w(TAG, "Changing shortcut target due to app component name change." - + " package=" + packageName); + + " component=" + applicationInfo.componentName + + ", user=" + user); } removeApp(i); } @@ -346,8 +348,9 @@ public class AllAppsList { } else { // Remove all data for this package. if (DEBUG) { - Log.w(TAG, "updatePromiseInstallInfo: no Activities matched updated package," - + " removing all apps from package=" + packageName); + Log.w(TAG, "updatePackage: no Activities matched updated package," + + " removing any AppInfo with package=" + packageName + + ", user=" + user); } for (int i = data.size() - 1; i >= 0; i--) { final AppInfo applicationInfo = data.get(i); diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java index f54fc57037..8d2a7f92d4 100644 --- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java +++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java @@ -121,13 +121,21 @@ public class GridSizeMigrationUtil { @NonNull DeviceGridState destDeviceState, @NonNull DatabaseHelper target, @NonNull SQLiteDatabase source) { + + Log.i("b/360462379", "Going from " + srcDeviceState.getColumns() + "x" + + srcDeviceState.getRows()); + Log.i("b/360462379", "Going to " + destDeviceState.getColumns() + "x" + + destDeviceState.getRows()); + if (!needsToMigrate(srcDeviceState, destDeviceState)) { + Log.i("b/360462379", "Does not need to migrate."); return true; } if (Flags.enableGridMigrationFix() && srcDeviceState.getColumns().equals(destDeviceState.getColumns()) && srcDeviceState.getRows() < destDeviceState.getRows()) { + Log.i("b/360462379", "Grid migration fix entry point."); // Only use this strategy when comparing the previous grid to the new grid and the // columns are the same and the destination has more rows copyTable(source, TABLE_NAME, target.getWritableDatabase(), TABLE_NAME, context); diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 605accf39c..609846f7fc 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -70,11 +70,11 @@ import com.android.launcher3.folder.FolderGridOrganizer; import com.android.launcher3.folder.FolderNameInfos; import com.android.launcher3.folder.FolderNameProvider; import com.android.launcher3.icons.ComponentWithLabelAndIcon; -import com.android.launcher3.icons.ComponentWithLabelAndIcon.ComponentWithIconCachingLogic; import com.android.launcher3.icons.IconCache; -import com.android.launcher3.icons.LauncherActivityCachingLogic; import com.android.launcher3.icons.ShortcutCachingLogic; +import com.android.launcher3.icons.cache.CachedObjectCachingLogic; import com.android.launcher3.icons.cache.IconCacheUpdateHandler; +import com.android.launcher3.icons.cache.LauncherActivityCachingLogic; import com.android.launcher3.logging.FileLog; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.AppPairInfo; @@ -298,7 +298,7 @@ public class LoaderTask implements Runnable { IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler(); setIgnorePackages(updateHandler); updateHandler.updateIcons(allActivityList, - LauncherActivityCachingLogic.newInstance(mApp.getContext()), + LauncherActivityCachingLogic.INSTANCE, mApp.getModel()::onPackageIconsUpdated); logASplit("update icon cache"); @@ -360,7 +360,7 @@ public class LoaderTask implements Runnable { } updateHandler.updateIcons(allWidgetsList, - new ComponentWithIconCachingLogic(mApp.getContext(), true), + new CachedObjectCachingLogic(mApp.getContext()), mApp.getModel()::onWidgetLabelsUpdated); logASplit("save widgets in icon cache"); diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 2febb22c4f..5464afed2e 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -119,7 +119,8 @@ public class PackageUpdatedTask implements ModelUpdateTask { final HashMap<String, List<LauncherActivityInfo>> activitiesLists = new HashMap<>(); if (DEBUG) { Log.d(TAG, "Package updated: mOp=" + getOpString() - + " packages=" + Arrays.toString(packages)); + + " packages=" + Arrays.toString(packages) + + ", user=" + mUser); } switch (mOp) { case OP_ADD: { diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java index 3f887176b7..ac9f2d68eb 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_HOME_SCREE 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 @@ public class WidgetItem extends ComponentKey { 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 @@ public class WidgetItem extends ComponentKey { /** 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 90e47d66cc..1f1e514ee3 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.Flags 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 @@ -76,7 +75,7 @@ class WorkspaceItemProcessor( 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 +96,7 @@ class WorkspaceItemProcessor( // 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 } @@ -168,7 +167,7 @@ class WorkspaceItemProcessor( 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 +177,7 @@ class WorkspaceItemProcessor( 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,7 +212,7 @@ class WorkspaceItemProcessor( else -> { c.markDeleted( "removing app that is not restored and not installing. package: $targetPkg", - RestoreError.APP_NOT_INSTALLED + RestoreError.APP_NOT_INSTALLED, ) return } @@ -238,7 +237,7 @@ class WorkspaceItemProcessor( // 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 +269,7 @@ class WorkspaceItemProcessor( // 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 } @@ -337,7 +336,7 @@ class WorkspaceItemProcessor( activityInfo, userCache.getUserInfo(c.user), ApiWrapper.INSTANCE[app.context], - pmHelper + pmHelper, ) } if ( @@ -445,7 +444,7 @@ class WorkspaceItemProcessor( ", id=${c.id}," + ", appWidgetId=${c.appWidgetId}," + ", component=${component}", - RestoreError.INVALID_LOCATION + RestoreError.INVALID_LOCATION, ) return } @@ -456,7 +455,7 @@ class WorkspaceItemProcessor( ", appWidgetId=${c.appWidgetId}," + ", component=${component}," + ", container=${c.container}", - RestoreError.INVALID_LOCATION + RestoreError.INVALID_LOCATION, ) return } @@ -470,7 +469,7 @@ class WorkspaceItemProcessor( TAG, "processWidget: id=${c.id}" + ", appWidgetId=${c.appWidgetId}" + - ", inflationResult=$inflationResult" + ", inflationResult=$inflationResult", ) when (inflationResult.type) { WidgetInflater.TYPE_DELETE -> { @@ -496,7 +495,7 @@ class WorkspaceItemProcessor( ", appWidgetId=${c.appWidgetId}" + ", component=${component}" + ", restoreFlag:=${c.restoreFlag}", - RestoreError.APP_NOT_INSTALLED + RestoreError.APP_NOT_INSTALLED, ) return } else if ( @@ -512,7 +511,7 @@ class WorkspaceItemProcessor( WidgetsModel.newPendingItemInfo( app.context, appWidgetInfo.providerName, - appWidgetInfo.user + appWidgetInfo.user, ) iconCache.getTitleAndIconForApp(appWidgetInfo.pendingItemInfo, false) } @@ -522,7 +521,7 @@ class WorkspaceItemProcessor( lapi, app.context, appWidgetInfo.spanX, - appWidgetInfo.spanY + appWidgetInfo.spanY, ) } @@ -541,7 +540,7 @@ class WorkspaceItemProcessor( " 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 +553,7 @@ class WorkspaceItemProcessor( private fun logWidgetInfo( idp: InvariantDeviceProfile, - widgetProviderInfo: LauncherAppWidgetProviderInfo + widgetProviderInfo: LauncherAppWidgetProviderInfo, ) { val cellSize = Point() for (deviceProfile in idp.supportedProfiles) { @@ -565,7 +564,7 @@ class WorkspaceItemProcessor( " available height: ${deviceProfile.availableHeightPx}," + " cellLayoutBorderSpacePx Horizontal: ${deviceProfile.cellLayoutBorderSpacePx.x}," + " cellLayoutBorderSpacePx Vertical: ${deviceProfile.cellLayoutBorderSpacePx.y}," + - " cellSize: $cellSize" + " cellSize: $cellSize", ) } val widgetDimension = StringBuilder() @@ -583,21 +582,19 @@ class WorkspaceItemProcessor( .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/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java index b82d0a0985..b706d249f2 100644 --- a/src/com/android/launcher3/model/data/ItemInfo.java +++ b/src/com/android/launcher3/model/data/ItemInfo.java @@ -51,6 +51,7 @@ import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.Workspace; import com.android.launcher3.logger.LauncherAtom; import com.android.launcher3.logger.LauncherAtom.AllAppsContainer; +import com.android.launcher3.logger.LauncherAtom.Attribute; import com.android.launcher3.logger.LauncherAtom.ContainerInfo; import com.android.launcher3.logger.LauncherAtom.PredictionContainer; import com.android.launcher3.logger.LauncherAtom.SettingsContainer; @@ -67,6 +68,9 @@ import com.android.launcher3.util.SettingsCache; import com.android.launcher3.util.UserIconInfo; import com.android.systemui.shared.system.SysUiStatsLog; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.Optional; /** @@ -77,8 +81,6 @@ public class ItemInfo { public static final boolean DEBUG = false; public static final int NO_ID = -1; - // An id that doesn't match any item, including predicted apps with have an id=NO_ID - public static final int NO_MATCHING_ID = Integer.MIN_VALUE; /** Hidden field Settings.Secure.NAV_BAR_KIDS_MODE */ private static final Uri NAV_BAR_KIDS_MODE = Settings.Secure.getUriFor("nav_bar_kids_mode"); @@ -187,6 +189,12 @@ public class ItemInfo { @NonNull public UserHandle user; + @NonNull + private ExtendedContainers mExtendedContainers = ExtendedContainers.getDefaultInstance(); + + @NonNull + private List<Attribute> mAttributeList = Collections.EMPTY_LIST; + public ItemInfo() { user = Process.myUserHandle(); } @@ -433,6 +441,7 @@ public class ItemInfo { UserCache.INSTANCE.executeIfCreated(cache -> itemBuilder.setUserType(getUserType(cache.getUserInfo(user)))); itemBuilder.setRank(rank); + itemBuilder.addAllItemAttributes(mAttributeList); return itemBuilder; } @@ -491,7 +500,7 @@ public class ItemInfo { default: if (container <= EXTENDED_CONTAINERS) { return ContainerInfo.newBuilder() - .setExtendedContainers(getExtendedContainer()) + .setExtendedContainers(mExtendedContainers) .build(); } } @@ -499,12 +508,21 @@ public class ItemInfo { } /** - * Returns non-AOSP container wrapped by {@link ExtendedContainers} object. Should be overridden - * by build variants. + * Sets extra container info wrapped by {@link ExtendedContainers} object. */ - @NonNull - protected ExtendedContainers getExtendedContainer() { - return ExtendedContainers.getDefaultInstance(); + public void setExtendedContainers(@NonNull ExtendedContainers extendedContainers) { + mExtendedContainers = extendedContainers; + } + + /** + * Adds extra attributes to be added during logs + */ + public void addLogAttributes(List<LauncherAtom.Attribute> attributeList) { + if (mAttributeList.isEmpty()) { + mAttributeList = new ArrayList<>(attributeList); + } else { + mAttributeList.addAll(attributeList); + } } /** @@ -525,6 +543,14 @@ public class ItemInfo { this.title = title; } + /** + * Returns a string ID that is stable for a user session, but may not be persisted + */ + @Nullable + public Object getStableId() { + return getComponentKey(); + } + private int getUserType(UserIconInfo info) { if (info == null) { return SysUiStatsLog.LAUNCHER_UICHANGED__USER_TYPE__TYPE_UNKNOWN; diff --git a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java index f4dda5593a..361f09d418 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_BOTTOM_ 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 @@ public class LauncherAppWidgetInfo extends ItemInfo { 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/PinRequestHelper.java b/src/com/android/launcher3/pm/PinRequestHelper.java index 667136ae00..47afeef703 100644 --- a/src/com/android/launcher3/pm/PinRequestHelper.java +++ b/src/com/android/launcher3/pm/PinRequestHelper.java @@ -77,8 +77,9 @@ public class PinRequestHelper { WorkspaceItemInfo info = new WorkspaceItemInfo(si, context); // Apply the unbadged icon synchronously using the caching logic directly and // fetch the actual icon asynchronously. - info.bitmap = new ShortcutCachingLogic().loadIcon(context, si); - LauncherAppState.getInstance(context).getModel().updateAndBindWorkspaceItem(info, si); + LauncherAppState app = LauncherAppState.getInstance(context); + info.bitmap = new ShortcutCachingLogic().loadIcon(context, app.getIconCache(), si); + app.getModel().updateAndBindWorkspaceItem(info, si); return info; } else { return null; diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index 4d4a8f749a..c2debfa2ed 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -16,8 +16,6 @@ package com.android.launcher3.popup; -import static androidx.core.content.ContextCompat.getColorStateList; - import static com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE; import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE; import static com.android.app.animation.Interpolators.LINEAR; @@ -56,8 +54,6 @@ import com.android.launcher3.util.Themes; import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; -import java.util.Arrays; - /** * A container for shortcuts to deep links and notifications associated with an app. * @@ -130,7 +126,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> // Tag for Views that have children that will need to be iterated to add styling. private final String mIterateChildrenTag; - protected final int[] mColorIds; + protected final int[] mColors; public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); @@ -142,8 +138,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> // Initialize arrow view final Resources resources = getResources(); - mArrowColor = getColorStateList(getContext(), R.color.popup_color_background) - .getDefaultColor(); + mArrowColor = Themes.getAttrColor(getContext(), R.attr.materialColorSurfaceContainer); mChildContainerMargin = resources.getDimensionPixelSize(R.dimen.popup_margin); mArrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width); mArrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height); @@ -158,21 +153,25 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> mRoundedTop = new GradientDrawable(); int popupPrimaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary); mRoundedTop.setColor(popupPrimaryColor); - mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius, + mRoundedTop.setCornerRadii(new float[]{mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius}); mRoundedBottom = new GradientDrawable(); mRoundedBottom.setColor(popupPrimaryColor); - mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius, + mRoundedBottom.setCornerRadii(new float[]{smallerRadius, smallerRadius, smallerRadius, smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius}); mIterateChildrenTag = getContext().getString(R.string.popup_container_iterate_children); if (mActivityContext.canUseMultipleShadesForPopup()) { - mColorIds = new int[]{R.color.popup_shade_first, R.color.popup_shade_second, - R.color.popup_shade_third}; + mColors = new int[]{ + getContext().getColor(R.color.popup_shade_first), + getContext().getColor(R.color.popup_shade_second), + getContext().getColor(R.color.popup_shade_third) + }; } else { - mColorIds = new int[]{R.color.popup_color_background}; + mColors = new int[]{Themes.getAttrColor(getContext(), + R.attr.materialColorSurfaceContainer)}; } } @@ -219,15 +218,14 @@ public abstract class ArrowPopup<T extends Context & ActivityContext> } /** - * @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColorIds}. + * @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColors}. * Otherwise, we will use this color for all child views. */ protected void assignMarginsAndBackgrounds(ViewGroup viewGroup, int backgroundColor) { int[] colors = null; if (backgroundColor == Color.TRANSPARENT) { // Lazily get the colors so they match the current wallpaper colors. - colors = Arrays.stream(mColorIds).map( - r -> getColorStateList(getContext(), r).getDefaultColor()).toArray(); + colors = mColors; } int count = viewGroup.getChildCount(); diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index 0c90eb904a..63c9d94795 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -1,5 +1,6 @@ package com.android.launcher3.popup; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DISMISS_PREDICTION_UNDO; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_INSTALL_SYSTEM_SHORTCUT_TAP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNINSTALL_SYSTEM_SHORTCUT_TAP; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP; @@ -7,7 +8,6 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP; import static com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.findAllWidgetsForPackageUser; -import android.app.ActivityOptions; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -35,12 +35,14 @@ import com.android.launcher3.allapps.PrivateProfileManager; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.pm.UserCache; +import com.android.launcher3.util.ActivityOptionsWrapper; import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.InstantAppResolver; import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.views.ActivityContext; +import com.android.launcher3.views.Snackbar; import com.android.launcher3.widget.WidgetsBottomSheet; import com.android.launcher3.widget.picker.model.data.WidgetPickerData; @@ -184,10 +186,12 @@ public abstract class SystemShortcut<T extends ActivityContext> extends ItemInfo @Override public void onClick(View view) { - dismissTaskMenuView(); Rect sourceBounds = Utilities.getViewBounds(view); + ActivityOptionsWrapper options = mTarget.getActivityLaunchOptions(view, mItemInfo); + // Dismiss the taskMenu when the app launch animation is complete + options.onEndCallback.add(this::dismissTaskMenuView); PackageManagerHelper.startDetailsActivityForInfo(view.getContext(), mItemInfo, - sourceBounds, ActivityOptions.makeBasic().toBundle()); + sourceBounds, options.toBundle()); mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo) .log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP); } @@ -334,6 +338,14 @@ public abstract class SystemShortcut<T extends ActivityContext> extends ItemInfo mTarget.getStatsLogManager().logger() .withItemInfo(mItemInfo) .log(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP); + if (Flags.enableDismissPredictionUndo()) { + Snackbar.show(mTarget, + view.getContext().getString(R.string.item_removed), R.string.undo, + () -> { }, () -> + mTarget.getStatsLogManager().logger() + .withItemInfo(mItemInfo) + .log(LAUNCHER_DISMISS_PREDICTION_UNDO)); + } } } diff --git a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt index 6ff51ca527..82229f8f21 100644 --- a/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt +++ b/src/com/android/launcher3/recyclerview/AllAppsRecyclerViewPool.kt @@ -24,7 +24,6 @@ import androidx.recyclerview.widget.RecyclerView.ViewHolder import com.android.launcher3.BubbleTextView import com.android.launcher3.BuildConfig import com.android.launcher3.allapps.BaseAllAppsAdapter -import com.android.launcher3.config.FeatureFlags import com.android.launcher3.util.CancellableTask import com.android.launcher3.util.Executors.MAIN_EXECUTOR import com.android.launcher3.util.Executors.VIEW_PREINFLATION_EXECUTOR @@ -78,7 +77,7 @@ class AllAppsRecyclerViewPool<T> : RecycledViewPool() { ActivityContextDelegate( context.createConfigurationContext(context.resources.configuration), Themes.getActivityThemeRes(context), - context + context, ) // Because we perform onCreateViewHolder() on worker thread, we need a separate @@ -91,7 +90,7 @@ class AllAppsRecyclerViewPool<T> : RecycledViewPool() { context, context.appsView.layoutInflater.cloneInContext(allAppsPreInflationContext), null, - null + null, ) { override fun setAppsPerRow(appsPerRow: Int) = Unit @@ -124,7 +123,7 @@ class AllAppsRecyclerViewPool<T> : RecycledViewPool() { for (i in 0 until minOf(viewHolders.size, getPreinflateCount(context))) { putRecycledView(viewHolders[i]) } - } + }, ) mCancellableTask = task VIEW_PREINFLATION_EXECUTOR.submit(mCancellableTask) @@ -144,18 +143,15 @@ class AllAppsRecyclerViewPool<T> : RecycledViewPool() { * app icons plus [EXTRA_ICONS_COUNT] is the magic minimal count of app icons to preinflate to * suffice fast scrolling. * - * Note that if [FeatureFlags.ALL_APPS_GONE_VISIBILITY] is enabled, we need to preinfate extra - * app icons in size of one all apps pages, so that opening all apps don't need to inflate app - * icons. + * Note that we need to preinfate extra app icons in size of one all apps pages, so that opening + * all apps don't need to inflate app icons. */ fun <T> getPreinflateCount(context: T): Int where T : Context, T : ActivityContext { var targetPreinflateCount = PREINFLATE_ICONS_ROW_COUNT * context.deviceProfile.numShownAllAppsColumns + EXTRA_ICONS_COUNT - if (FeatureFlags.ALL_APPS_GONE_VISIBILITY.get()) { - val grid = ActivityContext.lookupContext<T>(context).deviceProfile - targetPreinflateCount += grid.maxAllAppsRowCount * grid.numShownAllAppsColumns - } + val grid = ActivityContext.lookupContext<T>(context).deviceProfile + targetPreinflateCount += grid.maxAllAppsRowCount * grid.numShownAllAppsColumns if (hasWorkProfile) { targetPreinflateCount *= 2 } diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java index ac07c0f2cf..303290dda3 100644 --- a/src/com/android/launcher3/statemanager/StateManager.java +++ b/src/com/android/launcher3/statemanager/StateManager.java @@ -253,7 +253,7 @@ public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>, if (mConfig.currentAnimation == null) { // Run any queued runnable if (listener != null) { - listener.onAnimationEnd(null); + listener.onAnimationEnd(new AnimatorSet()); } return; } else if ((!mConfig.isUserControlled() && animated && mConfig.targetState == state) @@ -282,7 +282,7 @@ public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>, // Run any queued runnable if (listener != null) { - listener.onAnimationEnd(null); + listener.onAnimationEnd(new AnimatorSet()); } return; } diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index 3817563b0b..efd1f0d6b4 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.LauncherAnimUtils; 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 @@ public abstract class AbstractStateChangeTouchController } else { logReachedState(mToState); } + updateContextualEduStats(targetState); } protected void goToTargetState(LauncherState targetState) { @@ -403,6 +406,21 @@ public abstract class AbstractStateChangeTouchController .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/AllAppsSwipeController.java b/src/com/android/launcher3/touch/AllAppsSwipeController.java index fe4a83b8d0..9dcdf22852 100644 --- a/src/com/android/launcher3/touch/AllAppsSwipeController.java +++ b/src/com/android/launcher3/touch/AllAppsSwipeController.java @@ -22,13 +22,9 @@ import static com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE; import static com.android.app.animation.Interpolators.FINAL_FRAME; import static com.android.app.animation.Interpolators.INSTANT; import static com.android.app.animation.Interpolators.LINEAR; -import static com.android.app.animation.Interpolators.clampToProgress; -import static com.android.app.animation.Interpolators.mapToProgress; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.NORMAL; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_BOTTOM_SHEET_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_KEYBOARD_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH; import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_HOTSEAT_SCALE; @@ -37,15 +33,12 @@ import static com.android.launcher3.states.StateAnimationConfig.ANIM_SCRIM_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE; import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE; -import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; import android.view.MotionEvent; import android.view.animation.Interpolator; import com.android.app.animation.Interpolators; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.states.StateAnimationConfig; @@ -281,36 +274,6 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController { } } - /** - * Applies Animation config values for transition from overview to all apps. - * - * @param threshold progress at which all apps will open upon release - */ - public static void applyOverviewToAllAppsAnimConfig( - DeviceProfile deviceProfile, StateAnimationConfig config, float threshold) { - config.animProps |= StateAnimationConfig.USER_CONTROLLED; - config.animFlags = SKIP_OVERVIEW; - if (deviceProfile.isTablet) { - config.setInterpolator(ANIM_ALL_APPS_FADE, INSTANT); - config.setInterpolator(ANIM_SCRIM_FADE, ALL_APPS_SCRIM_RESPONDER); - // The fact that we end on Workspace is not very ideal, but since we do, fade it in at - // the end of the transition. Don't scale/translate it. - config.setInterpolator(ANIM_WORKSPACE_FADE, clampToProgress(LINEAR, 0.8f, 1)); - config.setInterpolator(ANIM_WORKSPACE_SCALE, INSTANT); - config.setInterpolator(ANIM_WORKSPACE_TRANSLATE, INSTANT); - } else { - // Pop the background panel, keyboard, and content in at full opacity at the threshold. - config.setInterpolator(ANIM_ALL_APPS_BOTTOM_SHEET_FADE, - thresholdInterpolator(threshold, INSTANT)); - config.setInterpolator(ANIM_ALL_APPS_KEYBOARD_FADE, - thresholdInterpolator(threshold, INSTANT)); - config.setInterpolator(ANIM_ALL_APPS_FADE, thresholdInterpolator(threshold, INSTANT)); - - config.setInterpolator(ANIM_VERTICAL_PROGRESS, - thresholdInterpolator(threshold, mapToProgress(LINEAR, threshold, 1f))); - } - } - /** Creates an interpolator that is 0 until the threshold, then follows given interpolator. */ private static Interpolator thresholdInterpolator(float threshold, Interpolator interpolator) { return progress -> progress <= threshold ? 0 : interpolator.getInterpolation(progress); diff --git a/src/com/android/launcher3/touch/BaseSwipeDetector.java b/src/com/android/launcher3/touch/BaseSwipeDetector.java index 52c358143a..faac4a3eb6 100644 --- a/src/com/android/launcher3/touch/BaseSwipeDetector.java +++ b/src/com/android/launcher3/touch/BaseSwipeDetector.java @@ -17,6 +17,8 @@ package com.android.launcher3.touch; 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 @@ public abstract class BaseSwipeDetector { 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 @@ public abstract class BaseSwipeDetector { return mState == ScrollState.DRAGGING || mState == ScrollState.SETTLING; } + public boolean isTrackpadGesture() { + return mIsTrackpadGesture; + } + public void finishedScrolling() { setState(ScrollState.IDLE); } @@ -147,7 +154,7 @@ public abstract class BaseSwipeDetector { 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/ActivityOptionsWrapper.java b/src/com/android/launcher3/util/ActivityOptionsWrapper.java index 99cc1f7b6c..17ff2a96b7 100644 --- a/src/com/android/launcher3/util/ActivityOptionsWrapper.java +++ b/src/com/android/launcher3/util/ActivityOptionsWrapper.java @@ -25,6 +25,7 @@ import android.os.Bundle; public class ActivityOptionsWrapper { public final ActivityOptions options; + // Called when the app launch animation is complete public final RunnableList onEndCallback; public ActivityOptionsWrapper(ActivityOptions options, RunnableList onEndCallback) { diff --git a/src/com/android/launcher3/util/DaggerSingletonObject.java b/src/com/android/launcher3/util/DaggerSingletonObject.java new file mode 100644 index 0000000000..b8cf2ae77a --- /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 0000000000..2946da1d0c --- /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 b1e82bbdc0..afa5075190 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.FlagDebugUtils.appendFlag; 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.content.res.Configuration; 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 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { } 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 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { && mInfo.mIsTaskbarPinnedInDesktopMode != prefs.get( TASKBAR_PINNING_IN_DESKTOP_MODE); if (isTaskbarPinningChanged || isTaskbarPinningDesktopModeChanged) { - handleInfoChange(mWindowContext.getDisplay()); + handleInfoChange(); } }; @@ -187,16 +178,18 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { return INSTANCE.get(context).getInfo().isTransientTaskbar(); } - /** Returns whether we are currently in Desktop mode. */ - public static boolean isInDesktopMode(Context context) { - return INSTANCE.get(context).getInfo().isInDesktopMode(); - } - /** * Handles info change for desktop mode. */ public static void handleInfoChangeForDesktopMode(Context context) { - INSTANCE.get(context).handleInfoChange(context.getDisplay()); + INSTANCE.get(context).handleInfoChange(); + } + + /** + * Handles info change for launcher visibility. + */ + public static void handleInfoChangeForLauncherVisibilityChanged(Context context) { + INSTANCE.get(context).handleInfoChange(); } /** @@ -222,6 +215,13 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { return INSTANCE.get(context).getInfo().isPinnedTaskbar(); } + /** + * Returns whether the taskbar is forced to be pinned when home is visible. + */ + public static boolean showLockedTaskbarOnHome(Context context) { + return INSTANCE.get(context).getInfo().showLockedTaskbarOnHome(); + } + @Override public void close() { mDestroyed = true; @@ -257,36 +257,22 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { 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"); + handleInfoChange(); } } @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) { + handleInfoChange(); } } @@ -309,17 +295,13 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { return mInfo; } - private Context getDisplayInfoContext(Display display) { - return Utilities.ATLEAST_S ? mWindowContext : mContext.createDisplayContext(display); - } - @AnyThread @VisibleForTesting - public void handleInfoChange(Display display) { + public void handleInfoChange() { 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 @@ -350,7 +332,8 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { } if ((newInfo.mIsTaskbarPinned != oldInfo.mIsTaskbarPinned) || (newInfo.mIsTaskbarPinnedInDesktopMode - != oldInfo.mIsTaskbarPinnedInDesktopMode)) { + != oldInfo.mIsTaskbarPinnedInDesktopMode) + || newInfo.isPinnedTaskbar() != oldInfo.isPinnedTaskbar()) { change |= CHANGE_TASKBAR_PINNING; } if (newInfo.mIsInDesktopMode != oldInfo.mIsInDesktopMode) { @@ -404,6 +387,9 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { private final boolean mIsInDesktopMode; + private final boolean mShowLockedTaskbarOnHome; + private final boolean mIsHomeVisible; + public Info(Context displayInfoContext) { /* don't need system overrides for external displays */ this(displayInfoContext, new WindowManagerProxy(), new ArrayMap<>()); @@ -465,6 +451,8 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { mIsTaskbarPinnedInDesktopMode = LauncherPrefs.get(displayInfoContext).get( TASKBAR_PINNING_IN_DESKTOP_MODE); mIsInDesktopMode = wmProxy.isInDesktopMode(); + mShowLockedTaskbarOnHome = wmProxy.showLockedTaskbarOnHome(displayInfoContext); + mIsHomeVisible = wmProxy.isHomeVisible(displayInfoContext); } /** @@ -481,6 +469,10 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { return sTransientTaskbarStatusForTests; } if (enableTaskbarPinning()) { + // If Launcher is visible on the freeform display, ensure the taskbar is pinned. + if (mShowLockedTaskbarOnHome && mIsHomeVisible) { + return false; + } if (mIsInDesktopMode) { return !mIsTaskbarPinnedInDesktopMode; } @@ -496,10 +488,6 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { return navigationMode == NavigationMode.NO_BUTTON && !isTransientTaskbar(); } - public boolean isInDesktopMode() { - return mIsInDesktopMode; - } - /** * Returns {@code true} if the bounds represent a tablet. */ @@ -552,6 +540,13 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable { return TYPE_PHONE; } } + + /** + * Returns whether the taskbar is forced to be pinned when home is visible. + */ + public boolean showLockedTaskbarOnHome() { + return mShowLockedTaskbarOnHome; + } } /** diff --git a/src/com/android/launcher3/util/EdgeEffectCompat.java b/src/com/android/launcher3/util/EdgeEffectCompat.java index ca3725923e..a949f50ca1 100644 --- a/src/com/android/launcher3/util/EdgeEffectCompat.java +++ b/src/com/android/launcher3/util/EdgeEffectCompat.java @@ -19,8 +19,6 @@ import android.content.Context; 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 @@ public class EdgeEffectCompat extends EdgeEffect { 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 0000000000..efc0eec194 --- /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 1a0f9a0a8b..e12ccbcf70 100644 --- a/src/com/android/launcher3/util/MainThreadInitializedObject.java +++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java @@ -18,13 +18,13 @@ package com.android.launcher3.util; 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; @@ -35,6 +35,9 @@ import java.util.function.Consumer; /** * Utility class for defining singletons which are initiated on main thread. + * + * TODO(b/361850561): Do not delete MainThreadInitializedObject until we find a way to + * unregister and understand how singleton objects are destroyed in dagger graph. */ public class MainThreadInitializedObject<T extends SafeCloseable> { @@ -115,7 +118,7 @@ public class MainThreadInitializedObject<T extends SafeCloseable> { * 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"; @@ -126,7 +129,8 @@ public class MainThreadInitializedObject<T extends SafeCloseable> { private boolean mDestroyed = false; public SandboxContext(Context base) { - super(base); + attachBaseContext(base); + initDagger(); } @Override @@ -135,6 +139,7 @@ public class MainThreadInitializedObject<T extends SafeCloseable> { } 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/MultiTranslateDelegate.java b/src/com/android/launcher3/util/MultiTranslateDelegate.java index 84ef445dcf..38c87c8d5a 100644 --- a/src/com/android/launcher3/util/MultiTranslateDelegate.java +++ b/src/com/android/launcher3/util/MultiTranslateDelegate.java @@ -37,6 +37,7 @@ public class MultiTranslateDelegate { public static final int INDEX_TASKBAR_ALIGNMENT_ANIM = 3; public static final int INDEX_TASKBAR_REVEAL_ANIM = 4; public static final int INDEX_TASKBAR_PINNING_ANIM = 5; + public static final int INDEX_NAV_BAR_ANIM = 6; // Affect all items inside of a MultipageCellLayout public static final int INDEX_CELLAYOUT_MULTIPAGE_SPACING = 3; @@ -47,7 +48,7 @@ public class MultiTranslateDelegate { // Specific for hotseat items when adjusting for bubbles public static final int INDEX_BUBBLE_ADJUSTMENT_ANIM = 3; - public static final int COUNT = 6; + public static final int COUNT = 7; private final MultiPropertyFactory<View> mTranslationX; private final MultiPropertyFactory<View> mTranslationY; diff --git a/src/com/android/launcher3/util/OverlayEdgeEffect.java b/src/com/android/launcher3/util/OverlayEdgeEffect.java index d09d801d66..0623af7e43 100644 --- a/src/com/android/launcher3/util/OverlayEdgeEffect.java +++ b/src/com/android/launcher3/util/OverlayEdgeEffect.java @@ -46,6 +46,7 @@ public class OverlayEdgeEffect extends EdgeEffectCompat { 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 8c5a76e665..b1913c0164 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -212,7 +212,7 @@ public class PackageManagerHelper implements SafeCloseable{ if (info instanceof ItemInfoWithIcon appInfo && (appInfo.runtimeStatusFlags & FLAG_INSTALL_SESSION_ACTIVE) != 0) { context.startActivity(ApiWrapper.INSTANCE.get(context).getAppMarketActivityIntent( - appInfo.getTargetComponent().getPackageName(), Process.myUserHandle())); + appInfo.getTargetComponent().getPackageName(), Process.myUserHandle()), opts); return; } ComponentName componentName = null; @@ -303,10 +303,7 @@ public class PackageManagerHelper implements SafeCloseable{ /** 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; + return (int) (100 * info.getLoadingProgress()); } /** Returns true in case app is installed on the device or in archived state. */ diff --git a/src/com/android/launcher3/util/StableViewInfo.kt b/src/com/android/launcher3/util/StableViewInfo.kt new file mode 100644 index 0000000000..29dcd59711 --- /dev/null +++ b/src/com/android/launcher3/util/StableViewInfo.kt @@ -0,0 +1,56 @@ +/* + * 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.os.IBinder +import com.android.launcher3.model.data.ItemInfo +import com.android.launcher3.model.data.ItemInfo.NO_ID + +/** Info parameters that can be used to identify a Launcher object */ +data class StableViewInfo(val itemId: Int, val containerId: Int, val stableId: Any) { + + fun matches(info: ItemInfo?) = + info != null && + itemId == info.id && + containerId == info.container && + stableId == info.stableId + + companion object { + + private fun ItemInfo.toStableViewInfo() = + stableId?.let { sId -> + if (id != NO_ID || container != NO_ID) StableViewInfo(id, container, sId) else null + } + + /** + * Return a new launch cookie for the activity launch if supported. + * + * @param info the item info for the launch + */ + @JvmStatic + fun toLaunchCookie(info: ItemInfo?) = + info?.toStableViewInfo()?.let { ObjectWrapper.wrap(it) } + + /** + * Unwraps the binder and returns the first non-null StableViewInfo in the list or null if + * none can be found + */ + @JvmStatic + fun fromLaunchCookies(launchCookies: List<IBinder>) = + launchCookies.firstNotNullOfOrNull { ObjectWrapper.unwrap<StableViewInfo>(it) } + } +} diff --git a/src/com/android/launcher3/util/Themes.java b/src/com/android/launcher3/util/Themes.java index 60951ba05a..104040afff 100644 --- a/src/com/android/launcher3/util/Themes.java +++ b/src/com/android/launcher3/util/Themes.java @@ -52,10 +52,8 @@ public class Themes { } 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 6bae1baf8c..adb8f9d053 100644 --- a/src/com/android/launcher3/util/VibratorWrapper.java +++ b/src/com/android/launcher3/util/VibratorWrapper.java @@ -25,16 +25,12 @@ import android.annotation.SuppressLint; import android.content.Context; import android.media.AudioAttributes; import android.net.Uri; -import android.os.SystemClock; import android.os.VibrationEffect; import android.os.Vibrator; import android.provider.Settings; -import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; -import com.android.launcher3.Utilities; - /** * Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary. */ @@ -54,20 +50,6 @@ public class VibratorWrapper implements SafeCloseable { static final Uri HAPTIC_FEEDBACK_URI = Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED); @VisibleForTesting static final float LOW_TICK_SCALE = 0.9f; - @VisibleForTesting static final float DRAG_TEXTURE_SCALE = 0.03f; - @VisibleForTesting static final float DRAG_COMMIT_SCALE = 0.5f; - @VisibleForTesting static final float DRAG_BUMP_SCALE = 0.4f; - @VisibleForTesting static final int DRAG_TEXTURE_EFFECT_SIZE = 200; - - @Nullable - private final VibrationEffect mDragEffect; - @Nullable - private final VibrationEffect mCommitEffect; - @Nullable - private final VibrationEffect mBumpEffect; - - private long mLastDragTime; - private final int mThresholdUntilNextDragCallMillis; /** * Haptic when entering overview. @@ -100,28 +82,6 @@ public class VibratorWrapper implements SafeCloseable { } else { mIsHapticFeedbackEnabled = false; } - - if (Utilities.ATLEAST_S && mVibrator.areAllPrimitivesSupported( - PRIMITIVE_LOW_TICK)) { - - // Drag texture, Commit, and Bump should only be used for premium phones. - // Before using these haptics make sure check if the device can use it - mDragEffect = getDragEffect(); - mCommitEffect = VibrationEffect.startComposition().addPrimitive( - VibrationEffect.Composition.PRIMITIVE_TICK, DRAG_COMMIT_SCALE).compose(); - mBumpEffect = VibrationEffect.startComposition().addPrimitive( - PRIMITIVE_LOW_TICK, DRAG_BUMP_SCALE).compose(); - int primitiveDuration = mVibrator.getPrimitiveDurations( - PRIMITIVE_LOW_TICK)[0]; - - mThresholdUntilNextDragCallMillis = - DRAG_TEXTURE_EFFECT_SIZE * primitiveDuration + 100; - } else { - mDragEffect = null; - mCommitEffect = null; - mBumpEffect = null; - mThresholdUntilNextDragCallMillis = 0; - } } @Override @@ -132,52 +92,11 @@ public class VibratorWrapper implements SafeCloseable { } /** - * This is called when the user swipes to/from all apps. This is meant to be used in between - * long animation progresses so that it gives a dragging texture effect. For a better - * experience, this should be used in combination with vibrateForDragCommit(). - */ - public void vibrateForDragTexture() { - if (mDragEffect == null) { - return; - } - long currentTime = SystemClock.elapsedRealtime(); - long elapsedTimeSinceDrag = currentTime - mLastDragTime; - if (elapsedTimeSinceDrag >= mThresholdUntilNextDragCallMillis) { - vibrate(mDragEffect); - mLastDragTime = currentTime; - } - } - - /** - * This is used when user reaches the commit threshold when swiping to/from from all apps. - */ - public void vibrateForDragCommit() { - if (mCommitEffect != null) { - vibrate(mCommitEffect); - } - // resetting dragTexture timestamp to be able to play dragTexture again - mLastDragTime = 0; - } - - /** - * The bump haptic is used to be called at the end of a swipe and only if it the gesture is a - * FLING going to/from all apps. Client can just call this method elsewhere just for the - * effect. - */ - public void vibrateForDragBump() { - if (mBumpEffect != null) { - vibrate(mBumpEffect); - } - } - - /** * This should be used to cancel a haptic in case where the haptic shouldn't be vibrating. For * example, when no animation is happening but a vibrator happens to be vibrating still. */ public void cancelVibrate() { UI_HELPER_EXECUTOR.execute(mVibrator::cancel); - // reset dragTexture timestamp to be able to play dragTexture again whenever cancelled - mLastDragTime = 0; } /** Vibrates with the given effect if haptic feedback is available and enabled. */ @@ -208,7 +127,7 @@ public class VibratorWrapper implements SafeCloseable { /** 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) @@ -217,13 +136,4 @@ public class VibratorWrapper implements SafeCloseable { vibrate(primitiveLowTickEffect); } } - - static VibrationEffect getDragEffect() { - VibrationEffect.Composition dragEffect = VibrationEffect.startComposition(); - for (int i = 0; i < DRAG_TEXTURE_EFFECT_SIZE; i++) { - dragEffect.addPrimitive( - PRIMITIVE_LOW_TICK, DRAG_TEXTURE_SCALE); - } - return dragEffect.compose(); - } } diff --git a/src/com/android/launcher3/util/WallpaperColorHints.kt b/src/com/android/launcher3/util/WallpaperColorHints.kt index 1361c1ed21..11d4c25689 100644 --- a/src/com/android/launcher3/util/WallpaperColorHints.kt +++ b/src/com/android/launcher3/util/WallpaperColorHints.kt @@ -23,7 +23,6 @@ import android.app.WallpaperManager.OnColorsChangedListener 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 @@ import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR 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 - ) - } - onClose = SafeCloseable { - UI_HELPER_EXECUTOR.execute { - wallpaperManager.removeOnColorsChangedListener(onColorsChangedListener) - } + 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 @@ class WallpaperColorHints(private val context: Context) : SafeCloseable { @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 0817c0ab78..84b4a36399 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.deltaRotation; 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.Insets; 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.NonNull; 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; @@ -122,6 +119,20 @@ public class WindowManagerProxy implements ResourceBasedOverride, SafeCloseable } /** + * Returns if the pinned taskbar should be shown when home is visible. + */ + public boolean showLockedTaskbarOnHome(Context displayInfoContext) { + return false; + } + + /** + * Returns if the home is visible. + */ + public boolean isHomeVisible(Context context) { + return false; + } + + /** * Returns the real bounds for the provided display after applying any insets normalization */ public WindowBounds getRealBounds(Context displayInfoContext, CachedDisplayInfo info) { @@ -216,7 +227,7 @@ public class WindowManagerProxy implements ResourceBasedOverride, SafeCloseable int screenWidthPx, @NonNull WindowInsets windowInsets, @NonNull WindowInsets.Builder insetsBuilder) { - if (!isLargeScreen || !Utilities.ATLEAST_S) { + if (!isLargeScreen) { return; } @@ -391,25 +402,16 @@ public class WindowManagerProxy implements ResourceBasedOverride, SafeCloseable /** * 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, @@ -478,8 +480,7 @@ public class WindowManagerProxy implements ResourceBasedOverride, SafeCloseable } } } - return Utilities.ATLEAST_S ? NavigationMode.NO_BUTTON : - NavigationMode.THREE_BUTTONS; + return NavigationMode.NO_BUTTON; } @Override diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index 4ee6affcb2..6739387cf9 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -253,11 +253,14 @@ public class FloatingIconView extends FrameLayout implements public static void getLocationBoundsForView(Launcher launcher, View v, boolean isOpening, RectF outRect, Rect outViewBounds) { boolean ignoreTransform = !isOpening; - if (v instanceof BubbleTextHolder) { - v = ((BubbleTextHolder) v).getBubbleText(); + if (v instanceof DeepShortcutView dsv) { + v = dsv.getIconView(); ignoreTransform = false; - } else if (v.getParent() instanceof DeepShortcutView) { - v = ((DeepShortcutView) v.getParent()).getIconView(); + } else if (v.getParent() instanceof DeepShortcutView dsv) { + v = dsv.getIconView(); + ignoreTransform = false; + } else if (v instanceof BubbleTextHolder bth) { + v = bth.getBubbleText(); ignoreTransform = false; } if (v == null) { @@ -298,10 +301,10 @@ public class FloatingIconView extends FrameLayout implements Drawable badge = null; if (info instanceof SystemShortcut) { - if (originalView instanceof ImageView) { - drawable = ((ImageView) originalView).getDrawable(); - } else if (originalView instanceof DeepShortcutView) { - drawable = ((DeepShortcutView) originalView).getIconView().getBackground(); + if (originalView instanceof ImageView iv) { + drawable = iv.getDrawable(); + } else if (originalView instanceof DeepShortcutView dsv) { + drawable = dsv.getIconView().getBackground(); } else { drawable = originalView.getBackground(); } diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java index 7fa751772e..5f8e2c0973 100644 --- a/src/com/android/launcher3/views/FloatingSurfaceView.java +++ b/src/com/android/launcher3/views/FloatingSurfaceView.java @@ -15,7 +15,6 @@ */ package com.android.launcher3.views; -import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.views.FloatingIconView.getLocationBoundsForView; import static com.android.launcher3.views.FloatingIconViewCompanion.setPropertiesVisible; @@ -160,7 +159,7 @@ public class FloatingSurfaceView extends AbstractFloatingView implements if (mContract == null) { return; } - View icon = mLauncher.getFirstMatchForAppClose(NO_MATCHING_ID, + View icon = mLauncher.getFirstMatchForAppClose(null /* StableViewInfo */, mContract.componentName.getPackageName(), mContract.user, false /* supportsAllAppsState */); diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index 62eed5c545..82cc40d93b 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -15,8 +15,6 @@ */ package com.android.launcher3.views; -import static androidx.core.content.ContextCompat.getColorStateList; - import static com.android.launcher3.BuildConfig.WIDGETS_ENABLED; import static com.android.launcher3.LauncherState.EDIT_MODE; import static com.android.launcher3.config.FeatureFlags.MULTI_SELECT_EDIT_MODE; @@ -147,8 +145,7 @@ public class OptionsPopupView<T extends Context & ActivityContext> extends Arrow @Override public void assignMarginsAndBackgrounds(ViewGroup viewGroup) { - assignMarginsAndBackgrounds(viewGroup, - getColorStateList(getContext(), mColorIds[0]).getDefaultColor()); + assignMarginsAndBackgrounds(viewGroup, mColors[0]); // last shortcut doesn't need bottom margin final int count = viewGroup.getChildCount() - 1; for (int i = 0; i < count; i++) { diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java index 63648dd348..6fd18beb1c 100644 --- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java +++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java @@ -355,7 +355,10 @@ public class RecyclerViewFastScroller extends View { if (!sectionName.equals(mPopupSectionName)) { mPopupSectionName = sectionName; mPopupView.setText(sectionName); - performHapticFeedback(CLOCK_TICK); + // AllApps haptics are taken care of by AllAppsFastScrollHelper. + if (mFastScrollerLocation != ALL_APPS_SCROLLER) { + performHapticFeedback(CLOCK_TICK); + } } animatePopupVisibility(!TextUtils.isEmpty(sectionName)); mLastTouchY = boundedY; diff --git a/src/com/android/launcher3/views/SpringRelativeLayout.java b/src/com/android/launcher3/views/SpringRelativeLayout.java index 923eb19d3b..a13152ec76 100644 --- a/src/com/android/launcher3/views/SpringRelativeLayout.java +++ b/src/com/android/launcher3/views/SpringRelativeLayout.java @@ -25,8 +25,6 @@ import androidx.annotation.NonNull; 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 class SpringRelativeLayout extends RelativeLayout { 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 856f4b36b6..12a14c2d0e 100644 --- a/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java +++ b/src/com/android/launcher3/widget/BaseLauncherAppWidgetHostView.java @@ -104,7 +104,7 @@ public abstract class BaseLauncherAppWidgetHostView extends NavigableAppWidgetHo @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 2817299d4a..ab42839e20 100644 --- a/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java +++ b/src/com/android/launcher3/widget/DatabaseWidgetPreviewLoader.java @@ -183,19 +183,14 @@ public class DatabaseWidgetPreviewLoader { // Draw horizontal and vertical lines to represent individual columns. final Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); - - 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); - } + 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); 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 3e4fd8caa8..e77ba249bd 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 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo 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 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo cellSize.y)); } - if (ATLEAST_S) { - // 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; - } + // 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; } // If minSpanX/Y > spanX/Y, ignore the minSpanX/Y to match the behavior described in @@ -213,8 +207,7 @@ public class LauncherAppWidgetProviderInfo extends AppWidgetProviderInfo } 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 8857774922..130d533ca4 100644 --- a/src/com/android/launcher3/widget/PendingItemDragHelper.java +++ b/src/com/android/launcher3/widget/PendingItemDragHelper.java @@ -136,9 +136,7 @@ public class PendingItemDragHelper extends DragPreviewProvider { 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 2e5e251f01..cadaf89ef0 100644 --- a/src/com/android/launcher3/widget/RoundedCornerEnforcement.java +++ b/src/com/android/launcher3/widget/RoundedCornerEnforcement.java @@ -28,8 +28,6 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.launcher3.R; -import com.android.launcher3.Utilities; -import com.android.launcher3.config.FeatureFlags; import java.util.ArrayList; import java.util.List; @@ -71,11 +69,6 @@ public class RoundedCornerEnforcement { 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 && FeatureFlags.ENABLE_ENFORCED_ROUNDED_CORNERS.get(); - } - /** * Computes the rounded rectangle needed for this app widget. * @@ -102,9 +95,6 @@ public class RoundedCornerEnforcement { * 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/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java index d3296741cf..f4b99a0e81 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java +++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java @@ -27,6 +27,7 @@ import static com.android.launcher3.widget.picker.model.data.WidgetPickerDataUti import android.content.Context; import android.graphics.Rect; import android.os.Process; +import android.os.UserHandle; import android.util.AttributeSet; import android.view.Gravity; import android.view.LayoutInflater; @@ -342,14 +343,9 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { false); mSuggestedWidgetsHeader.setExpanded(true); - PackageItemInfo packageItemInfo = new PackageItemInfo( + PackageItemInfo packageItemInfo = new HighresPackageItemInfo( /* packageName= */ SUGGESTIONS_PACKAGE_NAME, - Process.myUserHandle()) { - @Override - public boolean usingLowResIcon() { - return false; - } - }; + Process.myUserHandle()); String suggestionsHeaderTitle = getContext().getString( R.string.suggested_widgets_header_title); String suggestionsRightPaneTitle = getContext().getString( @@ -664,4 +660,15 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { */ public boolean showAllWidgets = false; } + + private static class HighresPackageItemInfo extends PackageItemInfo { + HighresPackageItemInfo(String packageName, UserHandle user) { + super(packageName, user); + } + + @Override + public boolean usingLowResIcon() { + return false; + } + } } diff --git a/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java index 4d7f93701e..63d87e8684 100644 --- a/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java +++ b/src_no_quickstep/com/android/launcher3/dagger/LauncherAppComponent.java @@ -18,12 +18,10 @@ package com.android.launcher3.dagger; import dagger.Component; -import javax.inject.Singleton; - /** * Root component for Dagger injection for Launcher AOSP. */ -@Singleton +@LauncherAppSingleton @Component public interface LauncherAppComponent extends LauncherBaseAppComponent { /** Builder for aosp LauncherAppComponent. */ diff --git a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java index a940774ff0..eaa9ef0b20 100644 --- a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java +++ b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java @@ -49,6 +49,8 @@ public interface LauncherOverlayManager { default void onActivityDestroyed() { } + default void onDisallowSwipeToMinusOnePage() {} + /** * @deprecated use LauncherOverlayTouchProxy directly */ diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java index ea58136385..d7dd40bb7f 100644 --- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java +++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java @@ -170,7 +170,7 @@ public final class TestProtocol { public static final String UIOBJECT_STALE_ELEMENT = "b/319501259"; public static final String TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE = "b/326908466"; public static final String WIDGET_CONFIG_NULL_EXTRA_INTENT = "b/324419890"; - public static final String OVERVIEW_SELECT_TOOLTIP_MISALIGNED = "b/332485341"; + public static final String REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW = "enable-grid-only-overview"; public static final String REQUEST_FLAG_ENABLE_APP_PAIRS = "enable-app-pairs"; diff --git a/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTests.kt b/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTest.kt index ac2c553634..d2103aeeac 100644 --- a/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTests.kt +++ b/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTest.kt @@ -31,7 +31,7 @@ import org.junit.Test import org.junit.runner.RunWith @RunWith(AndroidJUnit4::class) -class FloatingHeaderViewTests { +class FloatingHeaderViewTest { @get:Rule val mSetFlagsRule = SetFlagsRule() diff --git a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt index 41effa2f01..d2cce12650 100644 --- a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt @@ -38,7 +38,10 @@ import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext import com.android.launcher3.util.window.CachedDisplayInfo import com.android.launcher3.util.window.WindowManagerProxy +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 @@ -79,7 +82,7 @@ class DisplayControllerTest { 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 { @@ -111,6 +114,7 @@ class DisplayControllerTest { whenever(windowManagerProxy.getRealBounds(any(), any())).thenAnswer { i -> bounds[i.getArgument<CachedDisplayInfo>(1).rotation] } + whenever(windowManagerProxy.showLockedTaskbarOnHome(any())).thenReturn(false) whenever(windowManagerProxy.getNavigationMode(any())).thenReturn(NavigationMode.NO_BUTTON) // Mock context @@ -134,6 +138,13 @@ class DisplayControllerTest { 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() { @@ -167,7 +178,7 @@ class DisplayControllerTest { @UiThreadTest fun testTaskbarPinning() { whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(true) - displayController.handleInfoChange(display) + displayController.handleInfoChange() verify(displayInfoChangeListener) .onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING)) } @@ -176,8 +187,24 @@ class DisplayControllerTest { @UiThreadTest fun testTaskbarPinningChangeInDesktopMode() { whenever(launcherPrefs.get(TASKBAR_PINNING_IN_DESKTOP_MODE)).thenReturn(false) - displayController.handleInfoChange(display) + displayController.handleInfoChange() + verify(displayInfoChangeListener) + .onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING)) + } + + @Test + @UiThreadTest + fun testTaskbarPinningChangeInLockedTaskbarChange() { + whenever(windowManagerProxy.showLockedTaskbarOnHome(any())).thenReturn(true) + whenever(windowManagerProxy.isHomeVisible(any())).thenReturn(true) + whenever(windowManagerProxy.isInDesktopMode()).thenReturn(false) + whenever(launcherPrefs.get(TASKBAR_PINNING)).thenReturn(false) + DisplayController.enableTaskbarModePreferenceForTests(true) + + assertTrue(displayController.getInfo().isTransientTaskbar()) + displayController.handleInfoChange() verify(displayInfoChangeListener) .onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING)) + assertFalse(displayController.getInfo().isTransientTaskbar()) } } diff --git a/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt index 330c394199..d321e4144a 100644 --- a/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt +++ b/tests/multivalentTests/src/com/android/launcher3/util/VibratorWrapperTest.kt @@ -17,7 +17,6 @@ package com.android.launcher3.util import android.media.AudioAttributes -import android.os.SystemClock import android.os.VibrationEffect import android.os.VibrationEffect.Composition.PRIMITIVE_LOW_TICK import android.os.VibrationEffect.Composition.PRIMITIVE_TICK @@ -35,13 +34,11 @@ import org.mockito.ArgumentCaptor import org.mockito.Captor import org.mockito.Mock import org.mockito.Mockito.any -import org.mockito.Mockito.reset import org.mockito.Mockito.verify import org.mockito.Mockito.`when` import org.mockito.MockitoAnnotations import org.mockito.kotlin.never import org.mockito.kotlin.same -import org.mockito.kotlin.verifyNoMoreInteractions @SmallTest @RunWith(AndroidJUnit4::class) @@ -118,55 +115,6 @@ class VibratorWrapperTest { } @Test - fun vibrate_for_drag_bump() { - underTest.vibrateForDragBump() - - awaitTasksCompleted() - verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS)) - val expectedEffect = - VibrationEffect.startComposition() - .addPrimitive(PRIMITIVE_LOW_TICK, VibratorWrapper.DRAG_BUMP_SCALE) - .compose() - assertThat(vibrationEffectCaptor.value).isEqualTo(expectedEffect) - } - - @Test - fun vibrate_for_drag_commit() { - underTest.vibrateForDragCommit() - - awaitTasksCompleted() - verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS)) - val expectedEffect = - VibrationEffect.startComposition() - .addPrimitive(PRIMITIVE_TICK, VibratorWrapper.DRAG_COMMIT_SCALE) - .compose() - assertThat(vibrationEffectCaptor.value).isEqualTo(expectedEffect) - } - - @Test - fun vibrate_for_drag_texture() { - SystemClock.setCurrentTimeMillis(40000) - - underTest.vibrateForDragTexture() - - awaitTasksCompleted() - verify(vibrator).vibrate(vibrationEffectCaptor.capture(), same(VIBRATION_ATTRS)) - assertThat(vibrationEffectCaptor.value).isEqualTo(VibratorWrapper.getDragEffect()) - } - - @Test - fun vibrate_for_drag_texture_within_time_window_noOp() { - SystemClock.setCurrentTimeMillis(40000) - underTest.vibrateForDragTexture() - awaitTasksCompleted() - reset(vibrator) - - underTest.vibrateForDragTexture() - - verifyNoMoreInteractions(vibrator) - } - - @Test fun haptic_feedback_disabled_no_vibrate() { `when`(vibrator.hasVibrator()).thenReturn(false) underTest = VibratorWrapper(vibrator, settingsCache) diff --git a/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java b/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java index ad2d8c2413..6313cf02f7 100644 --- a/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java +++ b/tests/multivalentTests/src/com/android/launcher3/util/rule/TestStabilityRule.java @@ -47,7 +47,7 @@ public class TestStabilityRule implements TestRule { + ")$"); private static final Pattern PLATFORM_BUILD = Pattern.compile("^(" - + "(?<commandLine>eng\\.[a-z]+\\.[0-9]+\\.[0-9]+)|" + + "(?<commandLine>eng\\..+)|" + "(?<presubmit>P[0-9]+)|" + "(?<postsubmit>[0-9]+)" + ")$"); diff --git a/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt b/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt index 365ad4b0de..5e062d0584 100644 --- a/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt +++ b/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt @@ -35,9 +35,10 @@ class EventWaiter(val eventToWait: TestEvent) { companion object { private const val TAG = "EventWaiter" + private val SIGNAL_TIMEOUT = TimeUnit.SECONDS.toMillis(5) } - fun waitForSignal(timeout: Long = TimeUnit.SECONDS.toMillis(10)) = runBlocking { + fun waitForSignal(timeout: Long = SIGNAL_TIMEOUT) = runBlocking { var status = withTimeoutOrNull(timeout) { deferrable.await() } if (status == null) { status = EventStatus.TIMEOUT diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java index 76c194859d..8fe77acd5a 100644 --- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java +++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java @@ -197,7 +197,6 @@ public class TaplDragTest extends AbstractLauncherUiTest<Launcher> { @PlatinumTest(focusArea = "launcher") @Test @PortraitLandscape - @ScreenRecordRule.ScreenRecord // b/343953783 public void testDragAppIcon() { final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps(); diff --git a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java index dcfcad54c7..f54668cd04 100644 --- a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java +++ b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java @@ -19,19 +19,26 @@ package com.android.launcher3.popup; import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; +import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR; +import static com.android.launcher3.Flags.FLAG_ENABLE_DISMISS_PREDICTION_UNDO; import static com.android.launcher3.Flags.FLAG_ENABLE_PRIVATE_SPACE; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS; import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION; import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_DISMISS_PREDICTION_UNDO; +import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP; import static com.android.launcher3.model.data.WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -50,8 +57,13 @@ import android.view.View; import androidx.test.annotation.UiThreadTest; import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; +import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.R; import com.android.launcher3.allapps.PrivateProfileManager; +import com.android.launcher3.logging.StatsLogManager; +import com.android.launcher3.logging.StatsLogManager.StatsLogger; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.WorkspaceItemInfo; @@ -61,8 +73,9 @@ import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext; import com.android.launcher3.util.LauncherMultivalentJUnit; import com.android.launcher3.util.TestSandboxModelContextWrapper; +import com.android.launcher3.util.TestUtil; import com.android.launcher3.util.UserIconInfo; -import com.android.launcher3.views.BaseDragLayer; +import com.android.launcher3.views.Snackbar; import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider; import com.android.launcher3.widget.picker.model.data.WidgetPickerData; @@ -72,6 +85,7 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Answers; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -88,25 +102,31 @@ public class SystemShortcutTest { private PrivateProfileManager mPrivateProfileManager; private WidgetPickerDataProvider mWidgetPickerDataProvider; private AppInfo mAppInfo; + @Mock UserCache mUserCache; @Mock ApiWrapper mApiWrapper; - @Mock BaseDragLayer mBaseDragLayer; @Mock UserIconInfo mUserIconInfo; @Mock LauncherActivityInfo mLauncherActivityInfo; @Mock ApplicationInfo mApplicationInfo; @Mock Intent mIntent; + @Mock StatsLogManager mStatsLogManager; + @Mock(answer = Answers.RETURNS_SELF) StatsLogger mStatsLogger; @Before public void setUp() { MockitoAnnotations.initMocks(this); mSandboxContext.putObject(UserCache.INSTANCE, mUserCache); mSandboxContext.putObject(ApiWrapper.INSTANCE, mApiWrapper); - mTestContext = new TestSandboxModelContextWrapper(mSandboxContext); - mView = new View(mSandboxContext); - spyOn(mTestContext); + mTestContext = new TestSandboxModelContextWrapper(mSandboxContext) { + @Override + public StatsLogManager getStatsLogManager() { + return mStatsLogManager; + } + }; spyOn(mSandboxContext); - doReturn(mBaseDragLayer).when(mTestContext).getDragLayer(); + doReturn(mStatsLogger).when(mStatsLogManager).logger(); + mView = new View(mTestContext); mItemInfo = new ItemInfo(); LauncherApps mLauncherApps = mSandboxContext.spyService(LauncherApps.class); @@ -114,7 +134,6 @@ public class SystemShortcutTest { when(mLauncherActivityInfo.getApplicationInfo()).thenReturn(mApplicationInfo); when(mUserCache.getUserInfo(any())).thenReturn(mUserIconInfo); - when(mBaseDragLayer.getChildCount()).thenReturn(0); mPrivateProfileManager = mTestContext.getAppsView().getPrivateProfileManager(); spyOn(mPrivateProfileManager); when(mPrivateProfileManager.getProfileUser()).thenReturn(PRIVATE_HANDLE); @@ -168,6 +187,7 @@ public class SystemShortcutTest { } @Test + @DisableFlags(FLAG_ENABLE_DISMISS_PREDICTION_UNDO) public void testDontSuggestAppForPredictedItem() { mAppInfo = new AppInfo(); mAppInfo.componentName = new ComponentName(mTestContext, getClass()); @@ -176,7 +196,36 @@ public class SystemShortcutTest { SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP .getShortcut(mTestContext, mAppInfo, mView); assertNotNull(systemShortcut); - systemShortcut.onClick(mView); + + TestUtil.runOnExecutorSync(MAIN_EXECUTOR, () -> systemShortcut.onClick(mView)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + + verify(mStatsLogger).log(eq(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP)); + assertFalse(AbstractFloatingView.hasOpenView(mTestContext, TYPE_SNACKBAR)); + } + + @Test + @EnableFlags(FLAG_ENABLE_DISMISS_PREDICTION_UNDO) + public void testDontSuggestAppForPredictedItemWithUndo() { + mAppInfo = new AppInfo(); + mAppInfo.componentName = new ComponentName(mTestContext, getClass()); + mAppInfo.container = CONTAINER_HOTSEAT_PREDICTION; + assertTrue(mAppInfo.isPredictedItem()); + SystemShortcut systemShortcut = SystemShortcut.DONT_SUGGEST_APP + .getShortcut(mTestContext, mAppInfo, mView); + assertNotNull(systemShortcut); + + TestUtil.runOnExecutorSync(MAIN_EXECUTOR, () -> systemShortcut.onClick(mView)); + InstrumentationRegistry.getInstrumentation().waitForIdleSync(); + verify(mStatsLogger).log(eq(LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP)); + + // Undo bar shown + Snackbar snackbar = AbstractFloatingView.getOpenView(mTestContext, TYPE_SNACKBAR); + assertNotNull(snackbar); + reset(mStatsLogger); + TestUtil.runOnExecutorSync(MAIN_EXECUTOR, snackbar.findViewById( + R.id.action)::performClick); + verify(mStatsLogger).log(eq(LAUNCHER_DISMISS_PREDICTION_UNDO)); } @Test diff --git a/tests/src/com/android/launcher3/tablet/TaplIsTabletTest.kt b/tests/src/com/android/launcher3/tablet/TaplIsTabletTest.kt new file mode 100644 index 0000000000..a6de6073b8 --- /dev/null +++ b/tests/src/com/android/launcher3/tablet/TaplIsTabletTest.kt @@ -0,0 +1,48 @@ +/* + * 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.tablet + +import android.platform.test.rule.AllowedDevices +import android.platform.test.rule.DeviceProduct +import com.android.launcher3.Launcher +import com.android.launcher3.ui.AbstractLauncherUiTest +import junit.framework.TestCase.assertFalse +import junit.framework.TestCase.assertTrue +import org.junit.Test + +class TaplIsTabletTest : AbstractLauncherUiTest<Launcher>() { + + /** Investigating b/366237798 by isolating and seeing flake rate of mLauncher.isTablet */ + @Test + @AllowedDevices( + DeviceProduct.CF_FOLDABLE, + DeviceProduct.CF_TABLET, + DeviceProduct.TANGORPRO, + DeviceProduct.FELIX, + DeviceProduct.COMET, + ) + fun isTabletShouldBeTrue() { + assertTrue(mLauncher.isTablet) + } + + /** Investigating b/366237798 by isolating and seeing flake rate of mLauncher.isTablet */ + @Test + @AllowedDevices(DeviceProduct.CF_PHONE, DeviceProduct.CHEETAH) + fun isTabletShouldBeFalse() { + assertFalse(mLauncher.isTablet) + } +} diff --git a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java index b2e413de20..b38dd4ba11 100644 --- a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java +++ b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java @@ -45,7 +45,6 @@ import com.android.launcher3.allapps.WorkPausedCard; import com.android.launcher3.allapps.WorkProfileManager; import com.android.launcher3.tapl.LauncherInstrumentation; import com.android.launcher3.util.TestUtil; -import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord; import com.android.launcher3.util.rule.TestStabilityRule.Stability; import org.junit.After; @@ -147,7 +146,6 @@ public class TaplWorkProfileTest extends AbstractLauncherUiTest<Launcher> { // Staging; will be promoted to presubmit if stable @Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) - @ScreenRecord @Test public void toggleWorks() { assumeTrue(mWorkProfileSetupSuccessful); @@ -195,7 +193,6 @@ public class TaplWorkProfileTest extends AbstractLauncherUiTest<Launcher> { } - @ScreenRecord // b/322823478 @Test public void testEdu() { assumeTrue(mWorkProfileSetupSuccessful); diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java index 20c5a25c70..2edd1298de 100644 --- a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java +++ b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java @@ -164,7 +164,6 @@ public class TaplTwoPanelWorkspaceTest extends AbstractLauncherUiTest<Launcher> @Test @PortraitLandscape - @ScreenRecordRule.ScreenRecord // b/352130094 public void testDragIconToPage2() { Workspace workspace = mLauncher.getWorkspace(); @@ -242,7 +241,6 @@ public class TaplTwoPanelWorkspaceTest extends AbstractLauncherUiTest<Launcher> }); } - @ScreenRecordRule.ScreenRecord // b/329935119 @Test @PortraitLandscape public void testEmptyPageDoesNotGetRemovedIfPagePairIsNotEmpty() { diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java index 7c6d684e66..02a862d740 100644 --- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java +++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java @@ -18,6 +18,7 @@ package com.android.launcher3.tapl; import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE; +import android.graphics.Point; import android.util.Log; import android.widget.TextView; @@ -129,6 +130,14 @@ public abstract class AppIcon extends Launchable { } /** + * @return the center coordinates of the icon + */ + @NonNull + public Point getVisibleCenter() { + return getObject().getVisibleCenter(); + } + + /** * Create a regular expression pattern that matches strings containing all of the non-whitespace * characters of the app name, with any amount of whitespace added between characters (e.g. * newline for multiline app labels). diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index d3c423e30e..21e93c5e03 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -55,6 +55,7 @@ import android.os.DeadObjectException; import android.os.Parcelable; import android.os.RemoteException; import android.os.SystemClock; +import android.os.Trace; import android.text.TextUtils; import android.util.Log; import android.view.InputDevice; @@ -524,16 +525,19 @@ public final class LauncherInstrumentation { Closable addContextLayer(String piece) { mDiagnosticContext.addLast(piece); + Trace.beginSection("Context: " + piece); log("Entering context: " + piece); return () -> { + Trace.endSection(); log("Leaving context: " + piece); mDiagnosticContext.removeLast(); }; } public void dumpViewHierarchy() { - final ByteArrayOutputStream stream = new ByteArrayOutputStream(); try { + Trace.beginSection("dumpViewHierarchy"); + final ByteArrayOutputStream stream = new ByteArrayOutputStream(); mDevice.dumpWindowHierarchy(stream); stream.flush(); stream.close(); @@ -542,6 +546,8 @@ public final class LauncherInstrumentation { } } catch (IOException e) { Log.e(TAG, "error dumping XML to logcat", e); + } finally { + Trace.endSection(); } } @@ -621,15 +627,20 @@ public final class LauncherInstrumentation { */ public void checkForAnomaly( boolean ignoreNavmodeChangeStates, boolean ignoreOnlySystemUiViews) { - if (mTestAnomalyChecker != null) mTestAnomalyChecker.run(); - - final String systemAnomalyMessage = - getSystemAnomalyMessage(ignoreNavmodeChangeStates, ignoreOnlySystemUiViews); - if (systemAnomalyMessage != null) { - if (mOnFailure != null) mOnFailure.run(); - Assert.fail(formatSystemHealthMessage(formatErrorWithEvents( - "http://go/tapl : Tests are broken by a non-Launcher system error: " - + systemAnomalyMessage, false))); + try { + Trace.beginSection("checkForAnomaly"); + if (mTestAnomalyChecker != null) mTestAnomalyChecker.run(); + + final String systemAnomalyMessage = + getSystemAnomalyMessage(ignoreNavmodeChangeStates, ignoreOnlySystemUiViews); + if (systemAnomalyMessage != null) { + if (mOnFailure != null) mOnFailure.run(); + Assert.fail(formatSystemHealthMessage(formatErrorWithEvents( + "http://go/tapl : Tests are broken by a non-Launcher system error: " + + systemAnomalyMessage, false))); + } + } finally { + Trace.endSection(); } } @@ -1005,16 +1016,20 @@ public final class LauncherInstrumentation { } public void waitForLauncherInitialized() { - for (int i = 0; i < 100; ++i) { - if (getTestInfo( - TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED). - getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD)) { - return; + try { + Trace.beginSection("waitForLauncherInitialized"); + for (int i = 0; i < 100; ++i) { + if (getTestInfo(TestProtocol.REQUEST_IS_LAUNCHER_INITIALIZED).getBoolean( + TestProtocol.TEST_INFO_RESPONSE_FIELD)) { + return; + } + SystemClock.sleep(100); } - SystemClock.sleep(100); + checkForAnomaly(); + fail("Launcher didn't initialize"); + } finally { + Trace.endSection(); } - checkForAnomaly(); - fail("Launcher didn't initialize"); } public boolean isLauncherActivityStarted() { @@ -1259,8 +1274,13 @@ public final class LauncherInstrumentation { } boolean isLauncherVisible() { - mDevice.waitForIdle(); - return hasLauncherObject(getAnyObjectSelector()); + try { + Trace.beginSection("isLauncherVisible"); + mDevice.waitForIdle(); + return hasLauncherObject(getAnyObjectSelector()); + } finally { + Trace.endSection(); + } } boolean isLauncherContainerVisible() { diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java index ab48a211ca..9a8d95244b 100644 --- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java +++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java @@ -282,10 +282,11 @@ public final class OverviewTask { * Returns whether the given String is contained in this Task's contentDescription. Also returns * true if both Strings are null. * - * TODO(b/326565120): remove Nullable support once the bug causing it to be null is fixed. + * TODO(b/342627272): remove Nullable support once the bug causing it to be null is fixed. */ - public boolean containsContentDescription(@Nullable String expected) { - String actual = mTask.getContentDescription(); + public boolean containsContentDescription(@Nullable String expected, + OverviewSplitTask overviewSplitTask) { + String actual = findObjectInTask(overviewSplitTask.snapshotRes).getContentDescription(); if (actual == null && expected == null) { return true; } @@ -295,6 +296,14 @@ public final class OverviewTask { return actual.contains(expected); } + /** + * Returns whether the given String is contained in this Task's contentDescription. Also returns + * true if both Strings are null + */ + public boolean containsContentDescription(@Nullable String expected) { + return containsContentDescription(expected, DEFAULT); + } + private TaskViewType getType() { String resourceName = mTask.getResourceName(); if (resourceName.endsWith("task_view_grouped")) { diff --git a/tests/tapl/com/android/launcher3/tapl/Taskbar.java b/tests/tapl/com/android/launcher3/tapl/Taskbar.java index e6315f3d3b..b4aaab7a5c 100644 --- a/tests/tapl/com/android/launcher3/tapl/Taskbar.java +++ b/tests/tapl/com/android/launcher3/tapl/Taskbar.java @@ -52,7 +52,7 @@ public final class Taskbar { if (!mLauncher.isTransientTaskbar()) { Assert.assertEquals("Persistent taskbar should fill screen width", - getVisibleBounds().width(), mLauncher.getRealDisplaySize().x); + mLauncher.getRealDisplaySize().x, getVisibleBounds().width()); } } |