Merge changes I36871463,I691a5cbb,I62105c1c into sc-v2-dev
* changes:
Update reorder and folder creation radii
Fix misaligned folder creation drag over target
Update CellLayout.DEBUG_VISUALIZE_OCCUPIED to include drag over targets
diff --git a/Android.bp b/Android.bp
index c8d9186..8b7eb54 100644
--- a/Android.bp
+++ b/Android.bp
@@ -152,9 +152,13 @@
],
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"src_shortcuts_overrides/**/*.java",
+ "src_shortcuts_overrides/**/*.kt",
"src_ui_overrides/**/*.java",
+ "src_ui_overrides/**/*.kt",
"ext_tests/src/**/*.java",
+ "ext_tests/src/**/*.kt",
],
resource_dirs: [
"ext_tests/res",
@@ -211,7 +215,10 @@
// Source code used for test helpers
filegroup {
name: "launcher-src-ext-tests",
- srcs: ["ext_tests/src/**/*.java"],
+ srcs: [
+ "ext_tests/src/**/*.java",
+ "ext_tests/src/**/*.kt",
+ ],
}
// Common source files used to build launcher
@@ -219,8 +226,11 @@
name: "launcher-src-no-build-config",
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"src_shortcuts_overrides/**/*.java",
+ "src_shortcuts_overrides/**/*.kt",
"quickstep/src/**/*.java",
+ "quickstep/src/**/*.kt",
],
}
@@ -235,9 +245,13 @@
name: "LauncherGoResLib",
srcs: [
"src/**/*.java",
+ "src/**/*.kt",
"quickstep/src/**/*.java",
+ "quickstep/src/**/*.kt",
"go/src/**/*.java",
+ "go/src/**/*.kt",
"go/quickstep/src/**/*.java",
+ "go/quickstep/src/**/*.kt",
],
resource_dirs: [
"go/res",
@@ -264,16 +278,15 @@
srcs: [
":launcher-src-no-build-config",
],
- resource_dirs: [
- "quickstep/res",
- ],
+ resource_dirs: [],
libs: [
"framework-statsd",
],
static_libs: [
+ "QuickstepResLib",
"SystemUI-statsd",
"SystemUISharedLib",
- "Launcher3CommonDepsLib"
+ "Launcher3CommonDepsLib",
],
manifest: "quickstep/AndroidManifest.xml",
platform_apis: true,
diff --git a/Android.mk b/Android.mk
index c1dbc53..ceaaf13 100644
--- a/Android.mk
+++ b/Android.mk
@@ -105,7 +105,7 @@
LOCAL_SDK_VERSION := system_current
LOCAL_MIN_SDK_VERSION := 26
endif
-LOCAL_STATIC_ANDROID_LIBRARIES := Launcher3CommonDepsLib
+LOCAL_STATIC_ANDROID_LIBRARIES := LauncherGoResLib
LOCAL_SRC_FILES := \
$(call all-java-files-under, src) \
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c72f62d..b838a51 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -50,7 +50,7 @@
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
diff --git a/go/AndroidManifest-launcher.xml b/go/AndroidManifest-launcher.xml
index 6a8f715..2223036 100644
--- a/go/AndroidManifest-launcher.xml
+++ b/go/AndroidManifest-launcher.xml
@@ -49,7 +49,7 @@
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density|uiMode"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
diff --git a/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java b/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java
index 492611f..d4eca2f 100644
--- a/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/GoOverviewActionsView.java
@@ -35,6 +35,7 @@
*/
public class GoOverviewActionsView extends OverviewActionsView<OverlayUICallbacksGo> {
+ @Nullable
private ArrowTipView mArrowTipView;
public GoOverviewActionsView(Context context) {
diff --git a/quickstep/AndroidManifest-launcher.xml b/quickstep/AndroidManifest-launcher.xml
index 6808222..53910e3 100644
--- a/quickstep/AndroidManifest-launcher.xml
+++ b/quickstep/AndroidManifest-launcher.xml
@@ -49,7 +49,7 @@
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 124cd57..0f92274 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -65,7 +65,7 @@
android:stateNotNeeded="true"
android:theme="@style/LauncherTheme"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""/>
diff --git a/quickstep/res/drawable/bg_overview_clear_all_button.xml b/quickstep/res/drawable/bg_overview_clear_all_button.xml
index 47cbd9f..fb014f7 100644
--- a/quickstep/res/drawable/bg_overview_clear_all_button.xml
+++ b/quickstep/res/drawable/bg_overview_clear_all_button.xml
@@ -20,7 +20,7 @@
<item>
<shape android:shape="rectangle"
android:tint="?colorButtonNormal">
- <corners android:radius="18dp" />
+ <corners android:radius="24dp" />
<solid android:color="?androidprv:attr/colorSurface"/>
</shape>
</item>
diff --git a/quickstep/res/drawable/task_menu_item_bg.xml b/quickstep/res/drawable/task_menu_item_bg.xml
index b6a8b90..16c13eb 100644
--- a/quickstep/res/drawable/task_menu_item_bg.xml
+++ b/quickstep/res/drawable/task_menu_item_bg.xml
@@ -15,7 +15,8 @@
limitations under the License.
-->
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
- <solid android:color="?android:attr/colorPrimary"/>
- <corners android:radius="@dimen/task_menu_item_corner_radius"/>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <solid android:color="?androidprv:attr/colorSurface" />
+ <corners android:radius="@dimen/task_menu_item_corner_radius" />
</shape>
diff --git a/quickstep/res/layout/rotate_suggestion.xml b/quickstep/res/layout/rotate_suggestion.xml
new file mode 100644
index 0000000..07cf0c8
--- /dev/null
+++ b/quickstep/res/layout/rotate_suggestion.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2021 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ >
+ <com.android.systemui.shared.rotation.FloatingRotationButtonView
+ android:id="@+id/rotate_suggestion"
+ android:layout_width="@dimen/floating_rotation_button_diameter"
+ android:layout_height="@dimen/floating_rotation_button_diameter"
+ android:paddingStart="@dimen/navigation_key_padding"
+ android:paddingEnd="@dimen/navigation_key_padding"
+ android:layout_gravity="bottom|left"
+ android:scaleType="center"
+ android:visibility="invisible" />
+</FrameLayout>
diff --git a/quickstep/res/layout/task_menu_with_arrow.xml b/quickstep/res/layout/task_menu_with_arrow.xml
new file mode 100644
index 0000000..38573fd
--- /dev/null
+++ b/quickstep/res/layout/task_menu_with_arrow.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.quickstep.views.TaskMenuViewWithArrow
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:animateLayoutChanges="true"
+ android:background="@drawable/task_menu_bg"
+ android:orientation="vertical"
+ android:visibility="invisible">
+
+ <LinearLayout
+ android:id="@+id/menu_option_layout"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:showDividers="middle" />
+
+</com.android.quickstep.views.TaskMenuViewWithArrow>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_view_menu_option.xml b/quickstep/res/layout/task_view_menu_option.xml
index 5978b97..8a8fc36 100644
--- a/quickstep/res/layout/task_view_menu_option.xml
+++ b/quickstep/res/layout/task_view_menu_option.xml
@@ -18,7 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:orientation="vertical"
+ android:orientation="horizontal"
android:paddingTop="@dimen/task_card_menu_option_vertical_padding"
android:paddingBottom="@dimen/task_card_menu_option_vertical_padding"
android:background="@drawable/task_menu_item_bg"
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 459d32a..1185c03 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Skermkiekie"</string>
<string name="action_split" msgid="2098009717623550676">"Verdeel"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Probeer ander program om verdeelde skerm te gebruik"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Program steun nie verdeelde skerm nie."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Jou organisasie laat nie hierdie program toe nie"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Slaan navigasietutoriaal oor?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Jy kan dit later in die <xliff:g id="NAME">%1$s</xliff:g>-program kry"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Kanselleer"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Slaan oor"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Draai skerm"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taakbalkopvoeding het verskyn"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taakbalkopvoeding is toegemaak"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Raak en hou om die taakbalk te versteek"</string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 7961b28..73347df 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"ቅጽበታዊ ገጽ እይታ"</string>
<string name="action_split" msgid="2098009717623550676">"ክፈል"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"የተከፈለ ማያን ለመጠቀም ሌላ መተግበሪያ መታ ያድርጉ"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"መተግበሪያው የተከፈለ ማያ ገጽን አይደግፍም።"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ይህ ድርጊት በመተግበሪያው ወይም በእርስዎ ድርጅት አይፈቀድም"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"የአሰሳ አጋዥ ሥልጠናን ይዝለሉ?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ይህን በኋላ በ<xliff:g id="NAME">%1$s</xliff:g> መተግበሪያው ውስጥ ማግኘት ይችላሉ"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ይቅር"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ዝለል"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"ማያ ገጹን አዙር"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"የተግባር አሞሌ ትምህርት ይታያል"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"የተግባር አሞሌ ትምህርት ተዘግቷል"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"የተግባር አሞሌውን ለመደበቅ ነክተው ይያዙት"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index a293124..553c22f 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"لقطة شاشة"</string>
<string name="action_split" msgid="2098009717623550676">"تقسيم"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"انقر على تطبيق آخر لاستخدام وضع تقسيم الشاشة."</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"التطبيق لا يتيح تقسيم الشاشة."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"لا يسمح التطبيق أو لا تسمح مؤسستك بهذا الإجراء."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"هل تريد تخطي الدليل التوجيهي؟"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"يمكنك العثور على هذا الدليل التوجيهي لاحقًا في التطبيق \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"إلغاء"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"التخطي"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"تدوير الشاشة"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ظهرت لوحة تعليم استخدام شريط المهام."</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"تم إغلاق لوحة تعليم استخدام شريط المهام."</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"انقر مع الاستمرار لإخفاء شريط المهام."</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index cc4347a..1651e4f 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -23,7 +23,7 @@
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"কোনো শেহতীয়া বস্তু নাই"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"এপে ব্যৱহাৰ কৰা ডেটাৰ ছেটিং"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"সকলো মচক"</string>
+ <string name="recents_clear_all" msgid="5328176793634888831">"আটাইবোৰ মচক"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"শেহতীয়া এপসমূহ"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>, <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< ১ মিনিট"</string>
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"স্ক্ৰীনশ্বট"</string>
<string name="action_split" msgid="2098009717623550676">"বিভাজন কৰক"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপত টিপক"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"এপ্টোৱে বিভাজিত স্ক্ৰীন সমৰ্থন নকৰে।"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"এপ্টোৱে অথবা আপোনাৰ প্ৰতিষ্ঠানে এই কাৰ্যটোৰ অনুমতি নিদিয়ে"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"নেভিগেশ্বনৰ টিউট’ৰিয়েল এৰিব বিচাৰে নেকি?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"আপুনি এয়া পাছত <xliff:g id="NAME">%1$s</xliff:g> এপ্টোত বিচাৰিব পাৰিব"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"বাতিল কৰক"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"এৰি যাওক"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"স্ক্ৰীনখন ঘূৰাওক"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"টাস্কবাৰৰ শিক্ষাৰ পেনেলটো প্ৰদর্শিত হৈছে"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"টাস্কবাৰৰ শিক্ষাৰ পেনেলটো বন্ধ হৈছে"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"টাস্কবাৰডাল লুকুৱাবলৈ স্পৰ্শ কৰি ধৰি ৰাখক"</string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index e288b5d..0f302c4 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Skrinşot"</string>
<string name="action_split" msgid="2098009717623550676">"Ayırın"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Bölmə ekranını istifadə etmək üçün başqa tətbiqə toxunun"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Tətbiq ekran bölünməsini dəstəkləmir."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Bu əməliyyata tətbiq və ya təşkilatınız tərəfindən icazə verilmir"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Naviqasiya dərsliyi ötürülsün?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Bunu sonra <xliff:g id="NAME">%1$s</xliff:g> tətbiqində tapa bilərsiniz"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Ləğv edin"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ötürün"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ekranı fırladın"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Tapşırıq panelindəki təlim bölməsi görünür"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Tapşırıq panelindəki təlim bölməsi bağlanıb"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tapşırıq panelini toxunub saxlamaqla gizlədin"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 3ebaa40..0d96cb9 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
<string name="action_split" msgid="2098009717623550676">"Podeli"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Dodirnite drugu aplikaciju za podeljeni ekran"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikacija ne podržava podeljeni ekran."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili organizacija ne dozvoljavaju ovu radnju"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Želite da preskočite vodič za kretanje?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Možete da pronađete ovo kasnije u aplikaciji <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Otkaži"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotirajte ekran"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukativno okno iz trake zadataka se pojavilo"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Edukativno okno iz trake zadataka je zatvoreno"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Dodirnite i zadržite za skrivanje trake zadataka"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index bf21d81..44778be 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Здымак экрана"</string>
<string name="action_split" msgid="2098009717623550676">"Падзелены экран"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Для падзеленага экрана націсніце на іншую праграму"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Праграма не падтрымлівае рэжым падзеленага экрана."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Гэта дзеянне не дазволена праграмай ці вашай арганізацыяй"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Прапусціць дапаможнік па навігацыі?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Знайсці дапаможнік можна ў праграме \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Скасаваць"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Прапусціць"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Павярнуць экран"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"З\'явілася панэль навучання на панэлі задач"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Панэль навучання на панэлі задач закрыта"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Націсніце і ўтрымлівайце, каб схаваць панэль задач"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 659dcb6..5991ce7 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Екранна снимка"</string>
<string name="action_split" msgid="2098009717623550676">"Разделяне на екрана"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Докоснете друго прил., за да ползвате разд. екран"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Приложението не поддържа разделен екран."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Това действие не е разрешено от приложението или организацията ви"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Пропускане на урока за навигиране?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Урокът е налице в приложението <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Отказ"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Пропускане"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Завъртане на екрана"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Показва се урокът за лентата на задачите"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Урокът за лентата на задачите бе затворен"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Докоснете и задръжте, за да скриете лентата на задачите"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index cc8e186..1027853 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"স্ক্রিনশট নিন"</string>
<string name="action_split" msgid="2098009717623550676">"স্প্লিট"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"স্প্লিটস্ক্রিন ব্যবহার করতে অন্য অ্যাপে ট্যাপ করুন"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"স্প্লিট-স্ক্রিনে এই অ্যাপ কাজ করে না।"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"এই অ্যাপ বা আপনার প্রতিষ্ঠান এই অ্যাকশনটি পারফর্ম করার অনুমতি দেয়নি"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"নেভিগেশন টিউটোরিয়াল এড়িয়ে যেতে চান?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"আপনি <xliff:g id="NAME">%1$s</xliff:g> অ্যাপে পরে এটি খুঁজে পাবেন"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"বাতিল করুন"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"এড়িয়ে যান"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"স্ক্রিন ঘোরান"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"টাস্কবার এডুকেশন দেখানো হয়েছে"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"টাস্কবার এডুকেশন বন্ধ করা আছে"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"টাস্কবার লুকানোর জন্য টাচ করে ধরে থাকুন"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index bf2517f..6aee9f9 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
<string name="action_split" msgid="2098009717623550676">"Podijeli"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Dodirnite drugu apl. da koristite podijeljeni ekran"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikacija ne podržava podijeljeni ekran."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Ovu radnju ne dozvoljava aplikacija ili vaša organizacija"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Preskočiti vodič za navigiranje?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"To možete pronaći kasnije u aplikaciji <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Otkaži"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotiranje ekrana"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukacija o programskoj traci je prikazana"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Edukacija o programskoj traci je zatvorena"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Dodirnite i držite da sakrijete programsku traku"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 1b1ed61..a52025c 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
<string name="action_split" msgid="2098009717623550676">"Divideix"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Toca una altra aplicació per dividir la pantalla"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"L\'aplicació no admet la pantalla dividida."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"L\'aplicació o la teva organització no permeten aquesta acció"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vols ometre el tutorial de navegació?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Pots trobar-lo més tard a l\'aplicació <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel·la"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omet"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Gira la pantalla"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Ha aparegut el tauler educatiu de la barra de tasques"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"S\'ha tancat el tauler educatiu de la barra de tasques"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantén premut per amagar la barra de tasques"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index ae2e13f..95f39cc 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Snímek obrazovky"</string>
<string name="action_split" msgid="2098009717623550676">"Rozdělit"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Klepnutím na jinou aplikaci rozdělíte obrazovku"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikace nepodporuje režim rozdělené obrazovky."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikace nebo organizace zakazuje tuto akci"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Přeskočit výukový program k navigaci?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Program později najdete v aplikaci <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Zrušit"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Přeskočit"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Otočit obrazovku"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Zobrazila se výuka k hlavnímu panelu"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Výuka k hlavnímu panelu byla zavřena"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Hlavní panel můžete skrýt podržením"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 26de0c2..eb5b8ee 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Opdel"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Tryk på en anden app for at bruge opdelt skærm"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Appen understøtter ikke opdelt skærm."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller din organisation tillader ikke denne handling"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vil du springe selvstudiet for navigation over?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du kan finde dette senere i appen <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuller"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Spring over"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Roter skærm"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Vejledningen om proceslinjen blev åbnet"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Vejledningen om proceslinjen blev lukket"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Du kan skjule proceslinjen ved at holde fingeren nede"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 494f846..f8c1783 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Teilen"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Für „Bildschirm teilen“ auf weitere App tippen"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"„Bildschirm teilen“ wird von der App nicht unterstützt."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Die App oder deine Organisation lässt diese Aktion nicht zu"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Navigationstutorial überspringen?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du findest es später auch in der <xliff:g id="NAME">%1$s</xliff:g> App"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Abbrechen"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Überspringen"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Bildschirm drehen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Anleitung für Taskleiste eingeblendet"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Anleitung für Taskleiste geschlossen"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Gedrückt halten, um die Taskleiste auszublenden"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index a266ff8..233a1ba 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Στιγμιότυπο οθόνης"</string>
<string name="action_split" msgid="2098009717623550676">"Διαχωρισμός"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Πατήστε άλλη εφαρμογή για χρήση διαχωρισμού οθόνης"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Η εφαρμογή δεν υποστηρίζει διαχωρισμό οθόνης."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Αυτή η ενέργεια δεν επιτρέπεται από την εφαρμογή ή τον οργανισμό σας."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Παράβλεψη οδηγού πλοήγησης;"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Βρείτε τον αργότερα στην εφαρμογή <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Ακύρωση"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Παράβλεψη"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Περιστροφή οθόνης"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Η εκπαίδευση για τη γραμμή εργασιών εμφανίστηκε"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Η εκπαίδευση για τη γραμμή εργασιών έκλεισε"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Αγγίξτε παρατεταμένα για απόκρυψη της γραμμής εργασιών."</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index b787fdf..f4607c7 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Split"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Tap another app to use split-screen"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"App does not support split-screen."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index b787fdf..f4607c7 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Split"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Tap another app to use split-screen"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"App does not support split-screen."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index b787fdf..f4607c7 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Split"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Tap another app to use split-screen"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"App does not support split-screen."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index b787fdf..f4607c7 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Split"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Tap another app to use split-screen"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"App does not support split-screen."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organisation"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index c92af05..92574fe 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Split"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Tap another app to use splitscreen"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"App does not support split-screen."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"This action isn\'t allowed by the app or your organization"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Skip navigation tutorial?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"You can find this later in the <xliff:g id="NAME">%1$s</xliff:g> app"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancel"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Skip"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotate screen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taskbar education appeared"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taskbar education closed"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Touch & hold to hide the taskbar"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 118df33..6aa7a2f 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
<string name="action_split" msgid="2098009717623550676">"Pantalla dividida"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Presiona otra app para usar la pantalla dividida"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"La app no es compatible con la función de pantalla dividida."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"La app o tu organización no permiten realizar esta acción"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"¿Omitir el instructivo de navegación?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Puedes encontrarlo en la app de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omitir"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Girar pantalla"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Se abrió la barra de herramientas Educación"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Se cerró la barra de herramientas Educación"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantén presionado para ocultar la barra de tareas"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 5b2cee9..7c711a5 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Hacer captura"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Toca otra aplicación para usar la pantalla dividida"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"La aplicación no admite la pantalla dividida."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"No puedes hacerlo porque la aplicación o tu organización no lo permiten"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"¿Saltar tutorial de navegación?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Puedes consultarlo en otro momento en la aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Saltar"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Girar la pantalla"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Ha aparecido una nota sobre la barra de tareas"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Nota sobre la barra de tareas cerrada"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantén pulsada la barra de tareas para ocultarla"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 7b2b3da..6f93fb1 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
<string name="action_split" msgid="2098009717623550676">"Eralda"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Jagatud kuva kasutamiseks puudutage muud rakendust"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Rakendus ei toeta jagatud ekraani."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Rakendus või teie organisatsioon on selle toimingu keelanud"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Kas jätta navigeerimise õpetused vahele?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Leiate selle hiljem rakendusest <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Tühista"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Jäta vahele"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Pöörake ekraani"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Tegumiriba juhised kuvati"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Tegumiriba juhised on suletud"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tegumiriba peitmiseks puudutage pikalt"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 8e26e20..5e4d423 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Atera pantaila-argazki bat"</string>
<string name="action_split" msgid="2098009717623550676">"Zatitu"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Sakatu beste aplikazio bat pantaila zatitzeko"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikazioak ez du onartzen pantaila zatitua."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikazioak edo erakundeak ez du eman ekintza hori gauzatzeko baimena"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Nabigazio-tutoriala saltatu nahi duzu?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> aplikazioan dago eskuragarri tutoriala"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Utzi"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Saltatu"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Biratu pantaila"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Agertu egin da zereginen barraren tutoriala"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Itxi egin da zereginen barraren tutoriala"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Zereginen barra ezkutatzeko, eduki ezazu sakatuta"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index c0a805c..c6174a1 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"نماگرفت"</string>
<string name="action_split" msgid="2098009717623550676">"دونیمه"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"برای استفاده از صفحهٔ دونیمه، روی برنامه دیگری ضربه بزنید"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"برنامه از صفحهٔ دونیمه پشتیبانی نمیکند."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"برنامه یا سازمان شما اجازه نمیدهد این کنش انجام شود."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"آموزش گامبهگام پیمایش رد شود؟"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"میتوانید آن را بعداً در برنامه <xliff:g id="NAME">%1$s</xliff:g> پیدا کنید"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"لغو"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"رد شدن"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"چرخاندن صفحه"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"پانل آموزشی نوار وظیفه نمایان شد"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"پانل آموزشی نوار وظیفه بسته شد"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"برای پنهان کردن نوار وظیفه، لمس کنید و نگه دارید"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index e6f6ab1..151ad5c 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Kuvakaappaus"</string>
<string name="action_split" msgid="2098009717623550676">"Jaa"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Avaa jaettu näyttö napauttamalla toista sovellusta"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Sovellus ei tue jaetun näytön tilaa."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Sovellus tai organisaatio ei salli tätä toimintoa"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ohitetaanko navigointiohje?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Löydät tämän myöhemmin sovelluksesta: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Peru"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ohita"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Käännä näyttö"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Tehtäväpalkin ohje näkyvissä"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Tehtäväpalkin ohje suljettu"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Piilota tehtäväpalkki koskettamalla pitkään"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 3b611c4..474b86f 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
<string name="action_split" msgid="2098009717623550676">"Séparé"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Touchez une autre appli pour partager l\'écran"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"L\'appli n\'est pas compatible avec l\'écran partagé."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"L\'application ou votre organisation n\'autorise pas cette action"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ignorer le tutoriel sur la navigation?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Vous trouverez le tutoriel dans l\'application <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuler"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ignorer"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Faire pivoter l\'écran"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"La barre des tâches éducatives s\'est affichée"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"La barre des tâches éducatives est fermée"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Maintenez le doigt sur la barre des tâches pour la masquer"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 6f7149f..ee16bca 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
<string name="action_split" msgid="2098009717623550676">"Partager"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Appuyez sur autre appli pour utiliser écran partagé"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Appli incompatible avec l\'écran partagé."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Cette action n\'est pas autorisée par l\'application ou par votre organisation"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ignorer le tutoriel de navigation ?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Vous le retrouverez dans l\'appli <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuler"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Passer"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Faire pivoter l\'écran"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Infos sur la barre des tâches affichées"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Infos sur la barre des tâches fermées"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Appuyez de manière prolongée pour masquer barre des tâches"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index db28634..aac2076 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Para usar a pantalla dividida, toca outra app"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"A app non admite a función de pantalla dividida."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"A aplicación ou a túa organización non permite realizar esta acción"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Queres omitir o titorial de navegación?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Podes atopar isto máis tarde na aplicación <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omitir"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Xira a pantalla"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Panel de información de barra de tarefas aberto"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Panel de información de barra de tarefas pechado"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantén premida a barra de tarefas para ocultala"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index cc998b4..e943eff 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"સ્ક્રીનશૉટ"</string>
<string name="action_split" msgid="2098009717623550676">"વિભાજિત કરો"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"સ્પલિટસ્ક્રીનના વપરાશ માટે, કોઈ અન્ય ઍપ પર ટૅપ કરો"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ઍપ સ્ક્રીન-વિભાજનને સપોર્ટ કરતી નથી."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ઍપ કે તમારી સંસ્થા દ્વારા આ ક્રિયા કરવાની મંજૂરી નથી"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"નૅવિગેશન ટ્યૂટૉરિઅલ છોડી દઈએ?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"તમે આને પછીથી <xliff:g id="NAME">%1$s</xliff:g> ઍપમાં જોઈ શકો છો"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"રદ કરો"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"છોડો"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"સ્ક્રીન ફેરવો"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ટાસ્કબારનું શિક્ષણ આપતી પૅનલ દેખાય છે"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ટાસ્કબારનું શિક્ષણ આપતી પૅનલ બંધ થઈ છે"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ટાસ્કબાર છુપાવવા, તેને ટચ કરીને થોડીવાર દબાવી રાખો"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index fd06fca..fc4b27a 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट लें"</string>
<string name="action_split" msgid="2098009717623550676">"स्प्लिट स्क्रीन मोड"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"स्प्लिट स्क्रीन मोड के लिए, दूसरे ऐप पर टैप करें"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"यह ऐप्लिकेशन, स्प्लिट स्क्रीन पर काम नहीं करता है."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ऐप्लिकेशन या आपका संगठन इस कार्रवाई की अनुमति नहीं देता"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"नेविगेशन ट्यूटोरियल छोड़ना चाहते हैं?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"आप बाद में <xliff:g id="NAME">%1$s</xliff:g> ऐप्लिकेशन पर इसे देख सकते हैं"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"अभी नहीं"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"अभी नहीं"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"स्क्रीन घुमाएं"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबार ट्यूटोरियल दिखाया गया"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"टास्कबार ट्यूटोरियल बंद किया गया"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"टास्कबार को छिपाने के लिए, उसे दबाकर रखें"</string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index 2b31943..78dd559 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Snimka zaslona"</string>
<string name="action_split" msgid="2098009717623550676">"Podijeli"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Dodirnite drugu aplikaciju za podijeljeni zaslon"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikacija ne podržava podijeljeni zaslon."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ili vaša organizacija ne dopuštaju ovu radnju"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Želite li preskočiti vodič za kretanje?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Kasnije ga možete pronaći u aplikaciji <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Odustani"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Zakretanje zaslona"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Upute za programsku traku su se pojavile"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Upute za programsku traku su zatvorene"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Dodirnite i zadržite da biste sakrili programsku traku"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 06cfb71..c7f68a8 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Képernyőkép"</string>
<string name="action_split" msgid="2098009717623550676">"Felosztás"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Koppintson másik appra a képernyőmegosztáshoz"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Az alkalmazás nem támogatja az osztott képernyőt."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Az alkalmazás vagy az Ön szervezete nem engedélyezi ezt a műveletet"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Kihagyja a navigáció bemutatóját?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Ezt később megtalálhatja a(z) <xliff:g id="NAME">%1$s</xliff:g> alkalmazásban"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Mégse"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Kihagyás"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Képernyő elforgatása"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Az eszköztár használatát ismertető panel megjelent"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Az eszköztár használatát ismertető panel bezárult"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Nyomva tartással elrejthető az eszköztár"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 18a2ddd..c10db3e 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Սքրինշոթ անել"</string>
<string name="action_split" msgid="2098009717623550676">"Տրոհել"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Հպեք այլ հավելվածի՝ էկրանը տրոհելու համար"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Հավելվածը չի աջակցում էկրանի տրոհումը։"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Այս գործողությունն արգելված է հավելվածի կամ ձեր կազմակերպության կողմից"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Բաց թողնե՞լ նավիգացիայի ուղեցույցը"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Հետագայում սա կարող եք գտնել «<xliff:g id="NAME">%1$s</xliff:g>» հավելվածում"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Չեղարկել"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Բաց թողնել"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Պտտել էկրանը"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Խնդրագոտու «Կրթություն» վահանակը բացվեց"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Խնդրագոտու «Կրթություն» վահանակը փակվեց"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Հպեք և պահեք՝ խնդրագոտին թաքցնելու համար"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 5854104..97ddd9d 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Pisahkan"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Ketuk aplikasi lain untuk menggunakan layar terpisah"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikasi tidak mendukung layar terpisah."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak diizinkan oleh aplikasi atau organisasi Anda"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Lewati tutorial navigasi?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Anda dapat menemukan tutorial ini di lain waktu di aplikasi <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Batal"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Lewati"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Putar layar"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukasi taskbar ditampilkan"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Edukasi taskbar ditutup"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Sentuh lama untuk menyembunyikan taskbar"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index c5a47b1..e9bc164 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Skjámynd"</string>
<string name="action_split" msgid="2098009717623550676">"Skipta"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Ýttu á annað forrit til að nota skjáskiptingu"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Forritið styður ekki að skjánum sé skipt."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Forritið eða fyrirtækið leyfir ekki þessa aðgerð"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Sleppa flettileiðsögn?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Þú getur fundið þetta síðar í forritinu <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Hætta við"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Sleppa"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Snúa skjánum"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Leiðsögn verkefnastiku sýnileg"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Leiðsögn verkefnastiku lokað"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Haltu inni til að fela verkefnastikuna"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 2a5b87d..8550d1e 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Dividi"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Tocca un\'altra app per usare lo schermo diviso"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"L\'app non supporta la modalità Schermo diviso."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Questa azione non è consentita dall\'app o dall\'organizzazione"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Saltare il tutorial di navigazione?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Puoi trovarlo in un secondo momento nell\'app <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annulla"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Salta"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ruota lo schermo"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Riquadro Formazione barra delle applicazioni visualizzato"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Riquadro Formazione barra delle applicazioni chiuso"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tocca e tieni premuto per nascondere barra applicazioni"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 467f5b9..e208dd1 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"צילום מסך"</string>
<string name="action_split" msgid="2098009717623550676">"פיצול"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"צריך להקיש על אפליקציה אחרת כדי להשתמש במסך מפוצל"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"האפליקציה אינה תומכת במסך מפוצל."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"האפליקציה או הארגון שלך אינם מתירים את הפעולה הזאת"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"לדלג על המדריך לניווט?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ניתן למצוא את המדריך מאוחר יותר באפליקציה <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ביטול"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"דילוג"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"סיבוב המסך"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"חלונית ההסברים על שורת המשימות מופיעה"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"חלונית ההסברים על שורת המשימות נסגרה"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"כדי להסתיר את שורת המשימות, לוחצים לחיצה ארוכה"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 6b73a9b..b1f0280 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"スクリーンショット"</string>
<string name="action_split" msgid="2098009717623550676">"分割"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"分割画面を使用するには、他のアプリをタップします"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"アプリで分割画面がサポートされていません。"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"この操作はアプリまたは組織で許可されていません"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"操作チュートリアルをスキップしますか?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"チュートリアルは後から <xliff:g id="NAME">%1$s</xliff:g> アプリで確認できます"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"キャンセル"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"スキップ"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"画面を回転"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"タスクバーの説明を開きました"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"タスクバーの説明を閉じました"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"タスクバーを長押しすると非表示になります"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 22ead5c..5a1cc6d 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"ეკრანის ანაბეჭდი"</string>
<string name="action_split" msgid="2098009717623550676">"გაყოფა"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"შეეხეთ სხვა აპს ეკრანის გასაყოფად"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ეკრანის გაყოფა არ არის მხარდაჭერილი აპის მიერ."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ეს მოქმედება არ არის დაშვებული აპის ან თქვენი ორგანიზაციის მიერ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"გსურთ, გამოტოვოთ ნავიგაციის სახელმძღვანელო?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ამის მოგვიანებით პოვნა <xliff:g id="NAME">%1$s</xliff:g> აპში შეგიძლიათ"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"გაუქმება"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"გამოტოვება"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"ეკრანის შეტრიალება"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ამოცანების ზოლის სასწავლო არე გამოჩნდა"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ამოცანების ზოლის სასწავლო არე დაიხურა"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ხანგრძლივად შეეხეთ ამოცანების ზოლის დასამალად"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index cd86af4..390daa1 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="action_split" msgid="2098009717623550676">"Бөлу"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Экранды бөлу режимін пайдалану үшін басқа қолданбаны түртіңіз."</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Қолданбада экранды бөлу мүмкін емес."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Бұл әрекетке қолданба не ұйым рұқсат етпейді."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Қимылдар оқулығын өткізіп жіберу керек пе?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Мұны кейін <xliff:g id="NAME">%1$s</xliff:g> қолданбасынан таба аласыз."</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Бас тарту"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Өткізіп жіберу"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Экранды бұру"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Тапсырмалар тақтасы бойынша нұсқаулық ашылды."</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Тапсырмалар тақтасы бойынша нұсқаулық жабылды."</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Тапсырмалар тақтасын жасыру үшін басып тұрыңыз."</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 1e677c2..b2702db 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"រូបថតអេក្រង់"</string>
<string name="action_split" msgid="2098009717623550676">"បំបែក"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"ចុចកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"កម្មវិធីមិនអាចប្រើមុខងារបំបែកអេក្រង់បានទេ។"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"សកម្មភាពនេះមិនត្រូវបានអនុញ្ញាតដោយកម្មវិធី ឬស្ថាប័នរបស់អ្នកទេ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"រំលងមេរៀនអំពីការរុករកឬ?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"អ្នកអាចស្វែងរកមេរៀននេះនៅពេលក្រោយក្នុងកម្មវិធី <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"បោះបង់"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"រំលង"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"បង្វិលអេក្រង់"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ការបង្រៀនអំពីរបារកិច្ចការបានបង្ហាញ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ការបង្រៀនអំពីរបារកិច្ចការត្រូវបានបិទ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ចុចឱ្យជាប់ ដើម្បីលាក់របារកិច្ចការ"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index fa3f1f6..6c27841 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string>
<string name="action_split" msgid="2098009717623550676">"ವಿಭಜಿಸಿ"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಬಳಸಲು ಬೇರೊಂದು ಆ್ಯಪ್ ಮೇಲೆ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಅನ್ನು ಆ್ಯಪ್ ಬೆಂಬಲಿಸುವುದಿಲ್ಲ."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ಆ್ಯಪ್ ಅಥವಾ ನಿಮ್ಮ ಸಂಸ್ಥೆಯು ಈ ಕ್ರಿಯೆಯನ್ನು ಅನುಮತಿಸುವುದಿಲ್ಲ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ನ್ಯಾವಿಗೇಷನ್ ಟ್ಯುಟೋರಿಯಲ್ ಸ್ಕಿಪ್ ಮಾಡಿ?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> ಆ್ಯಪ್ನಲ್ಲಿ ಇದನ್ನು ನಂತರ ಕಾಣಬಹುದು"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ರದ್ದುಮಾಡಿ"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ಸ್ಕಿಪ್ ಮಾಡಿ"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"ಸ್ಕ್ರೀನ್ ತಿರುಗಿಸಿ"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ಟಾಸ್ಕ್ಬಾರ್ ಶಿಕ್ಷಣ ಕಾಣಿಸಿಕೊಂಡಿದೆ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ಟಾಸ್ಕ್ಬಾರ್ ಶಿಕ್ಷಣ ಮುಚ್ಚಿದೆ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ಟಾಸ್ಕ್ಬಾರ್ ಅನ್ನು ಮರೆಮಾಡಲು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 085f194..e31112e 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"스크린샷"</string>
<string name="action_split" msgid="2098009717623550676">"분할"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"다른 앱을 탭하여 화면 분할 사용"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"앱이 화면 분할을 지원하지 않습니다."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"이 작업은 앱 또는 조직에서 허용되지 않습니다."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"이동 방법 튜토리얼을 건너뛰시겠습니까?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"이 튜토리얼은 <xliff:g id="NAME">%1$s</xliff:g> 앱에서 다시 볼 수 있습니다"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"취소"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"건너뛰기"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"화면 회전"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"작업 표시줄 튜토리얼 패널 표시됨"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"작업 표시줄 튜토리얼 패널 닫힘"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"작업 표시줄을 숨기려면 길게 터치하세요."</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index ba23770..ae00943 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="action_split" msgid="2098009717623550676">"Бөлүү"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Экранды бөлүү үчүн башка колдонмону таптап коюңуз"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Колдонмодо экран бөлүнбөйт."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Бул аракетти аткарууга колдонмо же ишканаңыз тыюу салган"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Жаңсоолор үйрөткүчүн өткөрүп жибересизби?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Аны кийин <xliff:g id="NAME">%1$s</xliff:g> колдонмосунан табасыз"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Жокко чыгаруу"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Өткрп жиберүү"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Экранды буруу"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Тапшырмалар тактасынын окутуу панели көрсөтүлдү"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Тапшырмалар тактасынын окутуу панели жабылды"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Тапшырмалар тактасын жашыруу үчүн коё бербей басып туруңуз"</string>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 796de14..e2eef9d 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"ຮູບໜ້າຈໍ"</string>
<string name="action_split" msgid="2098009717623550676">"ແບ່ງ"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"ແຕະແອັບອື່ນເພື່ອໃຊ້ການແຍກໜ້າຈໍ"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ແອັບບໍ່ຮອງຮັບການແບ່ງໜ້າຈໍ."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ແອັບ ຫຼື ອົງການຂອງທ່ານບໍ່ອະນຸຍາດໃຫ້ໃຊ້ຄຳສັ່ງນີ້"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ຂ້າມການສອນການນຳໃຊ້ການນຳທາງບໍ?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ທ່ານສາມາດຊອກສ່ວນນີ້ພາຍຫຼັງໄດ້ໃນແອັບ <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ຍົກເລີກ"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ຂ້າມ"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"ໝຸນໜ້າຈໍ"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ສະແດງການສຶກສາແຖບໜ້າວຽກແລ້ວ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ປິດການສຶກສາແຖບໜ້າວຽກແລ້ວ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ແຕະຄ້າງໄວ້ເພື່ອເຊື່ອງແຖບໜ້າວຽກ"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index e20a780..8c27487 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Ekrano kopija"</string>
<string name="action_split" msgid="2098009717623550676">"Išskaidymo režimas"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Pal. kitą progr., kad gal. naud. išsk. ekr. rež."</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Programoje nepalaikomas išskaidyto ekrano režimas."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Jūsų organizacijoje arba naudojant šią programą neleidžiama atlikti šio veiksmo"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Praleisti naršymo mokymo programą?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Tai galėsite rasti vėliau programoje „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Atšaukti"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Praleisti"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Pasukti ekraną"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Užduočių juostos patarimai rodomi"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Užduočių juostos patarimai uždaryti"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Palieskite ir palaikykite, kad paslėptumėte užduočių juostą"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 148102f..be70bf5 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Veikt ekrānuzņēmumu"</string>
<string name="action_split" msgid="2098009717623550676">"Sadalīt"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Piesk. citai lietotnei, lai izm. ekrāna sadalīšanu"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Lietotnē netiek atbalstīta ekrāna sadalīšana."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Lietotne vai jūsu organizācija neatļauj veikt šo darbību."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vai izlaist navigācijas mācības?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Varēsiet to vēlāk atrast lietotnē <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Atcelt"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Izlaist"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Pagriezt ekrānu"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Tika atvērta uzdevumjoslas apmācība"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Tika aizvērta uzdevumjoslas apmācība"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Pieskarieties un turiet, lai paslēptu uzdevumjoslu."</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index e1bc7a6..2806746 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Слика од екранот"</string>
<string name="action_split" msgid="2098009717623550676">"Раздели"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Допрете друга апликација за да користите поделен екран"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Апликацијата не поддржува поделен екран."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Апликацијата или вашата организација не го дозволува дејствово"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Да се прескокне упатството за навигација?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Ова може да го најдете подоцна во апликацијата <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Откажи"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Прескокни"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ротирајте го екранот"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Се појави лентата за задачи за образование"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Затворена е лентата за задачи за образование"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Допрете и задржете за да се сокрие лентата за задачи"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 7342c3c..1794aec 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"സ്ക്രീൻഷോട്ട്"</string>
<string name="action_split" msgid="2098009717623550676">"വിഭജിക്കുക"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"സ്പ്ലിറ്റ് സ്ക്രീനിനായി മറ്റൊരു ആപ്പ് ടാപ്പുചെയ്യൂ"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"സ്പ്ലിറ്റ്-സ്ക്രീനിനെ ആപ്പ് പിന്തുണയ്ക്കുന്നില്ല."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ഈ നടപടി എടുക്കുന്നത് ആപ്പോ നിങ്ങളുടെ സ്ഥാപനമോ അനുവദിക്കുന്നില്ല"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"നാവിഗേഷൻ ട്യൂട്ടോറിയൽ ഒഴിവാക്കണോ?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> ആപ്പിൽ നിങ്ങൾക്ക് ഇത് പിന്നീട് കാണാനാകും"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"റദ്ദാക്കുക"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ഒഴിവാക്കുക"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"സ്ക്രീൻ റൊട്ടേറ്റ് ചെയ്യുക"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ടാസ്ക്ക്ബാർ വിവര പാനൽ ദൃശ്യമായി"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ടാസ്ക്ക്ബാർ വിവര പാനൽ അടച്ചു"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ടാസ്ക്ക്ബാർ മറയ്ക്കാൻ സ്പർശിച്ച് പിടിക്കുക"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 78ddb56..c8d614b 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Дэлгэцийн агшин дарах"</string>
<string name="action_split" msgid="2098009717623550676">"Хуваах"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Дэлгэц хуваахыг ашиглах бол өөр аппыг товшино уу"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Апп дэлгэцийг хуваах горимыг дэмждэггүй."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Энэ үйлдлийг апп эсвэл танай байгууллага зөвшөөрдөггүй"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Навигацын практик хичээлийг алгасах уу?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Та үүнийг дараа нь <xliff:g id="NAME">%1$s</xliff:g> аппаас олох боломжтой"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Цуцлах"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Алгасах"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Дэлгэцийг эргүүлэх"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Боловсролын ажлын талбар гарч ирсэн"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Боловсролын ажлын талбарыг хаасан"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Ажлын талбарыг нуухын тулд хүрээд удаан дарна уу"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index df94447..7540a5d 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट"</string>
<string name="action_split" msgid="2098009717623550676">"स्प्लिट"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"स्प्लिटस्क्रीन वापरण्यासाठी दुसऱ्या ॲपवर टॅप करा"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"अॅप हे स्प्लिट-स्क्रीनला सपोर्ट करत नाही."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"अॅप किंवा तुमच्या संस्थेद्वारे ही क्रिया करण्याची अनुमती नाही"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"नेव्हिगेशन ट्यूटोरियल वगळायचे आहे का?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"तुम्हाला हे नंतर <xliff:g id="NAME">%1$s</xliff:g> ॲपमध्ये मिळेल"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"रद्द करा"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"वगळा"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"स्क्रीन फिरवा"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबारशी संबंधित माहिती देणारे पॅनल उघडले आहे"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"टास्कबारशी संबंधित माहिती देणारे पॅनल बंद केले आहे"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"टास्कबार लपवण्यासाठी स्पर्श करा आणि धरून ठेवा"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index ba7a15e..9ea6e22 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Tangkapan skrin"</string>
<string name="action_split" msgid="2098009717623550676">"Pisah"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Ketik apl lain untuk menggunakan skrin pisah"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Apl tidak menyokong skrin pisah."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Tindakan ini tidak dibenarkan oleh apl atau organisasi anda"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Langkau tutorial navigasi?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Anda boleh mendapatkan tutorial ini kemudian dalam apl <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Batal"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Langkau"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Putar skrin"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Pendidikan bar tugas muncul"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Pendidikan bar tugas ditutup"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Sentuh & tahan untuk menyembunyikan bar tugas"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 17cd498..a8ccfb0 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -23,7 +23,7 @@
<string name="recent_task_option_freeform" msgid="48863056265284071">"အလွတ်ပုံစံ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"အက်ပ်အသုံးပြုမှု ဆက်တင်များ"</string>
- <string name="recents_clear_all" msgid="5328176793634888831">"အားလုံးထုတ်ပစ်ရန်"</string>
+ <string name="recents_clear_all" msgid="5328176793634888831">"အားလုံးရှင်းရန်"</string>
<string name="accessibility_recent_apps" msgid="4058661986695117371">"လတ်တလောသုံး အက်ပ်များ"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g>၊ <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< ၁ မိနစ်"</string>
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
<string name="action_split" msgid="2098009717623550676">"ခွဲထုတ်ရန်"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"မျက်နှာပြင်ခွဲ၍ပြသရန် အက်ပ်နောက်တစ်ခုကို တို့ပါ"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"အက်ပ်တွင် မျက်နှာပြင် ခွဲ၍ပြသခြင်း သုံး၍မရပါ။"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ဤလုပ်ဆောင်ချက်ကို အက်ပ် သို့မဟုတ် သင်၏အဖွဲ့အစည်းက ခွင့်မပြုပါ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"လမ်းညွှန်ခြင်း ရှင်းလင်းပို့ချချက်ကို ကျော်မလား။"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"၎င်းကို နောက်မှ <xliff:g id="NAME">%1$s</xliff:g> အက်ပ်တွင် ရှာနိုင်သည်"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"မလုပ်တော့"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ကျော်ရန်"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"ဖန်သားပြင်လှည့်ရန်"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ပညာရေး လုပ်ဆောင်စရာဘား ပြထားသည်"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ပညာရေး လုပ်ဆောင်စရာဘား ပိတ်ထားသည်"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"လုပ်ဆောင်စရာဘားကို ဖျောက်ရန် ထိပြီးဖိထားနိုင်သည်"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 6e43cfb..fe3e2e4 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Skjermdump"</string>
<string name="action_split" msgid="2098009717623550676">"Del opp"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Trykk på en annen app for å bruke delt skjerm"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Appen støtter ikke delt skjerm."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisasjonen din tillater ikke denne handlingen"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vil du hoppe over navigeringsveiledning?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du kan finne dette i <xliff:g id="NAME">%1$s</xliff:g>-appen senere"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Avbryt"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Hopp over"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotér skjermen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Opplæringen for oppgavelinjen vises"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Opplæringen for oppgavelinjen er lukket"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Trykk og hold for å skjule oppgavelinjen"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index f827bcc..09ef075 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रिनसट"</string>
<string name="action_split" msgid="2098009717623550676">"स्प्लिट गर्नुहोस्"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"स्प्लिटक्रिन प्रयोग गर्न अर्को एपमा ट्याप गर्नुहोस्"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"यो एपको स्क्रिन विभाजन गर्न मिल्दैन।"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"यो एप वा तपाईंको सङ्गठनले यो कारबाही गर्ने अनुमति दिँदैन"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"नेभिगेसन ट्युटोरियल स्किप गर्ने हो?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"तपाईं पछि <xliff:g id="NAME">%1$s</xliff:g> नामक एपमा गई यो ट्युटोरियल भेट्टाउन सक्नुहुन्छ"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"रद्द गर्नुहोस्"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"स्किप गर्नु…"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"स्क्रिन घुमाउनुहोस्"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"टास्कबार एजुकेसन देखिएको छ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"टास्कबार एजुकेसन बन्द गरिएको छ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"टास्कबार लुकाउन टास्कबार थिचिराख्नुहोस्"</string>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 81cda4d..be68c2c 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Splitsen"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Tik op nog een app om je scherm te splitsen"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"App ondersteunt geen gesplitst scherm."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Deze actie wordt niet toegestaan door de app of je organisatie"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Navigatietutorial overslaan?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Je vindt dit later terug in de app <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuleren"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Overslaan"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Scherm draaien"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Uitleg van taakbalk geopend"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Uitleg van taakbalk gesloten"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tik en houd vast om de taakbalk te verbergen"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 3535427..5b539d3 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"ସ୍କ୍ରିନସଟ୍"</string>
<string name="action_split" msgid="2098009717623550676">"ସ୍ପ୍ଲିଟ୍"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"ସ୍ପ୍ଲିଟସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପରେ ଟାପ କର"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ସ୍ପ୍ଲିଟ-ସ୍କ୍ରିନକୁ ଆପ ସମର୍ଥନ କରେ ନାହିଁ।"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ଆପ୍ କିମ୍ବା ଆପଣଙ୍କ ସଂସ୍ଥା ଦ୍ୱାରା ଏହି କାର୍ଯ୍ୟକୁ ଅନୁମତି ଦିଆଯାଇ ନାହିଁ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ନାଭିଗେସନ୍ ଟ୍ୟୁଟୋରିଆଲକୁ ବାଦ୍ ଦେବେ?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ଆପଣ ପରେ ଏହାକୁ <xliff:g id="NAME">%1$s</xliff:g> ଆପରେ ପାଇପାରିବେ"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ବାତିଲ୍ କରନ୍ତୁ"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ବାଦ୍ ଦିଅନ୍ତୁ"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"ସ୍କ୍ରିନ ଘୂରାନ୍ତୁ"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ଟାସ୍କବାର୍ ଶିକ୍ଷା ଦେଖାଯାଇଛି"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ଟାସ୍କବାର୍ ଶିକ୍ଷା ବନ୍ଦ ହୋଇଯାଇଛି"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ଟାସ୍କବାରକୁ ଲୁଚାଇବା ପାଇଁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 5f070ce..bc63fb6 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
<string name="action_split" msgid="2098009717623550676">"ਸਪਲਿਟ"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ਐਪ ਸਪਲਿਟ-ਸਕ੍ਰੀਨ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ।"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ਐਪ ਜਾਂ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਇਸ ਕਾਰਵਾਈ ਦੀ ਇਜਾਜ਼ਤ ਨਹੀਂ ਹੈ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ਕੀ ਨੈਵੀਗੇਸ਼ਨ ਟਿਊਟੋਰੀਅਲ ਨੂੰ ਛੱਡਣਾ ਹੈ?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ਤੁਸੀਂ ਇਸਨੂੰ ਬਾਅਦ ਵਿੱਚ <xliff:g id="NAME">%1$s</xliff:g> ਐਪ ਵਿੱਚ ਲੱਭ ਸਕਦੇ ਹੋ"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ਰੱਦ ਕਰੋ"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ਛੱਡੋ"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"ਸਕ੍ਰੀਨ ਘੁਮਾਓ"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ਟਾਸਕਵਾਰ ਸਿੱਖਿਆ ਪੈਨਲ ਦਿਖਾਇਆ ਗਿਆ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ਟਾਸਕਵਾਰ ਸਿੱਖਿਆ ਪੈਨਲ ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ਟਾਸਕਬਾਰ ਨੂੰ ਲੁਕਾਉਣ ਲਈ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 601aa4c..0c7828a 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Zrzut ekranu"</string>
<string name="action_split" msgid="2098009717623550676">"Podziel"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Kliknij drugą aplikację, aby podzielić ekran"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikacja nie obsługuje podzielonego ekranu."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Nie możesz wykonać tego działania, bo nie zezwala na to aplikacja lub Twoja organizacja"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Pominąć samouczek nawigacji?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Znajdziesz to później w aplikacji <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Anuluj"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Pomiń"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Obróć ekran"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Wskazówki na temat paska zadań zostały wyświetlone"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Wskazówki na temat paska zadań zostały zamknięte"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Naciśnij i przytrzymaj, aby ukryć pasek zadań"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 3f03537..73afdb3 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Fazer captura de ecrã"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Toque noutra app para utilizar o ecrã dividido"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"A app não é compatível com o ecrã dividido."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Esta ação não é permitida pela app ou a sua entidade."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ignorar o tutorial de navegação?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Pode encontrar isto mais tarde na app <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ignorar"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rodar ecrã"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Informação da barra de tarefas apresentada"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Informação da barra de tarefas fechada"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Toque sem soltar para ocultar a barra de tarefas"</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index d725576..e7d63ce 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Capturar tela"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Toque em outro app para dividir a tela"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"O app não tem suporte para a divisão de tela."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Essa ação não é permitida pelo app ou pela organização"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Pular o tutorial de navegação?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Veja o tutorial mais tarde no app <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Cancelar"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Pular"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Girar a tela"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"As dicas sobre a barra de tarefas foram abertas"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"As dicas sobre a barra de tarefas foram fechadas"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Mantenha a barra de tarefas pressionada para ocultá-la"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 27fd511..847bb57 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Captură de ecran"</string>
<string name="action_split" msgid="2098009717623550676">"Împărțit"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Atingeți altă aplicație pentru a folosi ecranul împărțit"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplicația nu acceptă ecranul împărțit."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Această acțiune nu este permisă de aplicație sau de organizația dvs."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Omiteți tutorialul de navigare?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Îl puteți găsi mai târziu în aplicația <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Anulați"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Omiteți"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotiți ecranul"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Panoul cu informații despre bara de activități s-a afișat"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Panoul cu informații despre bara de activități s-a închis"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Atingeți lung oricând pentru a ascunde bara de activități"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index ab8b8cf..5b47295 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="action_split" msgid="2098009717623550676">"Разделить"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Для разделения экрана нажмите на другое приложение."</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Приложение не поддерживает разделение экрана."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Это действие заблокировано приложением или организацией."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Пропустить руководство по жестам?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Его можно найти в приложении \"<xliff:g id="NAME">%1$s</xliff:g>\"."</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Отмена"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Пропустить"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Повернуть экран"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Обучение по работе с панелью задач показано"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Обучение по работе с панелью задач скрыто"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Чтобы скрыть панель задач, коснитесь ее и удерживайте."</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index f286b66..2676afb 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"තිර රුව"</string>
<string name="action_split" msgid="2098009717623550676">"බෙදන්න"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"බෙදුම් තිරය භාවිත කිරීමට තවත් යෙදුමක් තට්ටු කරන්න"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"යෙදුම බෙදුම් තිරය සඳහා සහාය නොදක්වයි."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"මෙම ක්රියාව යෙදුම හෝ ඔබේ සංවිධානය මගින් ඉඩ නොදේ"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"නිබන්ධනය සංචාලනය මඟ හරින්නද?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"ඔබට මෙය පසුව <xliff:g id="NAME">%1$s</xliff:g> යෙදුම තුළ සොයා ගත හැකිය"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"අවලංගු කරන්න"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"මඟ හරින්න"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"තිරය කරකවන්න"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"කාර්ය තීරු අධ්යාපනය දිස් විය"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"කාර්ය තීරු අධ්යාපනය වසා ඇත"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"කාර්ය තීරුව සැඟවීමට ස්පර්ශ කර අල්ලා ගෙන සිටින්න"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index ce71b88..f29b0d4 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Snímka obrazovky"</string>
<string name="action_split" msgid="2098009717623550676">"Rozdeliť"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Rozdel. obrazovku spustíte klepnutím na inú aplik."</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikácia nepodporuje rozdelenú obrazovku."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikácia alebo vaša organizácia túto akciu nepovoľuje"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Chcete preskočiť návod na navigáciu?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Tento návod nájdete v aplikácii <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Zrušiť"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskočiť"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Otočiť obrazovku"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Zobrazila sa výuka k hlavnému panelu"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Výuka k hlavnému panelu bola zatvorená"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Panel úloh skryjete pridržaním"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 13299f1..6276c3c 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Posnetek zaslona"</string>
<string name="action_split" msgid="2098009717623550676">"Razdeli"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Za uporabo razdeljenega zaslona se dotaknite še ene aplikacije."</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikacija ne podpira načina razdeljenega zaslona."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Aplikacija ali vaša organizacija ne dovoljuje tega dejanja"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Želite preskočiti vadnico za krmarjenje?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"To lahko pozneje najdete v aplikaciji <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Prekliči"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Preskoči"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Sukanje zaslona"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Poučni nasveti o opravilni vrstici so prikazani."</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Poučni nasveti o opravilni vrstici so zaprti."</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Pridržite, če želite opravilno vrstico skriti."</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 771eb13..6ef41a3 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Pamja e ekranit"</string>
<string name="action_split" msgid="2098009717623550676">"Ndaj"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Trokit aplikacion tjetër e përdor ekranin e ndarë"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Aplikacioni nuk mbështet ekranin e ndarë."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Ky veprim nuk lejohet nga aplikacioni ose organizata jote"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Të kapërcehet udhëzuesi i navigimit?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Këtë mund ta gjesh më vonë tek aplikacioni <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Anulo"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Kapërce"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rrotullo ekranin"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Edukimi i shiritit të detyrave u shfaq"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Edukimi nga shiriti i detyrave u mbyll"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Preke dhe mbaje prekur për ta fshehur shiritin e detyrave"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 73d3bfa..0208108 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Снимак екрана"</string>
<string name="action_split" msgid="2098009717623550676">"Подели"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Додирните другу апликацију за подељени екран"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Апликација не подржава подељени екран."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Апликација или организација не дозвољавају ову радњу"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Желите да прескочите водич за кретање?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Можете да пронађете ово касније у апликацији <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Откажи"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Прескочи"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ротирајте екран"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Едукативно окно из траке задатака се појавило"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Едукативно окно из траке задатака је затворено"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Додирните и задржите за скривање траке задатака"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index c741a39..ed79a77 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Skärmbild"</string>
<string name="action_split" msgid="2098009717623550676">"Delat"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Tryck på en annan app för att använda delad skärm"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Appen har inte stöd för delad skärm."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Appen eller organisationen tillåter inte den här åtgärden"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Vill du hoppa över självstudierna?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Du hittar det här igen i <xliff:g id="NAME">%1$s</xliff:g>-appen"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Avbryt"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Hoppa över"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Rotera skärmen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Information om aktivitetsfältet visades"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Information om aktivitetsfältet stängdes"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Tryck länge för att dölja aktivitetsfältet"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 8302751..34c64d5 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Picha ya skrini"</string>
<string name="action_split" msgid="2098009717623550676">"Iliyogawanywa"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Gusa programu nyingine ili utumie skrini iliyogawanywa"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Programu haiwezi kutumia skrini iliyogawanywa."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Kitendo hiki hakiruhusiwi na programu au shirika lako"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ungependa kuruka mafunzo ya usogezaji?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Utapata mafunzo haya baadaye katika programu ya <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Ghairi"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ruka"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Zungusha skrini"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Paneli ya elimu kwenye upau wa shughuli inaonyeshwa"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Paneli ya elimu kwenye upau wa shughuli imefungwa"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Gusa na ushikilie ili ufiche upau wa shughuli"</string>
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
new file mode 100644
index 0000000..5d9e059
--- /dev/null
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+-->
+<resources>
+ <dimen name="navigation_key_padding">25dp</dimen>
+</resources>
diff --git a/quickstep/res/values-sw900dp/dimens.xml b/quickstep/res/values-sw900dp/dimens.xml
new file mode 100644
index 0000000..3efa5e3
--- /dev/null
+++ b/quickstep/res/values-sw900dp/dimens.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+*/
+-->
+<resources>
+ <!-- The maximum width of the navigation bar ripples. -->
+ <dimen name="key_button_ripple_max_width">76dp</dimen>
+
+ <!-- The padding around the navigation buttons -->
+ <dimen name="navigation_key_padding">0dp</dimen>
+</resources>
\ No newline at end of file
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 0de21e8..dc3b253 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"ஸ்கிரீன்ஷாட்"</string>
<string name="action_split" msgid="2098009717623550676">"பிரி"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"ஸ்பிளிட் ஸ்கிரீனுக்கு மற்றொரு ஆப்ஸைத் தட்டவும்"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"திரைப் பிரிப்பு அம்சத்தை ஆப்ஸ் ஆதரிக்கவில்லை."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ஆப்ஸோ உங்கள் நிறுவனமோ இந்த செயலை அனுமதிப்பதில்லை"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"வழிகாட்டுதல் பயிற்சியைத் தவிர்க்கவா?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> ஆப்ஸில் பிறகு இதைக் கண்டறியலாம்"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ரத்துசெய்"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"தவிர்"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"திரையைச் சுழற்றும்"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"பணிப்பட்டியை எவ்வாறு பயன்படுத்துவது என்பது பற்றிய பலகம் காட்டப்படுகிறது"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"பணிப்பட்டியை எவ்வாறு பயன்படுத்துவது என்பது பற்றிய பலகம் மூடப்பட்டது"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"பணிப்பட்டியை மறைக்கத் தொட்டுப் பிடிக்கவும்"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 0f42271..a82a35a 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"స్క్రీన్షాట్"</string>
<string name="action_split" msgid="2098009717623550676">"స్ప్లిట్ చేయండి"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"స్క్రీన్ విభజనను ఉపయోగించడానికి మరొక యాప్ నొక్కండి"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"యాప్లో స్ప్లిట్-స్క్రీన్ పని చేయదు."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ఈ చర్యను యాప్ గానీ, మీ సంస్థ గానీ అనుమతించవు"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"నావిగేషన్ ట్యుటోరియల్ను స్కిప్ చేయాలా?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"<xliff:g id="NAME">%1$s</xliff:g> యాప్లో మీరు తర్వాత కనుగొనవచ్చు"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"రద్దు చేయి"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"స్కిప్ చేయి"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"స్క్రీన్ను తిప్పండి"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"టాస్క్బార్ శిక్షణకు సంబంధించిన ప్యానెల్ కనిపించింది"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"టాస్క్బార్ శిక్షణకు సంబంధించిన ప్యానెల్ మూసివేయబడింది"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"టాస్క్బార్ను దాచడానికి తాకి, నొక్కి ఉంచండి"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 435c774..4815c85 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"ภาพหน้าจอ"</string>
<string name="action_split" msgid="2098009717623550676">"แยก"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"แตะที่แอปอื่นเพื่อใช้แบ่งหน้าจอ"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"แอปไม่รองรับการแบ่งหน้าจอ"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"แอปหรือองค์กรของคุณไม่อนุญาตการดำเนินการนี้"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"ข้ามบทแนะนำการนำทางไหม"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"คุณดูบทแนะนำนี้ได้ภายหลังในแอป \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"ยกเลิก"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"ข้าม"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"หมุนหน้าจอ"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"แถบงาน Education ปรากฎขึ้น"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ปิดแถบงาน Education แล้ว"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"แตะค้างไว้เพื่อซ่อนแถบงาน"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 3ed75a9..c7521a0 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Split"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Mag-tap ng ibang app para gamitin ang splitscreen"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Hindi sinusuportahan ng app ang split-screen."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Hindi pinapayagan ng app o ng iyong organisasyon ang pagkilos na ito"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Laktawan ang tutorial sa pag-navigate?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Makikita mo ito sa <xliff:g id="NAME">%1$s</xliff:g> app sa ibang pagkakataon"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Kanselahin"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Laktawan"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"I-rotate ang screen"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Lumabas ang edukasyon sa taskbar"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Sarado ang edukasyon sa taskbar"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Pindutin nang matagal para itago ang taskbar"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 910affe..f23d476 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Ekran görüntüsü"</string>
<string name="action_split" msgid="2098009717623550676">"Böl"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Bölünmüş ekran için başka bir uygulamaya dokunun"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Uygulama bölünmüş ekranı desteklemiyor."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Uygulamanız veya kuruluşunuz bu işleme izin vermiyor"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Gezinme eğitimi atlansın mı?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Bunu daha sonra <xliff:g id="NAME">%1$s</xliff:g> uygulamasında bulabilirsiniz"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"İptal"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Atla"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ekranı döndür"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Görev çubuğu eğitimi görüntülendi"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Görev çubuğu eğitimi kapatıldı"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Görev çubuğunu gizlemek için basılı tutun"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 466da29..19f5017 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Знімок екрана"</string>
<string name="action_split" msgid="2098009717623550676">"Розділити"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Щоб розділити екран, виберіть ще один додаток"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Додаток не підтримує розділення екрана."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Ця дія заборонена додатком або адміністратором організації"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Пропустити посібник із навігації?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Ви знайдете його пізніше в додатку <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Скасувати"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Пропустити"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Обернути екран"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Панель завдань Education відкрито"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Панель завдань Education закрито"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Натисніть і втримуйте панель завдань, щоб сховати її"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index e0e9beb..4b3f141 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"اسکرین شاٹ"</string>
<string name="action_split" msgid="2098009717623550676">"اسپلٹ"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"اسپلٹ اسکرین کا استعمال کرنے کیلئے دوسری ایپ پر تھپتھپائیں"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"ایپ سپلٹ اسکرین کو سپورٹ نہیں کرتی۔"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"ایپ یا آپ کی تنظیم کی جانب سے اس کارروائی کی اجازت نہیں ہے"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"نیویگیشن کا ٹیوٹوریل نظر انداز کریں؟"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"آپ اسے بعد میں <xliff:g id="NAME">%1$s</xliff:g> ایپ میں تلاش کر سکتے ہیں"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"منسوخ کریں"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"نظر انداز کریں"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"اسکرین کو گھمائیں"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"ٹاکس بار کا تعلیمی پینل ظاہر ہو گیا"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"ٹاسک بار کا تعلیمی پینل بند ہو گیا"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"ٹاسک بار کو کسی بھی وقت چھپانے کیلئے ٹچ کریں اور دبائے رکھیں"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index ffa8a2d..730b23a 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Skrinshot"</string>
<string name="action_split" msgid="2098009717623550676">"Ajratish"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Ekranni ikkiga ajratish uchun boshqa ilovani bosing"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Bu ilovada ekranni ikkiga ajratish ishlamaydi."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Bu amal ilova yoki tashkilotingiz tomonidan taqiqlangan"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Navigatsiya darsi yopilsinmi?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Bu darslar <xliff:g id="NAME">%1$s</xliff:g> ilovasida chiqadi"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Bekor qilish"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Tashlab ketish"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Ekranni burish"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Taʼlim vazifalar paneli chiqdi"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Taʼlim vazifalar paneli yopildi"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Vazifalar panelini ustiga bosib turib yashirish mumkin"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 81d3dec..acf77ae 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Chụp ảnh màn hình"</string>
<string name="action_split" msgid="2098009717623550676">"Chia đôi màn hình"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Nhấn vào một ứng dụng khác để dùng màn hình chia đôi"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Ứng dụng không hỗ trợ chia đôi màn hình."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Ứng dụng hoặc tổ chức của bạn không cho phép thực hiện hành động này"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Bỏ qua phần hướng dẫn thao tác?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Bạn có thể tìm lại phần hướng dẫn này trong ứng dụng <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Hủy"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Bỏ qua"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Xoay màn hình"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Đã hiện bảng hướng dẫn trên thanh tác vụ"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Đã đóng bảng hướng dẫn trên thanh tác vụ"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Chạm và giữ để ẩn thanh tác vụ"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index a55a44c..b533820 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"屏幕截图"</string>
<string name="action_split" msgid="2098009717623550676">"拆分"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"点按另一个应用即可使用分屏"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"应用不支持分屏。"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"该应用或您所在的单位不允许执行此操作"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"要跳过导航教程吗?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"您之后可以在“<xliff:g id="NAME">%1$s</xliff:g>”应用中找到此教程"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"取消"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"跳过"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"旋转屏幕"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"任务栏教程已显示"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"任务栏教程已关闭"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"轻触并按住即可隐藏任务栏"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 42329eb..8ff8f69 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"螢幕截圖"</string>
<string name="action_split" msgid="2098009717623550676">"分割"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"輕按其他應用程式以使用分割螢幕"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"應用程式不支援分割螢幕。"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"應用程式或您的機構不允許此操作"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"要略過手勢操作教學課程嗎?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"您之後可以在「<xliff:g id="NAME">%1$s</xliff:g>」應用程式找到這些說明"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"取消"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"略過"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"旋轉螢幕"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"顯示咗工作列教學"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"閂咗工作列教學"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"按住即可隱藏工作列"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index a014adb..2b184e8 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"螢幕截圖"</string>
<string name="action_split" msgid="2098009717623550676">"分割"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"輕觸另一個應用程式即可使用分割畫面"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"這個應用程式不支援分割畫面。"</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"這個應用程式或貴機構不允許執行這個動作"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"要略過手勢操作教學課程嗎?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"你之後可以在「<xliff:g id="NAME">%1$s</xliff:g>」應用程式找到這些說明"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"取消"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"略過"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"旋轉螢幕"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"工作列教學課程已顯示"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"工作列教學課程已關閉"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"按住即可隱藏工作列"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index dfa67d0..92729ee 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -80,11 +80,13 @@
<string name="action_screenshot" msgid="8171125848358142917">"Isithombe-skrini"</string>
<string name="action_split" msgid="2098009717623550676">"Hlukanisa"</string>
<string name="toast_split_select_app" msgid="5453865907322018352">"Thepha enye i-app ukuze usebenzise isikrini sokuhlukanisa"</string>
+ <string name="toast_split_app_unsupported" msgid="3271526028981899666">"Uhlelo lokusebenza alusekeli isikrini esihlukanisiwe."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Lesi senzo asivunyelwanga uhlelo lokusebenza noma inhlangano yakho"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Yeqa isifundo sokuzulazula?"</string>
<string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Lokhu ungakuthola kamuva ku-app ye-<xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Khansela"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Yeqa"</string>
+ <string name="accessibility_rotate_button" msgid="4771825231336502943">"Zungezisa isikrini"</string>
<string name="taskbar_edu_opened" msgid="3950252793551919129">"Imfuno yebha yomsebenzi ivelile"</string>
<string name="taskbar_edu_closed" msgid="126643734478892862">"Imfundo yebha yomsebenzi ivaliwe"</string>
<string name="taskbar_edu_stashing" msgid="5212374387411764031">"Thinta futhi ubambe, bamba ukuze ufihle ibha yomsebenzi"</string>
diff --git a/quickstep/res/values/colors.xml b/quickstep/res/values/colors.xml
index fb2ee1c..f237d26 100644
--- a/quickstep/res/values/colors.xml
+++ b/quickstep/res/values/colors.xml
@@ -30,6 +30,9 @@
<color name="taskbar_stashed_handle_light_color">#EBffffff</color>
<color name="taskbar_stashed_handle_dark_color">#99000000</color>
+ <color name="rotation_button_light_color">#FFF</color>
+ <color name="rotation_button_dark_color">#99000000</color>
+
<!-- Gesture navigation tutorial -->
<color name="gesture_tutorial_back_arrow_color">#FFFFFFFF</color>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 4ebf5cf..e48c9e8 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -27,7 +27,7 @@
<dimen name="task_menu_corner_radius">22dp</dimen>
<dimen name="task_menu_item_corner_radius">4dp</dimen>
<dimen name="task_menu_spacing">2dp</dimen>
- <dimen name="task_menu_width_grid">200dp</dimen>
+ <dimen name="task_menu_width_grid">234dp</dimen>
<dimen name="overview_proactive_row_height">48dp</dimen>
<dimen name="overview_proactive_row_bottom_margin">16dp</dimen>
@@ -46,7 +46,8 @@
<dimen name="overview_actions_margin_three_button">8dp</dimen>
<dimen name="overview_actions_horizontal_margin">16dp</dimen>
- <dimen name="overview_grid_side_margin">50dp</dimen>
+ <dimen name="overview_grid_side_margin_portrait">60dp</dimen>
+ <dimen name="overview_grid_side_margin_landscape">52dp</dimen>
<dimen name="overview_grid_row_spacing_portrait">17.13dp</dimen>
<dimen name="overview_grid_row_spacing_landscape">13.38dp</dimen>
<dimen name="overview_grid_focus_vertical_margin">0dp</dimen>
@@ -90,7 +91,7 @@
<dimen name="task_menu_vertical_padding">8dp</dimen>
<dimen name="task_card_margin">8dp</dimen>
<dimen name="task_card_menu_shadow_height">3dp</dimen>
- <dimen name="task_menu_option_start_margin">12dp</dimen>
+ <dimen name="task_menu_option_start_margin">16dp</dimen>
<!-- Copied from framework resource:
docked_stack_divider_thickness - 2 * docked_stack_divider_insets -->
<dimen name="multi_window_task_divider_size">10dp</dimen>
@@ -197,6 +198,19 @@
<!-- Minimum distance to swipe to trigger accessibility gesture -->
<dimen name="accessibility_gesture_min_swipe_distance">80dp</dimen>
+ <!-- The maximum width of the navigation bar ripples. -->
+ <dimen name="key_button_ripple_max_width">95dp</dimen>
+
+ <dimen name="rounded_corner_content_padding">0dp</dimen>
+
+ <dimen name="navigation_key_padding">0dp</dimen>
+
+ <!-- Floating rotation button -->
+ <dimen name="floating_rotation_button_diameter">40dp</dimen>
+ <dimen name="floating_rotation_button_min_margin">20dp</dimen>
+ <dimen name="floating_rotation_button_taskbar_left_margin">20dp</dimen>
+ <dimen name="floating_rotation_button_taskbar_bottom_margin">10dp</dimen>
+
<!-- Taskbar -->
<dimen name="taskbar_size">@*android:dimen/taskbar_frame_height</dimen>
<dimen name="taskbar_icon_touch_size">48dp</dimen>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 88c98c0..151b8e4 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -208,6 +208,9 @@
<!-- Button text shown on a button on the tutorial skip dialog to exit the tutorial. [CHAR LIMIT=14] -->
<string name="gesture_tutorial_action_button_label_skip">Skip</string>
+ <!-- Accessibility label for the rotation suggestion button -->
+ <string name="accessibility_rotate_button">Rotate screen</string>
+
<!-- ******* Taskbar Edu ******* -->
<!-- Accessibility text spoken when the taskbar education panel appears [CHAR_LIMIT=NONE] -->
<string name="taskbar_edu_opened">Taskbar education appeared</string>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 40e18ec..2efe72e 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -137,8 +137,8 @@
<style name="OverviewClearAllButton" parent="@android:style/Widget.DeviceDefault.Button">
<item name="android:background">@drawable/bg_overview_clear_all_button</item>
- <item name="android:minWidth">85dp</item>
- <item name="android:minHeight">36dp</item>
+ <item name="android:minWidth">96dp</item>
+ <item name="android:minHeight">48dp</item>
<item name="android:stateListAnimator">@null</item>
</style>
diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java
index 5fc79f0..35151f1 100644
--- a/quickstep/src/com/android/launcher3/LauncherInitListener.java
+++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java
@@ -17,11 +17,8 @@
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
-import android.content.Context;
-import android.content.Intent;
import android.os.Build;
import android.os.CancellationSignal;
-import android.os.Handler;
import com.android.quickstep.util.ActivityInitListener;
import com.android.quickstep.util.RemoteAnimationProvider;
@@ -78,11 +75,4 @@
mRemoteAnimationProvider = null;
super.unregister();
}
-
- @Override
- public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
- Context context, Handler handler, long duration) {
- mRemoteAnimationProvider = animProvider;
- super.registerAndStartActivity(intent, animProvider, context, handler, duration);
- }
}
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 8a05533..51d7914 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -110,7 +110,6 @@
import com.android.quickstep.RemoteAnimationTargets;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TaskViewUtils;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.MultiValueUpdateListener;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RemoteAnimationProvider;
@@ -176,6 +175,7 @@
public static final int RECENTS_LAUNCH_DURATION = 336;
private static final int LAUNCHER_RESUME_START_DELAY = 100;
private static final int CLOSING_TRANSITION_DURATION_MS = 250;
+ public static final int SPLIT_LAUNCH_DURATION = 370;
public static final int CONTENT_ALPHA_DURATION = 217;
protected static final int CONTENT_SCALE_DURATION = 350;
@@ -286,7 +286,8 @@
long statusBarTransitionDelay = duration - STATUS_BAR_TRANSITION_DURATION
- STATUS_BAR_TRANSITION_PRE_DELAY;
RemoteAnimationAdapterCompat adapterCompat =
- new RemoteAnimationAdapterCompat(runner, duration, statusBarTransitionDelay);
+ new RemoteAnimationAdapterCompat(runner, duration, statusBarTransitionDelay,
+ mLauncher.getIApplicationThread());
return new ActivityOptionsWrapper(
ActivityOptionsCompat.makeRemoteAnimation(adapterCompat), onEndCallback);
}
@@ -1082,7 +1083,8 @@
new RemoteAnimationAdapterCompat(
new LauncherAnimationRunner(mHandler, mWallpaperOpenRunner,
false /* startAtFrontOfQueue */),
- CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+ CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */,
+ mLauncher.getIApplicationThread()));
if (KEYGUARD_ANIMATION.get()) {
mKeyguardGoingAwayRunner = createWallpaperOpenRunner(true /* fromUnlock */);
@@ -1092,7 +1094,8 @@
new LauncherAnimationRunner(
mHandler, mKeyguardGoingAwayRunner,
true /* startAtFrontOfQueue */),
- CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */));
+ CLOSING_TRANSITION_DURATION_MS, 0 /* statusBarTransitionDelay */,
+ mLauncher.getIApplicationThread()));
}
new ActivityCompat(mLauncher).registerRemoteAnimations(definition);
@@ -1110,7 +1113,7 @@
mWallpaperOpenTransitionRunner = createWallpaperOpenRunner(false /* fromUnlock */);
mLauncherOpenTransition = RemoteAnimationAdapterCompat.buildRemoteTransition(
new LauncherAnimationRunner(mHandler, mWallpaperOpenTransitionRunner,
- false /* startAtFrontOfQueue */));
+ false /* startAtFrontOfQueue */), mLauncher.getIApplicationThread());
mLauncherOpenTransition.addHomeOpenCheck(mLauncher.getComponentName());
SystemUiProxy.INSTANCE.getNoCreate().registerRemoteTransition(mLauncherOpenTransition);
}
@@ -1338,12 +1341,11 @@
RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect) {
@Override
- public void onUpdate(@Nullable AppCloseConfig values, RectF currentRectF,
- float progress) {
+ public void onUpdate(RectF currentRectF, float progress) {
finalFloatingIconView.update(1f, 255 /* fgAlpha */, currentRectF, progress,
windowAlphaThreshold, getCornerRadius(progress), false);
- super.onUpdate(values, currentRectF, progress);
+ super.onUpdate(currentRectF, progress);
}
};
anim.addOnUpdateListener(runner);
@@ -1356,8 +1358,7 @@
FloatingWidgetView finalFloatingWidget = floatingWidget;
RectFSpringAnim.OnUpdateListener runner = new SpringAnimRunner(targets, targetRect) {
@Override
- public void onUpdate(@Nullable AppCloseConfig values, RectF currentRectF,
- float progress) {
+ public void onUpdate(RectF currentRectF, float progress) {
final float fallbackBackgroundAlpha =
1 - mapBoundToRange(progress, 0.8f, 1, 0, 1, EXAGGERATED_EASE);
final float foregroundAlpha =
@@ -1365,7 +1366,7 @@
finalFloatingWidget.update(currentRectF, floatingWidgetAlpha, foregroundAlpha,
fallbackBackgroundAlpha, 1 - progress);
- super.onUpdate(values, currentRectF, progress);
+ super.onUpdate(currentRectF, progress);
}
};
anim.addOnUpdateListener(runner);
@@ -1557,7 +1558,8 @@
View workspaceView = findWorkspaceView(appTargets);
boolean isWorkspaceViewVisible = workspaceView != null
- && !mLauncher.isInState(LauncherState.ALL_APPS);
+ && !mLauncher.isInState(LauncherState.ALL_APPS)
+ && !mLauncher.getWorkspace().isOverlayShown();
boolean playFallBackAnimation = !isWorkspaceViewVisible
&& (launcherIsATargetWithMode(appTargets, MODE_OPENING)
|| mLauncher.isForceInvisible());
@@ -1776,7 +1778,7 @@
}
@Override
- public void onUpdate(@Nullable AppCloseConfig values, RectF currentRectF, float progress) {
+ public void onUpdate(RectF currentRectF, float progress) {
SurfaceParams[] params = new SurfaceParams[mAppTargets.length];
for (int i = mAppTargets.length - 1; i >= 0; i--) {
RemoteAnimationTargetCompat target = mAppTargets[i];
diff --git a/quickstep/src/com/android/launcher3/model/AppEventProducer.java b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
index 1305bbc..7c29c5b 100644
--- a/quickstep/src/com/android/launcher3/model/AppEventProducer.java
+++ b/quickstep/src/com/android/launcher3/model/AppEventProducer.java
@@ -271,9 +271,6 @@
case ALL_APPS_CONTAINER: {
return "all-apps";
}
- case SEARCH_RESULT_CONTAINER: {
- return "search-results";
- }
case PREDICTED_HOTSEAT_CONTAINER: {
return "predictions/hotseat";
}
@@ -293,6 +290,16 @@
}
return "folder";
}
+ case SEARCH_RESULT_CONTAINER:
+ return "search-results";
+ case EXTENDED_CONTAINERS: {
+ switch(ci.getExtendedContainers().getContainerCase()) {
+ case DEVICE_SEARCH_RESULT_CONTAINER:
+ case CORRECTED_DEVICE_SEARCH_RESULT_CONTAINER:
+ return "search-results";
+ }
+ }
+ default: // fall out
}
return "";
}
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 7794d27..e82c900 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -329,6 +329,8 @@
}
if (state.predictor != null) {
state.predictor.notifyAppTargetEvent(event);
+ Log.d(TAG, "notifyAppTargetEvent action=" + event.getAction()
+ + " launchLocation=" + event.getLaunchLocation());
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 648a16e..1c0c773 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -15,18 +15,10 @@
*/
package com.android.launcher3.taskbar;
-import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
-import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
-import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
-import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
-import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
-import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
+import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_RESUMED;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_EXTRA_NAVIGATION_BAR;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
import android.annotation.ColorInt;
import android.graphics.Rect;
import android.os.RemoteException;
@@ -44,27 +36,17 @@
import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimatorListeners;
-import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.statemanager.StateManager;
-import com.android.launcher3.util.MultiValueAlpha;
-import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.launcher3.util.OnboardingPrefs;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.RecentsAnimationCallbacks;
-import com.android.quickstep.RecentsAnimationCallbacks.RecentsAnimationListener;
-import com.android.quickstep.RecentsAnimationController;
-import com.android.quickstep.views.RecentsView;
-import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.Arrays;
import java.util.Set;
-import java.util.function.Supplier;
import java.util.stream.Stream;
/**
@@ -76,82 +58,15 @@
private final BaseQuickstepLauncher mLauncher;
- private final AnimatedFloat mIconAlignmentForResumedState =
- new AnimatedFloat(this::onIconAlignmentRatioChanged);
- private final AnimatedFloat mIconAlignmentForGestureState =
- new AnimatedFloat(this::onIconAlignmentRatioChanged);
- private final AnimatedFloat mIconAlignmentForLauncherState =
- new AnimatedFloat(this::onIconAlignmentRatioChangedForStateTransition);
-
private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
this::onStashedInAppChanged;
- private final StateManager.StateListener<LauncherState> mStateListener =
- new StateManager.StateListener<LauncherState>() {
- private Animator mAnimator;
-
- @Override
- public void onStateTransitionStart(LauncherState toState) {
- // Stash animation from going to launcher should be already handled in
- // createAnimToLauncher.
- TaskbarStashController controller = mControllers.taskbarStashController;
- long duration = TASKBAR_STASH_DURATION;
- controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
- toState.isTaskbarStashed());
- Animator stashAnimator = controller.applyStateWithoutStart(duration);
- if (stashAnimator != null) {
- if (mAnimator != null) {
- mAnimator.cancel();
- }
- PendingAnimation pendingAnimation = new PendingAnimation(duration);
- pendingAnimation.add(stashAnimator);
- pendingAnimation.setFloat(mIconAlignmentForLauncherState,
- AnimatedFloat.VALUE, toState.isTaskbarStashed() ? 0 : 1,
- FAST_OUT_SLOW_IN);
- pendingAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animator) {
- mTargetStateOverrideForStateTransition = toState;
- // Copy hotseat alpha over to taskbar icons
- mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha());
- mLauncher.getHotseat().setIconsAlpha(0);
- }
-
- @Override
- public void onAnimationEnd(Animator animator) {
- if (toState.isTaskbarStashed()) {
- // Reset hotseat alpha to default
- mLauncher.getHotseat().setIconsAlpha(1);
- }
- mTargetStateOverrideForStateTransition = null;
- mAnimator = null;
- }
- });
- mAnimator = pendingAnimation.buildAnim();
- mAnimator.start();
- }
- }
-
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- TaskbarStashController controller = mControllers.taskbarStashController;
- controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
- finalState.isTaskbarStashed());
- controller.applyState();
- }
- };
-
// Initialized in init.
private TaskbarControllers mControllers;
- private AnimatedFloat mTaskbarBackgroundAlpha;
private AnimatedFloat mTaskbarOverrideBackgroundAlpha;
- private AlphaProperty mIconAlphaForHome;
- private boolean mIsAnimatingToLauncherViaResume;
- private boolean mIsAnimatingToLauncherViaGesture;
private TaskbarKeyguardController mKeyguardController;
-
- private LauncherState mTargetStateOverride = null;
- private LauncherState mTargetStateOverrideForStateTransition = null;
+ private final TaskbarLauncherStateController
+ mTaskbarLauncherStateController = new TaskbarLauncherStateController();
private final DeviceProfile.OnDeviceProfileChangeListener mProfileChangeListener =
new DeviceProfile.OnDeviceProfileChangeListener() {
@@ -170,37 +85,26 @@
protected void init(TaskbarControllers taskbarControllers) {
mControllers = taskbarControllers;
- mTaskbarBackgroundAlpha = mControllers.taskbarDragLayerController
- .getTaskbarBackgroundAlpha();
+ mTaskbarLauncherStateController.init(mControllers, mLauncher);
mTaskbarOverrideBackgroundAlpha = mControllers.taskbarDragLayerController
.getOverrideBackgroundAlpha();
- MultiValueAlpha taskbarIconAlpha = mControllers.taskbarViewController.getTaskbarIconAlpha();
- mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME);
-
mLauncher.setTaskbarUIController(this);
mKeyguardController = taskbarControllers.taskbarKeyguardController;
onLauncherResumedOrPaused(mLauncher.hasBeenResumed(), true /* fromInit */);
- mIconAlignmentForResumedState.finishAnimation();
- onIconAlignmentRatioChanged();
onStashedInAppChanged(mLauncher.getDeviceProfile());
mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
- mLauncher.getStateManager().addStateListener(mStateListener);
mLauncher.addOnDeviceProfileChangeListener(mProfileChangeListener);
}
@Override
protected void onDestroy() {
onLauncherResumedOrPaused(false);
- mIconAlignmentForResumedState.finishAnimation();
- mIconAlignmentForGestureState.finishAnimation();
- mIconAlignmentForLauncherState.finishAnimation();
+ mTaskbarLauncherStateController.onDestroy();
mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
- mLauncher.getStateManager().removeStateListener(mStateListener);
- mLauncher.getHotseat().setIconsAlpha(1f);
mLauncher.setTaskbarUIController(null);
mLauncher.removeOnDeviceProfileChangeListener(mProfileChangeListener);
updateTaskTransitionSpec(true);
@@ -208,11 +112,7 @@
@Override
protected boolean isTaskbarTouchable() {
- return !isAnimatingToLauncher();
- }
-
- private boolean isAnimatingToLauncher() {
- return mIsAnimatingToLauncherViaResume || mIsAnimatingToLauncherViaGesture;
+ return !mTaskbarLauncherStateController.isAnimatingToLauncher();
}
@Override
@@ -239,24 +139,9 @@
}
}
- long duration = QuickstepTransitionManager.CONTENT_ALPHA_DURATION;
- if (fromInit) {
- // Since we are creating the starting state, we don't have a state to animate from, so
- // set our state immediately.
- duration = 0;
- }
- ObjectAnimator anim = mIconAlignmentForResumedState.animateToValue(
- getCurrentIconAlignmentRatio(), isResumed ? 1 : 0)
- .setDuration(duration);
-
- anim.addListener(AnimatorListeners.forEndCallback(
- () -> mIsAnimatingToLauncherViaResume = false));
- anim.start();
- mIsAnimatingToLauncherViaResume = isResumed;
-
- TaskbarStashController stashController = mControllers.taskbarStashController;
- stashController.updateStateForFlag(FLAG_IN_APP, !isResumed);
- stashController.applyState(duration);
+ mTaskbarLauncherStateController.updateStateForFlag(FLAG_RESUMED, isResumed);
+ mTaskbarLauncherStateController.applyState(
+ fromInit ? 0 : QuickstepTransitionManager.CONTENT_ALPHA_DURATION);
}
/**
@@ -267,77 +152,7 @@
*/
public Animator createAnimToLauncher(@NonNull LauncherState toState,
@NonNull RecentsAnimationCallbacks callbacks, long duration) {
- AnimatorSet animatorSet = new AnimatorSet();
- TaskbarStashController stashController = mControllers.taskbarStashController;
- stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
- toState.isTaskbarStashed());
- if (toState.isTaskbarStashed()) {
- animatorSet.play(stashController.applyStateWithoutStart(duration));
- } else {
- animatorSet.play(mIconAlignmentForGestureState
- .animateToValue(1)
- .setDuration(duration));
- }
- animatorSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animator) {
- mTargetStateOverride = null;
- animator.removeListener(this);
- }
-
- @Override
- public void onAnimationStart(Animator animator) {
- mTargetStateOverride = toState;
- mIsAnimatingToLauncherViaGesture = true;
- stashController.updateStateForFlag(FLAG_IN_APP, false);
- stashController.applyState(duration);
- }
- });
-
- TaskBarRecentsAnimationListener listener = new TaskBarRecentsAnimationListener(callbacks);
- callbacks.addListener(listener);
- RecentsView recentsView = mLauncher.getOverviewPanel();
- recentsView.setTaskLaunchListener(() -> {
- listener.endGestureStateOverride(true);
- callbacks.removeListener(listener);
- });
-
- return animatorSet;
- }
-
- private float getCurrentIconAlignmentRatio() {
- return Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value);
- }
-
- private float getCurrentIconAlignmentRatioForLauncherState() {
- return mIconAlignmentForLauncherState.value;
- }
-
- private void onIconAlignmentRatioChangedForStateTransition() {
- onIconAlignmentRatioChanged(
- mTargetStateOverrideForStateTransition != null
- ? mTargetStateOverrideForStateTransition
- : mLauncher.getStateManager().getState(),
- this::getCurrentIconAlignmentRatioForLauncherState);
- }
-
- private void onIconAlignmentRatioChanged() {
- onIconAlignmentRatioChanged(mTargetStateOverride != null ? mTargetStateOverride
- : mLauncher.getStateManager().getState(), this::getCurrentIconAlignmentRatio);
- }
-
- private void onIconAlignmentRatioChanged(LauncherState state,
- Supplier<Float> alignmentSupplier) {
- if (mControllers == null) {
- return;
- }
- float alignment = alignmentSupplier.get();
- mControllers.taskbarViewController.setLauncherIconAlignment(
- alignment, mLauncher.getDeviceProfile());
-
- mTaskbarBackgroundAlpha.updateValue(1 - alignment);
-
- setIconAlpha(state, alignment);
+ return mTaskbarLauncherStateController.createAnimToLauncher(toState, callbacks, duration);
}
/**
@@ -345,7 +160,8 @@
* @return Whether any Taskbar item could handle the given MotionEvent if given the chance.
*/
public boolean isEventOverAnyTaskbarItem(MotionEvent ev) {
- return mControllers.taskbarViewController.isEventOverAnyItem(ev);
+ return mControllers.taskbarViewController.isEventOverAnyItem(ev)
+ || mControllers.navbarButtonsViewController.isEventOverAnyItem(ev);
}
public boolean isDraggingItem() {
@@ -356,20 +172,6 @@
return mControllers.taskbarActivityContext.getDragLayer();
}
- private void setIconAlpha(LauncherState state, float progress) {
- if ((state.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
- // If the hotseat icons are visible, then switch taskbar in last frame
- setTaskbarViewVisible(progress < 1);
- } else {
- mIconAlphaForHome.setValue(1 - progress);
- }
- }
-
- private void setTaskbarViewVisible(boolean isVisible) {
- mIconAlphaForHome.setValue(isVisible ? 1 : 0);
- mLauncher.getHotseat().setIconsAlpha(isVisible ? 0f : 1f);
- }
-
@Override
protected void onStashedInAppChanged() {
onStashedInAppChanged(mLauncher.getDeviceProfile());
@@ -449,35 +251,4 @@
mLauncher.logAppLaunch(mControllers.taskbarActivityContext.getStatsLogManager(), item,
instanceId);
}
-
- private final class TaskBarRecentsAnimationListener implements RecentsAnimationListener {
- private final RecentsAnimationCallbacks mCallbacks;
-
- TaskBarRecentsAnimationListener(RecentsAnimationCallbacks callbacks) {
- mCallbacks = callbacks;
- }
-
- @Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
- endGestureStateOverride(true);
- }
-
- @Override
- public void onRecentsAnimationFinished(RecentsAnimationController controller) {
- endGestureStateOverride(!controller.getFinishTargetIsLauncher());
- }
-
- private void endGestureStateOverride(boolean finishedToApp) {
- mCallbacks.removeListener(this);
- mIsAnimatingToLauncherViaGesture = false;
-
- mIconAlignmentForGestureState
- .animateToValue(0)
- .start();
-
- TaskbarStashController controller = mControllers.taskbarStashController;
- controller.updateStateForFlag(FLAG_IN_APP, finishedToApp);
- controller.applyState();
- }
- }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 69804bd..4b6dacd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.taskbar;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y_LONG_CLICK;
@@ -38,6 +40,7 @@
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
+import android.content.Context;
import android.content.res.ColorStateList;
import android.graphics.Rect;
import android.graphics.Region;
@@ -45,6 +48,7 @@
import android.graphics.drawable.AnimatedVectorDrawable;
import android.util.Property;
import android.view.Gravity;
+import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnHoverListener;
@@ -57,11 +61,12 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AlphaUpdateListener;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
-import com.android.launcher3.taskbar.contextual.RotationButton;
-import com.android.launcher3.taskbar.contextual.RotationButtonController;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.Themes;
import com.android.quickstep.AnimatedFloat;
+import com.android.systemui.shared.rotation.FloatingRotationButton;
+import com.android.systemui.shared.rotation.RotationButton;
+import com.android.systemui.shared.rotation.RotationButtonController;
import java.util.ArrayList;
import java.util.function.IntPredicate;
@@ -103,12 +108,16 @@
this::updateNavButtonTranslationY);
private final AnimatedFloat mNavButtonTranslationYMultiplier = new AnimatedFloat(
this::updateNavButtonTranslationY);
+ private final RotationButtonListener mRotationButtonListener = new RotationButtonListener();
+
+ private final Rect mFloatingRotationButtonBounds = new Rect();
// Initialized in init.
private TaskbarControllers mControllers;
private View mA11yButton;
private int mSysuiStateFlags;
private View mBackButton;
+ private FloatingRotationButton mFloatingRotationButton;
public NavbarButtonsViewController(TaskbarActivityContext context, FrameLayout navButtonsView) {
mContext = context;
@@ -121,10 +130,9 @@
/**
* Initializes the controller
*/
- public void init(TaskbarControllers controllers, TaskbarSharedState sharedState) {
+ public void init(TaskbarControllers controllers) {
mControllers = controllers;
mNavButtonsView.getLayoutParams().height = mContext.getDeviceProfile().taskbarSize;
- parseSystemUiFlags(sharedState.sysuiStateFlags);
mNavButtonTranslationYMultiplier.value = 1;
mA11yLongClickListener = view -> {
@@ -199,9 +207,21 @@
addButton(mEndContextualContainer, R.id.rotate_suggestion,
R.layout.taskbar_contextual_button));
rotationButton.hide();
- mControllers.rotationButtonController.setRotationButton(rotationButton);
+ mControllers.rotationButtonController.setRotationButton(rotationButton, null);
} else {
- mControllers.rotationButtonController.setRotationButton(new RotationButton() {});
+ mFloatingRotationButton = new FloatingRotationButton(mContext,
+ R.string.accessibility_rotate_button,
+ R.layout.rotate_suggestion,
+ R.id.rotate_suggestion,
+ R.dimen.floating_rotation_button_min_margin,
+ R.dimen.rounded_corner_content_padding,
+ R.dimen.floating_rotation_button_taskbar_left_margin,
+ R.dimen.floating_rotation_button_taskbar_bottom_margin,
+ R.dimen.floating_rotation_button_diameter,
+ R.dimen.key_button_ripple_max_width);
+ mControllers.rotationButtonController.setRotationButton(mFloatingRotationButton,
+ mRotationButtonListener);
+
View imeDownButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
mStartContextualContainer, mControllers.navButtonController, R.id.back);
imeDownButton.setRotation(Utilities.isRtl(mContext.getResources()) ? 90 : -90);
@@ -290,12 +310,15 @@
}
}
- public void updateStateForSysuiFlags(int systemUiStateFlags) {
+ public void updateStateForSysuiFlags(int systemUiStateFlags, boolean skipAnim) {
if (systemUiStateFlags == mSysuiStateFlags) {
return;
}
parseSystemUiFlags(systemUiStateFlags);
applyState();
+ if (skipAnim) {
+ mPropertyHolders.forEach(StatePropertyHolder::endAnimation);
+ }
}
/**
@@ -403,8 +426,28 @@
return buttonView;
}
+ public boolean isEventOverAnyItem(MotionEvent ev) {
+ return mFloatingRotationButtonBounds.contains((int) ev.getX(), (int) ev.getY());
+ }
+
public void onDestroy() {
mPropertyHolders.clear();
+ mControllers.rotationButtonController.unregisterListeners();
+ if (mFloatingRotationButton != null) {
+ mFloatingRotationButton.hide();
+ }
+ }
+
+ private class RotationButtonListener implements RotationButton.RotationButtonUpdatesCallback {
+ @Override
+ public void onVisibilityChanged(boolean isVisible) {
+ if (isVisible) {
+ mFloatingRotationButton.getCurrentView()
+ .getBoundsOnScreen(mFloatingRotationButtonBounds);
+ } else {
+ mFloatingRotationButtonBounds.setEmpty();
+ }
+ }
}
private class RotationButtonImpl implements RotationButton {
@@ -422,6 +465,8 @@
mImageDrawable = (AnimatedVectorDrawable) mButton.getContext()
.getDrawable(rotationButtonController.getIconResId());
mButton.setImageDrawable(mImageDrawable);
+ mButton.setContentDescription(mButton.getResources()
+ .getString(R.string.accessibility_rotate_button));
mImageDrawable.setCallback(mButton);
}
@@ -431,17 +476,19 @@
}
@Override
- public void show() {
+ public boolean show() {
mButton.setVisibility(View.VISIBLE);
mState |= FLAG_ROTATION_BUTTON_VISIBLE;
applyState();
+ return true;
}
@Override
- public void hide() {
+ public boolean hide() {
mButton.setVisibility(View.GONE);
mState &= ~FLAG_ROTATION_BUTTON_VISIBLE;
applyState();
+ return true;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 172b396..cc83431 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -20,6 +20,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
+import static com.android.launcher3.testing.TestProtocol.TASKBAR_WINDOW_CRASH;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.shared.system.WindowManagerWrapper.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
@@ -60,7 +61,6 @@
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.taskbar.contextual.RotationButtonController;
import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.SettingsCache;
@@ -71,6 +71,7 @@
import com.android.quickstep.SysUINavigationMode;
import com.android.quickstep.SysUINavigationMode.Mode;
import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.rotation.RotationButtonController;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.WindowManagerWrapper;
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
@@ -106,6 +107,8 @@
private final boolean mIsSafeModeEnabled;
private final boolean mIsUserSetupComplete;
private boolean mIsDestroyed = false;
+ // The flag to know if the window is excluded from magnification region computation.
+ private boolean mIsExcludeFromMagnificationRegion = false;
public TaskbarActivityContext(Context windowContext, DeviceProfile dp,
TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
@@ -147,8 +150,14 @@
new TaskbarDragController(this),
buttonController,
new NavbarButtonsViewController(this, navButtonsView),
- new RotationButtonController(this, R.color.popup_color_primary_light,
- R.color.popup_color_primary_light),
+ new RotationButtonController(this,
+ c.getColor(R.color.rotation_button_light_color),
+ c.getColor(R.color.rotation_button_dark_color),
+ R.drawable.ic_sysbar_rotate_button_ccw_start_0,
+ R.drawable.ic_sysbar_rotate_button_ccw_start_90,
+ R.drawable.ic_sysbar_rotate_button_cw_start_0,
+ R.drawable.ic_sysbar_rotate_button_cw_start_90,
+ () -> getDisplay().getRotation()),
new TaskbarDragLayerController(this, mDragLayer),
new TaskbarViewController(this, taskbarView),
new TaskbarScrimViewController(this, taskbarScrimView),
@@ -158,7 +167,8 @@
new StashedHandleViewController(this, stashedHandleView),
new TaskbarStashController(this),
new TaskbarEduController(this),
- new TaskbarAutohideSuspendController(this));
+ new TaskbarAutohideSuspendController(this),
+ new TaskbarPopupController());
}
public void init(TaskbarSharedState sharedState) {
@@ -191,8 +201,10 @@
// Initialize controllers after all are constructed.
mControllers.init(sharedState);
+ updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
+ Log.d(TASKBAR_WINDOW_CRASH, "Adding taskbar window");
}
public boolean isThreeButtonNav() {
@@ -245,6 +257,11 @@
return false;
}
+ @Override
+ public View.OnClickListener getItemOnClickListener() {
+ return this::onTaskbarIconClicked;
+ }
+
/**
* Change from hotseat/predicted hotseat to taskbar container.
*/
@@ -323,28 +340,31 @@
setUIController(TaskbarUIController.DEFAULT);
mControllers.onDestroy();
mWindowManager.removeViewImmediate(mDragLayer);
+ Log.d(TASKBAR_WINDOW_CRASH, "Removing taskbar window");
}
- public void updateSysuiStateFlags(int systemUiStateFlags) {
- mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags);
+ public void updateSysuiStateFlags(int systemUiStateFlags, boolean fromInit) {
+ mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags,
+ fromInit);
mControllers.taskbarViewController.setImeIsVisible(
mControllers.navbarButtonsViewController.isImeVisible());
int shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
| SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
- onNotificationShadeExpandChanged((systemUiStateFlags & shadeExpandedFlags) != 0);
+ onNotificationShadeExpandChanged((systemUiStateFlags & shadeExpandedFlags) != 0, fromInit);
mControllers.taskbarViewController.setRecentsButtonDisabled(
mControllers.navbarButtonsViewController.isRecentsDisabled());
mControllers.stashedHandleViewController.setIsHomeButtonDisabled(
mControllers.navbarButtonsViewController.isHomeDisabled());
mControllers.taskbarKeyguardController.updateStateForSysuiFlags(systemUiStateFlags);
- mControllers.taskbarStashController.updateStateForSysuiFlags(systemUiStateFlags);
- mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags);
+ mControllers.taskbarStashController.updateStateForSysuiFlags(systemUiStateFlags, fromInit);
+ mControllers.taskbarScrimViewController.updateStateForSysuiFlags(systemUiStateFlags,
+ fromInit);
}
/**
* Hides the taskbar icons and background when the notication shade is expanded.
*/
- private void onNotificationShadeExpandChanged(boolean isExpanded) {
+ private void onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim) {
float alpha = isExpanded ? 0 : 1;
AnimatorSet anim = new AnimatorSet();
anim.play(mControllers.taskbarViewController.getTaskbarIconAlpha().getProperty(
@@ -354,6 +374,9 @@
.animateToValue(alpha));
}
anim.start();
+ if (skipAnim) {
+ anim.end();
+ }
}
public void onRotationProposal(int rotation, boolean isValid) {
@@ -498,4 +521,25 @@
protected boolean isUserSetupComplete() {
return mIsUserSetupComplete;
}
+
+ /**
+ * Called when we determine the touchable region.
+ *
+ * @param exclude {@code true} then the magnification region computation will omit the window.
+ */
+ public void excludeFromMagnificationRegion(boolean exclude) {
+ if (mIsExcludeFromMagnificationRegion == exclude) {
+ return;
+ }
+
+ mIsExcludeFromMagnificationRegion = exclude;
+ if (exclude) {
+ mWindowLayoutParams.privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
+ } else {
+ mWindowLayoutParams.privateFlags &=
+ ~WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
+ }
+ mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 7b0053e..56730db 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -17,7 +17,7 @@
import androidx.annotation.NonNull;
-import com.android.launcher3.taskbar.contextual.RotationButtonController;
+import com.android.systemui.shared.rotation.RotationButtonController;
/**
* Hosts various taskbar controllers to facilitate passing between one another.
@@ -38,6 +38,7 @@
public final TaskbarStashController taskbarStashController;
public final TaskbarEduController taskbarEduController;
public final TaskbarAutohideSuspendController taskbarAutohideSuspendController;
+ public final TaskbarPopupController taskbarPopupController;
/** Do not store this controller, as it may change at runtime. */
@NonNull public TaskbarUIController uiController = TaskbarUIController.DEFAULT;
@@ -55,7 +56,8 @@
StashedHandleViewController stashedHandleViewController,
TaskbarStashController taskbarStashController,
TaskbarEduController taskbarEduController,
- TaskbarAutohideSuspendController taskbarAutoHideSuspendController) {
+ TaskbarAutohideSuspendController taskbarAutoHideSuspendController,
+ TaskbarPopupController taskbarPopupController) {
this.taskbarActivityContext = taskbarActivityContext;
this.taskbarDragController = taskbarDragController;
this.navButtonController = navButtonController;
@@ -70,6 +72,7 @@
this.taskbarStashController = taskbarStashController;
this.taskbarEduController = taskbarEduController;
this.taskbarAutohideSuspendController = taskbarAutoHideSuspendController;
+ this.taskbarPopupController = taskbarPopupController;
}
/**
@@ -79,10 +82,8 @@
*/
public void init(TaskbarSharedState sharedState) {
taskbarDragController.init(this);
- navbarButtonsViewController.init(this, sharedState);
- if (taskbarActivityContext.isThreeButtonNav()) {
- rotationButtonController.init();
- }
+ navbarButtonsViewController.init(this);
+ rotationButtonController.init();
taskbarDragLayerController.init(this);
taskbarViewController.init(this);
taskbarScrimViewController.init(this);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 3bcacb6..b3a9f8d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -40,6 +40,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.R;
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragDriver;
import com.android.launcher3.dragndrop.DragOptions;
@@ -49,6 +50,7 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ClipDescriptionCompat;
import com.android.systemui.shared.system.LauncherAppsCompat;
@@ -139,11 +141,13 @@
mDragView = null;
}
};
- // TODO: open popup/pre-drag
- // PopupContainerWithArrow popupContainer = PopupContainerWithArrow.showForIcon(view);
- // if (popupContainer != null) {
- // dragOptions.preDragCondition = popupContainer.createPreDragCondition();
- // }
+ if (FeatureFlags.ENABLE_TASKBAR_POPUP_MENU.get()) {
+ PopupContainerWithArrow<TaskbarActivityContext> popupContainer =
+ mControllers.taskbarPopupController.showForIcon(btv);
+ if (popupContainer != null) {
+ dragOptions.preDragCondition = popupContainer.createPreDragCondition();
+ }
+ }
startDrag(
drawable,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index cec892f..8c6185c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -137,12 +137,14 @@
// Always have nav buttons be touchable
mControllers.navbarButtonsViewController.addVisibleButtonsRegion(
mTaskbarDragLayer, insetsInfo.touchableRegion);
+ boolean insetsIsTouchableRegion = true;
if (mTaskbarDragLayer.getAlpha() < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
} else if (mControllers.navbarButtonsViewController.isImeVisible()) {
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_CONTENT);
+ insetsIsTouchableRegion = false;
} else if (!mControllers.uiController.isTaskbarTouchable()) {
// Let touches pass through us.
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
@@ -151,9 +153,11 @@
// Taskbar has some touchable elements, take over the full taskbar area
insetsInfo.setTouchableInsets(mActivity.isTaskbarWindowFullscreen()
? TOUCHABLE_INSETS_FRAME : TOUCHABLE_INSETS_CONTENT);
+ insetsIsTouchableRegion = false;
} else {
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_REGION);
}
+ mActivity.excludeFromMagnificationRegion(insetsIsTouchableRegion);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
new file mode 100644
index 0000000..152b255
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import 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_STASHED_LAUNCHER_STATE;
+import static com.android.launcher3.taskbar.TaskbarStashController.TASKBAR_STASH_DURATION;
+import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.BaseQuickstepLauncher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.util.MultiValueAlpha;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.RecentsAnimationCallbacks;
+import com.android.quickstep.RecentsAnimationController;
+import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.recents.model.ThumbnailData;
+
+import java.util.HashMap;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+
+/**
+ * Track LauncherState, RecentsAnimation, resumed state for task bar in one place here and animate
+ * the task bar accordingly.
+ */
+ public class TaskbarLauncherStateController {
+
+ public static final int FLAG_RESUMED = 1 << 0;
+ public static final int FLAG_RECENTS_ANIMATION_RUNNING = 1 << 1;
+ public static final int FLAG_TRANSITION_STATE_START_STASHED = 1 << 2;
+ public static final int FLAG_TRANSITION_STATE_COMMITTED_STASHED = 1 << 3;
+
+ private final AnimatedFloat mIconAlignmentForResumedState =
+ new AnimatedFloat(this::onIconAlignmentRatioChanged);
+ private final AnimatedFloat mIconAlignmentForGestureState =
+ new AnimatedFloat(this::onIconAlignmentRatioChanged);
+ private final AnimatedFloat mIconAlignmentForLauncherState =
+ new AnimatedFloat(this::onIconAlignmentRatioChangedForStateTransition);
+
+ private TaskbarControllers mControllers;
+ private AnimatedFloat mTaskbarBackgroundAlpha;
+ private MultiValueAlpha.AlphaProperty mIconAlphaForHome;
+ private BaseQuickstepLauncher mLauncher;
+
+ private int mPrevState;
+ private int mState;
+
+ private LauncherState mTargetStateOverride = null;
+ private LauncherState mTargetStateOverrideForStateTransition = null;
+
+ private boolean mIsAnimatingToLauncherViaGesture;
+ private boolean mIsAnimatingToLauncherViaResume;
+
+ private final StateManager.StateListener<LauncherState> mStateListener =
+ new StateManager.StateListener<LauncherState>() {
+
+ @Override
+ public void onStateTransitionStart(LauncherState toState) {
+ mTargetStateOverrideForStateTransition = toState;
+ updateStateForFlag(FLAG_TRANSITION_STATE_START_STASHED,
+ toState.isTaskbarStashed());
+ applyState();
+ }
+
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ updateStateForFlag(FLAG_TRANSITION_STATE_COMMITTED_STASHED,
+ finalState.isTaskbarStashed());
+ applyState();
+ }
+ };
+
+ public void init(TaskbarControllers controllers, BaseQuickstepLauncher launcher) {
+ mControllers = controllers;
+ mLauncher = launcher;
+
+ mTaskbarBackgroundAlpha = mControllers.taskbarDragLayerController
+ .getTaskbarBackgroundAlpha();
+ MultiValueAlpha taskbarIconAlpha = mControllers.taskbarViewController.getTaskbarIconAlpha();
+ mIconAlphaForHome = taskbarIconAlpha.getProperty(ALPHA_INDEX_HOME);
+ mIconAlphaForHome.setConsumer(
+ (Consumer<Float>) alpha -> mLauncher.getHotseat().setIconsAlpha(alpha > 0 ? 0 : 1));
+
+ mIconAlignmentForResumedState.finishAnimation();
+ onIconAlignmentRatioChanged();
+
+ mLauncher.getStateManager().addStateListener(mStateListener);
+ }
+
+ public void onDestroy() {
+ mIconAlignmentForResumedState.finishAnimation();
+ mIconAlignmentForGestureState.finishAnimation();
+ mIconAlignmentForLauncherState.finishAnimation();
+
+ mIconAlphaForHome.setConsumer(null);
+ mLauncher.getHotseat().setIconsAlpha(1f);
+ mLauncher.getStateManager().removeStateListener(mStateListener);
+ }
+
+ public Animator createAnimToLauncher(@NonNull LauncherState toState,
+ @NonNull RecentsAnimationCallbacks callbacks, long duration) {
+ // If going to overview, stash the task bar
+ // If going home, align the icons to hotseat
+ AnimatorSet animatorSet = new AnimatorSet();
+
+ TaskbarStashController stashController = mControllers.taskbarStashController;
+ stashController.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
+ toState.isTaskbarStashed());
+ stashController.updateStateForFlag(FLAG_IN_APP, false);
+
+ updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, true);
+ animatorSet.play(stashController.applyStateWithoutStart(duration));
+ animatorSet.play(applyState(duration, false));
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ mTargetStateOverride = null;
+ animator.removeListener(this);
+ }
+
+ @Override
+ public void onAnimationStart(Animator animator) {
+ mTargetStateOverride = toState;
+ }
+ });
+
+ TaskBarRecentsAnimationListener listener = new TaskBarRecentsAnimationListener(callbacks);
+ callbacks.addListener(listener);
+ RecentsView recentsView = mLauncher.getOverviewPanel();
+ recentsView.setTaskLaunchListener(() -> {
+ listener.endGestureStateOverride(true);
+ callbacks.removeListener(listener);
+ });
+ return animatorSet;
+ }
+
+ public boolean isAnimatingToLauncher() {
+ return mIsAnimatingToLauncherViaResume || mIsAnimatingToLauncherViaGesture;
+ }
+
+ /**
+ * Updates the proper flag to change the state of the task bar.
+ *
+ * Note that this only updates the flag. {@link #applyState()} needs to be called separately.
+ *
+ * @param flag The flag to update.
+ * @param enabled Whether to enable the flag
+ */
+ public void updateStateForFlag(int flag, boolean enabled) {
+ if (enabled) {
+ mState |= flag;
+ } else {
+ mState &= ~flag;
+ }
+ }
+
+ private boolean hasAnyFlag(int flagMask) {
+ return hasAnyFlag(mState, flagMask);
+ }
+
+ private boolean hasAnyFlag(int flags, int flagMask) {
+ return (flags & flagMask) != 0;
+ }
+
+ public void applyState() {
+ applyState(TASKBAR_STASH_DURATION);
+ }
+
+ public void applyState(long duration) {
+ applyState(duration, true);
+ }
+
+ public Animator applyState(boolean start) {
+ return applyState(TASKBAR_STASH_DURATION, start);
+ }
+
+ public Animator applyState(long duration, boolean start) {
+ Animator animator = null;
+ if (mPrevState != mState) {
+ int changedFlags = mPrevState ^ mState;
+ animator = onStateChangeApplied(changedFlags, duration, start);
+ mPrevState = mState;
+ }
+ return animator;
+ }
+
+ private Animator onStateChangeApplied(int changedFlags, long duration, boolean start) {
+ AnimatorSet animatorSet = new AnimatorSet();
+ if (hasAnyFlag(changedFlags, FLAG_RESUMED)) {
+ boolean isResumed = isResumed();
+ ObjectAnimator anim = mIconAlignmentForResumedState
+ .animateToValue(getCurrentIconAlignmentRatio(), isResumed ? 1 : 0)
+ .setDuration(duration);
+
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsAnimatingToLauncherViaResume = false;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsAnimatingToLauncherViaResume = isResumed;
+
+ TaskbarStashController stashController = mControllers.taskbarStashController;
+ stashController.updateStateForFlag(FLAG_IN_APP, !isResumed);
+ stashController.applyState(duration);
+ }
+ });
+ animatorSet.play(anim);
+ }
+
+ if (hasAnyFlag(changedFlags, FLAG_RECENTS_ANIMATION_RUNNING)) {
+ boolean isRecentsAnimationRunning = isRecentsAnimationRunning();
+ Animator animator = mIconAlignmentForGestureState
+ .animateToValue(isRecentsAnimationRunning ? 1 : 0);
+ if (isRecentsAnimationRunning) {
+ animator.setDuration(duration);
+ }
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mIsAnimatingToLauncherViaGesture = false;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIsAnimatingToLauncherViaGesture = isRecentsAnimationRunning();
+ }
+ });
+ animatorSet.play(animator);
+ }
+
+ if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_START_STASHED)) {
+ playStateTransitionAnim(isTransitionStateStartStashed(), animatorSet, duration,
+ false /* committed */);
+ }
+
+ if (hasAnyFlag(changedFlags, FLAG_TRANSITION_STATE_COMMITTED_STASHED)) {
+ playStateTransitionAnim(isTransitionStateCommittedStashed(), animatorSet, duration,
+ true /* committed */);
+ }
+
+ if (start) {
+ animatorSet.start();
+ }
+ return animatorSet;
+ }
+
+ private void playStateTransitionAnim(boolean isTransitionStateStashed,
+ AnimatorSet animatorSet, long duration, boolean committed) {
+ TaskbarStashController controller = mControllers.taskbarStashController;
+ controller.updateStateForFlag(FLAG_IN_STASHED_LAUNCHER_STATE,
+ isTransitionStateStashed);
+ Animator stashAnimator = controller.applyStateWithoutStart(duration);
+ if (stashAnimator != null) {
+ stashAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (isTransitionStateStashed && committed) {
+ // Reset hotseat alpha to default
+ mLauncher.getHotseat().setIconsAlpha(1);
+ }
+ mTargetStateOverrideForStateTransition = null;
+ }
+
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mIconAlphaForHome.setValue(mLauncher.getHotseat().getIconsAlpha());
+ }
+ });
+ animatorSet.play(stashAnimator);
+ animatorSet.play(mIconAlignmentForLauncherState.animateToValue(
+ getCurrentIconAlignmentRatioForLauncherState(),
+ isTransitionStateStashed ? 0 : 1));
+ } else {
+ mTargetStateOverrideForStateTransition = null;
+ }
+ }
+
+ private boolean isResumed() {
+ return (mState & FLAG_RESUMED) != 0;
+ }
+
+ private boolean isRecentsAnimationRunning() {
+ return (mState & FLAG_RECENTS_ANIMATION_RUNNING) != 0;
+ }
+
+ private boolean isTransitionStateStartStashed() {
+ return (mState & FLAG_TRANSITION_STATE_START_STASHED) != 0;
+ }
+
+ private boolean isTransitionStateCommittedStashed() {
+ return (mState & FLAG_TRANSITION_STATE_COMMITTED_STASHED) != 0;
+ }
+
+ private void onIconAlignmentRatioChangedForStateTransition() {
+ onIconAlignmentRatioChanged(
+ mTargetStateOverrideForStateTransition != null
+ ? mTargetStateOverrideForStateTransition
+ : mLauncher.getStateManager().getState(),
+ this::getCurrentIconAlignmentRatioForLauncherState);
+ }
+
+ private void onIconAlignmentRatioChanged() {
+ onIconAlignmentRatioChanged(mTargetStateOverride != null ? mTargetStateOverride
+ : mLauncher.getStateManager().getState(), this::getCurrentIconAlignmentRatio);
+ }
+
+ private void onIconAlignmentRatioChanged(LauncherState state,
+ Supplier<Float> alignmentSupplier) {
+ if (mControllers == null) {
+ return;
+ }
+ float alignment = alignmentSupplier.get();
+ mControllers.taskbarViewController.setLauncherIconAlignment(
+ alignment, mLauncher.getDeviceProfile());
+
+ mTaskbarBackgroundAlpha.updateValue(1 - alignment);
+
+ setIconAlpha(state, alignment);
+ }
+
+ private float getCurrentIconAlignmentRatio() {
+ return Math.max(mIconAlignmentForResumedState.value, mIconAlignmentForGestureState.value);
+ }
+
+ private float getCurrentIconAlignmentRatioForLauncherState() {
+ return mIconAlignmentForLauncherState.value;
+ }
+
+ private void setIconAlpha(LauncherState state, float progress) {
+ if ((state.getVisibleElements(mLauncher) & HOTSEAT_ICONS) != 0) {
+ // If the hotseat icons are visible, then switch taskbar in last frame
+ setTaskbarViewVisible(progress < 1);
+ } else {
+ mIconAlphaForHome.setValue(1 - progress);
+ }
+ }
+
+ private void setTaskbarViewVisible(boolean isVisible) {
+ mIconAlphaForHome.setValue(isVisible ? 1 : 0);
+ }
+
+ private final class TaskBarRecentsAnimationListener implements
+ RecentsAnimationCallbacks.RecentsAnimationListener {
+ private final RecentsAnimationCallbacks mCallbacks;
+
+ TaskBarRecentsAnimationListener(RecentsAnimationCallbacks callbacks) {
+ mCallbacks = callbacks;
+ }
+
+ @Override
+ public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
+ endGestureStateOverride(true);
+ }
+
+ @Override
+ public void onRecentsAnimationFinished(RecentsAnimationController controller) {
+ endGestureStateOverride(!controller.getFinishTargetIsLauncher());
+ }
+
+ private void endGestureStateOverride(boolean finishedToApp) {
+ mCallbacks.removeListener(this);
+ updateStateForFlag(FLAG_RECENTS_ANIMATION_RUNNING, false);
+ applyState();
+
+ TaskbarStashController controller = mControllers.taskbarStashController;
+ controller.updateStateForFlag(FLAG_IN_APP, finishedToApp);
+ controller.applyState();
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 92cee04..b2b078c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -16,8 +16,9 @@
package com.android.launcher3.taskbar;
import static android.view.Display.DEFAULT_DISPLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
+import static com.android.launcher3.testing.TestProtocol.TASKBAR_WINDOW_CRASH;
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
import static com.android.launcher3.util.DisplayController.CHANGE_SUPPORTED_BOUNDS;
@@ -30,6 +31,7 @@
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.provider.Settings;
+import android.util.Log;
import android.view.Display;
import androidx.annotation.NonNull;
@@ -40,6 +42,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.StatefulActivity;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.SettingsCache;
@@ -91,7 +94,7 @@
mSysUINavigationMode = SysUINavigationMode.INSTANCE.get(service);
Display display =
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
- mContext = service.createWindowContext(display, TYPE_APPLICATION_OVERLAY, null);
+ mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null);
mNavButtonController = new TaskbarNavButtonController(service);
mUserSetupCompleteListener = isUserSetupComplete -> recreateTaskbar();
mComponentCallbacks = new ComponentCallbacks() {
@@ -101,7 +104,7 @@
public void onConfigurationChanged(Configuration newConfig) {
int configDiff = mOldConfig.diff(newConfig);
int configsRequiringRecreate = ActivityInfo.CONFIG_ASSETS_PATHS
- | ActivityInfo.CONFIG_LAYOUT_DIRECTION;
+ | ActivityInfo.CONFIG_LAYOUT_DIRECTION | ActivityInfo.CONFIG_UI_MODE;
if ((configDiff & configsRequiringRecreate) != 0) {
// Color has changed, recreate taskbar to reload background color & icons.
recreateTaskbar();
@@ -204,6 +207,8 @@
}
private void recreateTaskbar() {
+ Log.d(TASKBAR_WINDOW_CRASH, "Recreating taskbar: mTaskbarActivityContext="
+ + mTaskbarActivityContext);
destroyExistingTaskbar();
DeviceProfile dp =
@@ -226,12 +231,13 @@
mTaskbarActivityContext.setUIController(
createTaskbarUIControllerForActivity(mActivity));
}
+ Log.d(TASKBAR_WINDOW_CRASH, "Finished recreating taskbar");
}
public void onSystemUiFlagsChanged(int systemUiStateFlags) {
mSharedState.sysuiStateFlags = systemUiStateFlags;
if (mTaskbarActivityContext != null) {
- mTaskbarActivityContext.updateSysuiStateFlags(systemUiStateFlags);
+ mTaskbarActivityContext.updateSysuiStateFlags(systemUiStateFlags, false /* fromInit */);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 5e76b96..6dcfe56 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -23,6 +23,7 @@
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
@@ -30,6 +31,7 @@
import java.util.ArrayList;
import java.util.Collections;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -186,4 +188,9 @@
TaskbarStashController.FLAG_STASHED_IN_APP_EMPTY, isHotseatEmpty);
mControllers.taskbarStashController.applyState();
}
+
+ @Override
+ public void bindDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) {
+ mControllers.taskbarPopupController.setDeepShortcutMap(deepShortcutMapCopy);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index 6fbef9b..a8a0b59 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -102,9 +102,7 @@
}
private void showIMESwitcher() {
- mService.getSystemService(InputMethodManager.class)
- .showInputMethodPickerFromSystem(true /* showAuxiliarySubtypes */,
- DEFAULT_DISPLAY);
+ SystemUiProxy.INSTANCE.getNoCreate().onImeSwitcherPressed();
}
private void notifyImeClick(boolean longClick) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
new file mode 100644
index 0000000..952f597
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.R;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.popup.SystemShortcut;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.views.ActivityContext;
+
+import java.util.HashMap;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Implements interfaces required to show and allow interacting with a PopupContainerWithArrow.
+ */
+public class TaskbarPopupController {
+
+ private static final SystemShortcut.Factory<TaskbarActivityContext>
+ APP_INFO = SystemShortcut.AppInfo::new;
+
+ private final PopupDataProvider mPopupDataProvider;
+
+ public TaskbarPopupController() {
+ // TODO (b/198438631): add notifications dots change listener
+ mPopupDataProvider = new PopupDataProvider(packageUserKey -> {});
+ }
+
+ @NonNull
+ public PopupDataProvider getPopupDataProvider() {
+ return mPopupDataProvider;
+ }
+
+ public void setDeepShortcutMap(HashMap<ComponentKey, Integer> deepShortcutMapCopy) {
+ mPopupDataProvider.setDeepShortcutMap(deepShortcutMapCopy);
+ }
+
+ /**
+ * Shows the notifications and deep shortcuts associated with a Taskbar {@param icon}.
+ * @return the container if shown or null.
+ */
+ public PopupContainerWithArrow<TaskbarActivityContext> showForIcon(BubbleTextView icon) {
+ TaskbarActivityContext context = ActivityContext.lookupContext(icon.getContext());
+ if (PopupContainerWithArrow.getOpen(context) != null) {
+ // There is already an items container open, so don't open this one.
+ icon.clearFocus();
+ return null;
+ }
+ ItemInfo item = (ItemInfo) icon.getTag();
+ if (!PopupContainerWithArrow.canShow(icon, item)) {
+ return null;
+ }
+
+ final PopupContainerWithArrow<TaskbarActivityContext> container =
+ (PopupContainerWithArrow) context.getLayoutInflater().inflate(
+ R.layout.popup_container, context.getDragLayer(), false);
+ // TODO (b/198438631): configure for taskbar/context
+
+ container.populateAndShow(icon,
+ mPopupDataProvider.getShortcutCountForItem(item),
+ mPopupDataProvider.getNotificationKeysForItem(item),
+ // TODO (b/198438631): add support for INSTALL shortcut factory
+ Stream.of(APP_INFO)
+ .map(s -> s.getShortcut(context, item))
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList()));
+ container.requestFocus();
+ return container;
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index e7e55ef..4b4ee44 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -62,7 +62,7 @@
/**
* Updates the scrim state based on the flags.
*/
- public void updateStateForSysuiFlags(int stateFlags) {
+ public void updateStateForSysuiFlags(int stateFlags, boolean skipAnim) {
final boolean bubblesExpanded = (stateFlags & SYSUI_STATE_BUBBLES_EXPANDED) != 0;
final boolean manageMenuExpanded =
(stateFlags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0;
@@ -73,15 +73,18 @@
// what the total transparency would be.
? (SCRIM_ALPHA + (SCRIM_ALPHA * (1 - SCRIM_ALPHA)))
: showScrim ? SCRIM_ALPHA : 0;
- showScrim(showScrim, scrimAlpha);
+ showScrim(showScrim, scrimAlpha, skipAnim);
}
- private void showScrim(boolean showScrim, float alpha) {
+ private void showScrim(boolean showScrim, float alpha, boolean skipAnim) {
mScrimView.setOnClickListener(showScrim ? (view) -> onClick() : null);
mScrimView.setClickable(showScrim);
ObjectAnimator anim = mScrimAlpha.animateToValue(showScrim ? alpha : 0);
anim.setInterpolator(showScrim ? SCRIM_ALPHA_IN : SCRIM_ALPHA_OUT);
anim.start();
+ if (skipAnim) {
+ anim.end();
+ }
}
private void updateScrimAlpha() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 0dd4ef1..acb4aa8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -94,6 +94,7 @@
private final SharedPreferences mPrefs;
private final int mStashedHeight;
private final int mUnstashedHeight;
+ private final SystemUiProxy mSystemUiProxy;
// Initialized in init.
private TaskbarControllers mControllers;
@@ -127,6 +128,7 @@
mPrefs = Utilities.getPrefs(mActivity);
final Resources resources = mActivity.getResources();
mStashedHeight = resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
+ mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
mUnstashedHeight = mActivity.getDeviceProfile().taskbarSize;
}
@@ -155,8 +157,7 @@
!mActivity.isUserSetupComplete() || sharedState.setupUIVisible);
applyState();
- SystemUiProxy.INSTANCE.get(mActivity)
- .notifyTaskbarStatus(/* visible */ false, /* stashed */ isStashedInApp());
+ notifyStashChange(/* visible */ false, /* stashed */ isStashedInApp());
}
/**
@@ -408,10 +409,10 @@
}
/** Called when some system ui state has changed. (See SYSUI_STATE_... in QuickstepContract) */
- public void updateStateForSysuiFlags(int systemUiStateFlags) {
+ public void updateStateForSysuiFlags(int systemUiStateFlags, boolean skipAnim) {
updateStateForFlag(FLAG_STASHED_IN_APP_PINNED,
hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_PINNING));
- applyState();
+ applyState(skipAnim ? 0 : TASKBAR_STASH_DURATION);
}
/**
@@ -440,8 +441,7 @@
mControllers.uiController.onStashedInAppChanged();
}
if (hasAnyFlag(changedFlags, FLAGS_STASHED_IN_APP | FLAG_IN_APP)) {
- SystemUiProxy.INSTANCE.get(mActivity)
- .notifyTaskbarStatus(/* visible */ hasAnyFlag(FLAG_IN_APP),
+ notifyStashChange(/* visible */ hasAnyFlag(FLAG_IN_APP),
/* stashed */ isStashedInApp());
}
if (hasAnyFlag(changedFlags, FLAG_STASHED_IN_APP_MANUAL)) {
@@ -453,6 +453,11 @@
}
}
+ private void notifyStashChange(boolean visible, boolean stashed) {
+ mSystemUiProxy.notifyTaskbarStatus(visible, stashed);
+ mControllers.rotationButtonController.onTaskbarStateChange(visible, stashed);
+ }
+
private class StatePropertyHolder {
private final IntPredicate mStashCondition;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 09197c3..c47bde9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -261,7 +261,7 @@
private boolean mCanceledStashHint;
public View.OnClickListener getIconOnClickListener() {
- return mActivity::onTaskbarIconClicked;
+ return mActivity.getItemOnClickListener();
}
public View.OnLongClickListener getIconOnLongClickListener() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButton.java b/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButton.java
deleted file mode 100644
index 4093097..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButton.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.taskbar.contextual;
-
-import android.graphics.drawable.AnimatedVectorDrawable;
-import android.view.View;
-
-/**
- * Interface of a rotation button that interacts {@link RotationButtonController}.
- * This interface exists because of the two different styles of rotation button in Sysui,
- * one in contextual for 3 button nav and a floating rotation button for gestural.
- * Keeping the interface for eventual migration of floating button, so some methods are
- * pass through to "super" while others are trivially implemented.
- *
- * Changes:
- * * Directly use AnimatedVectorDrawable instead of KeyButtonDrawable
- */
-public interface RotationButton {
- default void setRotationButtonController(RotationButtonController rotationButtonController) { }
-
- default View getCurrentView() {
- return null;
- }
- default void show() { }
- default void hide() { }
- default boolean isVisible() {
- return false;
- }
-
- default void updateIcon(int lightIconColor, int darkIconColor) { }
- default void setOnClickListener(View.OnClickListener onClickListener) { }
- default void setOnHoverListener(View.OnHoverListener onHoverListener) { }
- default AnimatedVectorDrawable getImageDrawable() {
- return null;
- }
- default void setDarkIntensity(float darkIntensity) { }
- default boolean acceptRotationProposal() {
- return getCurrentView() != null;
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java b/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java
deleted file mode 100644
index c776f16..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/contextual/RotationButtonController.java
+++ /dev/null
@@ -1,512 +0,0 @@
-/*
- * Copyright 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.taskbar.contextual;
-
-import static android.view.Display.DEFAULT_DISPLAY;
-
-import static com.android.internal.view.RotationPolicy.NATURAL_ROTATION;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.annotation.ColorInt;
-import android.annotation.DrawableRes;
-import android.annotation.SuppressLint;
-import android.app.StatusBarManager;
-import android.content.ContentResolver;
-import android.content.Context;
-import android.graphics.drawable.AnimatedVectorDrawable;
-import android.os.Handler;
-import android.os.Looper;
-import android.os.RemoteException;
-import android.provider.Settings;
-import android.util.Log;
-import android.view.IRotationWatcher;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.View;
-import android.view.WindowInsetsController;
-import android.view.WindowManagerGlobal;
-import android.view.accessibility.AccessibilityManager;
-
-import com.android.internal.logging.UiEvent;
-import com.android.internal.logging.UiEventLogger;
-import com.android.internal.logging.UiEventLoggerImpl;
-import com.android.internal.view.RotationPolicy;
-import com.android.launcher3.R;
-import com.android.launcher3.util.DisplayController;
-import com.android.systemui.shared.recents.utilities.Utilities;
-import com.android.systemui.shared.recents.utilities.ViewRippler;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.TaskStackChangeListeners;
-
-import java.util.Optional;
-
-/**
- * Copied over from the SysUI equivalent class. Known issues/things not ported over
- * * When rotation button visible and in auto-hide mode, we ask auto-hide controller to
- * keep the navbar around longer. Will need to implement if we use auto-hide on taskbar
- *
- * Contains logic that deals with showing a rotate suggestion button with animation.
- */
-public class RotationButtonController {
-
- private static final String TAG = "StatusBar/RotationButtonController";
- private static final int BUTTON_FADE_IN_OUT_DURATION_MS = 100;
- private static final int NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS = 20000;
-
- private static final int NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION = 3;
-
- private final Context mContext;
- private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
- private final UiEventLogger mUiEventLogger = new UiEventLoggerImpl();
- private final ViewRippler mViewRippler = new ViewRippler();
- private final DisplayController mDisplayController;
- private RotationButton mRotationButton;
-
- private int mLastRotationSuggestion;
- private boolean mPendingRotationSuggestion;
- private boolean mHoveringRotationSuggestion;
- private final AccessibilityManager mAccessibilityManager;
- private final TaskStackListenerImpl mTaskStackListener;
- private boolean mListenersRegistered = false;
- private boolean mIsTaskbarShowing;
- @SuppressLint("InlinedApi")
- private @WindowInsetsController.Behavior
- int mBehavior = WindowInsetsController.BEHAVIOR_DEFAULT;
- private boolean mSkipOverrideUserLockPrefsOnce;
- private final int mLightIconColor;
- private final int mDarkIconColor;
- private int mIconResId = R.drawable.ic_sysbar_rotate_button_ccw_start_90;
-
- private final Runnable mRemoveRotationProposal =
- () -> setRotateSuggestionButtonState(false /* visible */);
- private final Runnable mCancelPendingRotationProposal =
- () -> mPendingRotationSuggestion = false;
- private Animator mRotateHideAnimator;
-
-
- private final IRotationWatcher.Stub mRotationWatcher = new IRotationWatcher.Stub() {
- @Override
- public void onRotationChanged(final int rotation) {
- // We need this to be scheduled as early as possible to beat the redrawing of
- // window in response to the orientation change.
- mMainThreadHandler.postAtFrontOfQueue(() -> {
- // If the screen rotation changes while locked, potentially update lock to flow with
- // new screen rotation and hide any showing suggestions.
- if (isRotationLocked()) {
- if (shouldOverrideUserLockPrefs(rotation)) {
- setRotationLockedAtAngle(rotation);
- }
- setRotateSuggestionButtonState(false /* visible */, true /* forced */);
- }
- });
- }
- };
-
- /**
- * Determines if rotation suggestions disabled2 flag exists in flag
- * @param disable2Flags see if rotation suggestion flag exists in this flag
- * @return whether flag exists
- */
- static boolean hasDisable2RotateSuggestionFlag(int disable2Flags) {
- return (disable2Flags & StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS) != 0;
- }
-
- public RotationButtonController(Context context, @ColorInt int lightIconColor,
- @ColorInt int darkIconColor) {
- mContext = context;
- mLightIconColor = lightIconColor;
- mDarkIconColor = darkIconColor;
-
- mAccessibilityManager = AccessibilityManager.getInstance(context);
- mTaskStackListener = new TaskStackListenerImpl();
- mDisplayController = DisplayController.INSTANCE.get(context);
- }
-
- public void setRotationButton(RotationButton rotationButton) {
- mRotationButton = rotationButton;
- mRotationButton.setRotationButtonController(this);
- mRotationButton.setOnClickListener(this::onRotateSuggestionClick);
- mRotationButton.setOnHoverListener(this::onRotateSuggestionHover);
- }
-
- public void init() {
- registerListeners();
- if (mContext.getDisplay().getDisplayId() != DEFAULT_DISPLAY) {
- // Currently there is no accelerometer sensor on non-default display, disable fixed
- // rotation for non-default display
- onDisable2FlagChanged(StatusBarManager.DISABLE2_ROTATE_SUGGESTIONS);
- }
- }
-
- public void onDestroy() {
- unregisterListeners();
- }
-
- private void registerListeners() {
- if (mListenersRegistered) {
- return;
- }
-
- mListenersRegistered = true;
- try {
- WindowManagerGlobal.getWindowManagerService()
- .watchRotation(mRotationWatcher, DEFAULT_DISPLAY);
- } catch (IllegalArgumentException e) {
- mListenersRegistered = false;
- Log.w(TAG, "RegisterListeners for the display failed");
- } catch (RemoteException e) {
- Log.e(TAG, "RegisterListeners caught a RemoteException", e);
- return;
- }
-
- TaskStackChangeListeners.getInstance().registerTaskStackListener(mTaskStackListener);
- }
-
- void unregisterListeners() {
- if (!mListenersRegistered) {
- return;
- }
-
- mListenersRegistered = false;
- try {
- WindowManagerGlobal.getWindowManagerService().removeRotationWatcher(mRotationWatcher);
- } catch (RemoteException e) {
- Log.e(TAG, "UnregisterListeners caught a RemoteException", e);
- return;
- }
-
- TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
- }
-
- void setRotationLockedAtAngle(int rotationSuggestion) {
- RotationPolicy.setRotationLockAtAngle(mContext, true, rotationSuggestion);
- }
-
- public boolean isRotationLocked() {
- return RotationPolicy.isRotationLocked(mContext);
- }
-
- public void setRotateSuggestionButtonState(boolean visible) {
- setRotateSuggestionButtonState(visible, false /* force */);
- }
-
- void setRotateSuggestionButtonState(final boolean visible, final boolean force) {
- // At any point the button can become invisible because an a11y service became active.
- // Similarly, a call to make the button visible may be rejected because an a11y service is
- // active. Must account for this.
- // Rerun a show animation to indicate change but don't rerun a hide animation
- if (!visible && !mRotationButton.isVisible()) return;
-
- final View view = mRotationButton.getCurrentView();
- if (view == null) return;
-
- final AnimatedVectorDrawable currentDrawable = mRotationButton.getImageDrawable();
- if (currentDrawable == null) return;
-
- // Clear any pending suggestion flag as it has either been nullified or is being shown
- mPendingRotationSuggestion = false;
- mMainThreadHandler.removeCallbacks(mCancelPendingRotationProposal);
-
- // Handle the visibility change and animation
- if (visible) { // Appear and change (cannot force)
- // Stop and clear any currently running hide animations
- if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
- mRotateHideAnimator.cancel();
- }
- mRotateHideAnimator = null;
-
- // Reset the alpha if any has changed due to hide animation
- view.setAlpha(1f);
-
- // Run the rotate icon's animation if it has one
- currentDrawable.reset();
- currentDrawable.start();
-
- // TODO(b/187754252): No idea why this doesn't work. If we remove the "false"
- // we see the animation show the pressed state... but it only shows the first time.
- if (!isRotateSuggestionIntroduced()) mViewRippler.start(view);
-
- // Set visibility unless a11y service is active.
- mRotationButton.show();
- } else { // Hide
- mViewRippler.stop(); // Prevent any pending ripples, force hide or not
-
- if (force) {
- // If a hide animator is running stop it and make invisible
- if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) {
- mRotateHideAnimator.pause();
- }
- mRotationButton.hide();
- return;
- }
-
- // Don't start any new hide animations if one is running
- if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
-
- ObjectAnimator fadeOut = ObjectAnimator.ofFloat(view, "alpha", 0f);
- fadeOut.setDuration(BUTTON_FADE_IN_OUT_DURATION_MS);
- fadeOut.setInterpolator(LINEAR);
- fadeOut.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mRotationButton.hide();
- }
- });
-
- mRotateHideAnimator = fadeOut;
- fadeOut.start();
- }
- }
-
- void setDarkIntensity(float darkIntensity) {
- mRotationButton.setDarkIntensity(darkIntensity);
- }
-
- public void onRotationProposal(int rotation, boolean isValid) {
- int windowRotation = mDisplayController.getInfo().rotation;
-
- if (!mRotationButton.acceptRotationProposal()) {
- return;
- }
-
- // This method will be called on rotation suggestion changes even if the proposed rotation
- // is not valid for the top app. Use invalid rotation choices as a signal to remove the
- // rotate button if shown.
- if (!isValid) {
- setRotateSuggestionButtonState(false /* visible */);
- return;
- }
-
- // If window rotation matches suggested rotation, remove any current suggestions
- if (rotation == windowRotation) {
- mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
- setRotateSuggestionButtonState(false /* visible */);
- return;
- }
-
- // Prepare to show the navbar icon by updating the icon style to change anim params
- mLastRotationSuggestion = rotation; // Remember rotation for click
- final boolean rotationCCW = Utilities.isRotationAnimationCCW(windowRotation, rotation);
- if (windowRotation == Surface.ROTATION_0 || windowRotation == Surface.ROTATION_180) {
- mIconResId = rotationCCW
- ? R.drawable.ic_sysbar_rotate_button_ccw_start_90
- : R.drawable.ic_sysbar_rotate_button_cw_start_90;
- } else { // 90 or 270
- mIconResId = rotationCCW
- ? R.drawable.ic_sysbar_rotate_button_ccw_start_0
- : R.drawable.ic_sysbar_rotate_button_ccw_start_0;
- }
- mRotationButton.updateIcon(mLightIconColor, mDarkIconColor);
-
- if (canShowRotationButton()) {
- // The navbar is visible / it's in visual immersive mode, so show the icon right away
- showAndLogRotationSuggestion();
- } else {
- // If the navbar isn't shown, flag the rotate icon to be shown should the navbar become
- // visible given some time limit.
- mPendingRotationSuggestion = true;
- mMainThreadHandler.removeCallbacks(mCancelPendingRotationProposal);
- mMainThreadHandler.postDelayed(mCancelPendingRotationProposal,
- NAVBAR_HIDDEN_PENDING_ICON_TIMEOUT_MS);
- }
- }
-
- public void onDisable2FlagChanged(int state2) {
- final boolean rotateSuggestionsDisabled = hasDisable2RotateSuggestionFlag(state2);
- if (rotateSuggestionsDisabled) onRotationSuggestionsDisabled();
- }
-
- public void onBehaviorChanged(int displayId, @WindowInsetsController.Behavior int behavior) {
- if (DEFAULT_DISPLAY != displayId) {
- return;
- }
-
- if (mBehavior != behavior) {
- mBehavior = behavior;
- showPendingRotationButtonIfNeeded();
- }
- }
-
- public void onTaskBarVisibilityChange(boolean showing) {
- if (mIsTaskbarShowing != showing) {
- mIsTaskbarShowing = showing;
- showPendingRotationButtonIfNeeded();
- }
- }
-
- private void showPendingRotationButtonIfNeeded() {
- if (canShowRotationButton() && mPendingRotationSuggestion) {
- showAndLogRotationSuggestion();
- }
- }
-
- /** Return true when either the task bar is visible or it's in visual immersive mode. */
- @SuppressLint("InlinedApi")
- private boolean canShowRotationButton() {
- return mIsTaskbarShowing || mBehavior == WindowInsetsController.BEHAVIOR_DEFAULT;
- }
-
- public @DrawableRes
- int getIconResId() {
- return mIconResId;
- }
-
- public @ColorInt int getLightIconColor() {
- return mLightIconColor;
- }
-
- public @ColorInt int getDarkIconColor() {
- return mDarkIconColor;
- }
-
- private void onRotateSuggestionClick(View v) {
- mUiEventLogger.log(RotationButtonEvent.ROTATION_SUGGESTION_ACCEPTED);
- incrementNumAcceptedRotationSuggestionsIfNeeded();
- setRotationLockedAtAngle(mLastRotationSuggestion);
- }
-
- private boolean onRotateSuggestionHover(View v, MotionEvent event) {
- final int action = event.getActionMasked();
- mHoveringRotationSuggestion = (action == MotionEvent.ACTION_HOVER_ENTER)
- || (action == MotionEvent.ACTION_HOVER_MOVE);
- rescheduleRotationTimeout(true /* reasonHover */);
- return false; // Must return false so a11y hover events are dispatched correctly.
- }
-
- private void onRotationSuggestionsDisabled() {
- // Immediately hide the rotate button and clear any planned removal
- setRotateSuggestionButtonState(false /* visible */, true /* force */);
- mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
- }
-
- private void showAndLogRotationSuggestion() {
- setRotateSuggestionButtonState(true /* visible */);
- rescheduleRotationTimeout(false /* reasonHover */);
- mUiEventLogger.log(RotationButtonEvent.ROTATION_SUGGESTION_SHOWN);
- }
-
- /**
- * Makes {@link #shouldOverrideUserLockPrefs} always return {@code false} once. It is used to
- * avoid losing original user rotation when display rotation is changed by entering the fixed
- * orientation overview.
- */
- void setSkipOverrideUserLockPrefsOnce() {
- mSkipOverrideUserLockPrefsOnce = true;
- }
-
- private boolean shouldOverrideUserLockPrefs(final int rotation) {
- if (mSkipOverrideUserLockPrefsOnce) {
- mSkipOverrideUserLockPrefsOnce = false;
- return false;
- }
- // Only override user prefs when returning to the natural rotation (normally portrait).
- // Don't let apps that force landscape or 180 alter user lock.
- return rotation == NATURAL_ROTATION;
- }
-
- private void rescheduleRotationTimeout(final boolean reasonHover) {
- // May be called due to a new rotation proposal or a change in hover state
- if (reasonHover) {
- // Don't reschedule if a hide animator is running
- if (mRotateHideAnimator != null && mRotateHideAnimator.isRunning()) return;
- // Don't reschedule if not visible
- if (!mRotationButton.isVisible()) return;
- }
-
- // Stop any pending removal
- mMainThreadHandler.removeCallbacks(mRemoveRotationProposal);
- // Schedule timeout
- mMainThreadHandler.postDelayed(mRemoveRotationProposal,
- computeRotationProposalTimeout());
- }
-
- private int computeRotationProposalTimeout() {
- return mAccessibilityManager.getRecommendedTimeoutMillis(
- mHoveringRotationSuggestion ? 16000 : 5000,
- AccessibilityManager.FLAG_CONTENT_CONTROLS);
- }
-
- private boolean isRotateSuggestionIntroduced() {
- ContentResolver cr = mContext.getContentResolver();
- return Settings.Secure.getInt(cr, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, 0)
- >= NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION;
- }
-
- private void incrementNumAcceptedRotationSuggestionsIfNeeded() {
- // Get the number of accepted suggestions
- ContentResolver cr = mContext.getContentResolver();
- final int numSuggestions = Settings.Secure.getInt(cr,
- Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED, 0);
-
- // Increment the number of accepted suggestions only if it would change intro mode
- if (numSuggestions < NUM_ACCEPTED_ROTATION_SUGGESTIONS_FOR_INTRODUCTION) {
- Settings.Secure.putInt(cr, Settings.Secure.NUM_ROTATION_SUGGESTIONS_ACCEPTED,
- numSuggestions + 1);
- }
- }
-
- private class TaskStackListenerImpl extends TaskStackChangeListener {
- // Invalidate any rotation suggestion on task change or activity orientation change
- // Note: all callbacks happen on main thread
-
- @Override
- public void onTaskStackChanged() {
- setRotateSuggestionButtonState(false /* visible */);
- }
-
- @Override
- public void onTaskRemoved(int taskId) {
- setRotateSuggestionButtonState(false /* visible */);
- }
-
- @Override
- public void onTaskMovedToFront(int taskId) {
- setRotateSuggestionButtonState(false /* visible */);
- }
-
- @Override
- public void onActivityRequestedOrientationChanged(int taskId, int requestedOrientation) {
- // Only hide the icon if the top task changes its requestedOrientation
- // Launcher can alter its requestedOrientation while it's not on top, don't hide on this
- Optional.ofNullable(ActivityManagerWrapper.getInstance())
- .map(ActivityManagerWrapper::getRunningTask)
- .ifPresent(a -> {
- if (a.id == taskId) setRotateSuggestionButtonState(false /* visible */);
- });
- }
- }
-
- enum RotationButtonEvent implements UiEventLogger.UiEventEnum {
- @UiEvent(doc = "The rotation button was shown")
- ROTATION_SUGGESTION_SHOWN(206),
- @UiEvent(doc = "The rotation button was clicked")
- ROTATION_SUGGESTION_ACCEPTED(207);
-
- private final int mId;
- RotationButtonEvent(int id) {
- mId = id;
- }
- @Override public int getId() {
- return mId;
- }
- }
-}
-
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index e8aa2fa..45b2081 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -121,6 +121,8 @@
import com.android.systemui.shared.system.TaskStackChangeListeners;
import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Arrays;
import java.util.function.Consumer;
/**
@@ -399,9 +401,10 @@
// Set up a entire animation lifecycle callback to notify the current recents view when
// the animation is canceled
mGestureState.runOnceAtState(STATE_RECENTS_ANIMATION_CANCELED, () -> {
- ThumbnailData snapshot = mGestureState.consumeRecentsAnimationCanceledSnapshot();
- if (snapshot != null) {
- mRecentsView.switchToScreenshot(snapshot, () -> {
+ HashMap<Integer, ThumbnailData> snapshots =
+ mGestureState.consumeRecentsAnimationCanceledSnapshot();
+ if (snapshots != null) {
+ mRecentsView.switchToScreenshot(snapshots, () -> {
if (mRecentsAnimationController != null) {
mRecentsAnimationController.cleanupScreenshot();
}
@@ -677,6 +680,9 @@
public WindowInsets onApplyWindowInsets(View view, WindowInsets windowInsets) {
WindowInsets result = view.onApplyWindowInsets(windowInsets);
buildAnimationController();
+ // Reapply the current shift to ensure it takes new insets into account, e.g. when long
+ // pressing to stash taskbar without moving the finger.
+ updateFinalShift();
return result;
}
@@ -806,7 +812,7 @@
}
@Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
ActiveGestureLog.INSTANCE.addLog("cancelRecentsAnimation");
mActivityInitListener.unregister();
mStateCallback.setStateOnUiThread(STATE_GESTURE_CANCELLED | STATE_HANDLER_INVALIDATED);
@@ -961,20 +967,23 @@
} else {
mStateCallback.setState(STATE_RESUME_LAST_TASK);
}
- TaskViewUtils.setSplitAuxiliarySurfacesShown(
- mRecentsAnimationTargets.nonApps, true);
+ if (mRecentsAnimationTargets != null) {
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(
+ mRecentsAnimationTargets.nonApps, true);
+ }
break;
}
ActiveGestureLog.INSTANCE.addLog("onSettledOnEndTarget " + endTarget);
}
/** @return Whether this was the task we were waiting to appear, and thus handled it. */
- protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ protected boolean handleTaskAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) {
if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) {
return false;
}
- if (mStateCallback.hasStates(STATE_START_NEW_TASK)
- && appearedTaskTarget.taskId == mGestureState.getLastStartedTaskId()) {
+ boolean hasStartedTaskBefore = Arrays.stream(appearedTaskTarget).anyMatch(
+ targetCompat -> targetCompat.taskId == mGestureState.getLastStartedTaskId());
+ if (mStateCallback.hasStates(STATE_START_NEW_TASK) && hasStartedTaskBefore) {
reset();
return true;
}
@@ -1447,7 +1456,7 @@
}
private void setupWindowAnimation(RectFSpringAnim[] anims) {
- anims[0].addOnUpdateListener((v, r, p) -> {
+ anims[0].addOnUpdateListener((r, p) -> {
updateSysUiFlags(Math.max(p, mCurrentShift.value));
});
anims[0].addAnimatorListener(new AnimationSuccessListener() {
@@ -1734,7 +1743,10 @@
endLauncherTransitionController();
mRecentsView.onSwipeUpAnimationSuccess();
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- mTaskAnimationManager.setLiveTileCleanUpHandler(mInputConsumerProxy::destroy);
+ mTaskAnimationManager.setLiveTileCleanUpHandler(() -> {
+ mRecentsView.cleanupRemoteTargets();
+ mInputConsumerProxy.destroy();
+ });
mTaskAnimationManager.enableLiveTileRestartListener();
}
@@ -1799,13 +1811,8 @@
mGestureState.updateLastStartedTaskId(taskId);
boolean hasTaskPreviouslyAppeared = mGestureState.getPreviouslyAppearedTaskIds()
.contains(taskId);
- boolean isOldTaskSplit = LauncherSplitScreenListener.INSTANCE.getNoCreate()
- .getRunningSplitTaskIds().length > 0;
nextTask.launchTask(success -> {
resultCallback.accept(success);
- if (isOldTaskSplit) {
- SystemUiProxy.INSTANCE.getNoCreate().exitSplitScreen(taskId);
- }
if (success) {
if (hasTaskPreviouslyAppeared) {
onRestartPreviouslyAppearedTask();
@@ -1861,9 +1868,9 @@
}
@Override
- public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ public void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) {
if (mRecentsAnimationController != null) {
- if (handleTaskAppeared(appearedTaskTarget)) {
+ if (handleTaskAppeared(appearedTaskTargets)) {
mRecentsAnimationController.finish(false /* toRecents */,
null /* onFinishComplete */);
mActivityInterface.onLaunchTaskSuccess();
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index cf06036..e15aa92 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -66,6 +66,7 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import java.util.HashMap;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -192,7 +193,8 @@
public void closeOverlay() { }
- public void switchRunningTaskViewToScreenshot(ThumbnailData thumbnailData, Runnable runnable) {
+ public void switchRunningTaskViewToScreenshot(HashMap<Integer, ThumbnailData> thumbnailDatas,
+ Runnable runnable) {
ACTIVITY_TYPE activity = getCreatedActivity();
if (activity == null) {
return;
@@ -204,7 +206,7 @@
}
return;
}
- recentsView.switchToScreenshot(thumbnailData, runnable);
+ recentsView.switchToScreenshot(thumbnailDatas, runnable);
}
/**
@@ -304,11 +306,10 @@
* Calculates the overview grid size for the provided device configuration.
*/
public final void calculateGridSize(Context context, DeviceProfile dp, Rect outRect) {
- Resources res = context.getResources();
Rect insets = dp.getInsets();
int topMargin = dp.overviewTaskThumbnailTopMarginPx;
int bottomMargin = getOverviewActionsHeight(context, dp);
- int sideMargin = res.getDimensionPixelSize(R.dimen.overview_grid_side_margin);
+ int sideMargin = dp.overviewGridSideMargin;
outRect.set(0, 0, dp.widthPx, dp.heightPx);
outRect.inset(Math.max(insets.left, sideMargin), insets.top + topMargin,
@@ -321,11 +322,11 @@
public final void calculateGridTaskSize(Context context, DeviceProfile dp, Rect outRect,
PagedOrientationHandler orientedState) {
Resources res = context.getResources();
- Rect gridRect = new Rect();
- calculateGridSize(context, dp, gridRect);
+ Rect taskRect = new Rect();
+ calculateTaskSize(context, dp, taskRect);
float rowHeight =
- (gridRect.height() + dp.overviewTaskThumbnailTopMarginPx - dp.overviewRowSpacing)
+ (taskRect.height() + dp.overviewTaskThumbnailTopMarginPx - dp.overviewRowSpacing)
/ 2f;
PointF taskDimension = getTaskDimension(context, dp);
@@ -335,7 +336,7 @@
int gravity = Gravity.TOP;
gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
- Gravity.apply(gravity, outWidth, outHeight, gridRect, outRect);
+ Gravity.apply(gravity, outWidth, outHeight, taskRect, outRect);
}
/**
diff --git a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
index c1b45e0..a82137e 100644
--- a/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/FallbackSwipeHandler.java
@@ -50,7 +50,6 @@
import android.view.SurfaceControl.Transaction;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
@@ -59,7 +58,6 @@
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.quickstep.fallback.FallbackRecentsView;
import com.android.quickstep.fallback.RecentsState;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
@@ -149,7 +147,7 @@
}
@Override
- protected boolean handleTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ protected boolean handleTaskAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) {
if (mActiveAnimationFactory != null
&& mActiveAnimationFactory.handleHomeTaskAppeared(appearedTaskTarget)) {
mActiveAnimationFactory = null;
@@ -262,7 +260,8 @@
}
}
- public boolean handleHomeTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ public boolean handleHomeTaskAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) {
+ RemoteAnimationTargetCompat appearedTaskTarget = appearedTaskTargets[0];
if (appearedTaskTarget.activityType == ACTIVITY_TYPE_HOME) {
RemoteAnimationTargets targets = new RemoteAnimationTargets(
new RemoteAnimationTargetCompat[] {appearedTaskTarget},
@@ -317,8 +316,7 @@
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) {
+ public void update(RectF currentRect, float progress, float radius) {
if (mSurfaceControl != null) {
currentRect.roundOut(mTempRect);
Transaction t = new Transaction();
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 99f1dc7..9bc98d6 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -35,6 +35,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
@@ -139,7 +140,7 @@
private Set<Integer> mPreviouslyAppearedTaskIds = new HashSet<>();
private int mLastStartedTaskId = -1;
private RecentsAnimationController mRecentsAnimationController;
- private ThumbnailData mRecentsAnimationCanceledSnapshot;
+ private HashMap<Integer, ThumbnailData> mRecentsAnimationCanceledSnapshots;
/** The time when the swipe up gesture is triggered. */
private long mSwipeUpStartTimeMs;
@@ -354,16 +355,16 @@
}
@Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
- mRecentsAnimationCanceledSnapshot = thumbnailData;
+ public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
+ mRecentsAnimationCanceledSnapshots = thumbnailDatas;
mStateCallback.setState(STATE_RECENTS_ANIMATION_CANCELED);
mStateCallback.setState(STATE_RECENTS_ANIMATION_ENDED);
- if (mRecentsAnimationCanceledSnapshot != null) {
+ if (mRecentsAnimationCanceledSnapshots != null) {
// Clean up the screenshot to finalize the recents animation cancel
if (mRecentsAnimationController != null) {
mRecentsAnimationController.cleanupScreenshot();
}
- mRecentsAnimationCanceledSnapshot = null;
+ mRecentsAnimationCanceledSnapshots = null;
}
}
@@ -378,9 +379,10 @@
* while STATE_RECENTS_ANIMATION_CANCELED state is being set, and the caller is responsible for
* calling {@link RecentsAnimationController#cleanupScreenshot()}.
*/
- ThumbnailData consumeRecentsAnimationCanceledSnapshot() {
- ThumbnailData data = mRecentsAnimationCanceledSnapshot;
- mRecentsAnimationCanceledSnapshot = null;
+ HashMap<Integer, ThumbnailData> consumeRecentsAnimationCanceledSnapshot() {
+ HashMap<Integer, ThumbnailData> data =
+ new HashMap<Integer, ThumbnailData>(mRecentsAnimationCanceledSnapshots);
+ mRecentsAnimationCanceledSnapshots = null;
return data;
}
diff --git a/quickstep/src/com/android/quickstep/KtR.java b/quickstep/src/com/android/quickstep/KtR.java
new file mode 100644
index 0000000..57dad08
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/KtR.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import com.android.launcher3.R;
+
+/**
+ * Bridge class to allow using resources in Kotlin.
+ * <br/>
+ * TODO(b/204069723) Can't use resources directly in Kotlin
+ */
+public class KtR {
+ public static final class id {
+ public static int menu_option_layout = R.id.menu_option_layout;
+ }
+
+ public static final class dimen {
+ public static int task_menu_spacing = R.dimen.task_menu_spacing;
+ }
+
+ public static final class layout {
+ public static int task_menu_with_arrow = R.layout.task_menu_with_arrow;
+ public static int task_view_menu_option = R.layout.task_view_menu_option;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 0181cd7..8a30aad 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -18,18 +18,14 @@
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.Utilities.boundToRange;
import static com.android.launcher3.Utilities.dpToPx;
import static com.android.launcher3.Utilities.mapBoundToRange;
import static com.android.launcher3.anim.Interpolators.EXAGGERATED_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
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;
-import static java.lang.Math.round;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -59,10 +55,8 @@
import com.android.launcher3.views.FloatingIconView;
import com.android.launcher3.views.FloatingView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
-import com.android.quickstep.util.WorkspaceRevealAnim;
import com.android.quickstep.views.FloatingWidgetView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -167,15 +161,9 @@
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect,
- float progress, float radius) {
- super.update(config, currentRect, progress, radius);
- int fgAlpha = 255;
- if (config != null && PROTOTYPE_APP_CLOSE.get()) {
- progress = config.getInterpolatedProgress();
- fgAlpha = config.getFgAlpha();
- }
- floatingIconView.update(1f, fgAlpha, currentRect, progress,
+ public void update(RectF currentRect, float progress, float radius) {
+ super.update(currentRect, progress, radius);
+ floatingIconView.update(1f /* alpha */, 255 /* fgAlpha */, currentRect, progress,
windowAlphaThreshold, radius, false);
}
};
@@ -232,9 +220,8 @@
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) {
- super.update(config, currentRect, progress, radius);
+ public void update(RectF currentRect, float progress, float radius) {
+ super.update(currentRect, progress, radius);
final float fallbackBackgroundAlpha =
1 - mapBoundToRange(progress, 0.8f, 1, 0, 1, EXAGGERATED_EASE);
final float foregroundAlpha =
@@ -293,27 +280,12 @@
private final float mTransY;
private final FloatingView mFloatingView;
private ValueAnimator mBounceBackAnimator;
- private final AnimatorSet mWorkspaceReveal;
FloatingViewHomeAnimationFactory(FloatingView floatingView) {
mFloatingView = floatingView;
ResourceProvider rp = DynamicResource.provider(mActivity);
mTransY = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
-
- mWorkspaceReveal = PROTOTYPE_APP_CLOSE.get()
- ? new WorkspaceRevealAnim(mActivity, true /* animateScrim */).getAnimators()
- : null;
- }
-
- @Override
- public @NonNull RectF getWindowTargetRect() {
- if (PROTOTYPE_APP_CLOSE.get()) {
- // We want the target rect to be at this offset position, so that all
- // launcher content can spring back upwards.
- mFloatingView.setPositionOffsetY(mTransY);
- }
- return super.getWindowTargetRect();
}
@Override
@@ -321,20 +293,6 @@
return false;
}
- @Override
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) {
- if (config != null && PROTOTYPE_APP_CLOSE.get()) {
- DragLayer dl = mActivity.getDragLayer();
- float translationY = config.getWorkspaceTransY();
- dl.setTranslationY(translationY);
-
- long duration = mWorkspaceReveal.getDuration();
- long playTime = boundToRange(round(duration * progress), 0, duration);
- mWorkspaceReveal.setCurrentPlayTime(playTime);
- }
- }
-
protected void bounceBackToRestingPosition() {
final float startValue = mTransY;
final float endValue = 0;
@@ -369,31 +327,6 @@
}
@Override
- public void setAnimation(RectFSpringAnim anim) {
- if (PROTOTYPE_APP_CLOSE.get()) {
- // Use a spring to put drag layer translation back to 0.
- anim.addAnimatorListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mFloatingView.setPositionOffsetY(0);
- bounceBackToRestingPosition();
- }
- });
-
- // Will be updated manually below so that the two animations are in sync.
- mWorkspaceReveal.start();
- mWorkspaceReveal.pause();
-
- anim.addAnimatorListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mWorkspaceReveal.end();
- }
- });
- }
- }
-
- @Override
public void onCancel() {
mFloatingView.fastFinish();
if (mBounceBackAnimator != null) {
@@ -425,13 +358,9 @@
@Override
public void playAtomicAnimation(float velocity) {
- if (!PROTOTYPE_APP_CLOSE.get()) {
- new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
- getViewIgnoredInWorkspaceRevealAnimation())
- .start();
- } else if (shouldPlayAtomicWorkspaceReveal()) {
- new WorkspaceRevealAnim(mActivity, true).start();
- }
+ new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
+ getViewIgnoredInWorkspaceRevealAnimation())
+ .start();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index b232464..75e8dd1 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -39,6 +39,7 @@
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import java.util.ArrayList;
+import java.util.HashMap;
/**
* Helper class to handle various atomic commands for switching between Overview.
@@ -116,11 +117,12 @@
mPendingCommands.clear();
}
+ @Nullable
private TaskView getNextTask(RecentsView view) {
final TaskView runningTaskView = view.getRunningTaskView();
if (runningTaskView == null) {
- return view.getTaskViewCount() > 0 ? view.getTaskViewAt(0) : null;
+ return view.getTaskViewAt(0);
} else {
final TaskView nextTask = view.getNextTaskView();
return nextTask != null ? nextTask : runningTaskView;
@@ -211,7 +213,7 @@
}
@Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
interactionHandler.onGestureCancelled();
cmd.removeListener(this);
@@ -255,8 +257,8 @@
// Ensure that recents view has focus so that it receives the followup key inputs
TaskView taskView = rv.getNextTaskView();
if (taskView == null) {
- if (rv.getTaskViewCount() > 0) {
- taskView = rv.getTaskViewAt(0);
+ taskView = rv.getTaskViewAt(0);
+ if (taskView != null) {
taskView.requestFocus();
} else {
rv.requestFocus();
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 3080f04..c5f4a53 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -22,35 +22,35 @@
import android.app.ActivityManager;
import android.os.Build;
import android.os.Process;
-import android.util.Log;
+import android.os.RemoteException;
import android.util.SparseBooleanArray;
import androidx.annotation.VisibleForTesting;
-import com.android.launcher3.testing.TestProtocol;
+import com.android.quickstep.util.GroupTask;
import com.android.launcher3.util.LooperExecutor;
+import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.KeyguardManagerCompat;
-import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.TaskStackChangeListeners;
+import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.util.GroupedRecentTaskInfo;
+import com.android.wm.shell.util.StagedSplitBounds;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.List;
import java.util.function.Consumer;
/**
* Manages the recent task list from the system, caching it as necessary.
*/
@TargetApi(Build.VERSION_CODES.R)
-public class RecentTasksList extends TaskStackChangeListener {
+public class RecentTasksList {
private static final TaskLoadResult INVALID_RESULT = new TaskLoadResult(-1, false, 0);
private final KeyguardManagerCompat mKeyguardManager;
private final LooperExecutor mMainThreadExecutor;
- private final ActivityManagerWrapper mActivityManagerWrapper;
+ private final SystemUiProxy mSysUiProxy;
// The list change id, increments as the task list changes in the system
private int mChangeId;
@@ -62,12 +62,17 @@
private TaskLoadResult mResultsUi = INVALID_RESULT;
public RecentTasksList(LooperExecutor mainThreadExecutor,
- KeyguardManagerCompat keyguardManager, ActivityManagerWrapper activityManagerWrapper) {
+ KeyguardManagerCompat keyguardManager, SystemUiProxy sysUiProxy) {
mMainThreadExecutor = mainThreadExecutor;
mKeyguardManager = keyguardManager;
mChangeId = 1;
- mActivityManagerWrapper = activityManagerWrapper;
- TaskStackChangeListeners.getInstance().registerTaskStackListener(this);
+ mSysUiProxy = sysUiProxy;
+ sysUiProxy.registerRecentTasksListener(new IRecentTasksListener.Stub() {
+ @Override
+ public void onRecentTasksChanged() throws RemoteException {
+ mMainThreadExecutor.execute(RecentTasksList.this::onRecentTasksChanged);
+ }
+ });
}
@VisibleForTesting
@@ -78,10 +83,11 @@
/**
* Fetches the task keys skipping any local cache.
*/
- public void getTaskKeys(int numTasks, Consumer<ArrayList<Task>> callback) {
+ public void getTaskKeys(int numTasks, Consumer<ArrayList<GroupTask>> callback) {
// Kick off task loading in the background
UI_HELPER_EXECUTOR.execute(() -> {
- ArrayList<Task> tasks = loadTasksInBackground(numTasks, -1, true /* loadKeysOnly */);
+ ArrayList<GroupTask> tasks = loadTasksInBackground(numTasks, -1,
+ true /* loadKeysOnly */);
mMainThreadExecutor.execute(() -> callback.accept(tasks));
});
}
@@ -93,14 +99,15 @@
* @param callback The callback to receive the list of recent tasks
* @return The change id of the current task list
*/
- public synchronized int getTasks(boolean loadKeysOnly, Consumer<ArrayList<Task>> callback) {
+ public synchronized int getTasks(boolean loadKeysOnly,
+ Consumer<ArrayList<GroupTask>> callback) {
final int requestLoadId = mChangeId;
if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) {
// The list is up to date, send the callback on the next frame,
// so that requestID can be returned first.
if (callback != null) {
// Copy synchronously as the changeId might change by next frame
- ArrayList<Task> result = copyOf(mResultsUi);
+ ArrayList<GroupTask> result = copyOf(mResultsUi);
mMainThreadExecutor.post(() -> {
callback.accept(result);
});
@@ -120,7 +127,7 @@
mLoadingTasksInBackground = false;
mResultsUi = loadResult;
if (callback != null) {
- ArrayList<Task> result = copyOf(mResultsUi);
+ ArrayList<GroupTask> result = copyOf(mResultsUi);
callback.accept(result);
}
});
@@ -136,35 +143,7 @@
return mChangeId == changeId;
}
- @Override
- public void onTaskStackChanged() {
- invalidateLoadedTasks();
- }
-
- @Override
- public void onRecentTaskListUpdated() {
- // In some cases immediately after booting, the tasks in the system recent task list may be
- // loaded, but not in the active task hierarchy in the system. These tasks are displayed in
- // overview, but removing them don't result in a onTaskStackChanged() nor a onTaskRemoved()
- // callback (those are for changes to the active tasks), but the task list is still updated,
- // so we should also invalidate the change id to ensure we load a new list instead of
- // reusing a stale list.
- invalidateLoadedTasks();
- }
-
- @Override
- public void onTaskRemoved(int taskId) {
- invalidateLoadedTasks();
- }
-
-
- @Override
- public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
- invalidateLoadedTasks();
- }
-
- @Override
- public synchronized void onActivityUnpinned() {
+ public void onRecentTasksChanged() {
invalidateLoadedTasks();
}
@@ -180,8 +159,8 @@
@VisibleForTesting
TaskLoadResult loadTasksInBackground(int numTasks, int requestId, boolean loadKeysOnly) {
int currentUserId = Process.myUserHandle().getIdentifier();
- List<ActivityManager.RecentTaskInfo> rawTasks =
- mActivityManagerWrapper.getRecentTasks(numTasks, currentUserId);
+ ArrayList<GroupedRecentTaskInfo> rawTasks =
+ mSysUiProxy.getRecentTasks(numTasks, currentUserId);
// The raw tasks are given in most-recent to least-recent order, we need to reverse it
Collections.reverse(rawTasks);
@@ -197,45 +176,64 @@
};
TaskLoadResult allTasks = new TaskLoadResult(requestId, loadKeysOnly, rawTasks.size());
- for (ActivityManager.RecentTaskInfo rawTask : rawTasks) {
- Task.TaskKey taskKey = new Task.TaskKey(rawTask);
- Task task;
- if (!loadKeysOnly) {
- boolean isLocked = tmpLockedUsers.get(taskKey.userId);
- task = Task.from(taskKey, rawTask, isLocked);
- } else {
- task = new Task(taskKey);
+ for (GroupedRecentTaskInfo rawTask : rawTasks) {
+ ActivityManager.RecentTaskInfo taskInfo1 = rawTask.mTaskInfo1;
+ ActivityManager.RecentTaskInfo taskInfo2 = rawTask.mTaskInfo2;
+ Task.TaskKey task1Key = new Task.TaskKey(taskInfo1);
+ Task task1 = loadKeysOnly
+ ? new Task(task1Key)
+ : Task.from(task1Key, taskInfo1,
+ tmpLockedUsers.get(task1Key.userId) /* isLocked */);
+ task1.setLastSnapshotData(taskInfo1);
+ Task task2 = null;
+ if (taskInfo2 != null) {
+ Task.TaskKey task2Key = new Task.TaskKey(taskInfo2);
+ task2 = loadKeysOnly
+ ? new Task(task2Key)
+ : Task.from(task2Key, taskInfo2,
+ tmpLockedUsers.get(task2Key.userId) /* isLocked */);
+ task2.setLastSnapshotData(taskInfo2);
}
- task.setLastSnapshotData(rawTask);
- allTasks.add(task);
+ final SplitConfigurationOptions.StagedSplitBounds launcherSplitBounds =
+ convertSplitBounds(rawTask.mStagedSplitBounds);
+ allTasks.add(new GroupTask(task1, task2, launcherSplitBounds));
}
return allTasks;
}
- private ArrayList<Task> copyOf(ArrayList<Task> tasks) {
- ArrayList<Task> newTasks = new ArrayList<>();
+ private SplitConfigurationOptions.StagedSplitBounds convertSplitBounds(
+ StagedSplitBounds shellSplitBounds) {
+ return shellSplitBounds == null ?
+ null :
+ new SplitConfigurationOptions.StagedSplitBounds(
+ shellSplitBounds.leftTopBounds, shellSplitBounds.rightBottomBounds,
+ shellSplitBounds.leftTopTaskId, shellSplitBounds.rightBottomTaskId);
+ }
+
+ private ArrayList<GroupTask> copyOf(ArrayList<GroupTask> tasks) {
+ ArrayList<GroupTask> newTasks = new ArrayList<>();
for (int i = 0; i < tasks.size(); i++) {
- newTasks.add(new Task(tasks.get(i)));
+ newTasks.add(new GroupTask(tasks.get(i)));
}
return newTasks;
}
- private static class TaskLoadResult extends ArrayList<Task> {
+ private static class TaskLoadResult extends ArrayList<GroupTask> {
- final int mId;
+ final int mRequestId;
// If the result was loaded with keysOnly = true
final boolean mKeysOnly;
- TaskLoadResult(int id, boolean keysOnly, int size) {
+ TaskLoadResult(int requestId, boolean keysOnly, int size) {
super(size);
- mId = id;
+ mRequestId = requestId;
mKeysOnly = keysOnly;
}
boolean isValidForRequest(int requestId, boolean loadKeysOnly) {
- return mId == requestId && (!mKeysOnly || loadKeysOnly);
+ return mRequestId == requestId && (!mKeysOnly || loadKeysOnly);
}
}
}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index ad7e4df..09a0b7d 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -245,7 +245,7 @@
RemoteAnimationAdapterCompat adapterCompat = new RemoteAnimationAdapterCompat(
wrapper, RECENTS_LAUNCH_DURATION,
RECENTS_LAUNCH_DURATION - STATUS_BAR_TRANSITION_DURATION
- - STATUS_BAR_TRANSITION_PRE_DELAY);
+ - STATUS_BAR_TRANSITION_PRE_DELAY, getIApplicationThread());
final ActivityOptionsWrapper activityOptions = new ActivityOptionsWrapper(
ActivityOptionsCompat.makeRemoteAnimation(adapterCompat),
onEndCallback);
@@ -394,7 +394,8 @@
LauncherAnimationRunner runner = new LauncherAnimationRunner(
getMainThreadHandler(), mAnimationToHomeFactory, true);
RemoteAnimationAdapterCompat adapterCompat =
- new RemoteAnimationAdapterCompat(runner, HOME_APPEAR_DURATION, 0);
+ new RemoteAnimationAdapterCompat(runner, HOME_APPEAR_DURATION, 0,
+ getIApplicationThread());
startActivity(createHomeIntent(),
ActivityOptionsCompat.makeRemoteAnimation(adapterCompat).toBundle());
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index e948221..dd6392c 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -32,6 +32,7 @@
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import java.util.Arrays;
+import java.util.HashMap;
import java.util.Set;
/**
@@ -125,20 +126,20 @@
@BinderThread
@Override
- public final void onAnimationCanceled(ThumbnailData thumbnailData) {
+ public final void onAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
for (RecentsAnimationListener listener : getListeners()) {
- listener.onRecentsAnimationCanceled(thumbnailData);
+ listener.onRecentsAnimationCanceled(thumbnailDatas);
}
});
}
@BinderThread
@Override
- public void onTaskAppeared(RemoteAnimationTargetCompat app) {
+ public void onTasksAppeared(RemoteAnimationTargetCompat[] apps) {
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
for (RecentsAnimationListener listener : getListeners()) {
- listener.onTaskAppeared(app);
+ listener.onTasksAppeared(apps);
}
});
}
@@ -166,7 +167,7 @@
* Callback from the system when the recents animation is canceled. {@param thumbnailData}
* is passed back for rendering screenshot to replace live tile.
*/
- default void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {}
+ default void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {}
/**
* Callback made whenever the recents animation is finished.
@@ -176,6 +177,6 @@
/**
* Callback made when a task started from the recents is ready for an app transition.
*/
- default void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {}
+ default void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTarget) {}
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 1e82c8c..ac97dd6 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -34,6 +34,7 @@
import com.android.launcher3.icons.IconProvider.IconChangeListener;
import com.android.launcher3.util.Executors.SimpleThreadFactory;
import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
@@ -70,7 +71,7 @@
private RecentsModel(Context context) {
mContext = context;
mTaskList = new RecentTasksList(MAIN_EXECUTOR,
- new KeyguardManagerCompat(context), ActivityManagerWrapper.getInstance());
+ new KeyguardManagerCompat(context), SystemUiProxy.INSTANCE.get(context));
IconProvider iconProvider = new IconProvider(context);
mIconCache = new TaskIconCache(context, RECENTS_MODEL_EXECUTOR, iconProvider);
@@ -95,7 +96,7 @@
* always called on the UI thread.
* @return the request id associated with this call.
*/
- public int getTasks(Consumer<ArrayList<Task>> callback) {
+ public int getTasks(Consumer<ArrayList<GroupTask>> callback) {
return mTaskList.getTasks(false /* loadKeysOnly */, callback);
}
@@ -120,9 +121,9 @@
* @param callback Receives true if task is removed, false otherwise
*/
public void isTaskRemoved(int taskId, Consumer<Boolean> callback) {
- mTaskList.getTasks(true /* loadKeysOnly */, (tasks) -> {
- for (Task task : tasks) {
- if (task.key.id == taskId) {
+ mTaskList.getTasks(true /* loadKeysOnly */, (taskGroups) -> {
+ for (GroupTask group : taskGroups) {
+ if (group.containsTask(taskId)) {
callback.accept(false);
return;
}
@@ -148,14 +149,15 @@
ActivityManager.RunningTaskInfo runningTask =
ActivityManagerWrapper.getInstance().getRunningTask();
int runningTaskId = runningTask != null ? runningTask.id : -1;
- mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), tasks -> {
- for (Task task : tasks) {
- if (task.key.id == runningTaskId) {
+ mTaskList.getTaskKeys(mThumbnailCache.getCacheSize(), taskGroups -> {
+ for (GroupTask group : taskGroups) {
+ if (group.containsTask(runningTaskId)) {
// Skip the running task, it's not going to have an up-to-date snapshot by the
// time the user next enters overview
continue;
}
- mThumbnailCache.updateThumbnailInCache(task);
+ mThumbnailCache.updateThumbnailInCache(group.task1);
+ mThumbnailCache.updateThumbnailInCache(group.task2);
}
});
}
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 825abed..b031c47 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -17,11 +17,10 @@
package com.android.quickstep;
import android.content.Context;
-import android.util.Log;
import androidx.annotation.Nullable;
-import com.android.launcher3.util.SplitConfigurationOptions;
+import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.quickstep.util.AnimatorControllerWithResistance;
import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.TaskViewSimulator;
@@ -33,10 +32,8 @@
* {@link TaskViewSimulator}
*/
public class RemoteTargetGluer {
- private static final String TAG = "RemoteTargetGluer";
-
private RemoteTargetHandle[] mRemoteTargetHandles;
- private SplitConfigurationOptions.StagedSplitBounds mStagedSplitBounds;
+ private StagedSplitBounds mStagedSplitBounds;
/**
* Use this constructor if remote targets are split-screen independent
@@ -88,39 +85,40 @@
/**
* Similar to {@link #assignTargets(RemoteAnimationTargets)}, except this matches the
- * apps in targets.apps to that of the split screened tasks. If split screen is active, then
- * {@link #mRemoteTargetHandles} index 0 will be the left/top task, index one right/bottom
+ * apps in targets.apps to that of the _active_ split screened tasks.
+ * See {@link #assignTargetsForSplitScreen(RemoteAnimationTargets, int[])}
*/
public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets) {
int[] splitIds = LauncherSplitScreenListener.INSTANCE.getNoCreate()
.getRunningSplitTaskIds();
- Log.d(TAG, "splitIds length: " + splitIds.length
- + " targetAppsLength: " + targets.apps.length
- + " remoteHandlesLength: " + mRemoteTargetHandles.length);
- if (splitIds.length == 0 && mRemoteTargetHandles.length > 1) {
- // There's a chance that between the creation of this class and assigning targets,
- // LauncherSplitScreenListener may have received callback that removes split
- mRemoteTargetHandles = new RemoteTargetHandle[]{mRemoteTargetHandles[0]};
- Log.w(TAG, "splitTaskIds changed between creation and assignment");
- }
+ return assignTargetsForSplitScreen(targets, splitIds);
+ }
+ /**
+ * Assigns the provided splitIDs to the {@link #mRemoteTargetHandles}, with index 0 will beint
+ * the left/top task, index 1 right/bottom
+ */
+ public RemoteTargetHandle[] assignTargetsForSplitScreen(RemoteAnimationTargets targets,
+ int[] splitIds) {
RemoteAnimationTargetCompat primaryTaskTarget;
RemoteAnimationTargetCompat secondaryTaskTarget;
if (mRemoteTargetHandles.length == 1) {
// If we're not in split screen, the splitIds count doesn't really matter since we
- // should always hit this case. Right now there's no use case for multiple app targets
- // without being in split screen
- primaryTaskTarget = targets.apps[0];
+ // should always hit this case.
mRemoteTargetHandles[0].mTransformParams.setTargetSet(targets);
- mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
+ if (targets.apps.length > 0) {
+ // Unclear why/when target.apps length == 0, but it sure does happen :(
+ primaryTaskTarget = targets.apps[0];
+ mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(primaryTaskTarget, null);
+ }
} else {
// split screen
primaryTaskTarget = targets.findTask(splitIds[0]);
secondaryTaskTarget = targets.findTask(splitIds[1]);
- mStagedSplitBounds = new SplitConfigurationOptions.StagedSplitBounds(
+ mStagedSplitBounds = new StagedSplitBounds(
primaryTaskTarget.screenSpaceBounds,
- secondaryTaskTarget.screenSpaceBounds);
+ secondaryTaskTarget.screenSpaceBounds, splitIds[0], splitIds[1]);
mRemoteTargetHandles[0].mTransformParams.setTargetSet(
createRemoteAnimationTargetsForTarget(primaryTaskTarget, targets));
mRemoteTargetHandles[0].mTaskViewSimulator.setPreview(primaryTaskTarget,
@@ -145,7 +143,7 @@
return mRemoteTargetHandles;
}
- public SplitConfigurationOptions.StagedSplitBounds getStagedSplitBounds() {
+ public StagedSplitBounds getStagedSplitBounds() {
return mStagedSplitBounds;
}
diff --git a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
index f64d506..b36cb0a 100644
--- a/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
+++ b/quickstep/src/com/android/quickstep/SwipeUpAnimationLogic.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.anim.Interpolators.ACCEL_1_5;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_SELECT;
-import static com.android.launcher3.config.FeatureFlags.PROTOTYPE_APP_CLOSE;
import android.animation.Animator;
import android.content.Context;
@@ -28,7 +27,6 @@
import android.graphics.RectF;
import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import com.android.launcher3.DeviceProfile;
@@ -39,10 +37,8 @@
import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.util.AnimatorControllerWithResistance;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.RectFSpringAnim;
-import com.android.quickstep.util.RectFSpringAnim2;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.util.TransformParams.BuilderProxy;
@@ -189,8 +185,7 @@
public boolean keepWindowOpaque() { return false; }
- public void update(@Nullable AppCloseConfig config, RectF currentRect, float progress,
- float radius) { }
+ public void update(RectF currentRect, float progress, float radius) { }
public void onCancel() { }
@@ -290,14 +285,7 @@
homeToWindowPositionMap.invert(windowToHomePositionMap);
windowToHomePositionMap.mapRect(startRect);
- RectFSpringAnim anim;
- if (PROTOTYPE_APP_CLOSE.get()) {
- anim = new RectFSpringAnim2(startRect, targetRect, mContext,
- taskViewSimulator.getCurrentCornerRadius(),
- homeAnimationFactory.getEndRadius(cropRectF));
- } else {
- anim = new RectFSpringAnim(startRect, targetRect, mContext, mDp);
- }
+ RectFSpringAnim anim = new RectFSpringAnim(startRect, targetRect, mContext, mDp);
homeAnimationFactory.setAnimation(anim);
SpringAnimationRunner runner = new SpringAnimationRunner(
@@ -343,17 +331,13 @@
}
@Override
- public void onUpdate(@Nullable AppCloseConfig config, RectF currentRect, float progress) {
+ public void onUpdate(RectF currentRect, float progress) {
mHomeAnim.setPlayFraction(progress);
mHomeToWindowPositionMap.mapRect(mWindowCurrentRect, currentRect);
mMatrix.setRectToRect(mCropRectF, mWindowCurrentRect, ScaleToFit.FILL);
float cornerRadius = Utilities.mapRange(progress, mStartRadius, mEndRadius);
float alpha = mAnimationFactory.getWindowAlpha(progress);
- if (config != null && PROTOTYPE_APP_CLOSE.get()) {
- alpha = config.getWindowAlpha();
- cornerRadius = config.getCornerRadius();
- }
if (mAnimationFactory.keepWindowOpaque()) {
alpha = 1f;
}
@@ -362,8 +346,7 @@
.setCornerRadius(cornerRadius);
mLocalTransformParams.applySurfaceParams(mLocalTransformParams
.createSurfaceParams(this));
- mAnimationFactory.update(config, currentRect, progress,
- mMatrix.mapRadius(cornerRadius));
+ mAnimationFactory.update(currentRect, progress, mMatrix.mapRadius(cornerRadius));
}
@Override
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index d9319a9..4239739 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep;
+import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.app.PendingIntent;
@@ -37,6 +39,7 @@
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -47,6 +50,9 @@
import com.android.wm.shell.onehanded.IOneHanded;
import com.android.wm.shell.pip.IPip;
import com.android.wm.shell.pip.IPipAnimationListener;
+import com.android.wm.shell.recents.IRecentTasks;
+import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.util.GroupedRecentTaskInfo;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
import com.android.wm.shell.startingsurface.IStartingWindow;
@@ -54,6 +60,7 @@
import com.android.wm.shell.transition.IShellTransitions;
import java.util.ArrayList;
+import java.util.Arrays;
/**
* Holds the reference to SystemUI.
@@ -72,6 +79,7 @@
private IOneHanded mOneHanded;
private IShellTransitions mShellTransitions;
private IStartingWindow mStartingWindow;
+ private IRecentTasks mRecentTasks;
private final DeathRecipient mSystemUiProxyDeathRecipient = () -> {
MAIN_EXECUTOR.execute(() -> clearProxy());
};
@@ -82,6 +90,7 @@
private ISplitScreenListener mPendingSplitScreenListener;
private IStartingWindowListener mPendingStartingWindowListener;
private ISmartspaceCallback mPendingSmartspaceCallback;
+ private IRecentTasksListener mPendingRecentTasksListener;
private final ArrayList<RemoteTransitionCompat> mPendingRemoteTransitions = new ArrayList<>();
// Used to dedupe calls to SystemUI
@@ -117,6 +126,17 @@
}
@Override
+ public void onImeSwitcherPressed() {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.onImeSwitcherPressed();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call onImeSwitcherPressed", e);
+ }
+ }
+ }
+
+ @Override
public void setHomeRotationEnabled(boolean enabled) {
if (mSystemUiProxy != null) {
try {
@@ -135,7 +155,7 @@
public void setProxy(ISystemUiProxy proxy, IPip pip, ISplitScreen splitScreen,
IOneHanded oneHanded, IShellTransitions shellTransitions,
- IStartingWindow startingWindow,
+ IStartingWindow startingWindow, IRecentTasks recentTasks,
ISmartspaceTransitionController smartSpaceTransitionController) {
unlinkToDeath();
mSystemUiProxy = proxy;
@@ -145,6 +165,7 @@
mShellTransitions = shellTransitions;
mStartingWindow = startingWindow;
mSmartspaceTransitionController = smartSpaceTransitionController;
+ mRecentTasks = recentTasks;
linkToDeath();
// re-attach the listeners once missing due to setProxy has not been initialized yet.
if (mPendingPipAnimationListener != null && mPip != null) {
@@ -167,6 +188,10 @@
registerRemoteTransition(mPendingRemoteTransitions.get(i));
}
mPendingRemoteTransitions.clear();
+ if (mPendingRecentTasksListener != null && mRecentTasks != null) {
+ registerRecentTasksListener(mPendingRecentTasksListener);
+ mPendingRecentTasksListener = null;
+ }
if (mPendingSetNavButtonAlpha != null) {
mPendingSetNavButtonAlpha.run();
@@ -175,7 +200,7 @@
}
public void clearProxy() {
- setProxy(null, null, null, null, null, null, null);
+ setProxy(null, null, null, null, null, null, null, null);
}
// TODO(141886704): Find a way to remove this
@@ -444,6 +469,8 @@
} catch (RemoteException e) {
Log.w(TAG, "Failed call handleImageBundleAsScreenshot");
}
+ } else if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SCREENSHOT, "sysuiproxy, no proxy available");
}
}
@@ -545,53 +572,6 @@
mPendingSplitScreenListener = null;
}
- public void setSideStageVisibility(boolean visible) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.setSideStageVisibility(visible);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call setSideStageVisibility");
- }
- }
- }
-
- /**
- * To be called whenever the user exits out of split screen apps (either by launching another
- * app or by swiping home)
- * @param topTaskId The taskId of the new app that was launched. System will then move this task
- * to the front of what the user sees while removing all other split stages.
- * If swiping to home (or there is no task to put at the top), can pass in -1.
- */
- public void exitSplitScreen(int topTaskId) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.exitSplitScreen(topTaskId);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call exitSplitScreen");
- }
- }
- }
-
- public void exitSplitScreenOnHide(boolean exitSplitScreenOnHide) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.exitSplitScreenOnHide(exitSplitScreenOnHide);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call exitSplitScreen");
- }
- }
- }
-
- public void startTask(int taskId, int stage, int position, Bundle options) {
- if (mSplitScreen != null) {
- try {
- mSplitScreen.startTask(taskId, stage, position, options);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed call startTask");
- }
- }
- }
-
/** Start multiple tasks in split-screen simultaneously. */
public void startTasks(int mainTaskId, Bundle mainOptions, int sideTaskId, Bundle sideOptions,
@SplitConfigurationOptions.StagePosition int sidePosition,
@@ -745,7 +725,6 @@
}
}
-
//
// SmartSpace transitions
//
@@ -761,4 +740,43 @@
mPendingSmartspaceCallback = callback;
}
}
+
+ //
+ // Recents
+ //
+
+ public void registerRecentTasksListener(IRecentTasksListener listener) {
+ if (mRecentTasks != null) {
+ try {
+ mRecentTasks.registerRecentTasksListener(listener);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call registerRecentTasksListener", e);
+ }
+ } else {
+ mPendingRecentTasksListener = listener;
+ }
+ }
+
+ public void unregisterRecentTasksListener(IRecentTasksListener listener) {
+ if (mRecentTasks != null) {
+ try {
+ mRecentTasks.unregisterRecentTasksListener(listener);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call unregisterRecentTasksListener");
+ }
+ }
+ mPendingRecentTasksListener = null;
+ }
+
+ public ArrayList<GroupedRecentTaskInfo> getRecentTasks(int numTasks, int userId) {
+ if (mRecentTasks != null) {
+ try {
+ return new ArrayList<>(Arrays.asList(mRecentTasks.getRecentTasks(numTasks,
+ RECENT_IGNORE_UNAVAILABLE, userId)));
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call getRecentTasks", e);
+ }
+ }
+ return new ArrayList<>();
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 4b89981..e69330a 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -42,6 +42,8 @@
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
+import java.util.HashMap;
+
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
public static final boolean ENABLE_SHELL_TRANSITIONS =
SystemProperties.getBoolean("persist.debug.shell_transit", false);
@@ -135,7 +137,7 @@
}
@Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
cleanUpRecentsAnimation();
}
@@ -145,16 +147,16 @@
}
@Override
- public void onTaskAppeared(RemoteAnimationTargetCompat appearedTaskTarget) {
+ public void onTasksAppeared(RemoteAnimationTargetCompat[] appearedTaskTargets) {
+ RemoteAnimationTargetCompat appearedTaskTarget = appearedTaskTargets[0];
BaseActivityInterface activityInterface = mLastGestureState.getActivityInterface();
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && activityInterface.isInLiveTileMode()
&& activityInterface.getCreatedActivity() != null) {
RecentsView recentsView =
activityInterface.getCreatedActivity().getOverviewPanel();
if (recentsView != null) {
- RemoteAnimationTargetCompat[] apps = new RemoteAnimationTargetCompat[1];
- apps[0] = appearedTaskTarget;
- recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId, apps,
+ recentsView.launchSideTaskInLiveTileMode(appearedTaskTarget.taskId,
+ appearedTaskTargets,
new RemoteAnimationTargetCompat[0] /* wallpaper */,
new RemoteAnimationTargetCompat[0] /* nonApps */);
return;
@@ -178,7 +180,8 @@
if (ENABLE_SHELL_TRANSITIONS) {
RemoteTransitionCompat transition = new RemoteTransitionCompat(mCallbacks,
- mController != null ? mController.getController() : null);
+ mController != null ? mController.getController() : null,
+ mCtx.getIApplicationThread());
Bundle options = ActivityOptionsCompat.makeRemoteTransition(transition)
.setTransientLaunch().toBundle();
mCtx.startActivity(intent, options);
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
index a8a0219..eaa43cf 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -104,6 +104,9 @@
* Synchronously fetches the thumbnail for the given {@param task} and puts it in the cache.
*/
public void updateThumbnailInCache(Task task) {
+ if (task == null) {
+ return;
+ }
Preconditions.assertUIThread();
// Fetch the thumbnail for this task and put it in the cache
if (task.thumbnail == null) {
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index 12b071d..6addfe3 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -28,10 +28,10 @@
import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_IN_INTERPOLATOR;
import static com.android.launcher3.QuickstepTransitionManager.NAV_FADE_OUT_INTERPOLATOR;
import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
+import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURATION;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR;
-import static com.android.launcher3.anim.Interpolators.TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL;
import static com.android.launcher3.anim.Interpolators.clampToProgress;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
@@ -176,8 +176,8 @@
} else {
RemoteTargetGluer gluer = new RemoteTargetGluer(v.getContext(),
recentsView.getSizeStrategy(), targets);
- if (recentsViewHandles != null && recentsViewHandles.length > 1) {
- remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets);
+ if (v.containsMultipleTasks()) {
+ remoteTargetHandles = gluer.assignTargetsForSplitScreen(targets, v.getTaskIds());
} else {
remoteTargetHandles = gluer.assignTargets(targets);
}
@@ -192,7 +192,6 @@
boolean showAsGrid = dp.overviewShowAsGrid;
boolean parallaxCenterAndAdjacentTask =
taskIndex != recentsView.getCurrentPage() && !showAsGrid;
- float gridTranslationSecondary = recentsView.getGridTranslationSecondary(taskIndex);
int startScroll = recentsView.getScrollOffset(taskIndex);
RemoteTargetHandle[] topMostSimulators = null;
@@ -210,10 +209,9 @@
tvsLocal.fullScreenProgress.value = 0;
tvsLocal.recentsViewScale.value = 1;
- if (showAsGrid) {
- tvsLocal.taskSecondaryTranslation.value = gridTranslationSecondary;
- }
tvsLocal.setScroll(startScroll);
+ tvsLocal.setIsGridTask(v.isGridTask());
+ tvsLocal.setGridTranslationY(v.getGridTranslationY());
// Fade in the task during the initial 20% of the animation
out.addFloat(targetHandle.getTransformParams(), TransformParams.TARGET_ALPHA, 0, 1,
@@ -228,10 +226,6 @@
out.setFloat(tvsLocal.recentsViewScale,
AnimatedFloat.VALUE, tvsLocal.getFullScreenScale(),
TOUCH_RESPONSE_INTERPOLATOR);
- if (showAsGrid) {
- out.setFloat(tvsLocal.taskSecondaryTranslation, AnimatedFloat.VALUE, 0,
- TOUCH_RESPONSE_INTERPOLATOR_ACCEL_DEACCEL);
- }
out.setFloat(tvsLocal.recentsViewScroll, AnimatedFloat.VALUE, 0,
TOUCH_RESPONSE_INTERPOLATOR);
@@ -459,6 +453,7 @@
final SurfaceControl.Transaction t = new SurfaceControl.Transaction();
ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+ animator.setDuration(SPLIT_LAUNCH_DURATION);
animator.addUpdateListener(valueAnimator -> {
float progress = valueAnimator.getAnimatedFraction();
for (SurfaceControl leash: openingTargets) {
@@ -559,7 +554,7 @@
anim.addListener(windowAnimEndListener);
}
- static void setSplitAuxiliarySurfacesShown(RemoteAnimationTargetCompat[] nonApps,
+ public static void setSplitAuxiliarySurfacesShown(RemoteAnimationTargetCompat[] nonApps,
boolean shown) {
// TODO(b/182592057): make this part of the animations instead.
if (nonApps != null && nonApps.length > 0) {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index ecc4b2b..377edbe 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -22,9 +22,11 @@
import static com.android.launcher3.config.FeatureFlags.ASSISTANT_GIVES_LAUNCHER_FOCUS;
import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
+import static com.android.launcher3.testing.TestProtocol.TASKBAR_WINDOW_CRASH;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.quickstep.GestureState.DEFAULT_STATE;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_RECENT_TASKS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_ONE_HANDED;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_PIP;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SHELL_SHELL_TRANSITIONS;
@@ -112,6 +114,7 @@
import com.android.systemui.shared.tracing.ProtoTraceable;
import com.android.wm.shell.onehanded.IOneHanded;
import com.android.wm.shell.pip.IPip;
+import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.startingsurface.IStartingWindow;
import com.android.wm.shell.transition.IShellTransitions;
@@ -170,9 +173,11 @@
ISmartspaceTransitionController smartspaceTransitionController =
ISmartspaceTransitionController.Stub.asInterface(
bundle.getBinder(KEY_EXTRA_SMARTSPACE_TRANSITION_CONTROLLER));
+ IRecentTasks recentTasks = IRecentTasks.Stub.asInterface(
+ bundle.getBinder(KEY_EXTRA_RECENT_TASKS));
MAIN_EXECUTOR.execute(() -> {
SystemUiProxy.INSTANCE.get(TouchInteractionService.this).setProxy(proxy, pip,
- splitscreen, onehanded, shellTransitions, startingWindow,
+ splitscreen, onehanded, shellTransitions, startingWindow, recentTasks,
smartspaceTransitionController);
TouchInteractionService.this.initInputMonitor();
preloadOverview(true /* fromInit */);
@@ -350,6 +355,7 @@
@Override
public void onCreate() {
super.onCreate();
+ Log.d(TASKBAR_WINDOW_CRASH, "TIS created");
// Initialize anything here that is needed in direct boot mode.
// Everything else should be initialized in onUserUnlocked() below.
mMainChoreographer = Choreographer.getInstance();
@@ -511,6 +517,7 @@
@Override
public void onDestroy() {
Log.d(TAG, "Touch service destroyed: user=" + getUserId());
+ Log.d(TASKBAR_WINDOW_CRASH, "TIS destroyed");
sIsInitialized = false;
if (mDeviceState.isUserUnlocked()) {
mInputConsumer.unregisterInputConsumer();
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 7e8b83e..95095fa 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -16,6 +16,7 @@
package com.android.quickstep.fallback;
import static com.android.quickstep.GestureState.GestureEndTarget.RECENTS;
+import static com.android.quickstep.ViewUtils.postFrameDrawn;
import static com.android.quickstep.fallback.RecentsState.DEFAULT;
import static com.android.quickstep.fallback.RecentsState.HOME;
import static com.android.quickstep.fallback.RecentsState.MODAL_TASK;
@@ -42,6 +43,7 @@
import com.android.quickstep.views.OverviewActionsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
+import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.Task.TaskKey;
@@ -144,38 +146,41 @@
RunningTaskInfo runningTaskInfo = runningTaskInfos[0];
if (mHomeTaskInfo != null && runningTaskInfo != null &&
mHomeTaskInfo.taskId == runningTaskInfo.taskId
- && getTaskViewCount() == 0) {
+ && getTaskViewCount() == 0 && mLoadPlanEverApplied) {
// Do not add a stub task if we are running over home with empty recents, so that we
// show the empty recents message instead of showing a stub task and later removing it.
+ // Ignore empty task signal if applyLoadPlan has never run.
return false;
}
return super.shouldAddStubTaskView(runningTaskInfos);
}
@Override
- protected void applyLoadPlan(ArrayList<Task> tasks) {
+ protected void applyLoadPlan(ArrayList<GroupTask> taskGroups) {
// When quick-switching on 3p-launcher, we add a "stub" tile corresponding to Launcher
// as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to
// track the index of the next task appropriately, as if we are switching on any other app.
// TODO(b/195607777) Confirm home task info is front-most task and not mixed in with others
int runningTaskId = getTaskIdsForRunningTaskView()[0];
- if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == runningTaskId && !tasks.isEmpty()) {
+ if (mHomeTaskInfo != null && mHomeTaskInfo.taskId == runningTaskId && !taskGroups.isEmpty()) {
// Check if the task list has running task
boolean found = false;
- for (Task t : tasks) {
- if (t.key.id == runningTaskId) {
+ for (GroupTask group : taskGroups) {
+ if (group.containsTask(runningTaskId)) {
found = true;
break;
}
}
if (!found) {
- ArrayList<Task> newList = new ArrayList<>(tasks.size() + 1);
- newList.addAll(tasks);
- newList.add(Task.from(new TaskKey(mHomeTaskInfo), mHomeTaskInfo, false));
- tasks = newList;
+ ArrayList<GroupTask> newList = new ArrayList<>(taskGroups.size() + 1);
+ newList.addAll(taskGroups);
+ newList.add(new GroupTask(
+ Task.from(new TaskKey(mHomeTaskInfo), mHomeTaskInfo, false),
+ null, null));
+ taskGroups = newList;
}
}
- super.applyLoadPlan(tasks);
+ super.applyLoadPlan(taskGroups);
}
@Override
@@ -214,8 +219,14 @@
@Override
public void onStateTransitionComplete(RecentsState finalState) {
- setOverlayEnabled(finalState == DEFAULT || finalState == MODAL_TASK);
+ boolean isOverlayEnabled = finalState == DEFAULT || finalState == MODAL_TASK;
+ setOverlayEnabled(isOverlayEnabled);
setFreezeViewVisibility(false);
+
+ if (isOverlayEnabled) {
+ postFrameDrawn(this, () -> runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true)));
+ }
}
@Override
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
index fcc0217..3d737ca 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java
@@ -60,6 +60,8 @@
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams.Builder;
+import java.util.HashMap;
+
/**
* A placeholder input consumer used when the device is still locked, e.g. from secure camera.
*/
@@ -239,7 +241,7 @@
}
@Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
mRecentsAnimationController = null;
mTransformParams.setTargetSet(null);
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
index c69b510..71dca66 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/ProgressDelegateInputConsumer.java
@@ -44,6 +44,8 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InputMonitorCompat;
+import java.util.HashMap;
+
/**
* Input consumer which delegates the swipe-progress handling
*/
@@ -151,10 +153,8 @@
ObjectAnimator anim = mProgress.animateToValue(endValue);
anim.setDuration(duration).setInterpolator(scrollInterpolatorForVelocity(velocity));
- if (mRecentsAnimationController != null) {
- anim.addListener(AnimatorListeners.forSuccessCallback(
- () -> mStateCallback.setState(STATE_FLING_FINISHED)));
- }
+ anim.addListener(AnimatorListeners.forSuccessCallback(
+ () -> mStateCallback.setState(STATE_FLING_FINISHED)));
anim.start();
}
@@ -174,7 +174,7 @@
}
@Override
- public void onRecentsAnimationCanceled(ThumbnailData thumbnailData) {
+ public void onRecentsAnimationCanceled(HashMap<Integer, ThumbnailData> thumbnailDatas) {
mRecentsAnimationController = null;
}
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 272a9a1..965c1bc 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -136,6 +136,9 @@
protected void onPause() {
super.onPause();
clearBinderOverride();
+ if (mSwipeProgress.value >= 1) {
+ finishAndRemoveTask();
+ }
}
private void clearBinderOverride() {
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index fb6cd8a..49d8203 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -43,6 +43,13 @@
}
@Override
+ public Integer getSuccessFeedbackSubtitle() {
+ return mTutorialFragment.isAtFinalStep()
+ ? R.string.back_gesture_feedback_complete_without_follow_up
+ : R.string.back_gesture_feedback_complete_with_overview_follow_up;
+ }
+
+ @Override
protected int getMockAppTaskLayoutResId() {
return getMockAppTaskCurrentPageLayoutResId();
}
@@ -85,10 +92,7 @@
case BACK_COMPLETED_FROM_RIGHT:
mTutorialFragment.releaseFeedbackAnimation();
updateFakeAppTaskViewLayout(getMockAppTaskPreviousPageLayoutResId());
- int subtitleResId = mTutorialFragment.isAtFinalStep()
- ? R.string.back_gesture_feedback_complete_without_follow_up
- : R.string.back_gesture_feedback_complete_with_overview_follow_up;
- showFeedback(subtitleResId, true);
+ showSuccessFeedback();
break;
case BACK_CANCELLED_FROM_LEFT:
case BACK_CANCELLED_FROM_RIGHT:
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index 7fb7d29..c2524b1 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -35,10 +35,9 @@
/** Shows the gesture interactive sandbox in full screen mode. */
public class GestureSandboxActivity extends FragmentActivity {
- private static final String LOG_TAG = "GestureSandboxActivity";
-
private static final String KEY_TUTORIAL_STEPS = "tutorial_steps";
private static final String KEY_CURRENT_STEP = "current_step";
+ private static final String KEY_GESTURE_COMPLETE = "gesture_complete";
private TutorialType[] mTutorialSteps;
private TutorialType mCurrentTutorialStep;
@@ -56,7 +55,8 @@
Bundle args = savedInstanceState == null ? getIntent().getExtras() : savedInstanceState;
mTutorialSteps = getTutorialSteps(args);
mCurrentTutorialStep = mTutorialSteps[mCurrentStep - 1];
- mFragment = TutorialFragment.newInstance(mCurrentTutorialStep);
+ mFragment = TutorialFragment.newInstance(
+ mCurrentTutorialStep, args.getBoolean(KEY_GESTURE_COMPLETE, false));
getSupportFragmentManager().beginTransaction()
.add(R.id.gesture_tutorial_fragment_container, mFragment)
.commit();
@@ -87,6 +87,7 @@
protected void onSaveInstanceState(@NonNull Bundle savedInstanceState) {
savedInstanceState.putStringArray(KEY_TUTORIAL_STEPS, getTutorialStepNames());
savedInstanceState.putInt(KEY_CURRENT_STEP, mCurrentStep);
+ savedInstanceState.putBoolean(KEY_GESTURE_COMPLETE, mFragment.isGestureComplete());
super.onSaveInstanceState(savedInstanceState);
}
@@ -121,7 +122,7 @@
return;
}
mCurrentTutorialStep = mTutorialSteps[mCurrentStep];
- mFragment = TutorialFragment.newInstance(mCurrentTutorialStep);
+ mFragment = TutorialFragment.newInstance(mCurrentTutorialStep, false);
getSupportFragmentManager().beginTransaction()
.replace(R.id.gesture_tutorial_fragment_container, mFragment)
.runOnCommit(() -> mFragment.onAttachedToWindow())
diff --git a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
index bbb22e6..0bc3691 100644
--- a/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/HomeGestureTutorialController.java
@@ -42,6 +42,13 @@
}
@Override
+ public Integer getSuccessFeedbackSubtitle() {
+ return mTutorialFragment.isAtFinalStep()
+ ? R.string.home_gesture_feedback_complete_without_follow_up
+ : R.string.home_gesture_feedback_complete_with_follow_up;
+ }
+
+ @Override
protected int getMockAppTaskLayoutResId() {
return mTutorialFragment.isLargeScreen()
? R.layout.gesture_tutorial_foldable_mock_webpage
@@ -84,10 +91,7 @@
case HOME_GESTURE_COMPLETED: {
mTutorialFragment.releaseFeedbackAnimation();
animateFakeTaskViewHome(finalVelocity, null);
- int subtitleResId = mTutorialFragment.isAtFinalStep()
- ? R.string.home_gesture_feedback_complete_without_follow_up
- : R.string.home_gesture_feedback_complete_with_follow_up;
- showFeedback(subtitleResId, true);
+ showSuccessFeedback();
break;
}
case HOME_NOT_STARTED_TOO_FAR_FROM_EDGE:
diff --git a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
index 0fea0d7..f308f27 100644
--- a/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/OverviewGestureTutorialController.java
@@ -52,6 +52,13 @@
}
@Override
+ public Integer getSuccessFeedbackSubtitle() {
+ return mTutorialFragment.getNumSteps() > 1 && mTutorialFragment.isAtFinalStep()
+ ? R.string.overview_gesture_feedback_complete_with_follow_up
+ : R.string.overview_gesture_feedback_complete_without_follow_up;
+ }
+
+ @Override
protected int getMockAppTaskLayoutResId() {
return mTutorialFragment.isLargeScreen()
? R.layout.gesture_tutorial_foldable_mock_conversation_list
@@ -106,11 +113,7 @@
mTutorialFragment.releaseFeedbackAnimation();
animateTaskViewToOverview();
onMotionPaused(true /*arbitrary value*/);
- int subtitleResId = mTutorialFragment.getNumSteps() > 1
- && mTutorialFragment.isAtFinalStep()
- ? R.string.overview_gesture_feedback_complete_with_follow_up
- : R.string.overview_gesture_feedback_complete_without_follow_up;
- showFeedback(subtitleResId, true);
+ 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/SwipeUpGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
index 68df208..672687d 100644
--- a/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/SwipeUpGestureTutorialController.java
@@ -53,7 +53,6 @@
import com.android.quickstep.RemoteTargetGluer;
import com.android.quickstep.SwipeUpAnimationLogic;
import com.android.quickstep.SwipeUpAnimationLogic.RunningWindowAnim;
-import com.android.quickstep.util.AppCloseConfig;
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.TransformParams;
import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams;
@@ -331,8 +330,7 @@
}
@Override
- public void update(@Nullable AppCloseConfig config, RectF rect, float progress,
- float radius) {
+ public void update(RectF rect, float progress, float radius) {
mFakeIconView.setVisibility(View.VISIBLE);
mFakeIconView.update(rect, progress,
1f - SHAPE_PROGRESS_DURATION /* shapeProgressStart */,
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialController.java b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
index 81e18f6..4145393 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialController.java
@@ -223,6 +223,11 @@
return null;
}
+ @StringRes
+ public Integer getSuccessFeedbackSubtitle() {
+ return null;
+ }
+
void showFeedback() {
if (mGestureCompleted) {
mFeedbackView.setTranslationY(0);
@@ -236,6 +241,13 @@
}
/**
+ * Show feedback reflecting a successful gesture attempt.
+ **/
+ void showSuccessFeedback() {
+ showFeedback(getSuccessFeedbackSubtitle(), true);
+ }
+
+ /**
* Show feedback reflecting a failed gesture attempt.
*
* @param subtitleResId Resource of the text to display.
diff --git a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
index 89be1a6..2fd7cde 100644
--- a/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
+++ b/quickstep/src/com/android/quickstep/interaction/TutorialFragment.java
@@ -49,8 +49,10 @@
private static final String LOG_TAG = "TutorialFragment";
static final String KEY_TUTORIAL_TYPE = "tutorial_type";
+ static final String KEY_GESTURE_COMPLETE = "gesture_complete";
TutorialType mTutorialType;
+ boolean mGestureComplete = false;
@Nullable TutorialController mTutorialController = null;
RootSandboxLayout mRootView;
View mFingerDotView;
@@ -67,7 +69,7 @@
private boolean mIsLargeScreen;
- public static TutorialFragment newInstance(TutorialType tutorialType) {
+ public static TutorialFragment newInstance(TutorialType tutorialType, boolean gestureComplete) {
TutorialFragment fragment = getFragmentForTutorialType(tutorialType);
if (fragment == null) {
fragment = new BackGestureTutorialFragment();
@@ -76,6 +78,7 @@
Bundle args = new Bundle();
args.putSerializable(KEY_TUTORIAL_TYPE, tutorialType);
+ args.putBoolean(KEY_GESTURE_COMPLETE, gestureComplete);
fragment.setArguments(args);
return fragment;
}
@@ -132,6 +135,7 @@
super.onCreate(savedInstanceState);
Bundle args = savedInstanceState != null ? savedInstanceState : getArguments();
mTutorialType = (TutorialType) args.getSerializable(KEY_TUTORIAL_TYPE);
+ mGestureComplete = args.getBoolean(KEY_GESTURE_COMPLETE, false);
mEdgeBackGestureHandler = new EdgeBackGestureHandler(getContext());
mNavBarGestureHandler = new NavBarGestureHandler(getContext());
@@ -186,11 +190,13 @@
}
void initializeFeedbackVideoView() {
- if (!updateFeedbackAnimation()) {
+ if (!updateFeedbackAnimation() || mTutorialController == null) {
return;
}
- if (!mIntroductionShown && mTutorialController != null) {
+ if (isGestureComplete()) {
+ mTutorialController.showSuccessFeedback();
+ } else if (!mIntroductionShown) {
Integer introTileStringResId = mTutorialController.getIntroductionTitle();
Integer introSubtitleResId = mTutorialController.getIntroductionSubtitle();
if (introTileStringResId != null && introSubtitleResId != null) {
@@ -372,6 +378,11 @@
return getCurrentStep() == getNumSteps();
}
+ boolean isGestureComplete() {
+ return mGestureComplete
+ || (mTutorialController != null && mTutorialController.isGestureCompleted());
+ }
+
@Nullable
private GestureSandboxActivity getGestureSandboxActivity() {
Context context = getContext();
diff --git a/quickstep/src/com/android/quickstep/util/ActivityInitListener.java b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
index b9879ab..aeec36f 100644
--- a/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
+++ b/quickstep/src/com/android/quickstep/util/ActivityInitListener.java
@@ -15,11 +15,6 @@
*/
package com.android.quickstep.util;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.Handler;
-
import com.android.launcher3.BaseActivity;
import com.android.launcher3.util.ActivityTracker;
import com.android.launcher3.util.ActivityTracker.SchedulerCallback;
@@ -75,17 +70,4 @@
mIsRegistered = false;
mOnInitListener = null;
}
-
- /**
- * Starts the given intent with the provided animation. Unlike {@link #register(Intent)}, this
- * method will not call {@link #init} if the activity already exists, it will only call it when
- * we get handleIntent() for the provided intent that we're starting.
- */
- public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
- Context context, Handler handler, long duration) {
- register();
-
- Bundle options = animProvider.toActivityOptions(handler, duration, context).toBundle();
- context.startActivity(new Intent(intent), options);
- }
}
diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.java b/quickstep/src/com/android/quickstep/util/GroupTask.java
new file mode 100644
index 0000000..e2563e3
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/GroupTask.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
+import com.android.systemui.shared.recents.model.Task;
+
+/**
+ * A {@link Task} container that can contain one or two tasks, depending on if the two tasks
+ * are represented as an app-pair in the recents task list.
+ */
+public class GroupTask {
+ public @NonNull Task task1;
+ public @Nullable Task task2;
+ public @Nullable StagedSplitBounds mStagedSplitBounds;
+
+ public GroupTask(@NonNull Task t1, @Nullable Task t2,
+ @Nullable StagedSplitBounds stagedSplitBounds) {
+ task1 = t1;
+ task2 = t2;
+ mStagedSplitBounds = stagedSplitBounds;
+ }
+
+ public GroupTask(@NonNull GroupTask group) {
+ task1 = new Task(group.task1);
+ task2 = group.task2 != null
+ ? new Task(group.task2)
+ : null;
+ mStagedSplitBounds = group.mStagedSplitBounds;
+ }
+
+ public boolean containsTask(int taskId) {
+ return task1.key.id == taskId || (task2 != null && task2.key.id == taskId);
+ }
+
+ public boolean hasMultipleTasks() {
+ return task2 != null;
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
index de7dbd6..b0c68c5 100644
--- a/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
+++ b/quickstep/src/com/android/quickstep/util/ImageActionUtils.java
@@ -49,6 +49,7 @@
import com.android.internal.app.ChooserActivity;
import com.android.launcher3.BuildConfig;
+import com.android.launcher3.testing.TestProtocol;
import com.android.quickstep.SystemUiProxy;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.utilities.BitmapUtil;
@@ -77,6 +78,9 @@
public static void saveScreenshot(SystemUiProxy systemUiProxy, Bitmap screenshot,
Rect screenshotBounds,
Insets visibleInsets, Task.TaskKey task) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SCREENSHOT, "image action utils calling into sysuiproxy");
+ }
systemUiProxy.handleImageBundleAsScreenshot(BitmapUtil.hardwareBitmapToBundle(screenshot),
screenshotBounds, visibleInsets, task);
}
diff --git a/quickstep/src/com/android/quickstep/util/LauncherSplitScreenListener.java b/quickstep/src/com/android/quickstep/util/LauncherSplitScreenListener.java
index fa4cddc..99efb39 100644
--- a/quickstep/src/com/android/quickstep/util/LauncherSplitScreenListener.java
+++ b/quickstep/src/com/android/quickstep/util/LauncherSplitScreenListener.java
@@ -149,7 +149,6 @@
return;
}
- SystemUiProxy.INSTANCE.getNoCreate().exitSplitScreen(-1);
mPersistentGroupedIds = EMPTY_ARRAY;
}
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
index 158fba9..c4909de 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -328,7 +328,7 @@
break;
}
for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
- onUpdateListener.onUpdate(null, mCurrentRect, mCurrentScaleProgress);
+ onUpdateListener.onUpdate(mCurrentRect, mCurrentScaleProgress);
}
}
}
@@ -353,7 +353,12 @@
}
public interface OnUpdateListener {
- void onUpdate(@Nullable AppCloseConfig values, RectF currentRect, float progress);
+ /**
+ * Called when an update is made to the animation.
+ * @param currentRect The rect of the window.
+ * @param progress [0, 1] The progress of the rect scale animation.
+ */
+ void onUpdate(RectF currentRect, float progress);
default void onCancel() { }
}
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
deleted file mode 100644
index cb35809..0000000
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim2.java
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2021 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.util;
-
-import static com.android.launcher3.Utilities.dpToPx;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
-import android.content.Context;
-import android.graphics.PointF;
-import android.graphics.RectF;
-import android.util.PathParser;
-import android.util.Property;
-import android.view.animation.Interpolator;
-
-import androidx.core.view.animation.PathInterpolatorCompat;
-import androidx.dynamicanimation.animation.FloatPropertyCompat;
-import androidx.dynamicanimation.animation.SpringAnimation;
-import androidx.dynamicanimation.animation.SpringForce;
-
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.util.DynamicResource;
-import com.android.systemui.plugins.ResourceProvider;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-/**
- * Applies spring forces to animate from a starting rect to a target rect,
- * while providing update callbacks to the caller.
- */
-public class RectFSpringAnim2 extends RectFSpringAnim {
-
- private static final FloatPropertyCompat<RectFSpringAnim2> RECT_CENTER_X =
- new FloatPropertyCompat<RectFSpringAnim2>("rectCenterXSpring") {
- @Override
- public float getValue(RectFSpringAnim2 anim) {
- return anim.mCurrentCenterX;
- }
-
- @Override
- public void setValue(RectFSpringAnim2 anim, float currentCenterX) {
- anim.mCurrentCenterX = currentCenterX;
- anim.onUpdate();
- }
- };
-
- private static final FloatPropertyCompat<RectFSpringAnim2> RECT_Y =
- new FloatPropertyCompat<RectFSpringAnim2>("rectYSpring") {
- @Override
- public float getValue(RectFSpringAnim2 anim) {
- return anim.mCurrentCenterY;
- }
-
- @Override
- public void setValue(RectFSpringAnim2 anim, float y) {
- anim.mCurrentCenterY = y;
- anim.onUpdate();
- }
- };
-
- private static final Property<RectFSpringAnim2, Float> PROGRESS =
- new Property<RectFSpringAnim2, Float>(Float.class, "rectFProgress") {
- @Override
- public Float get(RectFSpringAnim2 rectFSpringAnim) {
- return rectFSpringAnim.mProgress;
- }
-
- @Override
- public void set(RectFSpringAnim2 rectFSpringAnim, Float progress) {
- rectFSpringAnim.mProgress = progress;
- rectFSpringAnim.onUpdate();
- }
- };
-
- private final RectF mStartRect;
- private final RectF mTargetRect;
- private final RectF mCurrentRect = new RectF();
- private final List<OnUpdateListener> mOnUpdateListeners = new ArrayList<>();
- private final List<Animator.AnimatorListener> mAnimatorListeners = new ArrayList<>();
-
- private float mCurrentCenterX;
- private float mCurrentCenterY;
-
- private float mTargetX;
- private float mTargetY;
-
- // If true, tracking the bottom of the rects, else tracking the top.
- private float mProgress;
- private SpringAnimation mRectXAnim;
- private SpringAnimation mRectYAnim;
- private ValueAnimator mRectScaleAnim;
- private boolean mAnimsStarted;
- private boolean mRectXAnimEnded;
- private boolean mRectYAnimEnded;
- private boolean mRectScaleAnimEnded;
-
- private final float mXDamping;
- private final float mXStiffness;
-
- private final float mYDamping;
- private float mYStiffness;
-
- private long mDuration;
-
- private final Interpolator mCloseInterpolator;
-
- private AppCloseConfig mValues;
- final float mStartRadius;
- final float mEndRadius;
-
- final float mHomeTransYEnd;
- final float mScaleStart;
-
- public RectFSpringAnim2(RectF startRect, RectF targetRect, Context context, float startRadius,
- float endRadius) {
- super(startRect, targetRect, context, null);
- mStartRect = startRect;
- mTargetRect = targetRect;
-
- mCurrentCenterY = mStartRect.centerY();
- mCurrentCenterX = mStartRect.centerX();
-
- mTargetY = mTargetRect.centerY();
- mTargetX = mTargetRect.centerX();
-
- ResourceProvider rp = DynamicResource.provider(context);
- mXDamping = rp.getFloat(R.dimen.swipe_up_rect_2_x_damping_ratio);
- mXStiffness = rp.getFloat(R.dimen.swipe_up_rect_2_x_stiffness);
-
- mYDamping = rp.getFloat(R.dimen.swipe_up_rect_2_y_damping_ratio);
- mYStiffness = rp.getFloat(R.dimen.swipe_up_rect_2_y_stiffness);
- mDuration = Math.round(rp.getFloat(R.dimen.swipe_up_duration));
-
- mHomeTransYEnd = dpToPx(rp.getFloat(R.dimen.swipe_up_trans_y_dp));
- mScaleStart = rp.getFloat(R.dimen.swipe_up_scale_start);
-
- mCloseInterpolator = getAppCloseInterpolator(context);
-
- // End on a "round-enough" radius so that the shape reveal doesn't have to do too much
- // rounding at the end of the animation.
- mStartRadius = startRadius;
- mEndRadius = endRadius;
-
- setCanRelease(true);
- }
-
- public void onTargetPositionChanged() {
- if (mRectXAnim != null && mTargetX != mTargetRect.centerX()) {
- mTargetX = mTargetRect.centerX();
- mRectXAnim.animateToFinalPosition(mTargetX);
- }
-
- if (mRectYAnim != null) {
- if (mTargetY != mTargetRect.centerY()) {
- mTargetY = mTargetRect.centerY();
- mRectYAnim.animateToFinalPosition(mTargetY);
- }
- }
- }
-
- public void addOnUpdateListener(OnUpdateListener onUpdateListener) {
- mOnUpdateListeners.add(onUpdateListener);
- }
-
- public void addAnimatorListener(Animator.AnimatorListener animatorListener) {
- mAnimatorListeners.add(animatorListener);
- }
-
- /**
- * Starts the fling/spring animation.
- * @param context The activity context.
- * @param velocityPxPerMs Velocity of swipe in px/ms.
- */
- public void start(Context context, PointF velocityPxPerMs) {
- mRectXAnim = new SpringAnimation(this, RECT_CENTER_X)
- .setStartValue(mCurrentCenterX)
- .setStartVelocity(velocityPxPerMs.x * 1000)
- .setSpring(new SpringForce(mTargetX)
- .setStiffness(mXStiffness)
- .setDampingRatio(mXDamping));
- mRectXAnim.addEndListener(((animation, canceled, centerX, velocityX) -> {
- mRectXAnimEnded = true;
- maybeOnEnd();
- }));
-
- mRectYAnim = new SpringAnimation(this, RECT_Y)
- .setStartValue(mCurrentCenterY)
- .setStartVelocity(velocityPxPerMs.y * 1000)
- .setSpring(new SpringForce(mTargetY)
- .setStiffness(mYStiffness)
- .setDampingRatio(mYDamping));
- mRectYAnim.addEndListener(((animation, canceled, centerY, velocityY) -> {
- mRectYAnimEnded = true;
- maybeOnEnd();
- }));
-
- mRectScaleAnim = ObjectAnimator.ofFloat(this, PROGRESS, 0, 1f)
- .setDuration(mDuration);
- mRectScaleAnim.setInterpolator(mCloseInterpolator);
- mRectScaleAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mRectScaleAnimEnded = true;
- maybeOnEnd();
- }
- });
-
- mValues = buildConfig();
- mRectScaleAnim.addUpdateListener(mValues);
-
- setCanRelease(false);
- mAnimsStarted = true;
-
- mRectXAnim.start();
- mRectYAnim.start();
- mRectScaleAnim.start();
- for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
- animatorListener.onAnimationStart(null);
- }
- }
-
- private AppCloseConfig buildConfig() {
- return new AppCloseConfig() {
- FloatProp mHomeTransY = new FloatProp(0, mHomeTransYEnd, 0, mDuration, LINEAR);
- FloatProp mHomeScale = new FloatProp(mScaleStart, 1f, 0, mDuration, LINEAR);
- FloatProp mWindowFadeOut = new FloatProp(1f, 0f, 0, 116, LINEAR);
- // There should be a slight overlap b/w window fading out and fg fading in.
- // (fg startDelay < window fade out duration)
- FloatProp mFgFadeIn = new FloatProp(0, 255f, 100, mDuration - 100, LINEAR);
- FloatProp mRadius = new FloatProp(mStartRadius, mEndRadius, 0, mDuration, LINEAR);
- FloatProp mThreePointInterpolation = new FloatProp(0, 1, 0, mDuration, LINEAR);
-
- @Override
- public float getWorkspaceTransY() {
- return mHomeTransY.value;
- }
-
- @Override
- public float getWorkspaceScale() {
- return mHomeScale.value;
- }
-
- @Override
- public float getWindowAlpha() {
- return mWindowFadeOut.value;
- }
-
- @Override
- public int getFgAlpha() {
- return (int) mFgFadeIn.value;
- }
-
- @Override
- public float getCornerRadius() {
- return mRadius.value;
- }
-
- @Override
- public float getInterpolatedProgress() {
- return mThreePointInterpolation.value;
- }
-
- @Override
- public void onUpdate(float percent, boolean initOnly) {}
- };
- }
-
- public void end() {
- if (mAnimsStarted) {
- if (mRectXAnim.canSkipToEnd()) {
- mRectXAnim.skipToEnd();
- }
- if (mRectYAnim.canSkipToEnd()) {
- mRectYAnim.skipToEnd();
- }
- mRectScaleAnim.end();
- }
- mRectXAnimEnded = true;
- mRectYAnimEnded = true;
- mRectScaleAnimEnded = true;
- maybeOnEnd();
- }
-
- private boolean isEnded() {
- return mRectXAnimEnded && mRectYAnimEnded && mRectScaleAnimEnded;
- }
-
- private void onUpdate() {
- if (isEnded()) {
- // Prevent further updates from being called. This can happen between callbacks for
- // ending the x/y/scale animations.
- return;
- }
-
- if (!mOnUpdateListeners.isEmpty()) {
- float rectProgress = mProgress;
- float currentWidth = Utilities.mapRange(rectProgress, mStartRect.width(),
- mTargetRect.width());
- float currentHeight = Utilities.mapRange(rectProgress, mStartRect.height(),
- mTargetRect.height());
-
- mCurrentRect.set(mCurrentCenterX - currentWidth / 2,
- mCurrentCenterY - currentHeight / 2,
- mCurrentCenterX + currentWidth / 2,
- mCurrentCenterY + currentHeight / 2);
-
- float currentPlayTime = mRectScaleAnimEnded ? mRectScaleAnim.getDuration()
- : mRectScaleAnim.getCurrentPlayTime();
- float linearProgress = Math.min(1f, currentPlayTime / mRectScaleAnim.getDuration());
- for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
- onUpdateListener.onUpdate(mValues, mCurrentRect, linearProgress);
- }
- }
- }
-
- private void maybeOnEnd() {
- if (mAnimsStarted && isEnded()) {
- mAnimsStarted = false;
- setCanRelease(true);
- for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
- animatorListener.onAnimationEnd(null);
- }
- }
- }
-
- public void cancel() {
- if (mAnimsStarted) {
- for (OnUpdateListener onUpdateListener : mOnUpdateListeners) {
- onUpdateListener.onCancel();
- }
- }
- end();
- }
-
- private Interpolator getAppCloseInterpolator(Context context) {
- ResourceProvider rp = DynamicResource.provider(context);
- String path = String.format(Locale.ENGLISH,
- "M 0,0 C %f, %f, %f, %f, %f, %f C %f, %f, %f, %f, 1, 1",
- rp.getFloat(R.dimen.c1_a),
- rp.getFloat(R.dimen.c1_b),
- rp.getFloat(R.dimen.c1_c),
- rp.getFloat(R.dimen.c1_d),
- rp.getFloat(R.dimen.mp_x),
- rp.getFloat(R.dimen.mp_y),
- rp.getFloat(R.dimen.c2_a),
- rp.getFloat(R.dimen.c2_b),
- rp.getFloat(R.dimen.c2_c),
- rp.getFloat(R.dimen.c2_d));
- return PathInterpolatorCompat.create(PathParser.createPathFromPathData(path));
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
index 98dbd47..ee82ae6 100644
--- a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
@@ -16,32 +16,14 @@
package com.android.quickstep.util;
import android.animation.AnimatorSet;
-import android.app.ActivityOptions;
-import android.content.Context;
-import android.os.Handler;
-import com.android.launcher3.LauncherAnimationRunner;
-import com.android.launcher3.LauncherAnimationRunner.RemoteAnimationFactory;
-import com.android.systemui.shared.system.ActivityOptionsCompat;
-import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
public abstract class RemoteAnimationProvider {
- RemoteAnimationFactory mAnimationRunner;
-
public abstract AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] appTargets,
RemoteAnimationTargetCompat[] wallpaperTargets);
- ActivityOptions toActivityOptions(Handler handler, long duration, Context context) {
- mAnimationRunner = (transit, appTargets, wallpaperTargets, nonApps, result) ->
- result.setAnimation(createWindowAnimation(appTargets, wallpaperTargets), context);
- final LauncherAnimationRunner wrapper = new LauncherAnimationRunner(
- handler, mAnimationRunner, false /* startAtFrontOfQueue */);
- return ActivityOptionsCompat.makeRemoteAnimation(
- new RemoteAnimationAdapterCompat(wrapper, duration, 0));
- }
-
/**
* @return the target with the lowest opaque layer for a certain app animation, or null.
*/
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 1dae2c8..b32c4e5 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -21,8 +21,10 @@
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
+import android.app.ActivityOptions;
import android.app.ActivityThread;
import android.graphics.Rect;
+import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.view.RemoteAnimationAdapter;
@@ -56,6 +58,7 @@
private Task mInitialTask;
private Task mSecondTask;
private Rect mInitialBounds;
+ private boolean mRecentsAnimationRunning;
public SplitSelectStateController(Handler handler, SystemUiProxy systemUiProxy) {
mHandler = handler;
@@ -77,14 +80,15 @@
*/
public void setSecondTaskId(Task taskView, Consumer<Boolean> callback) {
mSecondTask = taskView;
- launchTasks(mInitialTask, mSecondTask, mStagePosition, callback);
+ launchTasks(mInitialTask, mSecondTask, mStagePosition, callback,
+ false /* freezeTaskList */);
}
/**
* @param stagePosition representing location of task1
*/
public void launchTasks(Task task1, Task task2, @StagePosition int stagePosition,
- Consumer<Boolean> callback) {
+ Consumer<Boolean> callback, boolean freezeTaskList) {
// Assume initial task is for top/left part of screen
final int[] taskIds = stagePosition == STAGE_POSITION_TOP_OR_LEFT
? new int[]{task1.key.id, task2.key.id}
@@ -94,7 +98,8 @@
new RemoteSplitLaunchTransitionRunner(task1, task2);
mSystemUiProxy.startTasks(taskIds[0], null /* mainOptions */, taskIds[1],
null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
- new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR));
+ new RemoteTransitionCompat(animationRunner, MAIN_EXECUTOR,
+ ActivityThread.currentActivityThread().getApplicationThread()));
} else {
RemoteSplitLaunchAnimationRunner animationRunner =
new RemoteSplitLaunchAnimationRunner(task1, task2, callback);
@@ -103,8 +108,13 @@
300, 150,
ActivityThread.currentActivityThread().getApplicationThread());
- mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], null /* mainOptions */,
- taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT, adapter);
+ ActivityOptions mainOpts = ActivityOptions.makeBasic();
+ if (freezeTaskList) {
+ mainOpts.setFreezeRecentTasksReordering();
+ }
+ mSystemUiProxy.startTasksWithLegacyTransition(taskIds[0], mainOpts.toBundle(),
+ taskIds[1], null /* sideOptions */, STAGE_POSITION_BOTTOM_OR_RIGHT,
+ adapter);
}
}
@@ -112,6 +122,10 @@
return mStagePosition;
}
+ public void setRecentsAnimationRunning(boolean running) {
+ this.mRecentsAnimationRunning = running;
+ }
+
/**
* Requires Shell Transitions
*/
@@ -171,7 +185,9 @@
public void onAnimationCancelled() {
postAsyncCallback(mHandler, () -> {
if (mSuccessCallback != null) {
- mSuccessCallback.accept(false);
+ // Launching legacy tasks while recents animation is running will always cause
+ // onAnimationCancelled to be called (should be fixed w/ shell transitions?)
+ mSuccessCallback.accept(mRecentsAnimationRunning);
}
resetState();
});
@@ -186,6 +202,7 @@
mSecondTask = null;
mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
mInitialBounds = null;
+ mRecentsAnimationRunning = false;
}
/**
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index a30216c..a534450 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -158,7 +158,7 @@
t.reparent(mContentOverlay, mLeash);
t.apply();
- addOnUpdateListener((values, currentRect, progress) -> {
+ addOnUpdateListener((currentRect, progress) -> {
float alpha = progress < 0.5f
? 0
: Utilities.mapToRange(Math.min(progress, 1f), 0.5f, 1f,
@@ -201,8 +201,7 @@
addOnUpdateListener(this::onAnimationUpdate);
}
- private void onAnimationUpdate(@Nullable AppCloseConfig values, RectF currentRect,
- float progress) {
+ private void onAnimationUpdate(RectF currentRect, float progress) {
if (mHasAnimationEnded) return;
final SurfaceControl.Transaction tx =
PipSurfaceTransactionHelper.newSurfaceControlTransaction();
diff --git a/quickstep/src/com/android/quickstep/util/TaskKeyLruCache.java b/quickstep/src/com/android/quickstep/util/TaskKeyLruCache.java
index d87feec..08a65fa 100644
--- a/quickstep/src/com/android/quickstep/util/TaskKeyLruCache.java
+++ b/quickstep/src/com/android/quickstep/util/TaskKeyLruCache.java
@@ -20,6 +20,7 @@
import com.android.systemui.shared.recents.model.Task.TaskKey;
import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.function.Predicate;
/**
@@ -117,7 +118,7 @@
}
@Override
- protected boolean removeEldestEntry(Entry<Integer, TaskKeyLruCache.Entry<V>> eldest) {
+ protected boolean removeEldestEntry(Map.Entry<Integer, TaskKeyLruCache.Entry<V>> eldest) {
return size() > mMaxSize;
}
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 734c844..7d396ba 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -15,13 +15,13 @@
*/
package com.android.quickstep.util;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.states.RotationHelper.deltaRotation;
import static com.android.launcher3.touch.PagedOrientationHandler.MATRIX_POST_TRANSLATE;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
-import static com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import static com.android.quickstep.util.RecentsOrientedState.postDisplayRotation;
import static com.android.quickstep.util.RecentsOrientedState.preDisplayRotation;
import static com.android.systemui.shared.system.WindowManagerWrapper.WINDOWING_MODE_FULLSCREEN;
@@ -40,6 +40,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.AnimatedFloat;
import com.android.quickstep.BaseActivityInterface;
@@ -99,6 +100,9 @@
private boolean mLayoutValid = false;
private int mOrientationStateId;
private StagedSplitBounds mStagedSplitBounds;
+ private boolean mDrawsBelowRecents;
+ private boolean mIsGridTask;
+ private float mGridTranslationY;
public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) {
mContext = context;
@@ -138,18 +142,29 @@
if (mDp == null) {
return 1;
}
- Rect fullTaskSize = new Rect();
- mSizeStrategy.calculateTaskSize(mContext, mDp, fullTaskSize);
+ if (mIsGridTask) {
+ mSizeStrategy.calculateGridTaskSize(mContext, mDp, mTaskRect,
+ mOrientationState.getOrientationHandler());
+ } else {
+ mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect);
+ }
+ Rect fullTaskSize;
if (mStagedSplitBounds != null) {
// The task rect changes according to the staged split task sizes, but recents
// fullscreen scale and pivot remains the same since the task fits into the existing
// sized task space bounds
- mSizeStrategy.calculateTaskSize(mContext, mDp, mTaskRect);
+ fullTaskSize = new Rect(mTaskRect);
mOrientationState.getOrientationHandler()
.setSplitTaskSwipeRect(mDp, mTaskRect, mStagedSplitBounds, mStagePosition);
+ if (mIsGridTask) {
+ mTaskRect.offset(0, (int) mGridTranslationY);
+ }
} else {
- mTaskRect.set(fullTaskSize);
+ fullTaskSize = mTaskRect;
+ }
+ if (mIsGridTask) {
+ fullTaskSize.offset(0, (int) mGridTranslationY);
}
return mOrientationState.getFullScreenScaleAndPivot(fullTaskSize, mDp, mPivot);
}
@@ -198,6 +213,24 @@
recentsViewScroll.value = scroll;
}
+ public void setDrawsBelowRecents(boolean drawsBelowRecents) {
+ mDrawsBelowRecents = drawsBelowRecents;
+ }
+
+ /**
+ * Sets whether the task is part of overview grid and not being focused.
+ */
+ public void setIsGridTask(boolean isGridTask) {
+ mIsGridTask = isGridTask;
+ }
+
+ /**
+ * Sets the y-translation when overview is in grid.
+ */
+ public void setGridTranslationY(float gridTranslationY) {
+ mGridTranslationY = gridTranslationY;
+ }
+
/**
* Adds animation for all the components corresponding to transition from an app to overview.
*/
@@ -301,14 +334,12 @@
mMatrix.postTranslate(insets.left, insets.top);
mMatrix.postScale(scale, scale);
- // Apply TaskView matrix: translate, scroll
+ // Apply TaskView matrix: taskRect, translate
mMatrix.postTranslate(mTaskRect.left, mTaskRect.top);
mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE,
taskPrimaryTranslation.value);
mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
taskSecondaryTranslation.value);
- mOrientationState.getOrientationHandler().set(
- mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value);
// Apply RecentsView matrix
mMatrix.postScale(recentsViewScale.value, recentsViewScale.value, mPivot.x, mPivot.y);
@@ -316,6 +347,8 @@
recentsViewSecondaryTranslation.value);
mOrientationState.getOrientationHandler().set(mMatrix, MATRIX_POST_TRANSLATE,
recentsViewPrimaryTranslation.value);
+ mOrientationState.getOrientationHandler().set(
+ mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value);
applyWindowToHomeRotation(mMatrix);
// Crop rect is the inverse of thumbnail matrix
@@ -351,6 +384,12 @@
builder.withMatrix(mMatrix)
.withWindowCrop(mTmpCropRect)
.withCornerRadius(getCurrentCornerRadius());
+
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get() && params.getRecentsSurface() != null) {
+ // When relativeLayer = 0, it reverts the surfaces back to the original order.
+ builder.withRelativeLayerTo(params.getRecentsSurface(),
+ mDrawsBelowRecents ? Integer.MIN_VALUE : 0);
+ }
}
/**
diff --git a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
index e9d7c3c..d79b318 100644
--- a/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
+++ b/quickstep/src/com/android/quickstep/views/AllAppsEduView.java
@@ -35,6 +35,7 @@
import android.view.MotionEvent;
import android.view.View;
+import androidx.annotation.Nullable;
import androidx.core.graphics.ColorUtils;
import com.android.launcher3.AbstractFloatingView;
@@ -58,6 +59,7 @@
private Launcher mLauncher;
private AllAppsEduTouchController mTouchController;
+ @Nullable
private AnimatorSet mAnimation;
private GradientDrawable mCircle;
diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
index 86be210..4f2ed4c 100644
--- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java
+++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java
@@ -21,6 +21,7 @@
import android.util.FloatProperty;
import android.widget.Button;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.touch.PagedOrientationHandler;
@@ -245,6 +246,9 @@
* Get the Y translation that is set in the original layout position, before scrolling.
*/
private float getOriginalTranslationY() {
- return mActivity.getDeviceProfile().overviewTaskThumbnailTopMarginPx / 2.0f;
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+ return deviceProfile.overviewShowAsGrid
+ ? deviceProfile.overviewRowSpacing
+ : deviceProfile.overviewTaskThumbnailTopMarginPx / 2.0f;
}
}
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 7c8041c..dbdcf19 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -44,6 +44,7 @@
import android.widget.FrameLayout;
import android.widget.TextView;
+import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import com.android.launcher3.BaseActivity;
@@ -69,6 +70,7 @@
private Task mTask;
private boolean mHasLimit;
private long mAppRemainingTimeMs;
+ @Nullable
private View mBanner;
private ViewOutlineProvider mOldBannerOutlineProvider;
private float mBannerOffsetPercentage;
@@ -234,7 +236,7 @@
task.titleDescription;
}
- private void replaceBanner(View view) {
+ private void replaceBanner(@Nullable View view) {
resetOldBanner();
setBanner(view);
}
@@ -248,7 +250,7 @@
}
}
- private void setBanner(View view) {
+ private void setBanner(@Nullable View view) {
mBanner = view;
if (view != null) {
setupAndAddBanner();
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index 5a86464..e2ffa18 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -15,6 +15,8 @@
import android.widget.FrameLayout;
import android.widget.ImageView;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
@@ -51,11 +53,11 @@
this(context, null);
}
- public FloatingTaskView(Context context, AttributeSet attrs) {
+ public FloatingTaskView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public FloatingTaskView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public FloatingTaskView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mLauncher = Launcher.getLauncher(context);
mIsRtl = Utilities.isRtl(getResources());
diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
index 1548268..c3b166f 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetBackgroundView.java
@@ -27,6 +27,8 @@
import android.view.ViewOutlineProvider;
import android.widget.RemoteViews.RemoteViewOutlineProvider;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.RoundedCornerEnforcement;
@@ -42,7 +44,9 @@
private final DrawableProperties mForegroundProperties = new DrawableProperties();
private final DrawableProperties mBackgroundProperties = new DrawableProperties();
+ @Nullable
private Drawable mOriginalForeground;
+ @Nullable
private Drawable mOriginalBackground;
private float mFinalRadius;
private float mInitialOutlineRadius;
@@ -50,7 +54,7 @@
private boolean mIsUsingFallback;
private View mSourceView;
- FloatingWidgetBackgroundView(Context context, AttributeSet attrs, int defStyleAttr) {
+ FloatingWidgetBackgroundView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOutlineProvider(new ViewOutlineProvider() {
@Override
@@ -161,8 +165,10 @@
/** Stores and modifies a drawable's properties through an animation. */
private static class DrawableProperties {
+ @Nullable
private Drawable mDrawable;
private float mOriginalRadius;
+ @Nullable
private float[] mOriginalRadii;
private final float[] mTmpRadii = new float[8];
diff --git a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
index 88b11a0..8a5f42a 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingWidgetView.java
@@ -30,6 +30,8 @@
import android.view.ViewTreeObserver.OnGlobalLayoutListener;
import android.widget.FrameLayout;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -55,10 +57,14 @@
private LauncherAppWidgetHostView mAppWidgetView;
private View mAppWidgetBackgroundView;
private RectF mBackgroundPosition;
+ @Nullable
private GhostView mForegroundOverlayView;
+ @Nullable
private Runnable mEndRunnable;
+ @Nullable
private Runnable mFastFinishRunnable;
+ @Nullable
private Runnable mOnTargetChangeRunnable;
private boolean mAppTargetIsTranslucent;
@@ -68,11 +74,11 @@
this(context, null);
}
- public FloatingWidgetView(Context context, AttributeSet attrs) {
+ public FloatingWidgetView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public FloatingWidgetView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public FloatingWidgetView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mLauncher = Launcher.getLauncher(context);
mListenerView = new ListenerView(context, attrs);
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
index 72d3731..df99d27 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java
@@ -24,6 +24,7 @@
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
+import java.util.HashMap;
import java.util.function.Consumer;
/**
@@ -38,10 +39,13 @@
*/
public class GroupedTaskView extends TaskView {
+ @Nullable
private Task mSecondaryTask;
private TaskThumbnailView mSnapshotView2;
private IconView mIconView2;
+ @Nullable
private CancellableTask<ThumbnailData> mThumbnailLoadRequest2;
+ @Nullable
private CancellableTask mIconLoadRequest2;
private final float[] mIcon2CenterCoords = new float[2];
private TransformingTouchDelegate mIcon2TouchDelegate;
@@ -70,7 +74,7 @@
}
public void bind(Task primary, Task secondary, RecentsOrientedState orientedState,
- StagedSplitBounds splitBoundsConfig) {
+ @Nullable StagedSplitBounds splitBoundsConfig) {
super.bind(primary, orientedState);
mSecondaryTask = secondary;
mTaskIdContainer[1] = secondary.key.id;
@@ -117,7 +121,11 @@
}
protected boolean showTaskMenuWithContainer(IconView iconView) {
- return TaskMenuView.showForTask(mTaskIdAttributeContainer[iconView == mIconView ? 0 : 1]);
+ if (mActivity.getDeviceProfile().overviewShowAsGrid) {
+ return TaskMenuViewWithArrow.Companion.showForTask(mTaskIdAttributeContainer[0]);
+ } else {
+ return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]);
+ }
}
public void updateSplitBoundsConfig(StagedSplitBounds stagedSplitBounds) {
@@ -148,17 +156,33 @@
}
}
+ @Nullable
@Override
public RunnableList launchTaskAnimated() {
getRecentsView().getSplitPlaceholder().launchTasks(mTask, mSecondaryTask,
- STAGE_POSITION_TOP_OR_LEFT, null /*callback*/);
+ STAGE_POSITION_TOP_OR_LEFT, null /*callback*/,
+ false /* freezeTaskList */);
return null;
}
@Override
public void launchTask(@NonNull Consumer<Boolean> callback, boolean freezeTaskList) {
getRecentsView().getSplitPlaceholder().launchTasks(mTask, mSecondaryTask,
- STAGE_POSITION_TOP_OR_LEFT, callback);
+ STAGE_POSITION_TOP_OR_LEFT, callback, freezeTaskList);
+ }
+
+ @Override
+ void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
+ super.refreshThumbnails(thumbnailDatas);
+ if (mSecondaryTask != null && thumbnailDatas != null) {
+ final ThumbnailData thumbnailData = thumbnailDatas.get(mSecondaryTask.key.id);
+ if (thumbnailData != null) {
+ mSnapshotView2.setThumbnail(mSecondaryTask, thumbnailData);
+ return;
+ }
+ }
+
+ mSnapshotView2.refresh();
}
@Override
@@ -221,4 +245,10 @@
taskIconHeight, mPrimaryTempRect, mSecondaryTempRect,
isRtl, deviceProfile, mSplitBoundsConfig);
}
+
+ @Override
+ protected void updateSnapshotRadius() {
+ super.updateSnapshotRadius();
+ mSnapshotView2.setFullscreenParams(mCurrentFullscreenParams);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/IconView.java b/quickstep/src/com/android/quickstep/views/IconView.java
index 813e653..ccb1a99 100644
--- a/quickstep/src/com/android/quickstep/views/IconView.java
+++ b/quickstep/src/com/android/quickstep/views/IconView.java
@@ -23,6 +23,8 @@
import android.view.Gravity;
import android.view.View;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.Utilities;
/**
@@ -31,6 +33,7 @@
*/
public class IconView extends View {
+ @Nullable
private Drawable mDrawable;
private int mDrawableWidth, mDrawableHeight;
@@ -46,7 +49,10 @@
super(context, attrs, defStyleAttr);
}
- public void setDrawable(Drawable d) {
+ /**
+ * Sets a {@link Drawable} to be displayed.
+ */
+ public void setDrawable(@Nullable Drawable d) {
if (mDrawable != null) {
mDrawable.setCallback(null);
}
@@ -76,6 +82,7 @@
mDrawable.setBounds(drawableRect);
}
+ @Nullable
public Drawable getDrawable() {
return mDrawable;
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 715d30e..3cba392 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -21,6 +21,7 @@
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.quickstep.ViewUtils.postFrameDrawn;
import android.annotation.TargetApi;
import android.content.Context;
@@ -30,6 +31,8 @@
import android.view.MotionEvent;
import android.view.Surface;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.BaseQuickstepLauncher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.statehandlers.DepthController;
@@ -49,11 +52,11 @@
this(context, null);
}
- public LauncherRecentsView(Context context, AttributeSet attrs) {
+ public LauncherRecentsView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public LauncherRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public LauncherRecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr, LauncherActivityInterface.INSTANCE);
mActivity.getStateManager().addStateListener(this);
}
@@ -102,8 +105,14 @@
@Override
public void onStateTransitionComplete(LauncherState finalState) {
- setOverlayEnabled(finalState == OVERVIEW || finalState == OVERVIEW_MODAL_TASK);
+ boolean isOverlayEnabled = finalState == OVERVIEW || finalState == OVERVIEW_MODAL_TASK;
+ setOverlayEnabled(isOverlayEnabled);
setFreezeViewVisibility(false);
+
+ if (isOverlayEnabled) {
+ postFrameDrawn(this, () -> runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true)));
+ }
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 76d3591..f3b6a63 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -20,6 +20,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.FrameLayout;
@@ -30,6 +31,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
+import com.android.launcher3.testing.TestProtocol;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.MultiValueAlpha.AlphaProperty;
import com.android.quickstep.SysUINavigationMode;
@@ -88,8 +90,10 @@
@ActionsDisabledFlags
protected int mDisabledFlags;
+ @Nullable
protected T mCallbacks;
+ @Nullable
protected DeviceProfile mDp;
public OverviewActionsView(Context context) {
@@ -110,6 +114,11 @@
protected void onFinishInflate() {
super.onFinishInflate();
findViewById(R.id.action_screenshot).setOnClickListener(this);
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SCREENSHOT, "Inflated OverviewActionsView and added screenshot"
+ + " listener.");
+ }
+
mSplitButton = findViewById(R.id.action_split);
mSplitButton.setOnClickListener(this);
}
@@ -120,11 +129,19 @@
* @param callbacks for callbacks, or {@code null} to clear the listener.
*/
public void setCallbacks(T callbacks) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SCREENSHOT, "OverviewActionsView setCallbacks: " + callbacks);
+ }
mCallbacks = callbacks;
}
@Override
public void onClick(View view) {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.NO_SCREENSHOT, "OverviewActionsView - onClick"
+ + " callbacks: " + mCallbacks + " view id: " + view.getId() + " "
+ + " is screenshot? " + (view.getId() == R.id.action_screenshot));
+ }
if (mCallbacks == null) {
return;
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 687a13a..7b5a6b9 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -137,8 +137,8 @@
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.ResourceBasedOverride.Overrides;
import com.android.launcher3.util.RunnableList;
-import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
+import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TranslateEdgeEffect;
import com.android.launcher3.util.ViewPool;
@@ -157,7 +157,7 @@
import com.android.quickstep.TaskThumbnailCache;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.ViewUtils;
-import com.android.quickstep.util.LauncherSplitScreenListener;
+import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.SplitScreenBounds;
@@ -179,6 +179,7 @@
import com.android.wm.shell.pip.IPipAnimationListener;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
import java.util.function.Consumer;
@@ -382,7 +383,9 @@
protected final RecentsOrientedState mOrientationState;
protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
+ @Nullable
protected RecentsAnimationController mRecentsAnimationController;
+ @Nullable
protected SurfaceTransactionApplier mSyncTransactionApplier;
protected int mTaskWidth;
protected int mTaskHeight;
@@ -393,12 +396,15 @@
// mTaskGridVerticalDiff and mTopBottomRowHeightDiff summed together provides the top
// position for bottom row of grid tasks.
+ @Nullable
protected RemoteTargetHandle[] mRemoteTargetHandles;
protected final Rect mLastComputedTaskSize = new Rect();
protected final Rect mLastComputedGridSize = new Rect();
protected final Rect mLastComputedGridTaskSize = new Rect();
// How much a task that is directly offscreen will be pushed out due to RecentsView scale/pivot.
+ @Nullable
protected Float mLastComputedTaskStartPushOutDistance = null;
+ @Nullable
protected Float mLastComputedTaskEndPushOutDistance = null;
protected boolean mEnableDrawingLiveTile = false;
protected final Rect mTempRect = new Rect();
@@ -453,11 +459,13 @@
private final IntSet mTopRowIdSet = new IntSet();
// The GestureEndTarget that is still in progress.
+ @Nullable
protected GestureState.GestureEndTarget mCurrentGestureEndTarget;
// TODO(b/187528071): Remove these and replace with a real scrim.
private float mColorTint;
private final int mTintingColor;
+ @Nullable
private ObjectAnimator mTintingAnimator;
private int mOverScrollShift = 0;
@@ -541,6 +549,7 @@
private int mTaskViewIdCount;
private final int[] INVALID_TASK_IDS = new int[]{-1, -1};
protected boolean mRunningTaskTileHidden;
+ @Nullable
private Task[] mTmpRunningTasks;
protected int mFocusedTaskViewId = -1;
@@ -555,7 +564,9 @@
private int mDownX;
private int mDownY;
+ @Nullable
private PendingAnimation mPendingAnimation;
+ @Nullable
private LayoutTransition mLayoutTransition;
@ViewDebug.ExportedProperty(category = "launcher")
@@ -571,6 +582,7 @@
// Keeps track of task id whose visual state should not be reset
private int mIgnoreResetTaskId = -1;
+ protected boolean mLoadPlanEverApplied;
// Variables for empty state
private final Drawable mEmptyIcon;
@@ -579,7 +591,9 @@
private final Point mLastMeasureSize = new Point();
private final int mEmptyMessagePadding;
private boolean mShowEmptyMessage;
+ @Nullable
private OnEmptyMessageUpdatedListener mOnEmptyMessageUpdatedListener;
+ @Nullable
private Layout mEmptyTextLayout;
/**
@@ -594,9 +608,12 @@
* ensure this View doesn't go back into the {@link #mTaskViewPool},
* see {@link #onViewRemoved(View)}
*/
+ @Nullable
private TaskView mSplitHiddenTaskView;
+ @Nullable
private TaskView mSecondSplitHiddenTaskView;
- private SplitConfigurationOptions.StagedSplitBounds mSplitBoundsConfig;
+ @Nullable
+ private StagedSplitBounds mSplitBoundsConfig;
private final Toast mSplitToast = Toast.makeText(getContext(),
R.string.toast_split_select_app, Toast.LENGTH_SHORT);
private final Toast mSplitUnsupportedToast = Toast.makeText(getContext(),
@@ -611,12 +628,15 @@
* removed from recentsView
*/
private int mSplitHiddenTaskViewIndex;
+ @Nullable
private FloatingTaskView mFirstFloatingTaskView;
+ @Nullable
private FloatingTaskView mSecondFloatingTaskView;
/**
* The task to be removed and immediately re-added. Should not be added to task pool.
*/
+ @Nullable
private TaskView mMovingTaskView;
private OverviewActionsView mActionsView;
@@ -636,10 +656,12 @@
}
};
+ @Nullable
private RunnableList mSideTaskLaunchCallback;
+ @Nullable
private TaskLaunchListener mTaskLaunchListener;
- public RecentsView(Context context, AttributeSet attrs, int defStyleAttr,
+ public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
BaseActivityInterface sizeStrategy) {
super(context, attrs, defStyleAttr);
setEnableFreeScroll(true);
@@ -662,9 +684,8 @@
mClearAllButton.setOnClickListener(this::dismissAllTasks);
mTaskViewPool = new ViewPool<>(context, this, R.layout.task, 20 /* max size */,
10 /* initial size */);
- // There's only one pair of grouped tasks we can envision at the moment
mGroupedTaskViewPool = new ViewPool<>(context, this,
- R.layout.task_grouped, 2 /* max size */, 1 /* initial size */);
+ R.layout.task_grouped, 20 /* max size */, 10 /* initial size */);
mIsRtl = mOrientationHandler.getRecentsRtlSetting(getResources());
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
@@ -781,6 +802,7 @@
}
@Override
+ @Nullable
public Task onTaskThumbnailChanged(int taskId, ThumbnailData thumbnailData) {
if (mHandleTaskStackChanges) {
TaskView taskView = getTaskViewByTaskId(taskId);
@@ -816,6 +838,7 @@
* Update the thumbnail of the task.
* @param refreshNow Refresh immediately if it's true.
*/
+ @Nullable
public TaskView updateThumbnail(int taskId, ThumbnailData thumbnailData, boolean refreshNow) {
TaskView taskView = getTaskViewByTaskId(taskId);
if (taskView != null) {
@@ -1016,9 +1039,13 @@
}
}
+ @Nullable
private TaskView getLastGridTaskView() {
- IntArray topRowIdArray = getTopRowIdArray();
- IntArray bottomRowIdArray = getBottomRowIdArray();
+ return getLastGridTaskView(getTopRowIdArray(), getBottomRowIdArray());
+ }
+
+ @Nullable
+ private TaskView getLastGridTaskView(IntArray topRowIdArray, IntArray bottomRowIdArray) {
if (topRowIdArray.isEmpty() && bottomRowIdArray.isEmpty()) {
return null;
}
@@ -1067,7 +1094,15 @@
return getScrollForPage(taskIndex) == getPagedOrientationHandler().getPrimaryScroll(this);
}
+ /**
+ * Returns a {@link TaskView} that has taskId matching {@code taskId} or null if no match.
+ */
+ @Nullable
public TaskView getTaskViewByTaskId(int taskId) {
+ if (taskId == -1) {
+ return null;
+ }
+
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView taskView = getTaskViewAt(i);
int[] taskIds = taskView.getTaskIds();
@@ -1296,13 +1331,14 @@
updateGridProperties();
}
- protected void applyLoadPlan(ArrayList<Task> tasks) {
+ protected void applyLoadPlan(ArrayList<GroupTask> taskGroups) {
if (mPendingAnimation != null) {
- mPendingAnimation.addEndListener(success -> applyLoadPlan(tasks));
+ mPendingAnimation.addEndListener(success -> applyLoadPlan(taskGroups));
return;
}
- if (tasks == null || tasks.isEmpty()) {
+ mLoadPlanEverApplied = true;
+ if (taskGroups == null || taskGroups.isEmpty()) {
removeTasksViewsAndClearAllButton();
onTaskStackUpdated();
return;
@@ -1320,70 +1356,38 @@
TaskView ignoreResetTaskView =
mIgnoreResetTaskId == -1 ? null : getTaskViewByTaskId(mIgnoreResetTaskId);
- int[] splitTaskIds =
- LauncherSplitScreenListener.INSTANCE.getNoCreate().getPersistentSplitIds();
- int requiredGroupTaskViews = splitTaskIds.length / 2;
-
- // Subtract half the number of split tasks and not total number because we've already
- // added a GroupedTaskView when swipe up gesture happens.
- // This will need to change if we start showing GroupedTaskViews during swipe up from home
- int requiredTaskViewCount = tasks.size() - requiredGroupTaskViews;
-
- if (getTaskViewCount() != requiredTaskViewCount) {
- if (indexOfChild(mClearAllButton) != -1) {
- removeView(mClearAllButton);
- }
-
- for (int i = getTaskViewCount(); i < requiredTaskViewCount; i++) {
- addView(getTaskViewFromPool(false));
- }
- while (getTaskViewCount() > requiredTaskViewCount) {
- removeView(getChildAt(getChildCount() - 1));
- }
- int groupedTaskViewCount = getGroupedTaskViewCount();
- while (requiredGroupTaskViews > groupedTaskViewCount) {
- // Add to front of list
- addView(getTaskViewFromPool(true), 0);
- requiredGroupTaskViews--;
- }
- if (requiredTaskViewCount > 0) {
- addView(mClearAllButton);
- }
- }
-
// Save running task ID if it exists before rebinding all taskViews, otherwise the task from
// the runningTaskView currently bound could get assigned to another TaskView
- // TODO set these type to array and check all taskIDs? Maybe we can get away w/ only one
int runningTaskId = getTaskIdsForTaskViewId(mRunningTaskViewId)[0];
int focusedTaskId = getTaskIdsForTaskViewId(mFocusedTaskViewId)[0];
- Log.d(TASK_VIEW_ID_CRASH, "runningTaskId beforeBind: " + runningTaskId
- + " runningTaskViewId: " + mRunningTaskViewId
- + " forTaskView: " + getTaskViewFromTaskViewId(mRunningTaskViewId));
- for (int taskViewIndex = requiredTaskViewCount - 1, taskDataIndex = tasks.size() - 1;
- taskViewIndex >= 0;
- taskViewIndex--, taskDataIndex--) {
- final int pageIndex = requiredTaskViewCount - taskViewIndex - 1;
- final Task task = tasks.get(taskDataIndex);
- final TaskView taskView = (TaskView) getChildAt(pageIndex);
- if (taskView instanceof GroupedTaskView) {
- Task leftTop;
- Task rightBottom;
- if (task.key.id == splitTaskIds[0]) {
- leftTop = task;
- taskDataIndex--;
- rightBottom = tasks.get(taskDataIndex);
- } else {
- rightBottom = task;
- taskDataIndex--;
- leftTop = tasks.get(taskDataIndex);
- }
- ((GroupedTaskView) taskView).bind(leftTop, rightBottom, mOrientationState,
- mSplitBoundsConfig);
+ // Removing views sets the currentPage to 0, so we save this and restore it after
+ // the new set of views are added
+ int previousPage = mCurrentPage;
+ removeAllViews();
+
+ // Add views as children based on whether it's grouped or single task
+ for (int i = taskGroups.size() - 1; i >= 0; i--) {
+ GroupTask groupTask = taskGroups.get(i);
+ boolean hasMultipleTasks = groupTask.hasMultipleTasks();
+ TaskView taskView = getTaskViewFromPool(hasMultipleTasks);
+ addView(taskView);
+
+ if (hasMultipleTasks) {
+ boolean firstTaskIsLeftTopTask =
+ groupTask.mStagedSplitBounds.leftTopTaskId == groupTask.task1.key.id;
+ Task leftTopTask = firstTaskIsLeftTopTask ? groupTask.task1 : groupTask.task2;
+ Task rightBottomTask = firstTaskIsLeftTopTask ? groupTask.task2 : groupTask.task1;
+ ((GroupedTaskView) taskView).bind(leftTopTask, rightBottomTask, mOrientationState,
+ groupTask.mStagedSplitBounds);
} else {
- taskView.bind(task, mOrientationState);
+ taskView.bind(groupTask.task1, mOrientationState);
}
}
+ if (!taskGroups.isEmpty()) {
+ addView(mClearAllButton);
+ }
+ setCurrentPage(previousPage);
// Keep same previous focused task
TaskView newFocusedTaskView = getTaskViewByTaskId(focusedTaskId);
@@ -1401,21 +1405,10 @@
// Update mRunningTaskViewId to be the new TaskView that was assigned by binding
// the full list of tasks to taskViews
newRunningTaskView = getTaskViewByTaskId(runningTaskId);
- if (newRunningTaskView == null) {
- StringBuilder sb = new StringBuilder();
- for (int i = requiredTaskViewCount - 1; i >= 0; i--) {
- final int pageIndex = requiredTaskViewCount - i - 1;
- final TaskView taskView = (TaskView) getChildAt(pageIndex);
- int taskViewId = taskView.getTaskViewId();
- sb.append(" taskViewId: " + taskViewId
- + " taskId: " + getTaskIdsForTaskViewId(taskViewId)[0]
- + " for taskView: " + taskView + "\n");
- }
- Log.d(TASK_VIEW_ID_CRASH, "taskViewCount: " + getTaskViewCount()
- + " " + sb.toString());
- mRunningTaskViewId = -1;
- } else {
+ if (newRunningTaskView != null) {
mRunningTaskViewId = newRunningTaskView.getTaskViewId();
+ } else {
+ mRunningTaskViewId = -1;
}
}
@@ -1515,17 +1508,6 @@
}
}
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
- // Since we reuse the same mLiveTileTaskViewSimulator in the RecentsView, we need
- // to reset the params after it settles in Overview from swipe up so that we don't
- // render with obsolete param values.
- runActionOnRemoteHandles(remoteTargetHandle -> {
- TaskViewSimulator simulator = remoteTargetHandle.getTaskViewSimulator();
- simulator.taskPrimaryTranslation.value = 0;
- simulator.taskSecondaryTranslation.value = 0;
- simulator.fullScreenProgress.value = 0;
- simulator.recentsViewScale.value = 1;
- });
-
// Similar to setRunningTaskHidden below, reapply the state before runningTaskView is
// null.
if (!mRunningTaskShowScreenshot) {
@@ -1911,8 +1893,11 @@
}
}
setEnableDrawingLiveTile(false);
- runActionOnRemoteHandles(remoteTargetHandle -> remoteTargetHandle.getTransformParams()
- .setTargetSet(null));
+ runActionOnRemoteHandles(remoteTargetHandle -> {
+ remoteTargetHandle.getTransformParams().setTargetSet(null);
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false);
+ });
+ mSplitSelectStateController.resetState();
// These are relatively expensive and don't need to be done this frame (RecentsView isn't
// visible anyway), so defer by a frame to get off the critical path, e.g. app to home.
@@ -1952,6 +1937,7 @@
return getTaskViewFromTaskViewId(mFocusedTaskViewId);
}
+ @Nullable
private TaskView getTaskViewFromTaskViewId(int taskViewId) {
if (taskViewId == -1) {
return null;
@@ -2762,6 +2748,9 @@
boolean isSplitPlaceholderFirstInGrid = isSplitPlaceholderFirstInGrid();
boolean isSplitPlaceholderLastInGrid = isSplitPlaceholderLastInGrid();
TaskView lastGridTaskView = showAsGrid ? getLastGridTaskView() : null;
+ int currentPageScroll = getScrollForPage(mCurrentPage);
+ int lastGridTaskScroll = getScrollForPage(indexOfChild(lastGridTaskView));
+ boolean currentPageSnapsToEndOfGrid = currentPageScroll == lastGridTaskScroll;
if (lastGridTaskView != null && lastGridTaskView.isVisibleToUser()) {
// After dismissal, animate translation of the remaining tasks to fill any gap left
// between the end of the grid and the clear all button. Only animate if the clear
@@ -2805,8 +2794,7 @@
// Shift all the tasks to make space for split placeholder.
longGridRowWidthDiff += mIsRtl ? mSplitPlaceholderSize : -mSplitPlaceholderSize;
}
- } else if (isLandscapeSplit && getScrollForPage(mCurrentPage)
- == getScrollForPage(indexOfChild(lastGridTaskView))) {
+ } else if (isLandscapeSplit && currentPageSnapsToEndOfGrid) {
// Use last task as reference point for scroll diff and snapping calculation as it's
// the only invariant point in landscape split screen.
snapToLastTask = true;
@@ -3017,6 +3005,10 @@
@SuppressWarnings("WrongCall")
private void onEnd(boolean success) {
+ // Reset task translations as they may have updated via animations in
+ // createTaskDismissAnimation
+ resetTaskVisuals();
+
if (success) {
if (shouldRemoveTask) {
if (dismissedTaskView.getTask() != null) {
@@ -3033,10 +3025,6 @@
}
}
- // Reset task translations as they may have updated via animations in
- // createTaskDismissAnimation
- resetTaskVisuals();
-
int pageToSnapTo = mCurrentPage;
mCurrentPageScrollDiff = 0;
int taskViewIdToSnapTo = -1;
@@ -3118,12 +3106,17 @@
} else if (dismissedIndex < pageToSnapTo || pageToSnapTo == taskCount - 1) {
pageToSnapTo--;
}
+ boolean isHomeTaskDismissed = dismissedTaskView == getHomeTaskView();
removeViewInLayout(dismissedTaskView);
mTopRowIdSet.remove(dismissedTaskViewId);
if (taskCount == 1) {
removeViewInLayout(mClearAllButton);
- startHome();
+ if (isHomeTaskDismissed) {
+ updateEmptyMessage();
+ } else {
+ startHome();
+ }
} else {
// Update focus task and its size.
if (finalIsFocusedTaskDismissed) {
@@ -3177,14 +3170,24 @@
}
}
+ IntArray topRowIdArray = getTopRowIdArray();
+ IntArray bottomRowIdArray = getBottomRowIdArray();
if (finalSnapToLastTask) {
// If snapping to last task, find the last task after dismissal.
- pageToSnapTo = indexOfChild(getLastGridTaskView());
+ pageToSnapTo = indexOfChild(
+ getLastGridTaskView(topRowIdArray, bottomRowIdArray));
} else if (taskViewIdToSnapTo != -1) {
// If snapping to another page due to indices rearranging, find
// the new index after dismissal & rearrange using the task view id.
pageToSnapTo = indexOfChild(
getTaskViewFromTaskViewId(taskViewIdToSnapTo));
+ if (!currentPageSnapsToEndOfGrid) {
+ // If it wasn't snapped to one of the last pages, but is now
+ // snapped to last pages, we'll need to compensate for the
+ // offset from the page's scroll to its visual position.
+ mCurrentPageScrollDiff += getOffsetFromScrollPosition(
+ pageToSnapTo, topRowIdArray, bottomRowIdArray);
+ }
}
}
setCurrentPage(pageToSnapTo);
@@ -3811,7 +3814,8 @@
* if RecentsView is in portrait or RecentsView isn't shown as grid.
*/
private boolean isSplitPlaceholderFirstInGrid() {
- if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()) {
+ if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()
+ || !isSplitSelectionActive()) {
return false;
}
@StagePosition int position = mSplitSelectStateController.getActiveSplitStagePosition();
@@ -3825,7 +3829,8 @@
* RecentsView is in portrait or RecentsView isn't shown as grid.
*/
private boolean isSplitPlaceholderLastInGrid() {
- if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()) {
+ if (!mActivity.getDeviceProfile().isLandscape || !showAsGrid()
+ || !isSplitSelectionActive()) {
return false;
}
@StagePosition int position = mSplitSelectStateController.getActiveSplitStagePosition();
@@ -4236,6 +4241,10 @@
}
mPendingAnimation.addEndListener(isSuccess -> {
if (isSuccess) {
+ if (tv.getTaskIds()[1] != -1) {
+ TaskViewUtils.setSplitAuxiliarySurfacesShown(mRemoteTargetHandles[0]
+ .getTransformParams().getTargetSet().nonApps, true);
+ }
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && tv.isRunningTask()) {
finishRecentsAnimation(false /* toRecents */, null);
onTaskLaunchAnimationEnd(true /* success */);
@@ -4339,6 +4348,7 @@
public void setRecentsAnimationTargets(RecentsAnimationController recentsAnimationController,
RecentsAnimationTargets recentsAnimationTargets) {
mRecentsAnimationController = recentsAnimationController;
+ mSplitSelectStateController.setRecentsAnimationRunning(true);
if (recentsAnimationTargets == null || recentsAnimationTargets.apps.length == 0) {
return;
}
@@ -4373,7 +4383,7 @@
}
/** Helper to avoid writing some for-loops to iterate over {@link #mRemoteTargetHandles} */
- private void runActionOnRemoteHandles(Consumer<RemoteTargetHandle> consumer) {
+ public void runActionOnRemoteHandles(Consumer<RemoteTargetHandle> consumer) {
if (mRemoteTargetHandles == null) {
return;
}
@@ -4383,14 +4393,17 @@
}
}
- public void finishRecentsAnimation(boolean toRecents, Runnable onFinishComplete) {
+ /**
+ * Finish recents animation.
+ */
+ public void finishRecentsAnimation(boolean toRecents, @Nullable Runnable onFinishComplete) {
finishRecentsAnimation(toRecents, true /* shouldPip */, onFinishComplete);
}
public void finishRecentsAnimation(boolean toRecents, boolean shouldPip,
- Runnable onFinishComplete) {
+ @Nullable Runnable onFinishComplete) {
// TODO(b/197232424#comment#10) Move this back into onRecentsAnimationComplete(). Maybe?
- mRemoteTargetHandles = null;
+ cleanupRemoteTargets();
if (!toRecents && ENABLE_QUICKSTEP_LIVE_TILE.get()) {
// Reset the minimized state since we force-toggled the minimized state when entering
// overview, but never actually finished the recents animation. This is a catch all for
@@ -4437,6 +4450,7 @@
// taps on QSB (3) user goes back to Overview and launch the most recent task.
setCurrentTask(-1);
mRecentsAnimationController = null;
+ mSplitSelectStateController.setRecentsAnimationRunning(false);
executeSideTaskLaunchCallback();
}
@@ -4611,21 +4625,58 @@
overScrollShift, getUndampedOverScrollShift());
}
return getScrollForPage(pageIndex) - mOrientationHandler.getPrimaryScroll(this)
- + overScrollShift;
+ + overScrollShift + getOffsetFromScrollPosition(pageIndex);
}
/**
- * Returns how many pixels the task is offset on the currently laid out secondary axis
- * according to {@link #mGridProgress}.
+ * Returns how many pixels the page is offset from its scroll position.
*/
- public float getGridTranslationSecondary(int pageIndex) {
+ private int getOffsetFromScrollPosition(int pageIndex) {
+ return getOffsetFromScrollPosition(pageIndex, getTopRowIdArray(), getBottomRowIdArray());
+ }
+
+ private int getOffsetFromScrollPosition(
+ int pageIndex, IntArray topRowIdArray, IntArray bottomRowIdArray) {
+ if (!showAsGrid()) {
+ return 0;
+ }
+
TaskView taskView = getTaskViewAt(pageIndex);
if (taskView == null) {
return 0;
}
- return mOrientationHandler.getSecondaryValue(taskView.getGridTranslationX(),
- taskView.getGridTranslationY());
+ TaskView lastGridTaskView = getLastGridTaskView(topRowIdArray, bottomRowIdArray);
+ if (lastGridTaskView == null) {
+ return 0;
+ }
+
+ if (getScrollForPage(pageIndex) != getScrollForPage(indexOfChild(lastGridTaskView))) {
+ return 0;
+ }
+
+ // Check distance from lastGridTaskView to taskView.
+ int lastGridTaskViewPosition =
+ getPositionInRow(lastGridTaskView, topRowIdArray, bottomRowIdArray);
+ int taskViewPosition = getPositionInRow(taskView, topRowIdArray, bottomRowIdArray);
+ int gridTaskSizeAndSpacing = mLastComputedGridTaskSize.width() + mPageSpacing;
+ int positionDiff = gridTaskSizeAndSpacing * (lastGridTaskViewPosition - taskViewPosition);
+
+ int lastTaskEnd = (mIsRtl
+ ? mLastComputedGridSize.left
+ : mLastComputedGridSize.right)
+ + (mIsRtl ? mPageSpacing : -mPageSpacing);
+ int taskEnd = lastTaskEnd + (mIsRtl ? positionDiff : -positionDiff);
+ int normalTaskEnd = mIsRtl
+ ? mLastComputedGridTaskSize.left
+ : mLastComputedGridTaskSize.right;
+ return taskEnd - normalTaskEnd;
+ }
+
+ private int getPositionInRow(
+ TaskView taskView, IntArray topRowIdArray, IntArray bottomRowIdArray) {
+ int position = topRowIdArray.indexOf(taskView.getTaskViewId());
+ return position != -1 ? position : bottomRowIdArray.indexOf(taskView.getTaskViewId());
}
public Consumer<MotionEvent> getEventDispatcher(float navbarRotation) {
@@ -4738,15 +4789,12 @@
* from gesture state, which is a larger change of it having to keep track of multiple tasks.
* OR. Maybe it doesn't need to pass in a thumbnail and we can use the exact same flow as above
*/
- public void switchToScreenshot(ThumbnailData thumbnailData, Runnable onFinishRunnable) {
- TaskView taskView = getRunningTaskView();
+ public void switchToScreenshot(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas,
+ Runnable onFinishRunnable) {
+ final TaskView taskView = getRunningTaskView();
if (taskView != null) {
taskView.setShowScreenshot(true);
- if (thumbnailData != null) {
- taskView.getThumbnail().setThumbnail(taskView.getTask(), thumbnailData);
- } else {
- taskView.getThumbnail().refresh();
- }
+ taskView.refreshThumbnails(thumbnailDatas);
ViewUtils.postFrameDrawn(taskView, onFinishRunnable);
} else {
onFinishRunnable.run();
@@ -4849,6 +4897,10 @@
&& mCurrentGestureEndTarget != GestureState.GestureEndTarget.RECENTS;
}
+ public void cleanupRemoteTargets() {
+ mRemoteTargetHandles = null;
+ }
+
/**
* Used to register callbacks for when our empty message state changes.
*
@@ -4898,10 +4950,13 @@
private static class PinnedStackAnimationListener<T extends BaseActivity> extends
IPipAnimationListener.Stub {
+ @Nullable
private T mActivity;
+ @Nullable
private RecentsView mRecentsView;
- public void setActivityAndRecentsView(T activity, RecentsView recentsView) {
+ public void setActivityAndRecentsView(@Nullable T activity,
+ @Nullable RecentsView recentsView) {
mActivity = activity;
mRecentsView = recentsView;
}
diff --git a/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java b/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
index 845e13e..04a5761 100644
--- a/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitPlaceholderView.java
@@ -40,6 +40,7 @@
}
};
+ @Nullable
private IconView mIconView;
public SplitPlaceholderView(Context context, AttributeSet attrs) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 5c73fbb..853a023 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -16,6 +16,7 @@
package com.android.quickstep.views;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA;
@@ -33,12 +34,13 @@
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
import android.view.ViewTreeObserver.OnScrollChangedListener;
import android.widget.LinearLayout;
import android.widget.TextView;
+import androidx.annotation.Nullable;
+
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.DeviceProfile;
@@ -67,6 +69,7 @@
private BaseDraggingActivity mActivity;
private TextView mTaskName;
+ @Nullable
private AnimatorSet mOpenCloseAnimator;
private TaskView mTaskView;
private TaskIdAttributeContainer mTaskContainer;
@@ -242,7 +245,17 @@
LayoutParams lp = (LayoutParams) menuOptionView.getLayoutParams();
mTaskView.getPagedOrientationHandler().setLayoutParamsForTaskMenuOptionItem(lp,
menuOptionView, mActivity.getDeviceProfile());
- menuOptionView.setOnClickListener(menuOption::onClick);
+ menuOptionView.setOnClickListener(view -> {
+ if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
+ RecentsView recentsView = mTaskView.getRecentsView();
+ recentsView.switchToScreenshot(null,
+ () -> recentsView.finishRecentsAnimation(true /* toRecents */,
+ false /* shouldPip */,
+ () -> menuOption.onClick(view)));
+ } else {
+ menuOption.onClick(view);
+ }
+ });
mOptionLayout.addView(menuOptionView);
}
@@ -259,15 +272,9 @@
BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams();
int padding = getResources()
.getDimensionPixelSize(R.dimen.task_menu_vertical_padding);
- if (deviceProfile.overviewShowAsGrid) {
- // TODO(b/193432925) temporary so it doesn't look terrible on large screen
- params.width =
- getContext().getResources().getDimensionPixelSize(R.dimen.task_menu_width_grid);
- } else {
- params.width = orientationHandler
- .getTaskMenuWidth(taskContainer.getThumbnailView(),
- deviceProfile) - (2 * padding);
- }
+ params.width = orientationHandler
+ .getTaskMenuWidth(taskContainer.getThumbnailView(),
+ deviceProfile) - (2 * padding);
// Gravity set to Left instead of Start as sTempRect.left measures Left distance not Start
params.gravity = Gravity.LEFT;
setLayoutParams(params);
@@ -338,13 +345,4 @@
return new RoundedRectRevealOutlineProvider(radius, radius, fromRect, toRect);
}
- public View findMenuItemByText(String text) {
- for (int i = mOptionLayout.getChildCount() - 1; i >= 0; --i) {
- final ViewGroup menuOptionView = (ViewGroup) mOptionLayout.getChildAt(i);
- if (text.equals(menuOptionView.<TextView>findViewById(R.id.text).getText())) {
- return menuOptionView;
- }
- }
- return null;
- }
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
new file mode 100644
index 0000000..5059f8b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.views
+
+import android.animation.AnimatorSet
+import android.animation.ObjectAnimator
+import android.content.Context
+import android.graphics.Rect
+import android.graphics.drawable.ShapeDrawable
+import android.graphics.drawable.shapes.RectShape
+import android.util.AttributeSet
+import android.view.MotionEvent
+import android.view.View
+import android.view.ViewGroup
+import android.widget.LinearLayout
+import com.android.launcher3.BaseDraggingActivity
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.R
+import com.android.launcher3.popup.ArrowPopup
+import com.android.launcher3.popup.SystemShortcut
+import com.android.launcher3.util.Themes
+import com.android.quickstep.KtR
+import com.android.quickstep.TaskOverlayFactory
+import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
+
+class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
+ companion object {
+ const val TAG = "TaskMenuViewWithArrow"
+
+ fun showForTask(taskContainer: TaskIdAttributeContainer): Boolean {
+ val activity = BaseDraggingActivity
+ .fromContext<BaseDraggingActivity>(taskContainer.taskView.context)
+ val taskMenuViewWithArrow = activity.layoutInflater
+ .inflate(KtR.layout.task_menu_with_arrow, activity.dragLayer, false) as TaskMenuViewWithArrow<*>
+
+ return taskMenuViewWithArrow.populateAndShowForTask(taskContainer)
+ }
+ }
+
+ constructor(context: Context) : super(context)
+ constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
+ constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
+
+ init {
+ clipToOutline = true
+ }
+
+ private val menuWidth = context.resources.getDimensionPixelSize(R.dimen.task_menu_width_grid)
+
+ private lateinit var taskView: TaskView
+ private lateinit var optionLayout: LinearLayout
+ private lateinit var taskContainer: TaskIdAttributeContainer
+
+ override fun isOfType(type: Int): Boolean = type and TYPE_TASK_MENU != 0
+
+ override fun getTargetObjectLocation(outPos: Rect?) {
+ popupContainer.getDescendantRectRelativeToSelf(taskView.iconView, outPos)
+ }
+
+ override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean {
+ if (ev?.action == MotionEvent.ACTION_DOWN) {
+ if (!popupContainer.isEventOverView(this, ev)) {
+ close(true)
+ return true
+ }
+ }
+ return false
+ }
+
+ override fun onFinishInflate() {
+ super.onFinishInflate()
+ optionLayout = findViewById(KtR.id.menu_option_layout)
+ }
+
+ private fun populateAndShowForTask(taskContainer: TaskIdAttributeContainer): Boolean {
+ if (isAttachedToWindow) {
+ return false
+ }
+
+ taskView = taskContainer.taskView
+ this.taskContainer = taskContainer
+ if (!populateMenu()) return false
+ show()
+ return true
+ }
+
+ /** @return true if successfully able to populate task view menu, false otherwise
+ */
+ private fun populateMenu(): Boolean {
+ // Icon may not be loaded
+ if (taskContainer.task.icon == null) return false
+
+ addMenuOptions()
+ return true
+ }
+
+ private fun addMenuOptions() {
+ // Add the options
+ TaskOverlayFactory
+ .getEnabledShortcuts(taskView, mActivityContext.deviceProfile, taskContainer)
+ .forEach { this.addMenuOption(it) }
+
+ // Add the spaces between items
+ val divider = ShapeDrawable(RectShape())
+ divider.paint.color = resources.getColor(android.R.color.transparent)
+ val dividerSpacing = resources.getDimension(KtR.dimen.task_menu_spacing).toInt()
+ optionLayout.showDividers = SHOW_DIVIDER_MIDDLE
+
+ // Set the orientation, which makes the menu show
+ val recentsView: RecentsView<*, *> = mActivityContext.getOverviewPanel()
+ val orientationHandler = recentsView.pagedOrientationHandler
+ val deviceProfile: DeviceProfile = mActivityContext.deviceProfile
+ orientationHandler.setTaskOptionsMenuLayoutOrientation(
+ deviceProfile,
+ optionLayout,
+ dividerSpacing,
+ divider
+ )
+ }
+
+ private fun addMenuOption(menuOption: SystemShortcut<*>) {
+ val menuOptionView = mActivityContext.layoutInflater.inflate(
+ KtR.layout.task_view_menu_option, this, false
+ ) as LinearLayout
+ menuOption.setIconAndLabelFor(
+ menuOptionView.findViewById(R.id.icon),
+ menuOptionView.findViewById(R.id.text)
+ )
+ val lp = menuOptionView.layoutParams as LayoutParams
+ lp.width = menuWidth
+ menuOptionView.setOnClickListener { view: View? -> menuOption.onClick(view) }
+ optionLayout.addView(menuOptionView)
+ }
+
+ override fun assignMarginsAndBackgrounds(viewGroup: ViewGroup) {
+ assignMarginsAndBackgrounds(this, Themes.getAttrColor(context, com.android.internal.R.attr.colorSurface))
+ }
+
+ override fun onCreateOpenAnimation(anim: AnimatorSet) {
+ anim.play(
+ ObjectAnimator.ofFloat(
+ taskContainer.thumbnailView, TaskThumbnailView.DIM_ALPHA,
+ TaskView.MAX_PAGE_SCRIM_ALPHA
+ )
+ )
+ }
+
+ override fun onCreateCloseAnimation(anim: AnimatorSet) {
+ anim.play(
+ ObjectAnimator.ofFloat(taskContainer.thumbnailView, TaskThumbnailView.DIM_ALPHA, 0f)
+ )
+ }
+}
\ No newline at end of file
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index a9db400..f8368ae 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -31,6 +31,8 @@
import android.graphics.Insets;
import android.graphics.Matrix;
import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Shader;
@@ -41,6 +43,7 @@
import android.view.Surface;
import android.view.View;
+import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.graphics.ColorUtils;
@@ -75,9 +78,11 @@
};
private final BaseActivity mActivity;
+ @Nullable
private TaskOverlay mOverlay;
private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
private final Paint mBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ private final Paint mClearPaint = new Paint();
private final Paint mDimmingPaintAfterClearing = new Paint();
private final int mDimColor;
@@ -86,8 +91,11 @@
private final PreviewPositionHelper mPreviewPositionHelper = new PreviewPositionHelper();
private TaskView.FullscreenDrawParams mFullscreenParams;
+ @Nullable
private Task mTask;
+ @Nullable
private ThumbnailData mThumbnailData;
+ @Nullable
protected BitmapShader mBitmapShader;
/** How much this thumbnail is dimmed, 0 not dimmed at all, 1 totally dimmed. */
@@ -99,14 +107,15 @@
this(context, null);
}
- public TaskThumbnailView(Context context, AttributeSet attrs) {
+ public TaskThumbnailView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public TaskThumbnailView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint.setFilterBitmap(true);
mBackgroundPaint.setColor(Color.WHITE);
+ mClearPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
mActivity = BaseActivity.fromContext(context);
// Initialize with placeholder value. It is overridden later by TaskView
mFullscreenParams = TEMP_PARAMS.get(context);
@@ -136,7 +145,8 @@
* upon swipe up so that a usable screenshot is accessible immediately when
* recents animation needs to be finished / cancelled.
*/
- public void setThumbnail(Task task, ThumbnailData thumbnailData, boolean refreshNow) {
+ public void setThumbnail(@Nullable Task task, @Nullable ThumbnailData thumbnailData,
+ boolean refreshNow) {
mTask = task;
mThumbnailData =
(thumbnailData != null && thumbnailData.thumbnail != null) ? thumbnailData : null;
@@ -146,7 +156,7 @@
}
/** See {@link #setThumbnail(Task, ThumbnailData, boolean)} */
- public void setThumbnail(Task task, ThumbnailData thumbnailData) {
+ public void setThumbnail(@Nullable Task task, @Nullable ThumbnailData thumbnailData) {
setThumbnail(task, thumbnailData, true /* refreshNow */);
}
@@ -271,6 +281,7 @@
float cornerRadius) {
if (ENABLE_QUICKSTEP_LIVE_TILE.get()) {
if (mTask != null && getTaskView().isRunningTask() && !getTaskView().showScreenshot()) {
+ canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius, mClearPaint);
canvas.drawRoundRect(x, y, width, height, cornerRadius, cornerRadius,
mDimmingPaintAfterClearing);
return;
@@ -360,6 +371,10 @@
return Utilities.makeColorTintingColorFilter(mDimColor, dimAmount);
}
+ /**
+ * Returns current thumbnail or null if none is set.
+ */
+ @Nullable
public Bitmap getThumbnail() {
if (mThumbnailData == null) {
return null;
@@ -444,15 +459,36 @@
float availableHeight = surfaceHeight
- (thumbnailClipHint.top + thumbnailClipHint.bottom);
- if (isRotated) {
- float canvasAspect = canvasWidth / (float) canvasHeight;
- float availableAspect = availableHeight / availableWidth;
+ float canvasAspect = canvasWidth / (float) canvasHeight;
+ float availableAspect = isRotated
+ ? availableHeight / availableWidth
+ : availableWidth / availableHeight;
+ boolean isAspectLargelyDifferent = Utilities.isRelativePercentDifferenceGreaterThan(
+ canvasAspect, availableAspect, 0.1f);
+ if (isRotated && isAspectLargelyDifferent) {
// Do not rotate thumbnail if it would not improve fit
- if (Utilities.isRelativePercentDifferenceGreaterThan(canvasAspect,
- availableAspect, 0.1f)) {
- isRotated = false;
- isOrientationDifferent = false;
+ isRotated = false;
+ isOrientationDifferent = false;
+ }
+
+ if (isAspectLargelyDifferent) {
+ // Crop letterbox insets if insets isn't already clipped
+ if (!TaskView.clipLeft(dp)) {
+ thumbnailClipHint.left = thumbnailData.letterboxInsets.left;
}
+ if (!TaskView.clipRight(dp)) {
+ thumbnailClipHint.right = thumbnailData.letterboxInsets.right;
+ }
+ if (!TaskView.clipTop(dp)) {
+ thumbnailClipHint.top = thumbnailData.letterboxInsets.top;
+ }
+ if (!TaskView.clipBottom(dp)) {
+ thumbnailClipHint.bottom = thumbnailData.letterboxInsets.bottom;
+ }
+ availableWidth = surfaceWidth
+ - (thumbnailClipHint.left + thumbnailClipHint.right);
+ availableHeight = surfaceHeight
+ - (thumbnailClipHint.top + thumbnailClipHint.bottom);
}
final float targetW, targetH;
@@ -463,30 +499,25 @@
targetW = canvasWidth;
targetH = canvasHeight;
}
- float canvasAspect = targetW / targetH;
+ float targetAspect = targetW / targetH;
// Update the clipHint such that
// > the final clipped position has same aspect ratio as requested by canvas
- // > the clipped region is within the task insets if possible
- // > the clipped region is not scaled up when drawing. If that is not possible
- // while staying within the taskInsets, move outside the insets.
+ // > first fit the width and crop the extra height
+ // > if that will leave empty space, fit the height and crop the width instead
float croppedWidth = availableWidth;
- if (croppedWidth < targetW) {
- croppedWidth = Math.min(targetW, surfaceWidth);
- }
-
- float croppedHeight = croppedWidth / canvasAspect;
+ float croppedHeight = croppedWidth / targetAspect;
if (croppedHeight > availableHeight) {
croppedHeight = availableHeight;
if (croppedHeight < targetH) {
croppedHeight = Math.min(targetH, surfaceHeight);
}
- croppedWidth = croppedHeight * canvasAspect;
+ croppedWidth = croppedHeight * targetAspect;
// One last check in case the task aspect radio messed up something
if (croppedWidth > surfaceWidth) {
croppedWidth = surfaceWidth;
- croppedHeight = croppedWidth / canvasAspect;
+ croppedHeight = croppedWidth / targetAspect;
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 8d77e44..e9a3779 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -61,6 +61,7 @@
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
@@ -91,12 +92,12 @@
import com.android.quickstep.TaskUtils;
import com.android.quickstep.TaskViewUtils;
import com.android.quickstep.util.CancellableTask;
-import com.android.quickstep.util.LauncherSplitScreenListener;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.quickstep.util.TaskCornerRadius;
import com.android.quickstep.util.TransformParams;
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
import com.android.systemui.shared.recents.model.Task;
+import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.QuickStepContract;
@@ -105,6 +106,7 @@
import java.lang.annotation.Retention;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Stream;
@@ -115,6 +117,7 @@
public class TaskView extends FrameLayout implements Reusable {
private static final String TAG = TaskView.class.getSimpleName();
+ private static final boolean DEBUG = false;
public static final int FLAG_UPDATE_ICON = 1;
public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1;
@@ -357,6 +360,7 @@
private final TaskOutlineProvider mOutlineProvider;
+ @Nullable
protected Task mTask;
protected TaskThumbnailView mSnapshotView;
protected IconView mIconView;
@@ -365,7 +369,7 @@
private float mGridProgress;
private float mNonGridScale = 1;
private float mDismissScale = 1;
- private final FullscreenDrawParams mCurrentFullscreenParams;
+ protected final FullscreenDrawParams mCurrentFullscreenParams;
protected final StatefulActivity mActivity;
// Various causes of changing primary translation, which we aggregate to setTranslationX/Y().
@@ -391,6 +395,7 @@
private float mSplitSelectTranslationX;
private float mSplitSelectScrollOffsetPrimary;
+ @Nullable
private ObjectAnimator mIconAndDimAnimator;
private float mIconScaleAnimStartProgress = 0;
private float mFocusTransitionProgress = 1;
@@ -408,7 +413,9 @@
private boolean mShowScreenshot;
// The current background requests to load the task thumbnail and icon
+ @Nullable
private CancellableTask mThumbnailLoadRequest;
+ @Nullable
private CancellableTask mIconLoadRequest;
private boolean mEndQuickswitchCuj;
@@ -421,11 +428,11 @@
this(context, null);
}
- public TaskView(Context context, AttributeSet attrs) {
+ public TaskView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
- public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
+ public TaskView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mActivity = StatefulActivity.fromContext(context);
setOnClickListener(this::onClick);
@@ -541,6 +548,7 @@
return mTaskIdAttributeContainer;
}
+ @Nullable
public Task getTask() {
return mTask;
}
@@ -553,10 +561,26 @@
return mTaskIdContainer;
}
+ public boolean containsMultipleTasks() {
+ return mTaskIdContainer[1] != -1;
+ }
+
public TaskThumbnailView getThumbnail() {
return mSnapshotView;
}
+ void refreshThumbnails(@Nullable HashMap<Integer, ThumbnailData> thumbnailDatas) {
+ if (mTask != null && thumbnailDatas != null) {
+ final ThumbnailData thumbnailData = thumbnailDatas.get(mTask.key.id);
+ if (thumbnailData != null) {
+ mSnapshotView.setThumbnail(mTask, thumbnailData);
+ return;
+ }
+ }
+
+ mSnapshotView.refresh();
+ }
+
/** TODO(b/197033698) Remove all usages of above method and migrate to this one */
public TaskThumbnailView[] getThumbnails() {
return new TaskThumbnailView[]{mSnapshotView};
@@ -653,19 +677,15 @@
* Starts the task associated with this view and animates the startup.
* @return CompletionStage to indicate the animation completion or null if the launch failed.
*/
+ @Nullable
public RunnableList launchTaskAnimated() {
if (mTask != null) {
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
ActivityOptionsWrapper opts = mActivity.getActivityLaunchOptions(this, null);
opts.options.setLaunchDisplayId(getRootViewDisplayId());
- boolean isOldTaskSplit = LauncherSplitScreenListener.INSTANCE.getNoCreate()
- .getPersistentSplitIds().length > 0;
if (ActivityManagerWrapper.getInstance()
.startActivityFromRecents(mTask.key, opts.options)) {
- if (isOldTaskSplit) {
- SystemUiProxy.INSTANCE.getNoCreate().exitSplitScreen(mTask.key.id);
- }
RecentsView recentsView = getRecentsView();
if (ENABLE_QUICKSTEP_LIVE_TILE.get() && recentsView.getRunningTaskViewId() != -1) {
recentsView.onTaskLaunchedInLiveTileMode();
@@ -808,10 +828,14 @@
}
protected boolean showTaskMenuWithContainer(IconView iconView) {
- return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]);
+ if (mActivity.getDeviceProfile().overviewShowAsGrid) {
+ return TaskMenuViewWithArrow.Companion.showForTask(mTaskIdAttributeContainer[0]);
+ } else {
+ return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]);
+ }
}
- protected void setIcon(IconView iconView, Drawable icon) {
+ protected void setIcon(IconView iconView, @Nullable Drawable icon) {
if (icon != null) {
iconView.setDrawable(icon);
iconView.setOnClickListener(v -> {
@@ -845,7 +869,7 @@
LayoutParams snapshotParams = (LayoutParams) mSnapshotView.getLayoutParams();
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
snapshotParams.topMargin = deviceProfile.overviewTaskThumbnailTopMarginPx;
- boolean isGridTask = deviceProfile.overviewShowAsGrid && !isFocusedTask();
+ boolean isGridTask = isGridTask();
int taskIconHeight = deviceProfile.overviewTaskIconSizePx;
int taskMargin = isGridTask ? deviceProfile.overviewTaskMarginGridPx
: deviceProfile.overviewTaskMarginPx;
@@ -865,6 +889,14 @@
mSnapshotView.getTaskOverlay().updateOrientationState(orientationState);
}
+ /**
+ * Returns whether the task is part of overview grid and not being focused.
+ */
+ public boolean isGridTask() {
+ DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+ return deviceProfile.overviewShowAsGrid && !isFocusedTask();
+ }
+
private void setIconAndDimTransitionProgress(float progress, boolean invert) {
if (invert) {
progress = 1 - progress;
@@ -1341,7 +1373,7 @@
invalidateOutline();
}
- void updateSnapshotRadius() {
+ protected void updateSnapshotRadius() {
updateCurrentFullscreenParams(mSnapshotView.getPreviewPositionHelper());
mSnapshotView.setFullscreenParams(mCurrentFullscreenParams);
}
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationBarRotationContextTest.java b/quickstep/tests/src/com/android/quickstep/NavigationBarRotationContextTest.java
index af5819a..de6740d 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationBarRotationContextTest.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationBarRotationContextTest.java
@@ -31,8 +31,8 @@
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.launcher3.taskbar.contextual.RotationButton;
-import com.android.launcher3.taskbar.contextual.RotationButtonController;
+import com.android.systemui.shared.rotation.RotationButton;
+import com.android.systemui.shared.rotation.RotationButtonController;
import org.junit.Before;
import org.junit.Test;
@@ -55,8 +55,9 @@
Context mTargetContext = InstrumentationRegistry.getTargetContext();
final View view = new View(mTargetContext);
RotationButton rotationButton = mock(RotationButton.class);
- mRotationButtonController = new RotationButtonController(mTargetContext, 0, 0);
- mRotationButtonController.setRotationButton(rotationButton);
+ mRotationButtonController = new RotationButtonController(mTargetContext, 0, 0, 0, 0, 0, 0,
+ () -> 0);
+ mRotationButtonController.setRotationButton(rotationButton, null);
// Due to a mockito issue, only spy the object after setting the initial state
mRotationButtonController = spy(mRotationButtonController);
final AnimatedVectorDrawable kbd = mock(AnimatedVectorDrawable.class);
@@ -85,7 +86,7 @@
// No navigation bar should not call to set visibility state
mRotationButtonController.onBehaviorChanged(DEFAULT_DISPLAY,
WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE);
- mRotationButtonController.onTaskBarVisibilityChange(false /* showing */);
+ mRotationButtonController.onNavigationBarWindowVisibilityChange(false /* showing */);
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
false /* visible */);
verify(mRotationButtonController, times(0)).setRotateSuggestionButtonState(
@@ -100,7 +101,7 @@
true /* visible */);
// Since rotation has changed rotation should be pending, show mButton when showing nav bar
- mRotationButtonController.onTaskBarVisibilityChange(true /* showing */);
+ mRotationButtonController.onNavigationBarWindowVisibilityChange(true /* showing */);
verify(mRotationButtonController, times(1)).setRotateSuggestionButtonState(
true /* visible */);
}
@@ -108,7 +109,7 @@
@Test
public void testOnRotationProposalShowButton() {
// Navigation bar being visible should not call to set visibility state
- mRotationButtonController.onTaskBarVisibilityChange(true /* showing */);
+ mRotationButtonController.onNavigationBarWindowVisibilityChange(true /* showing */);
verify(mRotationButtonController, times(0))
.setRotateSuggestionButtonState(false /* visible */);
verify(mRotationButtonController, times(0))
diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
index 79ddf7a..4e49716 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
+++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
@@ -30,70 +30,76 @@
import androidx.test.filters.SmallTest;
import com.android.launcher3.util.LooperExecutor;
-import com.android.systemui.shared.recents.model.Task;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.quickstep.util.GroupTask;
import com.android.systemui.shared.system.KeyguardManagerCompat;
+import com.android.wm.shell.util.GroupedRecentTaskInfo;
import org.junit.Before;
import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@SmallTest
public class RecentTasksListTest {
- private ActivityManagerWrapper mockActivityManagerWrapper;
+ @Mock
+ private SystemUiProxy mockSystemUiProxy;
// Class under test
private RecentTasksList mRecentTasksList;
@Before
public void setup() {
+ MockitoAnnotations.initMocks(this);
LooperExecutor mockMainThreadExecutor = mock(LooperExecutor.class);
KeyguardManagerCompat mockKeyguardManagerCompat = mock(KeyguardManagerCompat.class);
- mockActivityManagerWrapper = mock(ActivityManagerWrapper.class);
mRecentTasksList = new RecentTasksList(mockMainThreadExecutor, mockKeyguardManagerCompat,
- mockActivityManagerWrapper);
+ mockSystemUiProxy);
}
@Test
- public void onTaskRemoved_doesNotFetchTasks() {
- mRecentTasksList.onTaskRemoved(0);
- verify(mockActivityManagerWrapper, times(0))
- .getRecentTasks(anyInt(), anyInt());
- }
-
- @Test
- public void onTaskStackChanged_doesNotFetchTasks() {
- mRecentTasksList.onTaskStackChanged();
- verify(mockActivityManagerWrapper, times(0))
+ public void onRecentTasksChanged_doesNotFetchTasks() {
+ mRecentTasksList.onRecentTasksChanged();
+ verify(mockSystemUiProxy, times(0))
.getRecentTasks(anyInt(), anyInt());
}
@Test
public void loadTasksInBackground_onlyKeys_noValidTaskDescription() {
- ActivityManager.RecentTaskInfo recentTaskInfo = new ActivityManager.RecentTaskInfo();
- when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt()))
- .thenReturn(Collections.singletonList(recentTaskInfo));
+ GroupedRecentTaskInfo recentTaskInfos = new GroupedRecentTaskInfo(
+ new ActivityManager.RecentTaskInfo(), new ActivityManager.RecentTaskInfo(), null);
+ when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
+ .thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
- List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1, true);
+ List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1,
+ true);
assertEquals(1, taskList.size());
- assertNull(taskList.get(0).taskDescription.getLabel());
+ assertNull(taskList.get(0).task1.taskDescription.getLabel());
+ assertNull(taskList.get(0).task2.taskDescription.getLabel());
}
@Test
public void loadTasksInBackground_moreThanKeys_hasValidTaskDescription() {
String taskDescription = "Wheeee!";
- ActivityManager.RecentTaskInfo recentTaskInfo = new ActivityManager.RecentTaskInfo();
- recentTaskInfo.taskDescription = new ActivityManager.TaskDescription(taskDescription);
- when(mockActivityManagerWrapper.getRecentTasks(anyInt(), anyInt()))
- .thenReturn(Collections.singletonList(recentTaskInfo));
+ ActivityManager.RecentTaskInfo task1 = new ActivityManager.RecentTaskInfo();
+ task1.taskDescription = new ActivityManager.TaskDescription(taskDescription);
+ ActivityManager.RecentTaskInfo task2 = new ActivityManager.RecentTaskInfo();
+ task2.taskDescription = new ActivityManager.TaskDescription();
+ GroupedRecentTaskInfo recentTaskInfos = new GroupedRecentTaskInfo(
+ task1, task2, null);
+ when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
+ .thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
- List<Task> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1, false);
+ List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1,
+ false);
assertEquals(1, taskList.size());
- assertEquals(taskDescription, taskList.get(0).taskDescription.getLabel());
+ assertEquals(taskDescription, taskList.get(0).task1.taskDescription.getLabel());
+ assertNull(taskList.get(0).task2.taskDescription.getLabel());
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 4895b10..93be6fb 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -31,6 +31,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.tapl.AllApps;
import com.android.launcher3.tapl.Background;
import com.android.launcher3.tapl.LauncherInstrumentation.NavigationModel;
import com.android.launcher3.tapl.Overview;
@@ -43,12 +44,16 @@
import org.junit.After;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class TaplTestsQuickstep extends AbstractQuickStepTest {
+
+ private static final String APP_NAME = "LauncherTestApp";
+
@Before
public void setUp() throws Exception {
super.setUp();
@@ -266,7 +271,9 @@
background.quickSwitchToPreviousAppSwipeLeft();
assertTrue("The 2nd app we should have quick switched to is not running",
isTestActivityRunning(3));
- getAndAssertBackground();
+
+ background = getAndAssertBackground();
+ background.switchToOverview();
}
private boolean isTestActivityRunning(int activityNumber) {
@@ -286,6 +293,31 @@
getAndAssertBackground();
}
+ // TODO(b/204830798): test with all navigation modes(add @NavigationModeSwitch annotation)
+ // after the bug resolved.
+ @Ignore("b/205027405")
+ @Test
+ @PortraitLandscape
+ @ScreenRecord
+ public void testPressBack() throws Exception {
+ mLauncher.getWorkspace().switchToAllApps();
+ mLauncher.pressBack();
+ mLauncher.getWorkspace();
+ waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
+
+ AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ allApps.freeze();
+ try {
+ allApps.getAppIcon(APP_NAME).dragToWorkspace(false, false);
+ } finally {
+ allApps.unfreeze();
+ }
+ mLauncher.getWorkspace().getWorkspaceAppIcon(APP_NAME).launch(getAppPackageName());
+ mLauncher.pressBack();
+ mLauncher.getWorkspace();
+ waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
+ }
+
@Test
@PortraitLandscape
public void testOverviewForTablet() throws Exception {
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index a34baef..7f9f63e 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -43,15 +43,6 @@
<include layout="@layout/all_apps_personal_work_tabs" />
- <Button
- android:id="@+id/all_apps_button"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- android:text="@string/all_apps_label"
- android:background="@drawable/padded_rounded_action_button"
- android:visibility="gone"/>
-
</com.android.launcher3.allapps.FloatingHeaderView>
<include layout="@layout/search_container_all_apps" />
diff --git a/res/layout/all_apps_icon_twoline.xml b/res/layout/all_apps_icon_twoline.xml
new file mode 100644
index 0000000..54c7147
--- /dev/null
+++ b/res/layout/all_apps_icon_twoline.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2021 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<com.android.launcher3.BubbleTextView xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto"
+ style="@style/BaseIcon.AllApps"
+ android:id="@+id/icon"
+ android:singleLine="false"
+ android:lines="2"
+ android:inputType="textMultiLine"
+ launcher:iconDisplay="all_apps"
+ launcher:centerVertically="true" />
+
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 54da5f6..96d363a 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -57,8 +57,7 @@
<string name="all_apps_no_search_results" msgid="3200346862396363786">"<xliff:g id="QUERY">%1$s</xliff:g> sorğusuna uyğun tətbiq tapılmadı"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Daha çox tətbiq üçün axtarış edin"</string>
<string name="label_application" msgid="8531721983832654978">"Tətbiq"</string>
- <!-- no translation found for all_apps_label (5015784846527570951) -->
- <skip />
+ <string name="all_apps_label" msgid="5015784846527570951">"Bütün tətbiqlər"</string>
<string name="notifications_header" msgid="1404149926117359025">"Bildirişlər"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Qısayolu daşımaq üçün toxunub saxlayın."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Qısayolu daşımaq üçün iki dəfə toxunub saxlayın və ya fərdi əməliyyatlardan istifadə edin."</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 2cfa816..92be881 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -57,8 +57,7 @@
<string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" এর সাথে মেলে এমন কোনো অ্যাপ পাওয়া যায়নি"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"আরও অ্যাপ্লিকেশানের জন্য খুঁজুন"</string>
<string name="label_application" msgid="8531721983832654978">"অ্যাপ"</string>
- <!-- no translation found for all_apps_label (5015784846527570951) -->
- <skip />
+ <string name="all_apps_label" msgid="5015784846527570951">"সব অ্যাপ"</string>
<string name="notifications_header" msgid="1404149926117359025">"বিজ্ঞপ্তি"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"একটি শর্টকাট সরাতে টাচ করে ধরে রাখুন।"</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"একটি শর্টকাট সরাতে বা কাস্টম অ্যাকশন ব্যবহার করতে ডবল ট্যাপ করে ধরে রাখুন।"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 20e06e1..e884423 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -57,8 +57,7 @@
<string name="all_apps_no_search_results" msgid="3200346862396363786">"Keine Apps für \"<xliff:g id="QUERY">%1$s</xliff:g>\" gefunden"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Weitere Apps suchen"</string>
<string name="label_application" msgid="8531721983832654978">"App"</string>
- <!-- no translation found for all_apps_label (5015784846527570951) -->
- <skip />
+ <string name="all_apps_label" msgid="5015784846527570951">"Alle Apps"</string>
<string name="notifications_header" msgid="1404149926117359025">"Benachrichtigungen"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Zum Verschieben einer Verknüpfung berühren und halten"</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Doppeltippen und halten, um eine Verknüpfung zu bewegen oder benutzerdefinierte Aktionen zu nutzen."</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 3b85234..e9988c6 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -57,8 +57,7 @@
<string name="all_apps_no_search_results" msgid="3200346862396363786">"Aucune application trouvée correspondant à « <xliff:g id="QUERY">%1$s</xliff:g> »"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Rechercher plus d\'applications"</string>
<string name="label_application" msgid="8531721983832654978">"Application"</string>
- <!-- no translation found for all_apps_label (5015784846527570951) -->
- <skip />
+ <string name="all_apps_label" msgid="5015784846527570951">"Toutes les applications"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Maintenez le doigt sur un raccourci pour le déplacer."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Touchez deux fois un raccourci et maintenez le doigt dessus pour le déplacer ou utiliser des actions personnalisées."</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 46c017c..094af61 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -57,8 +57,7 @@
<string name="all_apps_no_search_results" msgid="3200346862396363786">"Non se atoparon aplicacións que coincidan con \"<xliff:g id="QUERY">%1$s</xliff:g>\""</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Buscar máis aplicacións"</string>
<string name="label_application" msgid="8531721983832654978">"Aplicación"</string>
- <!-- no translation found for all_apps_label (5015784846527570951) -->
- <skip />
+ <string name="all_apps_label" msgid="5015784846527570951">"Todas as aplicacións"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notificacións"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Mantén premido un atallo para movelo."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Toca dúas veces un atallo e manteno premido para movelo ou utiliza accións personalizadas."</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index ec8a708..de47dfb 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -57,8 +57,7 @@
<string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\"થી મેળ ખાતી કોઈ ઍપ્લિકેશનો મળી નથી"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"વધુ ઍપ્લિકેશનો શોધો"</string>
<string name="label_application" msgid="8531721983832654978">"ઍપ"</string>
- <!-- no translation found for all_apps_label (5015784846527570951) -->
- <skip />
+ <string name="all_apps_label" msgid="5015784846527570951">"બધી ઍપ"</string>
<string name="notifications_header" msgid="1404149926117359025">"નોટિફિકેશન"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"શૉર્ટકટ ખસેડવા ટચ કરીને થોડી વાર દબાવી રાખો."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"શૉર્ટકટ ખસેડવા બે વાર ટૅપ કરીને દબાવી રાખો અથવા કસ્ટમ ક્રિયાઓનો ઉપયોગ કરો."</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index e6a5aaf..f5c0410 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -57,8 +57,7 @@
<string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" сұрауына сәйкес келетін қолданбалар жоқ"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"Қосымша қолданбалар іздеу"</string>
<string name="label_application" msgid="8531721983832654978">"Қолданба"</string>
- <!-- no translation found for all_apps_label (5015784846527570951) -->
- <skip />
+ <string name="all_apps_label" msgid="5015784846527570951">"Барлық қолданба"</string>
<string name="notifications_header" msgid="1404149926117359025">"Хабарландырулар"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Таңбашаны жылжыту үшін басып тұрыңыз."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Таңбашаны жылжыту үшін екі рет түртіңіз де, ұстап тұрыңыз немесе арнаулы әрекеттерді пайдаланыңыз."</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index d28272b..fb2da8a 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -57,8 +57,7 @@
<string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ସହିତ ମେଳ ହେଉଥିବା କୌଣସି ଆପ୍ ମିଳିଲା ନାହିଁ"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"ଅଧିକ ଆପ୍ ଖୋଜନ୍ତୁ"</string>
<string name="label_application" msgid="8531721983832654978">"ଆପ୍"</string>
- <!-- no translation found for all_apps_label (5015784846527570951) -->
- <skip />
+ <string name="all_apps_label" msgid="5015784846527570951">"ସବୁ ଆପ"</string>
<string name="notifications_header" msgid="1404149926117359025">"ବିଜ୍ଞପ୍ତି"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"ଏକ ସର୍ଟକଟକୁ ମୁଭ୍ କରିବା ପାଇଁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ।"</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"ଏକ ସର୍ଟକଟକୁ ମୁଭ୍ କରିବା ପାଇଁ ଦୁଇଥର-ଟାପ୍ କରି ଧରି ରଖନ୍ତୁ କିମ୍ବା କଷ୍ଟମ୍ କାର୍ଯ୍ୟଗୁଡ଼ିକୁ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 7323c3f..994faf8 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -57,8 +57,7 @@
<string name="all_apps_no_search_results" msgid="3200346862396363786">"\"<xliff:g id="QUERY">%1$s</xliff:g>\" ਨਾਲ ਮੇਲ ਖਾਂਦੀਆਂ ਕੋਈ ਐਪਾਂ ਨਹੀਂ ਮਿਲੀਆਂ"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"ਹੋਰ ਐਪਾਂ ਖੋਜੋ"</string>
<string name="label_application" msgid="8531721983832654978">"ਐਪ"</string>
- <!-- no translation found for all_apps_label (5015784846527570951) -->
- <skip />
+ <string name="all_apps_label" msgid="5015784846527570951">"ਸਾਰੀਆਂ ਐਪਾਂ"</string>
<string name="notifications_header" msgid="1404149926117359025">"ਸੂਚਨਾਵਾਂ"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"ਕਿਸੇ ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਲਿਜਾਉਣ ਲਈ ਸਪੱਰਸ਼ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ।"</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"ਕਿਸੇ ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਲਿਜਾਉਣ ਲਈ ਡਬਲ ਟੈਪ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ ਜਾਂ ਵਿਉਂਤੀਆਂ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index bf0d9bc..735681e 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -67,7 +67,7 @@
<string name="all_apps_search_results" msgid="5889367432531296759">"Arama sonuçları"</string>
<string name="all_apps_button_personal_label" msgid="1315764287305224468">"Kişisel uygulamalar listesi"</string>
<string name="all_apps_button_work_label" msgid="7270707118948892488">"İş uygulamaları listesi"</string>
- <string name="remove_drop_target_label" msgid="7812859488053230776">"Kaldır"</string>
+ <string name="remove_drop_target_label" msgid="7812859488053230776">"Sil"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Kaldır"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Uygulama bilgileri"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Yükle"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 472ea46..4cc63ed 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -57,8 +57,7 @@
<string name="all_apps_no_search_results" msgid="3200346862396363786">"找不到與「<xliff:g id="QUERY">%1$s</xliff:g>」相符的應用程式"</string>
<string name="all_apps_search_market_message" msgid="1366263386197059176">"搜尋更多應用程式"</string>
<string name="label_application" msgid="8531721983832654978">"應用程式"</string>
- <!-- no translation found for all_apps_label (5015784846527570951) -->
- <skip />
+ <string name="all_apps_label" msgid="5015784846527570951">"所有應用程式"</string>
<string name="notifications_header" msgid="1404149926117359025">"通知"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"按住即可移動捷徑。"</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"輕觸兩下並按住即可移動捷徑或使用自訂操作。"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 6fdb4de..25911e6 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -136,7 +136,6 @@
<item name="swipe_up_rect_xy_fling_friction" type="dimen" format="float">1.5</item>
<item name="swipe_up_scale_start" type="dimen" format="float">0.88</item>
- <item name="swipe_up_duration" type="dimen" format="float">400</item>
<item name="swipe_up_trans_y_dp" type="dimen" format="float">4.5</item>
<item name="swipe_up_trans_y_dp_per_s" type="dimen" format="float">3</item>
@@ -147,33 +146,10 @@
<item name="swipe_up_rect_xy_damping_ratio" type="dimen" format="float">0.8</item>
<item name="swipe_up_rect_xy_stiffness" type="dimen" format="float">200</item>
-
- <item name="swipe_up_rect_2_x_damping_ratio" type="dimen" format="float">1</item>
- <item name="swipe_up_rect_2_x_stiffness" type="dimen" format="float">250</item>
-
- <item name="swipe_up_rect_2_y_damping_ratio" type="dimen" format="float">1</item>
- <item name="swipe_up_rect_2_y_stiffness" type="dimen" format="float">600</item>
-
- <item name="swipe_up_rect_2_y_stiffness_low_swipe_multiplier" type="dimen" format="float">0.8</item>
<item name="swipe_up_low_swipe_duration_multiplier" type="dimen" format="float">1</item>
<item name="swipe_up_launcher_alpha_max_progress" type="dimen" format="float">0.85</item>
-
- <item name="c1_a" type="dimen" format="float">0.05</item>
- <item name="c1_b" type="dimen" format="float">0</item>
- <item name="c1_c" type="dimen" format="float">0.133333</item>
- <item name="c1_d" type="dimen" format="float">0.06</item>
-
- <item name="mp_x" type="dimen" format="float">0.166666</item>
- <item name="mp_y" type="dimen" format="float">.4</item>
-
- <item name="c2_a" type="dimen" format="float">0.208333</item>
- <item name="c2_b" type="dimen" format="float">.82</item>
- <item name="c2_c" type="dimen" format="float">.25</item>
- <item name="c2_d" type="dimen" format="float">1</item>
-
-
<item name="staggered_damping_ratio" type="dimen" format="float">0.7</item>
<item name="staggered_stiffness" type="dimen" format="float">150</item>
<dimen name="unlock_staggered_velocity_dp_per_s">2dp</dimen>
@@ -188,33 +164,14 @@
<dimen name="swipe_up_max_velocity">7.619dp</dimen>
<array name="dynamic_resources">
- <item>@dimen/swipe_up_duration</item>
<item>@dimen/swipe_up_scale_start</item>
<item>@dimen/swipe_up_trans_y_dp</item>
<item>@dimen/swipe_up_trans_y_dp_per_s</item>
<item>@dimen/swipe_up_trans_y_damping</item>
<item>@dimen/swipe_up_trans_y_stiffness</item>
- <item>@dimen/swipe_up_rect_2_x_damping_ratio</item>
- <item>@dimen/swipe_up_rect_2_x_stiffness</item>
- <item>@dimen/swipe_up_rect_2_y_damping_ratio</item>
- <item>@dimen/swipe_up_rect_2_y_stiffness</item>
<item>@dimen/swipe_up_launcher_alpha_max_progress</item>
- <item>@dimen/swipe_up_rect_2_y_stiffness_low_swipe_multiplier</item>
<item>@dimen/swipe_up_low_swipe_duration_multiplier</item>
<item>@dimen/swipe_up_max_velocity</item>
-
- <item>@dimen/c1_a</item>
- <item>@dimen/c1_b</item>
- <item>@dimen/c1_c</item>
- <item>@dimen/c1_d</item>
-
- <item>@dimen/mp_x</item>
- <item>@dimen/mp_y</item>
-
- <item>@dimen/c2_a</item>
- <item>@dimen/c2_b</item>
- <item>@dimen/c2_c</item>
- <item>@dimen/c2_d</item>
</array>
<string-array name="filtered_components" ></string-array>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 4d137c8..78f3f11 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -104,8 +104,9 @@
<dimen name="all_apps_divider_height">2dp</dimen>
<dimen name="all_apps_divider_width">128dp</dimen>
<dimen name="all_apps_content_fade_in_offset">150dp</dimen>
-
<dimen name="all_apps_tip_bottom_margin">8dp</dimen>
+ <dimen name="all_apps_height_extra">6dp</dimen>
+
<!-- The size of corner radius of the arrow in the arrow toast. -->
<dimen name="arrow_toast_corner_radius">2dp</dimen>
<dimen name="arrow_toast_elevation">2dp</dimen>
@@ -333,6 +334,8 @@
<dimen name="overview_actions_top_margin_gesture_grid_landscape">0dp</dimen>
<dimen name="overview_actions_bottom_margin_gesture_grid_landscape">0dp</dimen>
<dimen name="overview_actions_margin_three_button">0dp</dimen>
+ <dimen name="overview_grid_side_margin_portrait">0dp</dimen>
+ <dimen name="overview_grid_side_margin_landscape">0dp</dimen>
<dimen name="overview_grid_row_spacing_portrait">0dp</dimen>
<dimen name="overview_grid_row_spacing_landscape">0dp</dimen>
<dimen name="recents_page_spacing">0dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index d7a1506..5f53d4e 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -40,9 +40,9 @@
<!-- Options for recent tasks -->
<!-- Title for an option to enter split screen mode for a given app -->
<string name="recent_task_option_split_screen">Split screen</string>
- <string translatable="false" name="split_screen_position_top">Pin to top</string>
- <string translatable="false" name="split_screen_position_left">Pin to left</string>
- <string translatable="false" name="split_screen_position_right">Pin to right</string>
+ <string translatable="false" name="split_screen_position_top">Split top</string>
+ <string translatable="false" name="split_screen_position_left">Split left</string>
+ <string translatable="false" name="split_screen_position_right">Split right</string>
<!-- Widgets -->
<!-- Message to tell the user to press and hold on a widget to add it [CHAR_LIMIT=50] -->
@@ -251,7 +251,7 @@
<string name="wallpaper_button_text">Wallpapers</string>
<!-- Text for wallpaper change button [CHAR LIMIT=30]-->
<string name="styles_wallpaper_button_text">Wallpaper & style</string>
- <!-- Text for settings button [CHAR LIMIT=30]-->
+ <!-- Text for settings button [CHAR LIMIT=20]-->
<string name="settings_button_text">Home settings</string>
<!-- Message shown when a feature is disabled by the administrator -->
<string name="msg_disabled_by_admin">Disabled by your admin</string>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 35c257f..1f1d57a 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -141,6 +141,7 @@
private final CheckLongPressHelper mLongPressHelper;
private final boolean mLayoutHorizontal;
+ private final boolean mIsRtl;
private final int mIconSize;
@ViewDebug.ExportedProperty(category = "launcher")
@@ -185,6 +186,8 @@
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.BubbleTextView, defStyle, 0);
mLayoutHorizontal = a.getBoolean(R.styleable.BubbleTextView_layoutHorizontal, false);
+ mIsRtl = (getResources().getConfiguration().getLayoutDirection()
+ == View.LAYOUT_DIRECTION_RTL);
DeviceProfile grid = mActivity.getDeviceProfile();
mDisplay = a.getInteger(R.styleable.BubbleTextView_iconDisplay, DISPLAY_WORKSPACE);
@@ -581,19 +584,29 @@
return mDotInfo != null;
}
+ /**
+ * Get the icon bounds on the view depending on the layout type.
+ */
public void getIconBounds(Rect outBounds) {
- getIconBounds(this, outBounds, mIconSize);
+ getIconBounds(mIconSize, outBounds);
}
- public static void getIconBounds(View iconView, Rect outBounds, int iconSize) {
- int top = iconView.getPaddingTop();
- int left = (iconView.getWidth() - iconSize) / 2;
- int right = left + iconSize;
- int bottom = top + iconSize;
- outBounds.set(left, top, right, bottom);
+ /**
+ * Get the icon bounds on the view depending on the layout type.
+ */
+ public void getIconBounds(int iconSize, Rect outBounds) {
+ Utilities.setRectToViewCenter(this, iconSize, outBounds);
+ if (mLayoutHorizontal) {
+ if (mIsRtl) {
+ outBounds.offsetTo(getWidth() - iconSize - getPaddingRight(), outBounds.top);
+ } else {
+ outBounds.offsetTo(getPaddingLeft(), outBounds.top);
+ }
+ } else {
+ outBounds.offsetTo(outBounds.left, getPaddingTop());
+ }
}
-
/**
* Sets whether to vertically center the content.
*/
@@ -980,8 +993,7 @@
@Override
public void getWorkspaceVisualDragBounds(Rect bounds) {
- DeviceProfile grid = mActivity.getDeviceProfile();
- BubbleTextView.getIconBounds(this, bounds, grid.iconSizePx);
+ getIconBounds(mIconSize, bounds);
}
private int getIconSizeForDisplay(int display) {
@@ -998,7 +1010,7 @@
}
public void getSourceVisualDragBounds(Rect bounds) {
- BubbleTextView.getIconBounds(this, bounds, getIconSizeForDisplay(mDisplay));
+ getIconBounds(mIconSize, bounds);
}
@Override
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 0b60b32..e64ea90 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -193,6 +193,7 @@
public final int overviewActionsBottomMarginGesturePx;
public int overviewPageSpacing;
public int overviewRowSpacing;
+ public int overviewGridSideMargin;
// Widgets
public final PointF appWidgetScale = new PointF(1.0f, 1.0f);
@@ -250,8 +251,7 @@
// Tablet UI does not support emulated landscape.
isTablet = allowRotation && info.isTablet(windowBounds);
isPhone = !isTablet;
- isTwoPanels = isTablet && useTwoPanels
- && (isLandscape || FeatureFlags.ENABLE_TWO_PANEL_HOME_IN_PORTRAIT.get());
+ isTwoPanels = isTablet && useTwoPanels;
aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx);
boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
@@ -399,6 +399,9 @@
overviewRowSpacing = isLandscape
? res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing_landscape)
: res.getDimensionPixelSize(R.dimen.overview_grid_row_spacing_portrait);
+ overviewGridSideMargin = isLandscape
+ ? res.getDimensionPixelSize(R.dimen.overview_grid_side_margin_landscape)
+ : res.getDimensionPixelSize(R.dimen.overview_grid_side_margin_portrait);
// Calculate all of the remaining variables.
extraSpace = updateAvailableDimensions(res);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8d92bf2..8154168 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -154,6 +154,7 @@
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.pm.PinRequestHelper;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.popup.ArrowPopup;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.popup.SystemShortcut;
@@ -3032,4 +3033,13 @@
public StatsLogManager getStatsLogManager() {
return super.getStatsLogManager().withDefaultInstanceId(mAllAppsSessionLogId);
}
+
+ /**
+ * Returns the current popup for testing, if any.
+ */
+ @VisibleForTesting
+ @Nullable
+ public ArrowPopup<?> getOptionsPopup() {
+ return findViewById(R.id.popup_container);
+ }
}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index df09f29..68e19cb 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -383,7 +383,7 @@
case LauncherSettings.Settings.METHOD_NEW_SCREEN_ID: {
Bundle result = new Bundle();
result.putInt(LauncherSettings.Settings.EXTRA_VALUE,
- mOpenHelper.generateNewScreenId());
+ mOpenHelper.getNewScreenId());
return result;
}
case LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB: {
@@ -483,7 +483,7 @@
LauncherSettings.Favorites.CONTAINER + " FROM "
+ Favorites.TABLE_NAME + ")";
- IntArray folderIds = LauncherDbUtils.queryIntArray(db, Favorites.TABLE_NAME,
+ IntArray folderIds = LauncherDbUtils.queryIntArray(false, db, Favorites.TABLE_NAME,
Favorites._ID, selection, null, null);
if (!folderIds.isEmpty()) {
db.delete(Favorites.TABLE_NAME, Utilities.createDbSelectionQuery(
@@ -628,7 +628,6 @@
private final Context mContext;
private final boolean mForMigration;
private int mMaxItemId = -1;
- private int mMaxScreenId = -1;
private boolean mBackupTableExists;
private boolean mHotseatRestoreTableExists;
@@ -672,9 +671,6 @@
if (mMaxItemId == -1) {
mMaxItemId = initializeMaxItemId(getWritableDatabase());
}
- if (mMaxScreenId == -1) {
- mMaxScreenId = initializeMaxScreenId(getWritableDatabase());
- }
}
@Override
@@ -682,7 +678,6 @@
if (LOGD) Log.d(TAG, "creating new launcher database");
mMaxItemId = 1;
- mMaxScreenId = 0;
addFavoritesTable(db, false);
@@ -835,8 +830,8 @@
case 27: {
// Update the favorites table so that the screen ids are ordered based on
// workspace page rank.
- IntArray finalScreens = LauncherDbUtils.queryIntArray(db, "workspaceScreens",
- BaseColumns._ID, null, null, "screenRank");
+ IntArray finalScreens = LauncherDbUtils.queryIntArray(false, db,
+ "workspaceScreens", BaseColumns._ID, null, null, "screenRank");
int[] original = finalScreens.toArray();
Arrays.sort(original);
String updatemap = "";
@@ -919,7 +914,7 @@
Log.e(TAG, "getAppWidgetIds not supported", e);
return;
}
- final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(db,
+ final IntSet validWidgets = IntSet.wrap(LauncherDbUtils.queryIntArray(false, db,
Favorites.TABLE_NAME, Favorites.APPWIDGET_ID,
"itemType=" + Favorites.ITEM_TYPE_APPWIDGET, null, null));
for (int widgetId : allWidgets) {
@@ -1043,36 +1038,19 @@
public void checkId(ContentValues values) {
int id = values.getAsInteger(Favorites._ID);
mMaxItemId = Math.max(id, mMaxItemId);
-
- Integer screen = values.getAsInteger(Favorites.SCREEN);
- Integer container = values.getAsInteger(Favorites.CONTAINER);
- if (screen != null && container != null
- && container.intValue() == Favorites.CONTAINER_DESKTOP) {
- mMaxScreenId = Math.max(screen, mMaxScreenId);
- }
}
private int initializeMaxItemId(SQLiteDatabase db) {
return getMaxId(db, "SELECT MAX(%1$s) FROM %2$s", Favorites._ID, Favorites.TABLE_NAME);
}
- // Generates a new ID to use for an workspace screen in your database. This method
- // should be only called from the main UI thread. As an exception, we do call it when we
- // call the constructor from the worker thread; however, this doesn't extend until after the
- // constructor is called, and we only pass a reference to LauncherProvider to LauncherApp
- // after that point
- public int generateNewScreenId() {
- if (mMaxScreenId < 0) {
- throw new RuntimeException("Error: max screen id was not initialized");
- }
- mMaxScreenId += 1;
- return mMaxScreenId;
- }
-
- private int initializeMaxScreenId(SQLiteDatabase db) {
- return getMaxId(db, "SELECT MAX(%1$s) FROM %2$s WHERE %3$s = %4$d AND %1$s >= 0",
+ // Returns a new ID to use for an workspace screen in your database that is greater than all
+ // existing screen IDs.
+ private int getNewScreenId() {
+ return getMaxId(getWritableDatabase(),
+ "SELECT MAX(%1$s) FROM %2$s WHERE %3$s = %4$d AND %1$s >= 0",
Favorites.SCREEN, Favorites.TABLE_NAME, Favorites.CONTAINER,
- Favorites.CONTAINER_DESKTOP);
+ Favorites.CONTAINER_DESKTOP) + 1;
}
@Thunk int loadFavorites(SQLiteDatabase db, AutoInstallsLayout loader) {
@@ -1081,7 +1059,6 @@
// Ensure that the max ids are initialized
mMaxItemId = initializeMaxItemId(db);
- mMaxScreenId = initializeMaxScreenId(db);
return count;
}
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 523ac72..cefadf7 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1721,6 +1721,10 @@
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ if (mScroller.isFinished()) {
+ // This was not caused by the scroller, skip it.
+ return;
+ }
int newDestinationPage = getDestinationPage();
if (newDestinationPage >= 0 && newDestinationPage != mCurrentScrollOverPage) {
mCurrentScrollOverPage = newDestinationPage;
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 7a38fe7..d2fe483 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -527,6 +527,18 @@
}
/**
+ * Using the view's bounds and icon size, calculate where the icon bounds will
+ * be if it was positioned at the center of the view.
+ */
+ public static void setRectToViewCenter(View iconView, int iconSize, Rect outBounds) {
+ int top = (iconView.getHeight() - iconSize) / 2;
+ int left = (iconView.getWidth() - iconSize) / 2;
+ int right = left + iconSize;
+ int bottom = top + iconSize;
+ outBounds.set(left, top, right, bottom);
+ }
+
+ /**
* Ensures that a value is within given bounds. Specifically:
* If value is less than lowerBound, return lowerBound; else if value is greater than upperBound,
* return upperBound; else return value unchanged.
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 00c8d8e..203df0a 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -326,6 +326,7 @@
}
updateWorkspaceScreensPadding();
+ updateWorkspaceWidgetsSizes();
}
private void updateWorkspaceScreensPadding() {
@@ -357,6 +358,25 @@
}
}
+ private void updateWorkspaceWidgetsSizes() {
+ int numberOfScreens = mScreenOrder.size();
+ for (int i = 0; i < numberOfScreens; i++) {
+ ShortcutAndWidgetContainer shortcutAndWidgetContainer =
+ mWorkspaceScreens.get(mScreenOrder.get(i)).getShortcutsAndWidgets();
+ int shortcutsAndWidgetCount = shortcutAndWidgetContainer.getChildCount();
+ for (int j = 0; j < shortcutsAndWidgetCount; j++) {
+ View view = shortcutAndWidgetContainer.getChildAt(j);
+ if (view instanceof LauncherAppWidgetHostView
+ && view.getTag() instanceof LauncherAppWidgetInfo) {
+ LauncherAppWidgetInfo launcherAppWidgetInfo =
+ (LauncherAppWidgetInfo) view.getTag();
+ WidgetSizes.updateWidgetSizeRanges((LauncherAppWidgetHostView) view,
+ mLauncher, launcherAppWidgetInfo.spanX, launcherAppWidgetInfo.spanY);
+ }
+ }
+ }
+ }
+
/**
* Estimates the size of an item using spans: hSpan, vSpan.
*
@@ -846,13 +866,13 @@
mWorkspaceScreens.remove(emptyScreenId);
mScreenOrder.removeValue(emptyScreenId);
- int newScreenId = -1;
+ int newScreenId = LauncherSettings.Settings.call(getContext().getContentResolver(),
+ LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
+ .getInt(LauncherSettings.Settings.EXTRA_VALUE);
// Launcher database isn't aware of empty pages that are already bound, so we need to
// skip those IDs manually.
- while (newScreenId == -1 || mWorkspaceScreens.containsKey(newScreenId)) {
- newScreenId = LauncherSettings.Settings.call(getContext().getContentResolver(),
- LauncherSettings.Settings.METHOD_NEW_SCREEN_ID)
- .getInt(LauncherSettings.Settings.EXTRA_VALUE);
+ while (mWorkspaceScreens.containsKey(newScreenId)) {
+ newScreenId++;
}
mWorkspaceScreens.put(newScreenId, cl);
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 874fe80..d5c9a53 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -41,7 +41,9 @@
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.util.PackageManagerHelper;
import java.util.Arrays;
@@ -95,16 +97,15 @@
// The type of this item
public int viewType;
- /** App-only properties */
- // The section name of this app. Note that there can be multiple items with different
+ // The section name of this item. Note that there can be multiple items with different
// sectionNames in the same section
public String sectionName = null;
// The row that this item shows up on
public int rowIndex;
// The index of this app in the row
public int rowAppIndex;
- // The associated AppInfo for the app
- public AppInfo appInfo = null;
+ // The associated ItemInfoWithIcon for the item
+ public ItemInfoWithIcon itemInfo = null;
// The index of this app not including sections
public int appIndex = -1;
// Search section associated to result
@@ -119,7 +120,7 @@
item.viewType = VIEW_TYPE_ICON;
item.position = pos;
item.sectionName = sectionName;
- item.appInfo = appInfo;
+ item.itemInfo = appInfo;
item.appIndex = appIndex;
return item;
}
@@ -273,6 +274,8 @@
// The intent to send off to the market app, updated each time the search query changes.
private Intent mMarketSearchIntent;
+ private final int mExtraHeight;
+
public AllAppsGridAdapter(BaseDraggingActivity launcher, LayoutInflater inflater,
AlphabeticalAppsList apps, BaseAdapterProvider[] adapterProviders) {
Resources res = launcher.getResources();
@@ -288,6 +291,7 @@
mAdapterProviders = adapterProviders;
setAppsPerRow(mLauncher.getDeviceProfile().numShownAllAppsColumns);
+ mExtraHeight = launcher.getResources().getDimensionPixelSize(R.dimen.all_apps_height_extra);
}
public void setAppsPerRow(int appsPerRow) {
@@ -347,14 +351,19 @@
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case VIEW_TYPE_ICON:
+ int layout = !FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get() ? R.layout.all_apps_icon
+ : R.layout.all_apps_icon_twoline;
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
- R.layout.all_apps_icon, parent, false);
+ layout, parent, false);
icon.setLongPressTimeoutFactor(1f);
icon.setOnFocusChangeListener(mIconFocusListener);
icon.setOnClickListener(mOnIconClickListener);
icon.setOnLongClickListener(mOnIconLongClickListener);
// Ensure the all apps icon height matches the workspace icons in portrait mode.
icon.getLayoutParams().height = mLauncher.getDeviceProfile().allAppsCellHeightPx;
+ if (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get()) {
+ icon.getLayoutParams().height += mExtraHeight;
+ }
return new ViewHolder(icon);
case VIEW_TYPE_EMPTY_SEARCH:
return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search,
@@ -373,7 +382,7 @@
if (adapterProvider != null) {
return adapterProvider.onCreateViewHolder(mLayoutInflater, parent, viewType);
}
- throw new RuntimeException("Unexpected view type");
+ throw new RuntimeException("Unexpected view type" + viewType);
}
}
@@ -382,10 +391,13 @@
switch (holder.getItemViewType()) {
case VIEW_TYPE_ICON:
AdapterItem adapterItem = mApps.getAdapterItems().get(position);
- AppInfo info = adapterItem.appInfo;
BubbleTextView icon = (BubbleTextView) holder.itemView;
icon.reset();
- icon.applyFromApplicationInfo(info);
+ if (adapterItem.itemInfo instanceof AppInfo) {
+ icon.applyFromApplicationInfo((AppInfo) adapterItem.itemInfo);
+ } else {
+ icon.applyFromItemInfoWithIcon(adapterItem.itemInfo);
+ }
break;
case VIEW_TYPE_EMPTY_SEARCH:
TextView emptyViewText = (TextView) holder.itemView;
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 3ca0303..85ee636 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -47,7 +47,6 @@
ValueAnimator.AnimatorUpdateListener, PluginListener<AllAppsRow>, Insettable,
OnHeightUpdatedListener {
- private static final long ALL_APPS_CONTENT_ANIM_DURATION = 150;
private final Rect mRVClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
private final Rect mHeaderClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
@@ -110,13 +109,6 @@
private FloatingHeaderRow[] mAllRows = FloatingHeaderRow.NO_ROWS;
- // members for handling suggestion state
- private final ValueAnimator mAllAppsContentAnimator = ValueAnimator.ofFloat(0, 0);
- private View mAllAppsButton;
- private int mAllAppsContentFadeInOffset;
- private boolean mInSuggestionMode = false;
-
-
public FloatingHeaderView(@NonNull Context context) {
this(context, null);
}
@@ -127,20 +119,12 @@
.getDimensionPixelSize(R.dimen.all_apps_header_top_padding);
mHeaderProtectionSupported = context.getResources().getBoolean(
R.bool.config_header_protection_supported);
- mAllAppsContentFadeInOffset = context.getResources()
- .getDimensionPixelSize(R.dimen.all_apps_content_fade_in_offset);
- mAllAppsContentAnimator.setDuration(ALL_APPS_CONTENT_ANIM_DURATION);
- mAllAppsContentAnimator.addUpdateListener(this::onAllAppsContentAnimationUpdate);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
mTabLayout = findViewById(R.id.tabs);
- mAllAppsButton = findViewById(R.id.all_apps_button);
- if (mAllAppsButton != null) {
- mAllAppsButton.setOnClickListener(this::onAllAppsButtonClicked);
- }
// Find all floating header rows.
ArrayList<FloatingHeaderRow> rows = new ArrayList<>();
@@ -329,7 +313,6 @@
}
mTabLayout.setTranslationY(mTranslationY);
- setSuggestionMode(false);
int clipHeight = mHeaderTopPadding - getPaddingBottom();
mRVClip.top = mTabsHidden ? clipHeight : 0;
@@ -365,7 +348,6 @@
mTranslationY = 0;
applyVerticalMove();
}
- setSuggestionMode(false);
mHeaderCollapsed = false;
mSnappedScrolledY = -mMaxTranslation;
mCurrentRV.scrollToTop();
@@ -461,38 +443,6 @@
}
return Math.max(getHeight() - getPaddingTop() + mTranslationY, 0);
}
-
- /**
- * When suggestion mode is enabled, hides AllApps content view and shows AllApps button.
- */
- public void setSuggestionMode(boolean isSuggestMode) {
- if (mInSuggestionMode == isSuggestMode || mAllAppsButton == null) return;
- if (!FeatureFlags.ENABLE_ONE_SEARCH.get()) return;
- AllAppsContainerView allApps = (AllAppsContainerView) getParent();
- mInSuggestionMode = isSuggestMode;
- if (isSuggestMode) {
- mTabLayout.setVisibility(GONE);
- mAllAppsButton.setVisibility(VISIBLE);
- allApps.getContentView().setVisibility(GONE);
- } else {
- mTabLayout.setVisibility(mTabsHidden ? GONE : VISIBLE);
- mAllAppsButton.setVisibility(GONE);
- allApps.getContentView().setVisibility(VISIBLE);
- }
- }
-
- private void onAllAppsButtonClicked(View view) {
- setSuggestionMode(false);
- mAllAppsContentAnimator.start();
- }
-
- private void onAllAppsContentAnimationUpdate(ValueAnimator valueAnimator) {
- float prog = valueAnimator.getAnimatedFraction();
- View allAppsList = ((AllAppsContainerView) getParent()).getContentView();
- allAppsList.setAlpha(255 * prog);
- allAppsList.setTranslationY((1 - prog) * mAllAppsContentFadeInOffset);
- }
-
}
diff --git a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
index 97052b2..dd58123 100644
--- a/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
+++ b/src/com/android/launcher3/compat/AccessibilityManagerCompat.java
@@ -41,11 +41,10 @@
}
/**
- *
* @param target The view the accessibility event is initialized on.
* If null, this method has no effect.
- * @param type See TYPE_ constants defined in {@link AccessibilityEvent}.
- * @param text Optional text to add to the event, which will be announced to the user.
+ * @param type See TYPE_ constants defined in {@link AccessibilityEvent}.
+ * @param text Optional text to add to the event, which will be announced to the user.
*/
public static void sendCustomAccessibilityEvent(@Nullable View target, int type,
@Nullable String text) {
@@ -97,6 +96,16 @@
null);
}
+ /**
+ * Notify running tests of a folder opened.
+ */
+ public static void sendFolderOpenedEventToTest(Context context) {
+ final AccessibilityManager accessibilityManager = getAccessibilityManagerForTest(context);
+ if (accessibilityManager == null) return;
+
+ sendEventToTest(accessibilityManager, context, TestProtocol.FOLDER_OPENED_MESSAGE, null);
+ }
+
private static void sendEventToTest(
AccessibilityManager accessibilityManager,
Context context, String eventTag, Bundle data) {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 796c912..c4d8166 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -94,6 +94,9 @@
public static final BooleanFlag ENABLE_ONE_SEARCH = new DeviceFlag("ENABLE_ONE_SEARCH", false,
"Use homescreen search box to complete allApps searches");
+ public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(
+ "ENABLE_TWOLINE_ALLAPPS", false, "Enables two line label inside all apps.");
+
public static final BooleanFlag ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING = new DeviceFlag(
"ENABLE_DEVICE_SEARCH_PERFORMANCE_LOGGING", true,
"Allows on device search in all apps logging");
@@ -154,15 +157,6 @@
"ENABLE_DATABASE_RESTORE", false,
"Enable database restore when new restore session is created");
- public static final BooleanFlag ENABLE_SMARTSPACE_UNIVERSAL = getDebugFlag(
- "ENABLE_SMARTSPACE_UNIVERSAL", false,
- "Replace Smartspace with a version rendered by System UI.");
-
- public static final BooleanFlag ENABLE_SMARTSPACE_ENHANCED = getDebugFlag(
- "ENABLE_SMARTSPACE_ENHANCED", true,
- "Replace Smartspace with the enhanced version. "
- + "Ignored if ENABLE_SMARTSPACE_UNIVERSAL is enabled.");
-
public static final BooleanFlag ENABLE_SMARTSPACE_DISMISS = getDebugFlag(
"ENABLE_SMARTSPACE_DISMISS", true,
"Adds a menu option to dismiss the current Enhanced Smartspace card.");
@@ -204,6 +198,10 @@
public static final BooleanFlag ENABLE_TASKBAR_EDU = getDebugFlag("ENABLE_TASKBAR_EDU", true,
"Enables showing taskbar education the first time an app is opened.");
+ public static final BooleanFlag ENABLE_TASKBAR_POPUP_MENU = getDebugFlag(
+ "ENABLE_TASKBAR_POPUP_MENU", false, "Enables long pressing taskbar icons to show the"
+ + " popup menu.");
+
public static final BooleanFlag ENABLE_OVERVIEW_GRID = getDebugFlag(
"ENABLE_OVERVIEW_GRID", true, "Uses grid overview layout. "
+ "Only applicable on large screen devices.");
@@ -212,10 +210,6 @@
"ENABLE_TWO_PANEL_HOME", true,
"Uses two panel on home screen. Only applicable on large screen devices.");
- public static final BooleanFlag ENABLE_TWO_PANEL_HOME_IN_PORTRAIT = getDebugFlag(
- "ENABLE_TWO_PANEL_HOME_IN_PORTRAIT", true,
- "Uses two panel on home screen in portrait if ENABLE_TWO_PANEL_HOME is enabled.");
-
public static final BooleanFlag ENABLE_SCRIM_FOR_APP_LAUNCH = getDebugFlag(
"ENABLE_SCRIM_FOR_APP_LAUNCH", false,
"Enables scrim during app launch animation.");
@@ -233,9 +227,6 @@
public static final BooleanFlag NOTIFY_CRASHES = getDebugFlag("NOTIFY_CRASHES", false,
"Sends a notification whenever launcher encounters an uncaught exception.");
- public static final BooleanFlag PROTOTYPE_APP_CLOSE = getDebugFlag(
- "PROTOTYPE_APP_CLOSE", false, "Enables new app close");
-
public static final BooleanFlag ENABLE_WALLPAPER_SCRIM = getDebugFlag(
"ENABLE_WALLPAPER_SCRIM", false,
"Enables scrim over wallpaper for text protection.");
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index 879739f..daef682 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -78,6 +78,7 @@
import com.android.launcher3.accessibility.AccessibleDragListenerAdapter;
import com.android.launcher3.accessibility.FolderAccessibilityHelper;
import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
+import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragController.DragListener;
@@ -687,6 +688,7 @@
public void onAnimationEnd(Animator animation) {
mState = STATE_OPEN;
announceAccessibilityChanges();
+ AccessibilityManagerCompat.sendFolderOpenedEventToTest(getContext());
mContent.setFocusOnFirstChild();
}
@@ -1265,7 +1267,8 @@
PendingAddShortcutInfo pasi = d.dragInfo instanceof PendingAddShortcutInfo
? (PendingAddShortcutInfo) d.dragInfo : null;
- WorkspaceItemInfo pasiSi = pasi != null ? pasi.activityInfo.createWorkspaceItemInfo() : null;
+ WorkspaceItemInfo pasiSi =
+ pasi != null ? pasi.activityInfo.createWorkspaceItemInfo() : null;
if (pasi != null && pasiSi == null) {
// There is no WorkspaceItemInfo, so we have to go through a configuration activity.
pasi.container = mInfo.id;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 439df80..98be72a 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -628,7 +628,10 @@
public void drawDot(Canvas canvas) {
if (!mForceHideDot && ((mDotInfo != null && mDotInfo.hasDot()) || mDotScale > 0)) {
Rect iconBounds = mDotParams.iconBounds;
- BubbleTextView.getIconBounds(this, iconBounds, mActivity.getDeviceProfile().iconSizePx);
+
+ Utilities.setRectToViewCenter(this, mActivity.getDeviceProfile().iconSizePx,
+ iconBounds);
+ iconBounds.offsetTo(iconBounds.left, getPaddingTop());
float iconScale = (float) mBackground.previewSize / iconBounds.width();
Utilities.scaleRectAboutCenter(iconBounds, iconScale);
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index d987212..8b7bebc 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -518,7 +518,10 @@
LAUNCHER_TASKBAR_LONGPRESS_HIDE(896),
@UiEvent(doc = "User long pressed on the taskbar gesture handle to show the taskbar")
- LAUNCHER_TASKBAR_LONGPRESS_SHOW(897);
+ LAUNCHER_TASKBAR_LONGPRESS_SHOW(897),
+
+ @UiEvent(doc = "User clicks on the search icon on header to launch search in app.")
+ LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH(913);
// ADD MORE
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index fea15c4..a13fa55 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -16,7 +16,6 @@
package com.android.launcher3.model;
import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
-import static com.android.launcher3.WorkspaceLayoutManager.SECOND_SCREEN_ID;
import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
@@ -300,11 +299,6 @@
IntSet screensToExclude = new IntSet();
if (FeatureFlags.QSB_ON_FIRST_SCREEN) {
screensToExclude.add(FIRST_SCREEN_ID);
-
- // On split display we don't want to add the new items onto the second screen.
- if (app.getInvariantDeviceProfile().isSplitDisplay) {
- screensToExclude.add(SECOND_SCREEN_ID);
- }
}
for (int screen = 0; screen < screenCount; screen++) {
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 0439e75..94e06d1 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -292,7 +292,7 @@
FileLog.d(TAG, "removing items from db " + items.stream().map(
(item) -> item.getTargetComponent() == null ? ""
: item.getTargetComponent().getPackageName()).collect(
- Collectors.joining(",")), new Exception());
+ Collectors.joining(",")));
notifyDelete(items);
enqueueDeleteRunnable(() -> {
for (ItemInfo item : items) {
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 97398de..b72f462 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -373,7 +373,7 @@
protected LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() {
LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
- itemBuilder.setIsWork(user != Process.myUserHandle());
+ itemBuilder.setIsWork(!Process.myUserHandle().equals(user));
return itemBuilder;
}
diff --git a/src/com/android/launcher3/model/data/SearchActionItemInfo.java b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
index 293c095..c6e5e8a 100644
--- a/src/com/android/launcher3/model/data/SearchActionItemInfo.java
+++ b/src/com/android/launcher3/model/data/SearchActionItemInfo.java
@@ -46,6 +46,7 @@
public static final int FLAG_PRIMARY_ICON_FROM_TITLE = 1 << 4;
public static final int FLAG_BADGE_WITH_COMPONENT_NAME = 1 << 5;
public static final int FLAG_ALLOW_PINNING = 1 << 6;
+ public static final int FLAG_SEARCH_IN_APP = 1 << 7;
private String mFallbackPackageName;
private int mFlags = 0;
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
index 2230914..5a1e4bf 100644
--- a/src/com/android/launcher3/popup/ArrowPopup.java
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -234,7 +234,7 @@
* @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColorIds}.
* Otherwise, we will use this color for all child views.
*/
- private void assignMarginsAndBackgrounds(ViewGroup viewGroup, int backgroundColor) {
+ 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.
@@ -445,7 +445,7 @@
animateOpen();
}
- private void setupForDisplay() {
+ protected void setupForDisplay() {
setVisibility(View.INVISIBLE);
mIsOpen = true;
getPopupContainer().addView(this);
@@ -482,7 +482,7 @@
mArrow.setVisibility(show && shouldAddArrow() ? VISIBLE : INVISIBLE);
}
- private void addArrow() {
+ protected void addArrow() {
getPopupContainer().addView(mArrow);
mArrow.setX(getX() + getArrowLeft());
@@ -686,12 +686,13 @@
return getChildCount() > 0 ? getChildAt(0) : this;
}
- private void animateOpen() {
+ protected void animateOpen() {
setVisibility(View.VISIBLE);
mOpenCloseAnimator = getOpenCloseAnimator(true, OPEN_DURATION, OPEN_FADE_START_DELAY,
OPEN_FADE_DURATION, OPEN_CHILD_FADE_START_DELAY, OPEN_CHILD_FADE_DURATION,
DECELERATED_EASE);
+ onCreateOpenAnimation(mOpenCloseAnimator);
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -785,6 +786,11 @@
}
/**
+ * Called when creating the open transition allowing subclass can add additional animations.
+ */
+ protected void onCreateOpenAnimation(AnimatorSet anim) { }
+
+ /**
* Called when creating the close transition allowing subclass can add additional animations.
*/
protected void onCreateCloseAnimation(AnimatorSet anim) { }
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index 6855bb1..b510378 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -31,11 +31,11 @@
*/
public class LauncherDbUtils {
- public static IntArray queryIntArray(SQLiteDatabase db, String tableName, String columnName,
- String selection, String groupBy, String orderBy) {
+ public static IntArray queryIntArray(boolean distinct, SQLiteDatabase db, String tableName,
+ String columnName, String selection, String groupBy, String orderBy) {
IntArray out = new IntArray();
- try (Cursor c = db.query(tableName, new String[] { columnName }, selection, null,
- groupBy, null, orderBy)) {
+ try (Cursor c = db.query(distinct, tableName, new String[] { columnName }, selection, null,
+ groupBy, null, orderBy, null)) {
while (c.moveToNext()) {
out.add(c.getInt(0));
}
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index 257d732..8f607a1 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -16,6 +16,7 @@
package com.android.launcher3.provider;
+import static com.android.launcher3.model.DeviceGridState.TYPE_MULTI_DISPLAY;
import static com.android.launcher3.model.DeviceGridState.TYPE_PHONE;
import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
@@ -96,7 +97,7 @@
try (SQLiteTransaction t = new SQLiteTransaction(db)) {
RestoreDbTask task = new RestoreDbTask();
task.backupWorkspace(context, db);
- task.sanitizeDB(helper, db, new BackupManager(context));
+ task.sanitizeDB(context, helper, db, new BackupManager(context));
task.restoreAppWidgetIdsIfExists(context);
t.commit();
return true;
@@ -139,7 +140,7 @@
GridBackupTable backupTable = new GridBackupTable(context, db, idp.numDatabaseHotseatIcons,
idp.numColumns, idp.numRows);
if (backupTable.restoreFromRawBackupIfAvailable(getDefaultProfileId(db))) {
- int itemsDeleted = sanitizeDB(helper, db, backupManager);
+ int itemsDeleted = sanitizeDB(context, helper, db, backupManager);
LauncherAppState.getInstance(context).getModel().forceReload();
restoreAppWidgetIdsIfExists(context);
if (itemsDeleted == 0) {
@@ -156,11 +157,12 @@
* the restored apps get installed.
* 3. If the user serial for any restored profile is different than that of the previous
* device, update the entries to the new profile id.
+ * 4. If restored from a single display backup, remove gaps between screenIds
*
* @return number of items deleted.
*/
- private int sanitizeDB(DatabaseHelper helper, SQLiteDatabase db, BackupManager backupManager)
- throws Exception {
+ private int sanitizeDB(Context context, DatabaseHelper helper, SQLiteDatabase db,
+ BackupManager backupManager) throws Exception {
// Primary user ids
long myProfileId = helper.getDefaultUserSerial();
long oldProfileId = getDefaultProfileId(db);
@@ -236,10 +238,43 @@
if (myProfileId != oldProfileId) {
changeDefaultColumn(db, myProfileId);
}
+
+ // If restored from a single display backup, remove gaps between screenIds
+ if (Utilities.getPrefs(context).getInt(RESTORED_DEVICE_TYPE, TYPE_PHONE)
+ != TYPE_MULTI_DISPLAY) {
+ removeScreenIdGaps(db);
+ }
+
return itemsDeleted;
}
/**
+ * Remove gaps between screenIds to make sure no empty pages are left in between.
+ *
+ * e.g. [0, 3, 4, 6, 7] -> [0, 1, 2, 3, 4]
+ */
+ protected void removeScreenIdGaps(SQLiteDatabase db) {
+ FileLog.d(TAG, "Removing gaps between screenIds");
+ IntArray distinctScreens = LauncherDbUtils.queryIntArray(true, db, Favorites.TABLE_NAME,
+ Favorites.SCREEN, Favorites.CONTAINER + " = " + Favorites.CONTAINER_DESKTOP, null,
+ Favorites.SCREEN);
+ if (distinctScreens.isEmpty()) {
+ return;
+ }
+
+ StringBuilder sql = new StringBuilder("UPDATE ").append(Favorites.TABLE_NAME)
+ .append(" SET ").append(Favorites.SCREEN).append(" =\nCASE\n");
+ int screenId = distinctScreens.contains(0) ? 0 : 1;
+ for (int i = 0; i < distinctScreens.size(); i++) {
+ sql.append("WHEN ").append(Favorites.SCREEN).append(" == ")
+ .append(distinctScreens.get(i)).append(" THEN ").append(screenId++).append("\n");
+ }
+ sql.append("ELSE screen\nEND WHERE ").append(Favorites.CONTAINER).append(" = ")
+ .append(Favorites.CONTAINER_DESKTOP).append(";");
+ db.execSQL(sql.toString());
+ }
+
+ /**
* Updates profile id of all entries from {@param oldProfileId} to {@param newProfileId}.
*/
protected void migrateProfileId(SQLiteDatabase db, long oldProfileId, long newProfileId) {
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index b34af97..1767939 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -84,7 +84,7 @@
+ ", mCurrentStableState:" + mCurrentStableState
+ ", mState:" + mState
+ ", mRestState:" + mRestState
- + ", isInTransition:" + (mConfig.currentAnimation != null) + ")";
+ + ", isInTransition:" + isInTransition() + ")";
}
public void dump(String prefix, PrintWriter writer) {
@@ -93,7 +93,7 @@
writer.println(prefix + "\tmCurrentStableState:" + mCurrentStableState);
writer.println(prefix + "\tmState:" + mState);
writer.println(prefix + "\tmRestState:" + mRestState);
- writer.println(prefix + "\tisInTransition:" + (mConfig.currentAnimation != null));
+ writer.println(prefix + "\tisInTransition:" + isInTransition());
}
public StateHandler[] getStateHandlers() {
@@ -130,6 +130,13 @@
}
/**
+ * @return {@code true} If there is an active transition.
+ */
+ public boolean isInTransition() {
+ return mConfig.currentAnimation != null;
+ }
+
+ /**
* @see #goToState(STATE_TYPE, boolean, AnimatorListener)
*/
public void goToState(STATE_TYPE state) {
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 5a9c074..8ebfd62 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -21,6 +21,7 @@
import android.annotation.TargetApi;
import android.app.Activity;
import android.content.Context;
+import android.content.res.Resources;
import android.graphics.Insets;
import android.os.Build;
import android.os.Bundle;
@@ -148,6 +149,20 @@
TestProtocol.TEST_INFO_RESPONSE_FIELD, TestLogging.sHadEventsNotFromTest);
return response;
+ case TestProtocol.REQUEST_START_DRAG_THRESHOLD: {
+ final Resources resources = mContext.getResources();
+ response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+ resources.getDimensionPixelSize(R.dimen.deep_shortcuts_start_drag_threshold)
+ + resources.getDimensionPixelSize(R.dimen.pre_drag_view_scale));
+ return response;
+ }
+
+ case TestProtocol.REQUEST_ENABLE_ROTATION:
+ MAIN_EXECUTOR.submit(() ->
+ Launcher.ACTIVITY_TRACKER.getCreatedActivity().getRotationHelper()
+ .forceAllowRotationForTesting(Boolean.parseBoolean(arg)));
+ return null;
+
default:
return null;
}
@@ -193,6 +208,7 @@
/**
* Generic interface for setting a fiend in bundle
+ *
* @param <T> the type of value being set
*/
public interface BundleSetter<T> {
diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java
index 5bf0342..9a74fb1 100644
--- a/src/com/android/launcher3/testing/TestProtocol.java
+++ b/src/com/android/launcher3/testing/TestProtocol.java
@@ -25,6 +25,7 @@
public static final String SCROLL_FINISHED_MESSAGE = "TAPL_SCROLL_FINISHED";
public static final String PAUSE_DETECTED_MESSAGE = "TAPL_PAUSE_DETECTED";
public static final String DISMISS_ANIMATION_ENDS_MESSAGE = "TAPL_DISMISS_ANIMATION_ENDS";
+ public static final String FOLDER_OPENED_MESSAGE = "TAPL_FOLDER_OPENED";
public static final int NORMAL_STATE_ORDINAL = 0;
public static final int SPRING_LOADED_STATE_ORDINAL = 1;
public static final int OVERVIEW_STATE_ORDINAL = 2;
@@ -99,6 +100,7 @@
public static final String REQUEST_CLEAR_DATA = "clear-data";
public static final String REQUEST_IS_TABLET = "is-tablet";
public static final String REQUEST_IS_TWO_PANELS = "is-two-panel";
+ public static final String REQUEST_START_DRAG_THRESHOLD = "start-drag-threshold";
public static final String REQUEST_GET_ACTIVITIES_CREATED_COUNT =
"get-activities-created-count";
public static final String REQUEST_GET_ACTIVITIES = "get-activities";
@@ -106,6 +108,7 @@
"get-focused-task-height-for-tablet";
public static final String REQUEST_GET_GRID_TASK_SIZE_RECT_FOR_TABLET =
"get-grid-task-size-rect-for-tablet";
+ public static final String REQUEST_ENABLE_ROTATION = "enable_rotation";
public static Long sForcePauseTimeout;
public static final String REQUEST_SET_FORCE_PAUSE_TIMEOUT = "set-force-pause-timeout";
@@ -119,7 +122,9 @@
public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
+ public static final String TASKBAR_WINDOW_CRASH = "b/201305599";
public static final String TASK_VIEW_ID_CRASH = "b/195430732";
public static final String NO_DROP_TARGET = "b/195031154";
public static final String NULL_INT_SET = "b/200572078";
+ public static final String NO_SCREENSHOT = "b/202414125";
}
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 5e907a4..8d57d69 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET;
import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
@@ -286,7 +287,13 @@
Toast.LENGTH_SHORT).show();
}
}
- launcher.getStatsLogManager().logger().withItemInfo(itemInfo).log(LAUNCHER_APP_LAUNCH_TAP);
+ if (itemInfo.hasFlags(SearchActionItemInfo.FLAG_SEARCH_IN_APP)) {
+ launcher.getStatsLogManager().logger().withItemInfo(itemInfo).log(
+ LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH);
+ } else {
+ launcher.getStatsLogManager().logger().withItemInfo(itemInfo).log(
+ LAUNCHER_APP_LAUNCH_TAP);
+ }
}
private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
diff --git a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
index a190f52..93e3ea7 100644
--- a/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/LandscapePagedViewHandler.java
@@ -390,7 +390,7 @@
@Override
public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
int parentWidth, int parentHeight,
- SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, DeviceProfile dp) {
+ StagedSplitBounds splitBoundsConfig, DeviceProfile dp) {
int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
int dividerBar = splitBoundsConfig.visualDividerBounds.width();
@@ -435,15 +435,18 @@
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams =
new FrameLayout.LayoutParams(primaryIconParams);
+ int dividerBar = (splitConfig.appsStackedVertically ?
+ splitConfig.visualDividerBounds.height() :
+ splitConfig.visualDividerBounds.width());
int primaryHeight = primarySnapshotBounds.height();
- int secondaryHeight = secondarySnapshotBounds.height();
primaryIconParams.gravity = (isRtl ? START : END) | TOP;
- primaryIconView.setTranslationY((primaryHeight + taskIconHeight) / 2f );
+ primaryIconView.setTranslationY(primaryHeight - primaryIconView.getHeight() / 2f);
+ primaryIconView.setTranslationX(0);
secondaryIconParams.gravity = (isRtl ? START : END) | TOP;
- secondaryIconView.setTranslationY(primaryHeight
- + ((secondaryHeight + taskIconHeight) / 2f));
+ secondaryIconView.setTranslationY(primaryHeight + taskIconHeight + dividerBar);
+ secondaryIconView.setTranslationX(0);
primaryIconView.setLayoutParams(primaryIconParams);
secondaryIconView.setLayoutParams(secondaryIconParams);
}
diff --git a/src/com/android/launcher3/touch/PagedOrientationHandler.java b/src/com/android/launcher3/touch/PagedOrientationHandler.java
index 8112afd..2ff2feb 100644
--- a/src/com/android/launcher3/touch/PagedOrientationHandler.java
+++ b/src/com/android/launcher3/touch/PagedOrientationHandler.java
@@ -141,13 +141,12 @@
* @param desiredStagePosition Which stage position (topLeft/rightBottom) we want to resize
* outRect for
*/
- void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect,
- StagedSplitBounds splitInfo,
+ void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect, StagedSplitBounds splitInfo,
@SplitConfigurationOptions.StagePosition int desiredStagePosition);
void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
int parentWidth, int parentHeight,
- SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, DeviceProfile dp);
+ StagedSplitBounds splitBoundsConfig, DeviceProfile dp);
// Overview TaskMenuView methods
void setIconAndSnapshotParams(View iconView, int taskIconMargin, int taskIconHeight,
diff --git a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
index 576c6f5..ba9d09c 100644
--- a/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
+++ b/src/com/android/launcher3/touch/PortraitPagedViewHandler.java
@@ -16,7 +16,6 @@
package com.android.launcher3.touch;
-import static android.view.Gravity.BOTTOM;
import static android.view.Gravity.CENTER_HORIZONTAL;
import static android.view.Gravity.START;
import static android.view.Gravity.TOP;
@@ -452,24 +451,19 @@
public void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect,
StagedSplitBounds splitInfo, int desiredStagePosition) {
boolean isLandscape = dp.isLandscape;
- float verticalDividerDiff = splitInfo.visualDividerBounds.height() / 2f;
- float horizontalDividerDiff = splitInfo.visualDividerBounds.width() / 2f;
- float diff;
if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) {
if (isLandscape) {
- diff = outRect.width() * (1f - splitInfo.leftTaskPercent) + horizontalDividerDiff;
- outRect.right -= diff;
+ outRect.right = outRect.left + (int) (outRect.width() * splitInfo.leftTaskPercent);
} else {
- diff = outRect.height() * (1f - splitInfo.topTaskPercent) + verticalDividerDiff;
- outRect.bottom -= diff;
+ outRect.bottom = outRect.top + (int) (outRect.height() * splitInfo.topTaskPercent);
}
} else {
if (isLandscape) {
- diff = outRect.width() * splitInfo.leftTaskPercent + horizontalDividerDiff;
- outRect.left += diff;
+ outRect.left += (int) (outRect.width() *
+ (splitInfo.leftTaskPercent + splitInfo.dividerWidthPercent));
} else {
- diff = outRect.height() * splitInfo.topTaskPercent + verticalDividerDiff;
- outRect.top += diff;
+ outRect.top += (int) (outRect.height() *
+ (splitInfo.topTaskPercent + splitInfo.dividerHeightPercent));
}
}
}
@@ -477,12 +471,12 @@
@Override
public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
int parentWidth, int parentHeight,
- SplitConfigurationOptions.StagedSplitBounds splitBoundsConfig, DeviceProfile dp) {
+ StagedSplitBounds splitBoundsConfig, DeviceProfile dp) {
int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
- int dividerBar = (splitBoundsConfig.appsStackedVertically ?
- splitBoundsConfig.visualDividerBounds.height() :
- splitBoundsConfig.visualDividerBounds.width());
+ int dividerBar = splitBoundsConfig.appsStackedVertically
+ ? (int) (splitBoundsConfig.dividerHeightPercent * parentHeight)
+ : (int) (splitBoundsConfig.dividerWidthPercent * parentWidth);
int primarySnapshotHeight;
int primarySnapshotWidth;
int secondarySnapshotHeight;
@@ -535,23 +529,27 @@
(FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
FrameLayout.LayoutParams secondaryIconParams =
new FrameLayout.LayoutParams(primaryIconParams);
+ int dividerBar = (splitConfig.appsStackedVertically ?
+ splitConfig.visualDividerBounds.height() :
+ splitConfig.visualDividerBounds.width());
+ int primaryWidth = primarySnapshotBounds.width();
if (deviceProfile.isLandscape) {
- int primaryWidth = primarySnapshotBounds.width();
- int secondaryWidth = secondarySnapshotBounds.width();
primaryIconParams.gravity = TOP | START;
- primaryIconView.setTranslationX((primaryWidth - taskIconHeight) / 2f );
+ primaryIconView.setTranslationX(primaryWidth - primaryIconView.getWidth());
+ primaryIconView.setTranslationY(0);
secondaryIconParams.gravity = TOP | START;
- secondaryIconView.setTranslationX(primaryWidth
- + ((secondaryWidth - taskIconHeight) / 2f));
- } else {
- primaryIconView.setTranslationX(0);
- secondaryIconView.setTranslationX(0);
- primaryIconView.setTranslationY(0);
+ secondaryIconView.setTranslationX(primaryWidth + dividerBar);
secondaryIconView.setTranslationY(0);
- secondaryIconParams.gravity = BOTTOM | CENTER_HORIZONTAL;
- secondaryIconParams.bottomMargin = -(secondaryIconParams.topMargin + taskIconHeight);
+ } else {
+ primaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
+ primaryIconView.setTranslationX(-(primaryIconView.getWidth()) / 2f);
+ primaryIconView.setTranslationY(0);
+
+ secondaryIconParams.gravity = TOP | CENTER_HORIZONTAL;
+ secondaryIconView.setTranslationX(secondaryIconView.getWidth() / 2f);
+ secondaryIconView.setTranslationY(0);
}
primaryIconView.setLayoutParams(primaryIconParams);
secondaryIconView.setLayoutParams(secondaryIconParams);
diff --git a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
index d5851c8..a0dde22 100644
--- a/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
+++ b/src/com/android/launcher3/touch/SeascapePagedViewHandler.java
@@ -19,6 +19,7 @@
import static android.view.Gravity.CENTER_VERTICAL;
import static android.view.Gravity.END;
import static android.view.Gravity.START;
+import static android.view.Gravity.TOP;
import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -36,7 +37,9 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
+import com.android.launcher3.util.SplitConfigurationOptions.StagedSplitBounds;
import com.android.launcher3.views.BaseDragLayer;
import java.util.Collections;
@@ -127,6 +130,23 @@
iconParams.topMargin = snapshotParams.topMargin / 2;
}
+ @Override
+ public void setSplitIconParams(View primaryIconView, View secondaryIconView,
+ int taskIconHeight, Rect primarySnapshotBounds, Rect secondarySnapshotBounds,
+ boolean isRtl, DeviceProfile deviceProfile, StagedSplitBounds splitConfig) {
+ super.setSplitIconParams(primaryIconView, secondaryIconView, taskIconHeight,
+ primarySnapshotBounds, secondarySnapshotBounds, isRtl, deviceProfile, splitConfig);
+ FrameLayout.LayoutParams primaryIconParams =
+ (FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
+ FrameLayout.LayoutParams secondaryIconParams =
+ (FrameLayout.LayoutParams) secondaryIconView.getLayoutParams();
+
+ primaryIconParams.gravity = (isRtl ? END : START) | TOP;
+ secondaryIconParams.gravity = (isRtl ? END : START) | TOP;
+ primaryIconView.setLayoutParams(primaryIconParams);
+ secondaryIconView.setLayoutParams(secondaryIconParams);
+ }
+
/* ---------- The following are only used by TaskViewTouchHandler. ---------- */
@Override
diff --git a/src/com/android/launcher3/util/MultiValueAlpha.java b/src/com/android/launcher3/util/MultiValueAlpha.java
index bd39391..326141d 100644
--- a/src/com/android/launcher3/util/MultiValueAlpha.java
+++ b/src/com/android/launcher3/util/MultiValueAlpha.java
@@ -24,6 +24,7 @@
import com.android.launcher3.anim.AlphaUpdateListener;
import java.util.Arrays;
+import java.util.function.Consumer;
/**
* Utility class to handle separating a single value as a factor of multiple values
@@ -85,6 +86,8 @@
// Factor of all other alpha channels, only valid if mMyMask is present in mValidMask.
private float mOthers = 1;
+ private Consumer<Float> mConsumer;
+
AlphaProperty(int myMask) {
mMyMask = myMask;
}
@@ -109,16 +112,24 @@
mValidMask = mMyMask;
mValue = value;
- mView.setAlpha(mOthers * mValue);
+ final float alpha = mOthers * mValue;
+ mView.setAlpha(alpha);
if (mUpdateVisibility) {
AlphaUpdateListener.updateVisibility(mView);
}
+ if (mConsumer != null) {
+ mConsumer.accept(mValue);
+ }
}
public float getValue() {
return mValue;
}
+ public void setConsumer(Consumer<Float> consumer) {
+ mConsumer = consumer;
+ }
+
@Override
public String toString() {
return Float.toString(mValue);
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index 0b083e3..53b1c3e 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -85,6 +85,12 @@
}
}
+ /**
+ * NOTE: Engineers complained about too little ambiguity in the last survey, so there is a class
+ * with the same name/functionality in wm.shell.util (which launcher3 cannot be built against)
+ *
+ * If you make changes here, consider making the same changes there
+ */
public static class StagedSplitBounds {
public final Rect leftTopBounds;
public final Rect rightBottomBounds;
@@ -93,6 +99,8 @@
// This class is orientation-agnostic, so we compute both for later use
public final float topTaskPercent;
public final float leftTaskPercent;
+ public final float dividerWidthPercent;
+ public final float dividerHeightPercent;
/**
* If {@code true}, that means at the time of creation of this object, the
* split-screened apps were vertically stacked. This is useful in scenarios like
@@ -100,10 +108,15 @@
* the bounds were originally in
*/
public final boolean appsStackedVertically;
+ public final int leftTopTaskId;
+ public final int rightBottomTaskId;
- public StagedSplitBounds(Rect leftTopBounds, Rect rightBottomBounds) {
+ public StagedSplitBounds(Rect leftTopBounds, Rect rightBottomBounds, int leftTopTaskId,
+ int rightBottomTaskId) {
this.leftTopBounds = leftTopBounds;
this.rightBottomBounds = rightBottomBounds;
+ this.leftTopTaskId = leftTopTaskId;
+ this.rightBottomTaskId = rightBottomTaskId;
if (rightBottomBounds.top > leftTopBounds.top) {
// vertical apps, horizontal divider
@@ -119,6 +132,8 @@
leftTaskPercent = this.leftTopBounds.width() / (float) rightBottomBounds.right;
topTaskPercent = this.leftTopBounds.height() / (float) rightBottomBounds.bottom;
+ dividerWidthPercent = visualDividerBounds.width() / (float) rightBottomBounds.right;
+ dividerHeightPercent = visualDividerBounds.height() / (float) rightBottomBounds.bottom;
}
}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index 9774c46..fc8b4b7 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -37,7 +37,6 @@
import android.widget.Toast;
import androidx.annotation.Nullable;
-import androidx.annotation.VisibleForTesting;
import androidx.core.content.ContextCompat;
import com.android.launcher3.AbstractFloatingView;
@@ -176,11 +175,6 @@
return children;
}
- @VisibleForTesting
- public static ArrowPopup getOptionsPopup(Launcher launcher) {
- return launcher.findViewById(R.id.popup_container);
- }
-
/**
* Returns the list of supported actions
*/
diff --git a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
index 9c32e42..57f8bc7 100644
--- a/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/DeferredAppWidgetHostView.java
@@ -16,6 +16,7 @@
package com.android.launcher3.widget;
+import android.annotation.SuppressLint;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
import android.graphics.Canvas;
@@ -30,6 +31,9 @@
import com.android.launcher3.R;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
/**
* A widget host views created while the host has not bind to the system service.
*/
@@ -75,8 +79,22 @@
&& mSetupTextLayout.getWidth() == availableWidth) {
return;
}
- mSetupTextLayout = new StaticLayout(info.label, mPaint, availableWidth,
- Layout.Alignment.ALIGN_CENTER, 1, 0, true);
+ try {
+ mSetupTextLayout = new StaticLayout(info.label, mPaint, availableWidth,
+ Layout.Alignment.ALIGN_CENTER, 1, 0, true);
+ } catch (IllegalArgumentException e) {
+ @SuppressLint("DrawAllocation") StringWriter stringWriter = new StringWriter();
+ @SuppressLint("DrawAllocation") PrintWriter printWriter = new PrintWriter(stringWriter);
+ mActivity.getDeviceProfile().dump(/*prefix=*/"", printWriter);
+ printWriter.flush();
+ String message = "b/203530620 "
+ + "- availableWidth: " + availableWidth
+ + ", getMeasuredWidth: " + getMeasuredWidth()
+ + ", getPaddingLeft: " + getPaddingLeft()
+ + ", getPaddingRight: " + getPaddingRight()
+ + ", deviceProfile: " + stringWriter.toString();
+ throw new IllegalArgumentException(message, e);
+ }
}
@Override
diff --git a/src_plugins/com/android/systemui/plugins/OneSearch.java b/src_plugins/com/android/systemui/plugins/OneSearch.java
index 8bd0b75..13a956b 100644
--- a/src_plugins/com/android/systemui/plugins/OneSearch.java
+++ b/src_plugins/com/android/systemui/plugins/OneSearch.java
@@ -28,7 +28,7 @@
@ProvidesInterface(action = OneSearch.ACTION, version = OneSearch.VERSION)
public interface OneSearch extends Plugin {
String ACTION = "com.android.systemui.action.PLUGIN_ONE_SEARCH";
- int VERSION = 3;
+ int VERSION = 5;
/**
* Get the content provider warmed up.
@@ -37,7 +37,18 @@
/**
* Get the suggest search target list for the query.
+ *
* @param query The query to get the search suggests for.
*/
ArrayList<Parcelable> getSuggests(Parcelable query);
+
+ /** Get image bitmap with the URL. */
+ Parcelable getImageBitmap(String imageUrl);
+
+ /**
+ * Notifies search events to plugin
+ *
+ * @param event the SearchTargetEvent event created due to user action
+ */
+ void notifyEvent(Parcelable event);
}
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index aae8fb5..4390211 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -109,7 +109,7 @@
<activity
android:name="com.android.launcher3.testcomponent.TestLauncherActivity"
android:clearTaskOnLaunch="true"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|density"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
android:enabled="false"
android:label="Test launcher"
android:launchMode="singleTask"
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
index 16f024e..8a4590a 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
+++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
@@ -86,8 +86,6 @@
@Test
public void testFindSpaceForItem_prefers_second() throws Exception {
- mIdp.isSplitDisplay = false;
-
// First screen has only one hole of size 1
int nextId = setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3));
@@ -109,24 +107,6 @@
}
@Test
- public void testFindSpaceForItem_prefers_third_on_split_display() throws Exception {
- mIdp.isSplitDisplay = true;
- // First screen has only one hole of size 1
- int nextId = setupWorkspaceWithHoles(1, 1, new Rect(2, 2, 3, 3));
-
- // Second screen has 2 holes of sizes 3x2 and 2x3
- setupWorkspaceWithHoles(nextId, 2, new Rect(2, 0, 5, 2), new Rect(0, 2, 2, 5));
-
- int[] spaceFound = newTask().findSpaceForItem(
- mAppState, mModelHelper.getBgDataModel(), mExistingScreens, mNewScreens, 1, 1);
- // For split display, it picks the next screen, even if there is enough space
- // on previous screen
- assertEquals(2, spaceFound[0]);
- assertTrue(mScreenOccupancy.get(spaceFound[0])
- .isRegionVacant(spaceFound[1], spaceFound[2], 1, 1));
- }
-
- @Test
public void testFindSpaceForItem_adds_new_screen() throws Exception {
// First screen has 2 holes of sizes 3x2 and 2x3
setupWorkspaceWithHoles(1, 1, new Rect(2, 0, 5, 2), new Rect(0, 2, 2, 5));
diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index 48305ee..9c8de1c 100644
--- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.provider;
+import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import android.content.ContentValues;
@@ -87,6 +88,56 @@
assertEquals(1, getCount(db, "select * from favorites where profileId = 33"));
}
+ @Test
+ public void testRemoveScreenIdGaps_firstScreenEmpty() {
+ runRemoveScreenIdGapsTest(
+ new int[]{1, 2, 5, 6, 6, 7, 9, 9},
+ new int[]{1, 2, 3, 4, 4, 5, 6, 6});
+ }
+
+ @Test
+ public void testRemoveScreenIdGaps_firstScreenOccupied() {
+ runRemoveScreenIdGapsTest(
+ new int[]{0, 2, 5, 6, 6, 7, 9, 9},
+ new int[]{0, 1, 2, 3, 3, 4, 5, 5});
+ }
+
+ @Test
+ public void testRemoveScreenIdGaps_noGap() {
+ runRemoveScreenIdGapsTest(
+ new int[]{0, 1, 1, 2, 3, 3, 4, 5},
+ new int[]{0, 1, 1, 2, 3, 3, 4, 5});
+ }
+
+ private void runRemoveScreenIdGapsTest(int[] screenIds, int[] expectedScreenIds) {
+ SQLiteDatabase db = new MyDatabaseHelper(42).getWritableDatabase();
+ // Add some mock data
+ for (int i = 0; i < screenIds.length; i++) {
+ ContentValues values = new ContentValues();
+ values.put(Favorites._ID, i);
+ values.put(Favorites.SCREEN, screenIds[i]);
+ values.put(Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP);
+ db.insert(Favorites.TABLE_NAME, null, values);
+ }
+ // Verify items are added
+ assertEquals(screenIds.length,
+ getCount(db, "select * from favorites where container = -100"));
+
+ new RestoreDbTask().removeScreenIdGaps(db);
+
+ // verify screenId gaps removed
+ int[] resultScreenIds = new int[screenIds.length];
+ try (Cursor c = db.rawQuery(
+ "select screen from favorites where container = -100 order by screen", null)) {
+ int i = 0;
+ while (c.moveToNext()) {
+ resultScreenIds[i++] = c.getInt(0);
+ }
+ }
+
+ assertArrayEquals(expectedScreenIds, resultScreenIds);
+ }
+
private int getCount(SQLiteDatabase db, String sql) {
try (Cursor c = db.rawQuery(sql, null)) {
return c.getCount();
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 0ffbeeb..44f2719 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -211,7 +211,8 @@
}
protected TestRule getRulesInsideActivityMonitor() {
- final RuleChain inner = RuleChain.outerRule(new PortraitLandscapeRunner(this))
+ final RuleChain inner = RuleChain
+ .outerRule(new PortraitLandscapeRunner(this))
.around(new FailureWatcher(mDevice, mLauncher));
return TestHelpers.isInLauncherProcess()
@@ -345,13 +346,20 @@
}
// Cannot be used in TaplTests between a Tapl call injecting a gesture and a tapl call
- // expecting
- // the results of that gesture because the wait can hide flakeness.
+ // expecting the results of that gesture because the wait can hide flakeness.
protected void waitForState(String message, Supplier<LauncherState> state) {
waitForLauncherCondition(message,
launcher -> launcher.getStateManager().getCurrentStableState() == state.get());
}
+ // Cannot be used in TaplTests between a Tapl call injecting a gesture and a tapl call
+ // expecting the results of that gesture because the wait can hide flakeness.
+ protected void waitForStateTransitionToEnd(String message, Supplier<LauncherState> state) {
+ waitForLauncherCondition(message,
+ launcher -> launcher.getStateManager().isInStableState(state.get())
+ && !launcher.getStateManager().isInTransition());
+ }
+
protected void waitForResumed(String message) {
waitForLauncherCondition(message, launcher -> launcher.hasBeenResumed());
}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
index 881f50c..c90d283 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java
@@ -34,9 +34,10 @@
import com.android.launcher3.tapl.AppIcon;
import com.android.launcher3.tapl.AppIconMenu;
import com.android.launcher3.tapl.AppIconMenuItem;
+import com.android.launcher3.tapl.Folder;
+import com.android.launcher3.tapl.FolderIcon;
import com.android.launcher3.tapl.Widgets;
import com.android.launcher3.tapl.Workspace;
-import com.android.launcher3.views.OptionsPopupView;
import com.android.launcher3.widget.picker.WidgetsFullSheet;
import com.android.launcher3.widget.picker.WidgetsRecyclerView;
@@ -100,20 +101,12 @@
mDevice.pressMenu();
mDevice.waitForIdle();
executeOnLauncher(
- launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
- OptionsPopupView.getOptionsPopup(launcher) != null));
+ launcher -> assertNotNull("Launcher internal state didn't switch to Showing Menu",
+ launcher.getOptionsPopup()));
// Check that pressHome works when the menu is shown.
mLauncher.pressHome();
}
- @Ignore
- public void testOpenHomeSettingsFromWorkspace() {
- mDevice.pressMenu();
- mDevice.waitForIdle();
- mLauncher.getOptionsPopupMenu().getMenuItem("Home settings")
- .launch(mDevice.getLauncherPackageName());
- }
-
@Test
public void testPressHomeOnAllAppsContextMenu() throws Exception {
final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
@@ -284,7 +277,7 @@
}
private boolean isOptionsPopupVisible(Launcher launcher) {
- final ArrowPopup popup = OptionsPopupView.getOptionsPopup(launcher);
+ final ArrowPopup<?> popup = launcher.getOptionsPopup();
return popup != null && popup.isShown();
}
@@ -369,6 +362,71 @@
}
}
+ private AppIcon createShortcutIfNotExist(String name) {
+ AppIcon appIcon = mLauncher.getWorkspace().tryGetWorkspaceAppIcon(name);
+ if (appIcon == null) {
+ AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ allApps.freeze();
+ try {
+ appIcon = allApps.getAppIcon(name);
+ appIcon.dragToWorkspace(false, false);
+ } finally {
+ allApps.unfreeze();
+ }
+ appIcon = mLauncher.getWorkspace().getWorkspaceAppIcon(name);
+ }
+ return appIcon;
+ }
+
+ @Ignore("b/205014516")
+ @Test
+ @PortraitLandscape
+ public void testDragToFolder() throws Exception {
+ final AppIcon playStoreIcon = createShortcutIfNotExist("Play Store");
+ final AppIcon gmailIcon = createShortcutIfNotExist("Gmail");
+
+ FolderIcon folderIcon = gmailIcon.dragToIcon(playStoreIcon);
+
+ Folder folder = folderIcon.open();
+ folder.getAppIcon("Play Store");
+ folder.getAppIcon("Gmail");
+ Workspace workspace = folder.close();
+
+ assertNull("Gmail should be moved to a folder.",
+ workspace.tryGetWorkspaceAppIcon("Gmail"));
+ assertNull("Play Store should be moved to a folder.",
+ workspace.tryGetWorkspaceAppIcon("Play Store"));
+
+ final AppIcon youTubeIcon = createShortcutIfNotExist("YouTube");
+
+ folderIcon = youTubeIcon.dragToIcon(folderIcon);
+ folder = folderIcon.open();
+ folder.getAppIcon("YouTube");
+ folder.close();
+ }
+
+ @Ignore("b/205027405")
+ @Test
+ @PortraitLandscape
+ public void testPressBack() throws Exception {
+ mLauncher.getWorkspace().switchToAllApps();
+ mLauncher.pressBack();
+ mLauncher.getWorkspace();
+ waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
+
+ AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ allApps.freeze();
+ try {
+ allApps.getAppIcon(APP_NAME).dragToWorkspace(false, false);
+ } finally {
+ allApps.unfreeze();
+ }
+ mLauncher.getWorkspace().getWorkspaceAppIcon(APP_NAME).launch(getAppPackageName());
+ mLauncher.pressBack();
+ mLauncher.getWorkspace();
+ waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
+ }
+
public static String getAppPackageName() {
return getInstrumentation().getContext().getPackageName();
}
diff --git a/tests/src/com/android/launcher3/ui/WorkProfileTest.java b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
index fcb0b7f..45d20e2 100644
--- a/tests/src/com/android/launcher3/ui/WorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/WorkProfileTest.java
@@ -22,6 +22,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.util.Log;
import android.view.View;
import com.android.launcher3.R;
@@ -31,6 +32,7 @@
import com.android.launcher3.allapps.WorkEduCard;
import com.android.launcher3.allapps.WorkProfileManager;
import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import org.junit.After;
import org.junit.Before;
@@ -51,11 +53,21 @@
String output =
mDevice.executeShellCommand(
"pm create-user --profileOf 0 --managed TestProfile");
+ Log.d("b/203817455", "pm create-user; output: " + output);
assertTrue("Failed to create work profile", output.startsWith("Success"));
String[] tokens = output.split("\\s+");
mProfileUserId = Integer.parseInt(tokens[tokens.length - 1]);
mDevice.executeShellCommand("am start-user " + mProfileUserId);
+
+ mDevice.pressHome();
+ waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
+ waitForStateTransitionToEnd("Launcher internal state didn't switch to Normal",
+ () -> NORMAL);
+ waitForResumed("Launcher internal state is still Background");
+ executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
+ waitForStateTransitionToEnd("Launcher internal state didn't switch to All Apps",
+ () -> ALL_APPS);
}
@After
@@ -84,12 +96,8 @@
}
@Test
+ @ScreenRecord // b/202735477
public void workTabExists() {
- mDevice.pressHome();
- waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
- waitForState("Launcher internal state didn't switch to Normal", () -> NORMAL);
- executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
- waitForState("Launcher internal state didn't switch to All Apps", () -> ALL_APPS);
waitForLauncherCondition("Personal tab is missing",
launcher -> launcher.getAppsView().isPersonalTabVisible(),
LauncherInstrumentation.WAIT_TIME_MS);
@@ -100,12 +108,6 @@
@Test
public void toggleWorks() {
- mDevice.pressHome();
- waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
- waitForState("Launcher internal state didn't switch to Normal", () -> NORMAL);
- executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
- waitForState("Launcher internal state didn't switch to All Apps", () -> ALL_APPS);
-
waitForWorkTabSetup();
executeOnLauncher(launcher -> {
@@ -147,11 +149,6 @@
@Test
public void testEdu() {
- mDevice.pressHome();
- waitForLauncherCondition("Launcher didn't start", Objects::nonNull);
- waitForState("Launcher internal state didn't switch to Normal", () -> NORMAL);
- executeOnLauncher(launcher -> launcher.getStateManager().goToState(ALL_APPS));
- waitForState("Launcher internal state didn't switch to All Apps", () -> ALL_APPS);
waitForWorkTabSetup();
executeOnLauncher(l -> {
l.getSharedPrefs().edit().putInt(WorkAdapterProvider.KEY_WORK_EDU_STEP, 0).commit();
diff --git a/tests/tapl/com/android/launcher3/tapl/AppIcon.java b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
index 21099b4..6da59da 100644
--- a/tests/tapl/com/android/launcher3/tapl/AppIcon.java
+++ b/tests/tapl/com/android/launcher3/tapl/AppIcon.java
@@ -16,8 +16,11 @@
package com.android.launcher3.tapl;
+import android.graphics.Point;
+import android.graphics.Rect;
import android.widget.TextView;
+import androidx.annotation.NonNull;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.BySelector;
import androidx.test.uiautomator.UiObject2;
@@ -29,7 +32,7 @@
/**
* App icon, whether in all apps or in workspace/
*/
-public final class AppIcon extends Launchable {
+public final class AppIcon extends Launchable implements FolderDragTarget {
private static final Pattern LONG_CLICK_EVENT = Pattern.compile("onAllAppsItemLongClick");
@@ -61,6 +64,29 @@
}
}
+ /**
+ * Drag the AppIcon to the given position of other icon. The drag must result in a folder.
+ *
+ * @param target the destination icon.
+ */
+ @NonNull
+ public FolderIcon dragToIcon(FolderDragTarget target) {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer("want to drag icon")) {
+ final Rect dropBounds = target.getDropLocationBounds();
+ Workspace.dragIconToWorkspace(
+ mLauncher, this,
+ () -> {
+ final Rect bounds = target.getDropLocationBounds();
+ return new Point(bounds.centerX(), bounds.centerY());
+ },
+ getLongPressIndicator());
+ FolderIcon result = target.getTargetFolder(dropBounds);
+ mLauncher.assertTrue("Can't find the target folder.", result != null);
+ return result;
+ }
+ }
+
@Override
protected void addExpectedEventsForLongClick() {
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT);
@@ -80,4 +106,20 @@
protected String launchableType() {
return "app icon";
}
+
+ @Override
+ public Rect getDropLocationBounds() {
+ return mLauncher.getVisibleBounds(mObject);
+ }
+
+ @Override
+ public FolderIcon getTargetFolder(Rect bounds) {
+ for (FolderIcon folderIcon : mLauncher.getWorkspace().getFolderIcons()) {
+ final Rect folderIconBounds = folderIcon.getDropLocationBounds();
+ if (bounds.contains(folderIconBounds.centerX(), folderIconBounds.centerY())) {
+ return folderIcon;
+ }
+ }
+ return null;
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Background.java b/tests/tapl/com/android/launcher3/tapl/Background.java
index b290bb1..4eaecca 100644
--- a/tests/tapl/com/android/launcher3/tapl/Background.java
+++ b/tests/tapl/com/android/launcher3/tapl/Background.java
@@ -30,6 +30,7 @@
import com.android.launcher3.testing.TestProtocol;
+import java.util.List;
import java.util.regex.Pattern;
/**
@@ -62,11 +63,12 @@
"want to switch from background to overview")) {
verifyActiveContainer();
goToOverviewUnchecked();
- return mLauncher.isFallbackOverview() ?
- new BaseOverview(mLauncher) : new Overview(mLauncher);
+ return mLauncher.isFallbackOverview()
+ ? new BaseOverview(mLauncher) : new Overview(mLauncher);
}
}
+
protected boolean zeroButtonToOverviewGestureStartsInLauncher() {
return mLauncher.isTablet();
}
@@ -78,47 +80,56 @@
protected void goToOverviewUnchecked() {
switch (mLauncher.getNavigationModel()) {
case ZERO_BUTTON: {
- final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
- final int startY = getSwipeStartY();
- final int swipeHeight = mLauncher.getTestInfo(getSwipeHeightRequestName()).
- getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
- final Point start = new Point(centerX, startY);
- final Point end =
- new Point(centerX, startY - swipeHeight - mLauncher.getTouchSlop());
-
- final long downTime = SystemClock.uptimeMillis();
- final LauncherInstrumentation.GestureScope gestureScope =
- zeroButtonToOverviewGestureStartsInLauncher()
- ? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE
- : LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER;
-
- mLauncher.sendPointer(
- downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope);
- Runnable swipeAndHold = () -> mLauncher.movePointer(
- downTime,
- downTime,
- ZERO_BUTTON_SWIPE_UP_GESTURE_DURATION,
- start,
- end,
- gestureScope);
- String swipeAndHoldAction = "swiping and holding";
- Runnable up = () -> mLauncher.sendPointer(
- downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, end,
- gestureScope);
- String upAction = "sending UP event";
+ sendDownPointerToEnterOverviewToLauncher();
+ String swipeAndHoldToEnterOverviewActionName =
+ "swiping and holding to enter overview";
+ // If swiping from an app (e.g. Overview is in Background), we pause and hold on
+ // swipe up to make overview appear, or else swiping without holding would take
+ // us to the Home state. If swiping up from Home (e.g. Overview in Home or
+ // Workspace state where the below condition is true), there is no need to pause,
+ // and we will not test for an intermediate carousel as one will not exist.
if (zeroButtonToOverviewGestureStateTransitionWhileHolding()) {
- mLauncher.runToState(swipeAndHold, OVERVIEW_STATE_ORDINAL, swipeAndHoldAction);
- try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(upAction)) {
- up.run();
- }
+ mLauncher.runToState(this::sendSwipeUpAndHoldToEnterOverviewGestureToLauncher,
+ OVERVIEW_STATE_ORDINAL, swipeAndHoldToEnterOverviewActionName);
+ sendUpPointerToEnterOverviewToLauncher();
} else {
+ // If swiping up from an app to overview, pause on intermediate carousel
+ // until snapshots are visible. No intermediate carousel when swiping from
+ // Home. The task swiped up is not a snapshot but the TaskViewSimulator. If
+ // only a single task exists, no snapshots will be available during swipe up.
mLauncher.executeAndWaitForLauncherEvent(
- swipeAndHold,
+ this::sendSwipeUpAndHoldToEnterOverviewGestureToLauncher,
event -> TestProtocol.PAUSE_DETECTED_MESSAGE.equals(
- event.getClassName()),
+ event.getClassName().toString()),
() -> "Pause wasn't detected",
- swipeAndHoldAction);
- mLauncher.runToState(up, OVERVIEW_STATE_ORDINAL, upAction);
+ swipeAndHoldToEnterOverviewActionName);
+ try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "paused on swipe up to overview")) {
+ if (mLauncher.getRecentTasks().size() > 1) {
+ // When swiping up to grid-overview for tablets, the swiped tab will be
+ // in the middle of the screen (TaskViewSimulator, not a snapshot), and
+ // all remaining snapshots will be to the left of that task. In
+ // non-tablet overview, snapshots can be on either side of the swiped
+ // task, but we still check that they become visible after swiping and
+ // pausing.
+ mLauncher.waitForOverviewObject("snapshot");
+ if (mLauncher.isTablet()) {
+ List<UiObject2> tasks = mLauncher.getDevice().findObjects(
+ mLauncher.getOverviewObjectSelector("snapshot"));
+ final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
+ mLauncher.assertTrue(
+ "All tasks not to the left of the swiped task",
+ tasks.stream()
+ .allMatch(
+ t -> t.getVisibleBounds().right < centerX));
+ }
+
+ }
+ String upPointerToEnterOverviewActionName =
+ "sending UP pointer to enter overview";
+ mLauncher.runToState(this::sendUpPointerToEnterOverviewToLauncher,
+ OVERVIEW_STATE_ORDINAL, upPointerToEnterOverviewActionName);
+ }
}
break;
}
@@ -167,6 +178,60 @@
private void expectSwitchToOverviewEvents() {
}
+ private void sendDownPointerToEnterOverviewToLauncher() {
+ final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
+ final int startY = getSwipeStartY();
+ final Point start = new Point(centerX, startY);
+ final long downTime = SystemClock.uptimeMillis();
+ final LauncherInstrumentation.GestureScope gestureScope =
+ zeroButtonToOverviewGestureStartsInLauncher()
+ ? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE
+ : LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER;
+
+ mLauncher.sendPointer(
+ downTime, downTime, MotionEvent.ACTION_DOWN, start, gestureScope);
+ }
+
+ private void sendSwipeUpAndHoldToEnterOverviewGestureToLauncher() {
+ final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
+ final int startY = getSwipeStartY();
+ final int swipeHeight = mLauncher.getTestInfo(getSwipeHeightRequestName()).getInt(
+ TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ final Point start = new Point(centerX, startY);
+ final Point end =
+ new Point(centerX, startY - swipeHeight - mLauncher.getTouchSlop());
+ final long downTime = SystemClock.uptimeMillis();
+ final LauncherInstrumentation.GestureScope gestureScope =
+ zeroButtonToOverviewGestureStartsInLauncher()
+ ? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE
+ : LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER;
+
+ mLauncher.movePointer(
+ downTime,
+ downTime,
+ ZERO_BUTTON_SWIPE_UP_GESTURE_DURATION,
+ start,
+ end,
+ gestureScope);
+ }
+
+ private void sendUpPointerToEnterOverviewToLauncher() {
+ final int centerX = mLauncher.getDevice().getDisplayWidth() / 2;
+ final int startY = getSwipeStartY();
+ final int swipeHeight = mLauncher.getTestInfo(getSwipeHeightRequestName()).getInt(
+ TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ final Point end =
+ new Point(centerX, startY - swipeHeight - mLauncher.getTouchSlop());
+ final long downTime = SystemClock.uptimeMillis();
+ final LauncherInstrumentation.GestureScope gestureScope =
+ zeroButtonToOverviewGestureStartsInLauncher()
+ ? LauncherInstrumentation.GestureScope.INSIDE_TO_OUTSIDE
+ : LauncherInstrumentation.GestureScope.OUTSIDE_WITH_PILFER;
+
+ mLauncher.sendPointer(downTime, SystemClock.uptimeMillis(),
+ MotionEvent.ACTION_UP, end, gestureScope);
+ }
+
@NonNull
public Background quickSwitchToPreviousApp() {
boolean toRight = true;
diff --git a/tests/tapl/com/android/launcher3/tapl/Folder.java b/tests/tapl/com/android/launcher3/tapl/Folder.java
new file mode 100644
index 0000000..dba308d
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/Folder.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.tapl;
+
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.view.MotionEvent;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiObject2;
+
+public class Folder {
+
+ protected static final String FOLDER_CONTENT_RES_ID = "folder_content";
+
+ private final UiObject2 mContainer;
+ private final LauncherInstrumentation mLauncher;
+
+ Folder(LauncherInstrumentation launcher) {
+ this.mLauncher = launcher;
+ this.mContainer = launcher.waitForLauncherObject(FOLDER_CONTENT_RES_ID);
+ }
+
+ /**
+ * Find an app icon with given name or raise assertion error.
+ */
+ @NonNull
+ public AppIcon getAppIcon(String appName) {
+ try (LauncherInstrumentation.Closable ignored = mLauncher.addContextLayer(
+ "Want to get app icon in folder")) {
+ return new AppIcon(mLauncher,
+ mLauncher.waitForObjectInContainer(
+ mContainer,
+ AppIcon.getAppIconSelector(appName, mLauncher)));
+ }
+ }
+
+ private void touchOutsideFolder() {
+ Rect containerBounds = mLauncher.getVisibleBounds(this.mContainer);
+ final long downTime = SystemClock.uptimeMillis();
+ Point containerLeftTopCorner = new Point(containerBounds.left - 1, containerBounds.top - 1);
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
+ containerLeftTopCorner, LauncherInstrumentation.GestureScope.INSIDE);
+ mLauncher.sendPointer(downTime, downTime, MotionEvent.ACTION_UP,
+ containerLeftTopCorner, LauncherInstrumentation.GestureScope.INSIDE);
+ }
+
+ /**
+ * CLose opened folder if possible. It throws assertion error if the folder is already closed.
+ */
+ public Workspace close() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
+ "Want to close opened folder")) {
+ mLauncher.waitForLauncherObject(FOLDER_CONTENT_RES_ID);
+ touchOutsideFolder();
+ mLauncher.waitUntilLauncherObjectGone(FOLDER_CONTENT_RES_ID);
+ return mLauncher.getWorkspace();
+ }
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java b/tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java
new file mode 100644
index 0000000..d797418
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/FolderDragTarget.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.tapl;
+
+import android.graphics.Rect;
+
+public interface FolderDragTarget {
+ Rect getDropLocationBounds();
+
+ FolderIcon getTargetFolder(Rect bounds);
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/FolderIcon.java b/tests/tapl/com/android/launcher3/tapl/FolderIcon.java
new file mode 100644
index 0000000..2e79d70
--- /dev/null
+++ b/tests/tapl/com/android/launcher3/tapl/FolderIcon.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.tapl;
+
+import android.graphics.Rect;
+
+import androidx.annotation.NonNull;
+import androidx.test.uiautomator.UiObject2;
+
+import com.android.launcher3.testing.TestProtocol;
+
+/**
+ * Folder Icon, an app folder in workspace.
+ */
+public class FolderIcon implements FolderDragTarget {
+
+ protected final UiObject2 mObject;
+ protected final LauncherInstrumentation mLauncher;
+
+ FolderIcon(LauncherInstrumentation launcher, UiObject2 icon) {
+ mObject = icon;
+ mLauncher = launcher;
+ }
+
+ /**
+ * Open and return a folder or raise assertion error.
+ */
+ @NonNull
+ public Folder open() {
+ try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
+ LauncherInstrumentation.Closable c = mLauncher.addContextLayer("open folder")) {
+ mLauncher.executeAndWaitForLauncherEvent(() -> mLauncher.clickLauncherObject(mObject),
+ event -> TestProtocol.FOLDER_OPENED_MESSAGE.equals(
+ event.getClassName().toString()),
+ () -> "Fail to open folder.",
+ "open folder");
+ }
+ return new Folder(mLauncher);
+ }
+
+ @Override
+ public Rect getDropLocationBounds() {
+ return mLauncher.getVisibleBounds(mObject.getParent());
+ }
+
+ @Override
+ public FolderIcon getTargetFolder(Rect bounds) {
+ return this;
+ }
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 7ffdf4c..2fbe460 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -21,6 +21,7 @@
import static android.content.pm.PackageManager.MATCH_ALL;
import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static com.android.launcher3.tapl.Folder.FOLDER_CONTENT_RES_ID;
import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName;
import static com.android.launcher3.testing.TestProtocol.NORMAL_STATE_ORDINAL;
@@ -75,11 +76,13 @@
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Deque;
import java.util.LinkedList;
import java.util.List;
+import java.util.Optional;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.function.Consumer;
@@ -108,6 +111,9 @@
static final Pattern EVENT_TOUCH_DOWN_TIS = getTouchEventPatternTIS("ACTION_DOWN");
static final Pattern EVENT_TOUCH_UP_TIS = getTouchEventPatternTIS("ACTION_UP");
+ static final Pattern EVENT_KEY_BACK_DOWN = getKeyEventPattern("ACTION_DOWN", "KEYCODE_BACK");
+ static final Pattern EVENT_KEY_BACK_UP = getKeyEventPattern("ACTION_UP", "KEYCODE_BACK");
+
private final String mLauncherPackage;
private Boolean mIsLauncher3;
private long mTestStartTime = -1;
@@ -123,7 +129,8 @@
// Where the gesture happens: outside of Launcher, inside or from inside to outside and
// whether the gesture recognition triggers pilfer.
public enum GestureScope {
- OUTSIDE_WITHOUT_PILFER, OUTSIDE_WITH_PILFER, INSIDE, INSIDE_TO_OUTSIDE
+ OUTSIDE_WITHOUT_PILFER, OUTSIDE_WITH_PILFER, INSIDE, INSIDE_TO_OUTSIDE,
+ INSIDE_TO_OUTSIDE_WITHOUT_PILFER,
}
// Base class for launcher containers.
@@ -193,6 +200,10 @@
return getTouchEventPattern("TouchInteractionService.onInputEvent", action);
}
+ private static Pattern getKeyEventPattern(String action, String keyCode) {
+ return Pattern.compile("Key event: KeyEvent.*action=" + action + ".*keyCode=" + keyCode);
+ }
+
/**
* Constructs the root of TAPL hierarchy. You get all other objects from it.
*/
@@ -339,6 +350,10 @@
getTestInfo(TestProtocol.REQUEST_SET_FORCE_PAUSE_TIMEOUT, Long.toString(timeout));
}
+ public void setEnableRotation(boolean on) {
+ getTestInfo(TestProtocol.REQUEST_ENABLE_ROTATION, Boolean.toString(on));
+ }
+
public boolean hadNontestEvents() {
return getTestInfo(TestProtocol.REQUEST_GET_HAD_NONTEST_EVENTS)
.getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
@@ -768,6 +783,47 @@
}
/**
+ * Get the resource ID of visible floating view.
+ */
+ private Optional<String> getFloatingResId() {
+ if (hasLauncherObject(CONTEXT_MENU_RES_ID)) {
+ return Optional.of(CONTEXT_MENU_RES_ID);
+ }
+ if (hasLauncherObject(FOLDER_CONTENT_RES_ID)) {
+ return Optional.of(FOLDER_CONTENT_RES_ID);
+ }
+ return Optional.empty();
+ }
+
+ /**
+ * Using swiping up gesture to dismiss closable floating views, such as Menu or Folder Content.
+ */
+ private void swipeUpToCloseFloatingView(boolean gestureStartFromLauncher) {
+ final Point displaySize = getRealDisplaySize();
+
+ final Optional<String> floatingRes = getFloatingResId();
+
+ if (!floatingRes.isPresent()) {
+ return;
+ }
+
+ GestureScope gestureScope = gestureStartFromLauncher
+ ? (isTablet() ? GestureScope.INSIDE : GestureScope.INSIDE_TO_OUTSIDE)
+ : GestureScope.OUTSIDE_WITH_PILFER;
+ linearGesture(
+ displaySize.x / 2, displaySize.y - 1,
+ displaySize.x / 2, 0,
+ ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
+ false, gestureScope);
+
+ try (LauncherInstrumentation.Closable c1 = addContextLayer(
+ String.format("Swiped up from floating view %s to home", floatingRes.get()))) {
+ waitUntilLauncherObjectGone(floatingRes.get());
+ waitForLauncherObject(getAnyObjectSelector());
+ }
+ }
+
+ /**
* Presses nav bar home button.
*
* @return the Workspace object.
@@ -791,21 +847,9 @@
? !isLauncher3() || hasLauncherObject(WORKSPACE_RES_ID)
: isLauncherVisible();
- if (hasLauncherObject(CONTEXT_MENU_RES_ID)) {
- GestureScope gestureScope = gestureStartFromLauncher
- ? (isTablet() ? GestureScope.INSIDE : GestureScope.INSIDE_TO_OUTSIDE)
- : GestureScope.OUTSIDE_WITH_PILFER;
- linearGesture(
- displaySize.x / 2, displaySize.y - 1,
- displaySize.x / 2, 0,
- ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
- false, gestureScope);
- try (LauncherInstrumentation.Closable c1 = addContextLayer(
- "Swiped up from context menu to home")) {
- waitUntilLauncherObjectGone(CONTEXT_MENU_RES_ID);
- waitForLauncherObject(getAnyObjectSelector());
- }
- }
+ // CLose floating views before going back to home.
+ swipeUpToCloseFloatingView(gestureStartFromLauncher);
+
if (hasLauncherObject(WORKSPACE_RES_ID)) {
log(action = "already at home");
} else {
@@ -848,6 +892,38 @@
}
}
+ /**
+ * Press navbar back button or swipe back if in gesture navigation mode.
+ */
+ public void pressBack() {
+ try (Closable e = eventsCheck(); Closable c = addContextLayer("want to press back")) {
+ waitForLauncherInitialized();
+ final boolean launcherVisible =
+ isTablet() ? isLauncherContainerVisible() : isLauncherVisible();
+ if (getNavigationModel() == NavigationModel.ZERO_BUTTON) {
+ final Point displaySize = getRealDisplaySize();
+ final GestureScope gestureScope =
+ launcherVisible ? GestureScope.INSIDE_TO_OUTSIDE_WITHOUT_PILFER
+ : GestureScope.OUTSIDE_WITHOUT_PILFER;
+ linearGesture(0, displaySize.y / 2, displaySize.x / 2, displaySize.y / 2,
+ 10, false, gestureScope);
+ } else {
+ waitForNavigationUiObject("back").click();
+ if (isTablet()) {
+ expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_TOUCH_DOWN);
+ expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_TOUCH_UP);
+ } else if (!isLauncher3() && getNavigationModel() == NavigationModel.TWO_BUTTON) {
+ expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_DOWN_TIS);
+ expectEvent(TestProtocol.SEQUENCE_TIS, EVENT_TOUCH_UP_TIS);
+ }
+ }
+ if (launcherVisible) {
+ expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_DOWN);
+ expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_UP);
+ }
+ }
+ }
+
private static BySelector getAnyObjectSelector() {
return By.textStartsWith("");
}
@@ -857,6 +933,11 @@
return hasLauncherObject(getAnyObjectSelector());
}
+ boolean isLauncherContainerVisible() {
+ final String[] containerResources = {WORKSPACE_RES_ID, OVERVIEW_RES_ID, APPS_RES_ID};
+ return Arrays.stream(containerResources).anyMatch(r -> hasLauncherObject(r));
+ }
+
/**
* Gets the Workspace object if the current state is "active home", i.e. workspace. Fails if the
* launcher is not in that state.
@@ -944,20 +1025,6 @@
}
}
- /**
- * Gets the Options Popup Menu object if the current state is showing the popup menu. Fails if
- * the launcher is not in that state.
- *
- * @return Options Popup Menu object.
- */
- @NonNull
- public OptionsPopupMenu getOptionsPopupMenu() {
- try (LauncherInstrumentation.Closable c = addContextLayer(
- "want to get context menu object")) {
- return new OptionsPopupMenu(this);
- }
- }
-
void waitUntilLauncherObjectGone(String resId) {
waitUntilGoneBySelector(getLauncherObjectSelector(resId));
}
@@ -1075,6 +1142,11 @@
}
@NonNull
+ UiObject2 waitForOverviewObject(String resName) {
+ return waitForObjectBySelector(getOverviewObjectSelector(resName));
+ }
+
+ @NonNull
UiObject2 waitForLauncherObject(String resName) {
return waitForObjectBySelector(getLauncherObjectSelector(resName));
}
@@ -1383,6 +1455,7 @@
break;
case MotionEvent.ACTION_UP:
if (notLauncher3 && gestureScope != GestureScope.INSIDE
+ && gestureScope != GestureScope.INSIDE_TO_OUTSIDE_WITHOUT_PILFER
&& (gestureScope == GestureScope.OUTSIDE_WITH_PILFER
|| gestureScope == GestureScope.INSIDE_TO_OUTSIDE)) {
expectEvent(TestProtocol.SEQUENCE_PILFER, EVENT_PILFER_POINTERS);
diff --git a/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenu.java b/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenu.java
deleted file mode 100644
index 787dc70..0000000
--- a/tests/tapl/com/android/launcher3/tapl/OptionsPopupMenu.java
+++ /dev/null
@@ -1,41 +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.tapl;
-
-import androidx.annotation.NonNull;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiObject2;
-
-public class OptionsPopupMenu {
-
- private final LauncherInstrumentation mLauncher;
- private final UiObject2 mDeepShortcutsContainer;
-
- OptionsPopupMenu(LauncherInstrumentation launcher) {
- mLauncher = launcher;
- mDeepShortcutsContainer = launcher.waitForLauncherObject("popup_container");
- }
-
- /**
- * Returns a menu item with a given label. Fails if it doesn't exist.
- */
- @NonNull
- public OptionsPopupMenuItem getMenuItem(@NonNull final String label) {
- final UiObject2 menuItem = mLauncher.waitForObjectInContainer(mDeepShortcutsContainer,
- By.text(label));
- return new OptionsPopupMenuItem(mLauncher, menuItem);
- }
-}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 288c853..0145690 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -36,7 +36,10 @@
import com.android.launcher3.testing.TestProtocol;
+import java.util.List;
+import java.util.function.Supplier;
import java.util.regex.Pattern;
+import java.util.stream.Collectors;
/**
* Operations on the workspace screen.
@@ -170,40 +173,100 @@
mHotseat, AppIcon.getAppIconSelector(appName, mLauncher)));
}
- static void dragIconToWorkspace(
- LauncherInstrumentation launcher, Launchable launchable, Point dest,
- String longPressIndicator, boolean startsActivity, boolean isWidgetShortcut,
- Runnable expectLongClickEvents) {
- LauncherInstrumentation.log("dragIconToWorkspace: begin");
- final Point launchableCenter = launchable.getObject().getVisibleCenter();
- final long downTime = SystemClock.uptimeMillis();
- launcher.runToState(
- () -> {
- launcher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
- launchableCenter, LauncherInstrumentation.GestureScope.INSIDE);
- LauncherInstrumentation.log("dragIconToWorkspace: sent down");
- expectLongClickEvents.run();
- launcher.waitForLauncherObject(longPressIndicator);
- LauncherInstrumentation.log("dragIconToWorkspace: indicator");
- launcher.movePointer(launchableCenter, dest, 10, downTime, true,
- LauncherInstrumentation.GestureScope.INSIDE);
- },
- SPRING_LOADED_STATE_ORDINAL,
- "long-pressing and moving");
- LauncherInstrumentation.log("dragIconToWorkspace: moved pointer");
+ private static int getStartDragThreshold(LauncherInstrumentation launcher) {
+ return launcher.getTestInfo(TestProtocol.REQUEST_START_DRAG_THRESHOLD).getInt(
+ TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
+ /**
+ * Finds folder icons in the current workspace.
+ *
+ * @return a list of folder icons.
+ */
+ List<FolderIcon> getFolderIcons() {
+ final UiObject2 workspace = verifyActiveContainer();
+ return mLauncher.getObjectsInContainer(workspace, "folder_icon_name").stream().map(
+ o -> new FolderIcon(mLauncher, o)).collect(Collectors.toList());
+ }
+
+ /**
+ * Drag an icon up with a short distance that makes workspace go to spring loaded state.
+ *
+ * @return the position after dragging.
+ */
+ private static Point dragIconToSpringLoaded(LauncherInstrumentation launcher, long downTime,
+ UiObject2 icon,
+ String longPressIndicator, Runnable expectLongClickEvents) {
+ final Point iconCenter = icon.getVisibleCenter();
+ final Point dragStartCenter = new Point(iconCenter.x,
+ iconCenter.y - getStartDragThreshold(launcher));
+
+ launcher.runToState(() -> {
+ launcher.sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN,
+ iconCenter, LauncherInstrumentation.GestureScope.INSIDE);
+ LauncherInstrumentation.log("dragIconToSpringLoaded: sent down");
+ expectLongClickEvents.run();
+ launcher.waitForLauncherObject(longPressIndicator);
+ LauncherInstrumentation.log("dragIconToSpringLoaded: indicator");
+ launcher.movePointer(iconCenter, dragStartCenter, 10, downTime, true,
+ LauncherInstrumentation.GestureScope.INSIDE);
+ }, SPRING_LOADED_STATE_ORDINAL, "long-pressing and triggering drag start");
+ return dragStartCenter;
+ }
+
+ private static void dropDraggedIcon(LauncherInstrumentation launcher, Point dest, long downTime,
+ @Nullable Runnable expectedEvents) {
launcher.runToState(
() -> launcher.sendPointer(
downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, dest,
LauncherInstrumentation.GestureScope.INSIDE),
NORMAL_STATE_ORDINAL,
"sending UP event");
- if (startsActivity || isWidgetShortcut) {
- launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LauncherInstrumentation.EVENT_START);
+ if (expectedEvents != null) {
+ expectedEvents.run();
}
- LauncherInstrumentation.log("dragIconToWorkspace: end");
+ LauncherInstrumentation.log("dropIcon: end");
launcher.waitUntilLauncherObjectGone("drop_target_bar");
}
+ static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable,
+ Point dest, String longPressIndicator, boolean startsActivity, boolean isWidgetShortcut,
+ Runnable expectLongClickEvents) {
+ Runnable expectDropEvents = null;
+ if (startsActivity || isWidgetShortcut) {
+ expectDropEvents = () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN,
+ LauncherInstrumentation.EVENT_START);
+ }
+ dragIconToWorkspace(launcher, launchable, () -> dest, longPressIndicator,
+ expectLongClickEvents, expectDropEvents);
+ }
+
+ /**
+ * Drag icon in workspace to else where.
+ * This function expects the launchable is inside the workspace and there is no drop event.
+ */
+ static void dragIconToWorkspace(LauncherInstrumentation launcher, Launchable launchable,
+ Supplier<Point> destSupplier, String longPressIndicator) {
+ dragIconToWorkspace(launcher, launchable, destSupplier, longPressIndicator,
+ () -> launcher.expectEvent(TestProtocol.SEQUENCE_MAIN, LONG_CLICK_EVENT), null);
+ }
+
+ static void dragIconToWorkspace(
+ LauncherInstrumentation launcher, Launchable launchable, Supplier<Point> dest,
+ String longPressIndicator, Runnable expectLongClickEvents,
+ @Nullable Runnable expectDropEvents) {
+ try (LauncherInstrumentation.Closable ignored = launcher.addContextLayer(
+ "want to drag icon to workspace")) {
+ final long downTime = SystemClock.uptimeMillis();
+ final Point dragStartCenter = dragIconToSpringLoaded(launcher, downTime,
+ launchable.getObject(), longPressIndicator, expectLongClickEvents);
+ final Point targetDest = dest.get();
+ launcher.movePointer(dragStartCenter, targetDest, 10, downTime, true,
+ LauncherInstrumentation.GestureScope.INSIDE);
+ dropDraggedIcon(launcher, targetDest, downTime, expectDropEvents);
+ }
+ }
+
/**
* Flings to get to screens on the right. Waits for scrolling and a possible overscroll
* recoil to complete.