Merge "Tapping overflow button toggles KQS" into main
diff --git a/Android.bp b/Android.bp
index 9d7aa73..223e2c2 100644
--- a/Android.bp
+++ b/Android.bp
@@ -66,6 +66,8 @@
srcs: [
"quickstep/src/**/*.kt",
"quickstep/src/**/*.java",
+ ],
+ device_common_srcs: [
":launcher-quickstep-processed-protolog-src",
],
}
@@ -90,7 +92,7 @@
],
}
-genrule {
+java_genrule {
name: "launcher-quickstep-processed-protolog-src",
srcs: [
":protolog-impl",
@@ -108,7 +110,7 @@
out: ["launcher.quickstep.protolog.srcjar"],
}
-genrule {
+java_genrule {
name: "gen-launcher.quickstep.protolog.pb",
srcs: [
":launcher-quickstep-unprocessed-protolog-src",
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index c71b833..6ff3bb2 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -492,3 +492,10 @@
description: "Enforce system radius for widget corners instead of a separate 16.dp value"
bug: "370950552"
}
+
+flag {
+ name: "enable_launcher_pill"
+ namespace: "launcher"
+ description: "Enable Workspace Launcher Pill in Simple Mode View."
+ bug: "341217082"
+}
\ No newline at end of file
diff --git a/aconfig/launcher_overview.aconfig b/aconfig/launcher_overview.aconfig
index c59978f..4335f76 100644
--- a/aconfig/launcher_overview.aconfig
+++ b/aconfig/launcher_overview.aconfig
@@ -47,4 +47,11 @@
metadata {
purpose: PURPOSE_BUGFIX
}
+}
+
+flag {
+ name: "enable_desktop_windowing_carousel_detach"
+ namespace: "launcher_overview"
+ description: "Makes the desktop windowing task carousel detaches from fullscreen task carousel during quickswitch."
+ bug: "353947917"
}
\ No newline at end of file
diff --git a/quickstep/res/color/taskbar_minimized_app_indicator_color.xml b/quickstep/res/color/taskbar_minimized_app_indicator_color.xml
new file mode 100644
index 0000000..1596fe1
--- /dev/null
+++ b/quickstep/res/color/taskbar_minimized_app_indicator_color.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?attr/materialColorOutline"/>
+</selector>
diff --git a/quickstep/res/color/taskbar_running_app_indicator_color.xml b/quickstep/res/color/taskbar_running_app_indicator_color.xml
new file mode 100644
index 0000000..5dc9781
--- /dev/null
+++ b/quickstep/res/color/taskbar_running_app_indicator_color.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="?attr/materialColorTertiary"/>
+</selector>
diff --git a/quickstep/res/layout/taskbar_overflow_button.xml b/quickstep/res/layout/taskbar_overflow_view.xml
similarity index 86%
rename from quickstep/res/layout/taskbar_overflow_button.xml
rename to quickstep/res/layout/taskbar_overflow_view.xml
index 20104f2..7444e59 100644
--- a/quickstep/res/layout/taskbar_overflow_button.xml
+++ b/quickstep/res/layout/taskbar_overflow_view.xml
@@ -15,8 +15,7 @@
-->
<!-- Note: The actual size will match the taskbar icon sizes in TaskbarView#onLayout(). -->
-<com.android.launcher3.views.IconButtonView xmlns:android="http://schemas.android.com/apk/res/android"
- style="@style/BaseIcon.Workspace.Taskbar"
+<com.android.launcher3.taskbar.TaskbarOverflowView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/taskbar_icon_min_touch_size"
android:layout_height="@dimen/taskbar_icon_min_touch_size"
android:backgroundTint="@android:color/transparent"
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 5cbe556..eac8043 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Speld vas"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vormvry"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Rekenaar"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Skuif na eksterne skerm"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Werkskerm"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Geen onlangse items nie"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programgebruikinstellings"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Maak almal toe"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"vou <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> uit"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"vou <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> in"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Omkring en Soek"</string>
</resources>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index ce12f9d..b9ee381 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ሰካ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ነፃ ቅጽ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ዴስክቶፕ"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"ወደ ውጫዊ ማሳያ አንቀሳቅስ"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"ዴስክቶፕ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"የመተግበሪያ አጠቃቀም ቅንብሮች"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"ሁሉንም አሰናብት"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>ን ዘርጋ"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>ን ሰብስብ"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"ለመፈለግ ክበብ"</string>
</resources>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 0f3a854..b699d93 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"تثبيت"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"شكل مجاني"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"الكمبيوتر المكتبي"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"نقل التطبيق إلى شاشة خارجية"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"كمبيوتر مكتبي"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ما مِن عناصر تم استخدامها مؤخرًا"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"إعدادات استخدام التطبيق"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"إغلاق الكل"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"توسيع <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"تصغير <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"دائرة البحث"</string>
</resources>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 1d536e8..7599530 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"পিন"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ডেস্কটপ"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"বাহ্যিক ডিছপ্লে’লৈ নিয়ক"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"ডেস্কটপ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"কোনো শেহতীয়া বস্তু নাই"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"এপে ব্যৱহাৰ কৰা ডেটাৰ ছেটিং"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"সকলো অগ্ৰাহ্য কৰক"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> বিস্তাৰ কৰক"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> সংকোচন কৰক"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"সন্ধান কৰিবৰ বাবে বৃত্ত"</string>
</resources>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 2e6337a..a87ed44 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sancın"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Sərbəst rejim"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Masaüstü"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Xarici displeyə köçürün"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Masaüstü"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Son elementlər yoxdur"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tətbiq istifadə ayarları"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Hamısını kənarlaşdırın"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"genişləndirin: <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"yığcamlaşdırın: <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Dairəyə alaraq axtarın"</string>
</resources>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 93a8d48..cbcffdf 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Računar"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Premestite na spoljni ekran"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Računari"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Podešavanja korišćenja aplikacije"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Odbaci sve"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"proširite oblačić <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"skupite oblačić <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Pretraga zaokruživanjem"</string>
</resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 3f5a617..103e243 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Замацаваць"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Адвольная форма"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Працоўны стол"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Перамясціць на знешні дысплэй"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Працоўны стол"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Няма новых элементаў"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налады выкарыстання праграмы"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Закрыць усе"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>: разгарнуць"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>: згарнуць"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Абвесці для пошуку"</string>
</resources>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index adabb31..d624914 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Фиксиране"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Свободна форма"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"За компютър"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Преместване към външния екран"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Настолен компютър"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Няма скорошни елементи"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки за използването на приложенията"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Отхвърляне на всички"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"разгъване на <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"свиване на <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Търсене с ограждане"</string>
</resources>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 7d93d9b..c7bc2cf 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"পিন করুন"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ফ্রি-ফর্ম"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ডেস্কটপ"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"এক্সটার্নাল ডিসপ্লেতে সরিয়ে নিয়ে যান"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"ডেস্কটপ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"কোনও সাম্প্রতিক আইটেম নেই"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"অ্যাপ ব্যবহারের সেটিংস"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"সব বাতিল করুন"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> বড় করুন"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> আড়াল করুন"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"খোঁজার জন্য সার্কেল বানান"</string>
</resources>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 2ac0ab1..cea1921 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodan oblik"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Radna površina"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Premještanje na vanjski ekran"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Radna površina"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke korištenja aplikacije"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Odbacivanje svega"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"proširivanje oblačića <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"sužavanje oblačića <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Pretraživanje zaokruživanjem"</string>
</resources>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 1c27b08..e2352d7 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixa"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format lliure"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Escriptori"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Mou a la pantalla externa"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Escriptori"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hi ha cap element recent"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuració d\'ús d\'aplicacions"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Ignora-ho tot"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"desplega <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"replega <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Encercla per cercar"</string>
</resources>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 2f8d4b0..f868baa 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Připnout"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Neomezený režim"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Počítač"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Přesunout na externí displej"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Počítač"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Žádné položky z nedávné doby"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavení využití aplikací"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Zavřít vše"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"rozbalit <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"sbalit <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Zakroužkuj a hledej"</string>
</resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 4684af2..07ab18b 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fastgør"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Frit format"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Computertilstand"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Flyt til ekstern skærm"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Computer"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ingen nye elementer"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Indstillinger for appforbrug"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Afvis alle"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"udvid <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"skjul <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circle to Search"</string>
</resources>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 155abb4..f70e408 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixieren"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform-Modus"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktopmodus"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Auf externes Display verschieben"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Desktopmodus"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Keine kürzlich verwendeten Elemente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Einstellungen zur App-Nutzung"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Alle schließen"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"„<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>“ maximieren"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"„<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>“ minimieren"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circle to Search"</string>
</resources>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 39e8916..d7ff2ad 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Καρφίτσωμα"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Ελεύθερη μορφή"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Υπολογιστής"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Μετακίνηση σε εξωτερική οθόνη"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Υπολογιστής"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ρυθμίσεις χρήσης εφαρμογής"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Παράβλεψη όλων"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"ανάπτυξη <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"σύμπτυξη <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Κυκλώστε για αναζήτηση"</string>
</resources>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index bc73bfe..6b81b05 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Move to external display"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Dismiss all"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"expand <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"collapse <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circle to Search"</string>
</resources>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index bc73bfe..6b81b05 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Move to external display"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Dismiss all"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"expand <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"collapse <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circle to Search"</string>
</resources>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index bc73bfe..6b81b05 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Move to external display"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Dismiss all"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"expand <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"collapse <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circle to Search"</string>
</resources>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 25bbba2..57333f4 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formato libre"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Mover a pantalla externa"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Computadoras"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hay elementos recientes"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración de uso de la app"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Descartar todo"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"expandir <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"contraer <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Busca con un círculo"</string>
</resources>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index a4d7a8b..8355a88 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fijar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formato libre"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Mover a pantalla externa"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Ordenador"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No hay nada reciente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ajustes de uso de la aplicación"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Cerrar todo"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"desplegar <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"contraer <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Rodea para buscar"</string>
</resources>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 63d4d2f..6192e81 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kinnita"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vabavorm"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Lauaarvuti režiim"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Liikuge välisele ekraanile"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Töölaud"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Hiljutisi üksusi pole"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Rakenduse kasutuse seaded"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Loobu kõigist"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"Toiminguriba <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> laiendamine"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"Toiminguriba <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ahendamine"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Ring otsimiseks"</string>
</resources>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 3c0698c..de19f15 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Ainguratu"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Modu librea"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordenagailua"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Eraman kanpoko pantailara"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Mahaigaina"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ez dago azkenaldi honetako ezer"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Aplikazioen erabileraren ezarpenak"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Baztertu guztiak"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"zabaldu <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"tolestu <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Inguratu bilatzeko"</string>
</resources>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 8d5d15e..bc14f0b 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"پین"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"حالت رایانه"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"انتقال به نمایشگر خارجی"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"رایانه"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"چیز جدیدی اینجا نیست"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"تنظیمات استفاده از برنامه"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"رد کردن همه"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"ازهم باز کردن <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"جمع کردن <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"حلقه جستجو"</string>
</resources>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 10ea9ee..10e4699 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kiinnitä"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vapaamuotoinen"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Tietokone"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Siirrä ulkoiselle näytölle"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Tietokone"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ei viimeaikaisia kohteita"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Sovelluksen käyttöasetukset"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Hylkää kaikki"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"laajenna <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"tiivistä <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circle to Search"</string>
</resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index b624b4f..746bf50 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forme libre"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur de bureau"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Passer à un écran externe"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Ordinateur de bureau"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres d\'utilisation de l\'appli"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Tout ignorer"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"Développer <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"Réduire <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Encercler et rechercher"</string>
</resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 3f61d65..6d2fba2 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format libre"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Déplacer vers l\'écran externe"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Ordinateur"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres de consommation de l\'application"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Tout fermer"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"Développer <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"Réduire <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Entourer pour chercher"</string>
</resources>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index d9d06a1..d9a78ee 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libre"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Escritorio"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Mover á pantalla externa"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Ordenador"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Non hai elementos recentes"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configuración do uso de aplicacións"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Pechar todo"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"despregar <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"contraer <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Rodear para buscar"</string>
</resources>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 7716d4d..1bdcaa1 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"પિન કરો"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ફ્રિફોર્મ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ડેસ્કટૉપ"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"બાહ્ય ડિસ્પ્લે પર ખસેડો"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"ડેસ્કટૉપ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"તાજેતરની કોઈ આઇટમ નથી"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ઍપ વપરાશનું સેટિંગ"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"તમામ છોડી દો"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> મોટો કરો"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> નાનો કરો"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"શોધવા માટે વર્તુળ દોરો"</string>
</resources>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 02e23ec..e97aa78 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करें"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ़्रीफ़ॉर्म"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटॉप"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"बाहरी डिसप्ले पर जाएं"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"डेस्कटॉप"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"हाल ही का कोई आइटम नहीं है"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ऐप्लिकेशन इस्तेमाल की सेटिंग"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"सभी खारिज करें"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> को बड़ा करें"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> को छोटा करें"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"सर्कल बनाकर ढूंढें"</string>
</resources>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index a742c01..c350bc5 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Prikvači"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Računalo"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Premještanje na vanjski zaslon"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Radna površina"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nema nedavnih stavki"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Postavke upotrebe aplikacija"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Odbaci sve"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"proširite oblačić <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"sažmite oblačić <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Zaokružite i potražite"</string>
</resources>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 439d6ed..ea29620 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kitűzés"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Szabad forma"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Asztali"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Áthelyezés külső kijelzőre"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Asztali"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nincsenek mostanában használt elemek"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Alkalmazáshasználati beállítások"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Az összes elvetése"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> kibontása"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> összecsukása"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Bekarikázással keresés"</string>
</resources>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 87681c0..14d715d 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Ամրացնել"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Կամայական ձև"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Համակարգիչ"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Տեղափոխել արտաքին էկրան"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Համակարգիչ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Այստեղ դեռ ոչինչ չկա"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Հավելվածի օգտագործման կարգավորումներ"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Փակել բոլորը"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>. ծավալել"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>. ծալել"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Շրջագծել որոնելու համար"</string>
</resources>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 119ed6b..e1400a9 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sematkan"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format bebas"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Pindahkan ke layar eksternal"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Tidak ada item yang baru dibuka"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setelan penggunaan aplikasi"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Tutup semua"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"luaskan <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"ciutkan <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Lingkari untuk Menelusuri"</string>
</resources>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index 68f4656..bf2a211 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Festa"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Frjálst snið"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Tölva"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Færa í annað tæki"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Tölva"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Engin nýleg atriði"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Notkunarstillingar forrits"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Hunsa allt"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"stækka <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"minnka <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circle to Search"</string>
</resources>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 0498c4e..af77be4 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Blocca su schermo"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libera"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Sposta sul display esterno"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nessun elemento recente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Impostazioni di utilizzo delle app"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Ignora tutte"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"espandi <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"comprimi <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Cerchia e Cerca"</string>
</resources>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index ad52560..ad26421 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"הצמדה"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"מצב חופשי"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"במחשב"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"העברה למסך חיצוני"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"מחשב"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"אין פריטים אחרונים"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"הגדרות שימוש באפליקציה"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"ביטול של הכול"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"הרחבה של <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"כיווץ של <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"מקיפים ומחפשים"</string>
</resources>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 4cfe9ed..b30b000 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"フリーフォーム"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"デスクトップ"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"外部ディスプレイに移動する"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"パソコン"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近のアイテムはありません"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"アプリの使用状況の設定"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"すべて解除"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>を開きます"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>を閉じます"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"かこって検索"</string>
</resources>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index c02e9ad..1f877e9 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ჩამაგრება"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"თავისუფალი ფორმა"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"დესკტოპი"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"გარე ეკრანზე გადასვლა"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"დესკტოპი"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ბოლოს გამოყენებული ერთეულები არ არის"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"აპების გამოყენების პარამეტრები"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"ყველას დახურვა"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>-ის გაფართოება"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>-ის ჩაკეცვა"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"ძიება წრის მოხაზვით"</string>
</resources>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 64b3e53..5fd172e 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Бекіту"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Еркін форма"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Компьютер"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Сыртқы дисплейге ауыстыру"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Жұмыс үстелі"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Соңғы элементтер жоқ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Қолданбаны пайдалану параметрлері"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Барлығын жабу"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>: жаю"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>: жию"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Қоршау арқылы іздеу"</string>
</resources>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index d962ba5..4c8227e 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ខ្ទាស់"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"មុខងារទម្រង់សេរី"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ដែសថប"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"ផ្លាស់ទីទៅផ្ទាំងអេក្រង់ខាងក្រៅ"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"អេក្រង់ដើម"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"មិនមានធាតុថ្មីៗទេ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ការកំណត់ការប្រើប្រាស់កម្មវិធី"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"ច្រានចោលទាំងអស់"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"ពង្រីក <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"បង្រួម <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"គូររង្វង់ដើម្បីស្វែងរក"</string>
</resources>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 3a05e21..afd53ac 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ಪಿನ್ ಮಾಡಿ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ಮುಕ್ತಸ್ವರೂಪ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ಡೆಸ್ಕ್ಟಾಪ್"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"ಬಾಹ್ಯ ಡಿಸ್ಪ್ಲೇಗೆ ಸರಿಸಿ"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"ಡೆಸ್ಕ್ಟಾಪ್"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ಆ್ಯಪ್ ಬಳಕೆಯ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"ಎಲ್ಲವನ್ನು ವಜಾಗೊಳಿಸಿ"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ಅನ್ನು ವಿಸ್ತೃತಗೊಳಿಸಿ"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ಅನ್ನು ಕುಗ್ಗಿಸಿ"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"ಹುಡುಕಲು ಒಂದು ಸರ್ಕಲ್ ರಚಿಸಿ"</string>
</resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 6a7ba74..d602482 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"고정"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"자유 형식"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"데스크톱"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"외부 디스플레이로 이동"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"데스크톱"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"최근 항목이 없습니다."</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"앱 사용 설정"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"모두 닫기"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> 펼치기"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> 접기"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"서클 투 서치"</string>
</resources>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index e92b920..e5fed79 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Кадап коюу"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Эркин форма режими"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Компьютер"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Тышкы экранга жылдыруу"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Компьютер"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Акыркы колдонмолор жок"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Колдонмону пайдалануу параметрлери"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Баарын четке кагуу"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> жайып көрсөтүү"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> жыйыштыруу"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Тегеректеп издөө"</string>
</resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index f45c8ce..2df1a49 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ປັກໝຸດ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ຮູບແບບອິດສະຫລະ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ເດັສທັອບ"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"ຍ້າຍໄປຫາຈໍສະແດງຜົນພາຍນອກ"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"ເດັສທັອບ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ບໍ່ມີລາຍການຫຼ້າສຸດ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ການຕັ້ງຄ່າການນຳໃຊ້ແອັບ"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"ປິດທັງໝົດ"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"ຂະຫຍາຍ <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"ຫຍໍ້ <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ລົງ"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"ແຕ້ມວົງມົນເພື່ອຊອກຫາ"</string>
</resources>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index c488859..1d29f57 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Prisegti"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Laisva forma"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Stalinis kompiuteris"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Perkelkite į išorinį ekraną"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Stalinis kompiuteris"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nėra jokių naujausių elementų"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programos naudojimo nustatymai"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 23e64a7..805a598 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Piespraust"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Brīva forma"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Dators"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Pārvietošana uz ārējo displeju"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Darbvirsma"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nav nesenu vienumu."</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Lietotņu izmantošanas iestatījumi"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Nerādīt nevienu"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"izvērst “<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>”"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"sakļaut “<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>”"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Apvilkt un meklēt"</string>
</resources>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index f0588e8..2634b94 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Работна површина"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Префрлете се на надворешниот екран"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"За компјутер"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Нема неодамнешни ставки"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Поставки за користење на апликациите"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Отфрли ги сите"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"прошири <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"собери <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Пребарување со заокружување"</string>
</resources>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 833090c..92cad89 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"പിൻ ചെയ്യുക"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ഫ്രീഫോം"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ഡെസ്ക്ടോപ്പ്"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"ബാഹ്യ ഡിസ്പ്ലേയിലേക്ക് നീക്കുക"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"ഡെസ്ക്ടോപ്പ്"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ആപ്പ് ഉപയോഗ ക്രമീകരണം"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"എല്ലാം ഡിസ്മിസ് ചെയ്യുക"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> വികസിപ്പിക്കുക"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ചുരുക്കുക"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"തിരയാൻ വട്ടം വരയ്ക്കൽ"</string>
</resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 100b8ed..539e104 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Бэхлэх"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Чөлөөтэй хувьсах"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Компьютер"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Гадаад дэлгэц рүү зөөх"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Дэлгэц"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Сүүлийн үеийн зүйл алга"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Апп ашиглалтын тохиргоо"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Бүгдийг үл хэрэгсэх"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>-г дэлгэх"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>-г хураах"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Тойруулж зураад хай"</string>
</resources>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 870cf4e..dd2003f 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करा"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रीफॉर्म"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटॉप"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"बाह्य डिस्प्लेवर हलवा"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"डेस्कटॉप"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"कोणतेही अलीकडील आयटम नाहीत"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"अॅप वापर सेटिंग्ज"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"सर्व डिसमिस करा"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> चा विस्तार करा"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> कोलॅप्स करा"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"शोधण्यासाठी वर्तुळ करा"</string>
</resources>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index bed2fce..af388bc 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Semat"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Bentuk bebas"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Alihkan kepada paparan luaran"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Tiada item terbaharu"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Tetapan penggunaan apl"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Ketepikan semua"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"kembangkan <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"kuncupkan <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Bulatkan untuk Membuat Carian"</string>
</resources>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index ae0f66d..55b65c8 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ပင်ထိုးရန်"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"အလွတ်ပုံစံ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ဒက်စ်တော့"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"ပြင်ပဖန်သားပြင်သို့ ရွှေ့ရန်"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"ဒက်စ်တော့"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"အက်ပ်အသုံးပြုမှု ဆက်တင်များ"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"အားလုံးကို ပယ်ရန်"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ကို ပိုပြပါ"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ကို လျှော့ပြပါ"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"ရှာရန် ကွက်၍ဝိုင်းလိုက်ပါ"</string>
</resources>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 1ce18c1..077bc0a 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fest"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Skrivebord"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Flytt til ekstern skjerm"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Skrivebord"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ingen nylige elementer"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Innstillinger for appbruk"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Lukk alle"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"vis <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"skjul <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circle to Search"</string>
</resources>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 1921fed..49d1664 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन गर्नुहोस्"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रिफर्म"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटप"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"सारेर बाह्य डिस्प्लेमा लैजानुहोस्"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"डेस्कटप"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"हालसालैको कुनै पनि वस्तु छैन"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"एपको उपयोगका सेटिङहरू"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"सबै हटाउनुहोस्"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> एक्स्पान्ड गर्नुहोस्"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> कोल्याप्स गर्नुहोस्"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"खोज्न सर्कल बनाउनुहोस्"</string>
</resources>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 995d8d4..529516c 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Vastzetten"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vrije vorm"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Verplaatsen naar extern scherm"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Geen recente items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Instellingen voor app-gebruik"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Alles sluiten"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> uitvouwen"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> samenvouwen"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circle to Search"</string>
</resources>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 430058b..afc909d 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ପିନ୍"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ଫ୍ରିଫର୍ମ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ଡେସ୍କଟପ"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"ଏକ୍ସଟର୍ନଲ ଡିସପ୍ଲେକୁ ମୁଭ କରନ୍ତୁ"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"ଡେସ୍କଟପ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ବର୍ତ୍ତମାନର କୌଣସି ଆଇଟମ ନାହିଁ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ଆପ ବ୍ୟବହାର ସେଟିଂସ"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"ସବୁ ଖାରଜ କରନ୍ତୁ"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ବିସ୍ତାର କରନ୍ତୁ"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"ସର୍ଚ୍ଚ କରିବାକୁ ସର୍କଲ କରନ୍ତୁ"</string>
</resources>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index d8d0907..69b33f9 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ਪਿੰਨ ਕਰੋ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ਫ੍ਰੀਫਾਰਮ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ਡੈਸਕਟਾਪ"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"ਬਾਹਰੀ ਡਿਸਪਲੇ \'ਤੇ ਜਾਓ"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"ਡੈਸਕਟਾਪ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮ ਨਹੀਂ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ਐਪ ਵਰਤੋਂ ਦੀਆਂ ਸੈਟਿੰਗਾਂ"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"ਸਭ ਖਾਰਜ ਕਰੋ"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ਨੂੰ ਸਮੇਟੋ"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"ਖੋਜਣ ਲਈ ਚੱਕਰ ਬਣਾਓ"</string>
</resources>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 957e5c4..88b5053 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Przypnij"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Tryb dowolny"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Pulpit"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Przenieś na wyświetlacz zewnętrzny"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Pulpit"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Brak ostatnich elementów"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ustawienia użycia aplikacji"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Zamknij wszystkie"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"rozwiń dymek: <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"zwiń dymek: <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Zaznacz, aby wyszukać"</string>
</resources>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index ca7cd58..84120a1 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma livre"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Computador"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Mover para o ecrã externo"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Computador"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Definições de utilização de aplicações"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Ignorar tudo"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"expandir <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"reduzir <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circundar para Pesquisar"</string>
</resources>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index aee1c8d..3238c99 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma livre"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Modo área de trabalho"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Mover para a tela externa"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Computador"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nenhum item recente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Configurações de uso do app"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Dispensar todos"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"abrir <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"fechar <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circule para pesquisar"</string>
</resources>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index c05b85b..e6aad47 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixează"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formă liberă"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Mută pe ecranul extern"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Computer"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Niciun element recent"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setări de utilizare a aplicației"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Închide-le pe toate"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"extinde <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"restrânge <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Încercuiește și caută"</string>
</resources>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index fca0a05..297ae02 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закрепить"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Произвольная форма"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Мультиоконный режим"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Перенести на внешний дисплей"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Мультиоконный режим"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Здесь пока ничего нет."</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки использования приложения"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Закрыть все"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"Развернуто: <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"Свернуто: <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Обвести и найти"</string>
</resources>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index cfbf1dd..2c7c672 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"අමුණන්න"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ඩෙස්ක්ටොපය"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"බාහිර සංදර්ශකය වෙත ගෙන යන්න"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"ඩෙස්ක්ටොපය"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"මෑත අයිතම නැත"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"යෙදුම් භාවිත සැකසීම්"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"සියල්ල ඉවතලන්න"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> දිග හරින්න"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> හකුළන්න"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"සෙවීමට කවයසෙවීමට කවය අදින්න"</string>
</resources>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index b3145de..638e88a 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pripnúť"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Voľný režim"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Počítač"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Presunúť na externú obrazovku"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Počítač"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Žiadne nedávne položky"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavenia využívania aplikácie"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Zavrieť všetko"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"rozbaliť <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"zbaliť <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Vyhľadávanie krúžením"</string>
</resources>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index d72436a..30d2c03 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pripni"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Prosta oblika"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Namizni računalnik"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Premik v zunanji zaslon"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Namizni način"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ni nedavnih elementov"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavitve uporabe aplikacij"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Opusti vse"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"razširitev oblačka <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"strnitev oblačka <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Iskanje z obkroževanjem"</string>
</resources>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 30ba61d..b4b6711 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Gozhdo"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Formë e lirë"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktopi"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Zhvendose tek ekrani i jashtëm"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Desktopi"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nuk ka asnjë artikull të fundit"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cilësimet e përdorimit të aplikacionit"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Hiqi të gjitha"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"zgjero <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"palos <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Qarko për të kërkuar"</string>
</resources>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index b83a4f2..6622217 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Слободни облик"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Рачунар"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Преместите на спољни екран"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Рачунари"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Нема недавних ставки"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Подешавања коришћења апликације"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Одбаци све"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"проширите облачић <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"скупите облачић <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Претрага заокруживањем"</string>
</resources>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 5ab3866..089d1b5 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fäst"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Dator"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Flytta till extern skärm"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Dator"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Listan är tom"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Inställningar för appanvändning"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Stäng alla"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"utöka <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"komprimera <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circle to Search"</string>
</resources>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 9d13df8..821797b 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Bandika"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Muundo huru"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Kompyuta ya mezani"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Hamishia programu kwenye skrini ya nje"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Kompyuta ya Mezani"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Hakuna vipengee vya hivi karibuni"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mipangilio ya matumizi ya programu"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Ondoa vyote"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"panua <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"kunja <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Chora Mviringo ili Kutafuta"</string>
</resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 8ac0ff8..7bbfaba 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"பின் செய்தல்"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"குறிப்பிட்ட வடிவமில்லாத பயன்முறை"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"டெஸ்க்டாப்"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"வெளிப்புற டிஸ்ப்ளேவிற்கு நகர்த்துதல்"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"டெஸ்க்டாப்"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"சமீபத்தியவை எதுவுமில்லை"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ஆப்ஸ் உபயோக அமைப்புகள்"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"அனைத்தையும் மூடும்"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ஐ விரிவாக்கும்"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> ஐச் சுருக்கும்"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"வட்டமிட்டுத் தேடல்"</string>
</resources>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 4ae7a58..5439e80 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"పిన్ చేయండి"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"సంప్రదాయేతర"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"డెస్క్టాప్"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"ఎక్స్టర్నల్ డిస్ప్లేకు తరలించండి"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"డెస్క్టాప్"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ఇటీవలి ఐటెమ్లు ఏవీ లేవు"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"యాప్ వినియోగ సెట్టింగ్లు"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"అన్నింటినీ విస్మరించండి"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>ను విస్తరించండి"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>ను కుదించండి"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"సెర్చ్ చేయడానికి సర్కిల్ గీయండి"</string>
</resources>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 210e996..99b53d9 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"ปักหมุด"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"รูปแบบอิสระ"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"เดสก์ท็อป"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"ย้ายไปยังจอแสดงผลภายนอก"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"เดสก์ท็อป"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ไม่มีรายการล่าสุด"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"การตั้งค่าการใช้แอป"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"ปิดทั้งหมด"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"ขยาย <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"ยุบ <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"วงเพื่อค้นหา"</string>
</resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 13d89a2..583f419 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"I-pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Ilipat sa external na display"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Walang kamakailang item"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Mga setting ng paggamit ng app"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"I-dismiss lahat"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"i-expand ang <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"i-collapse ang <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Circle to Search"</string>
</resources>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 1cb1fa7..c50c1f8 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sabitle"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Serbest çalışma"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Masaüstü"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Harici ekrana taşı"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Masaüstü"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Yeni öğe yok"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Uygulama kullanım ayarları"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Tümünü kapat"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"genişlet: <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"daralt: <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Seçerek Arat"</string>
</resources>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 84ddd81..d75f8b4 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закріпити"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Довільна форма"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Робочий стіл"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Перемістити на зовнішній екран"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Комп’ютер"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Немає нещодавніх додатків"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Налаштування використання додатка"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Закрити все"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"розгорнути \"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>\""</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"згорнути \"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>\""</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Обвести й знайти"</string>
</resources>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 43e97c2..68f838f 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"پن کریں"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"فری فارم"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"ڈیسک ٹاپ"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"بیرونی ڈسپلے پر متقل کریں"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"ڈیسک ٹاپ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"کوئی حالیہ آئٹم نہیں"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ایپ کے استعمال کی ترتیبات"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"سبھی کو برخاست کریں"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> کو پھیلائیں"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g> کو سکیڑیں"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"تلاش کرنے کیلئے دائرہ بنائیں"</string>
</resources>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 090753f..294be84 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Qadash"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Erkin shakl"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Tashqi displeyga olish"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Yaqinda ishlatilgan ilovalar yo‘q"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ilovadan foydalanish sozlamalari"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Hammasini yopish"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>ni yoyish"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>ni yigʻish"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Chizib qidirish"</string>
</resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index b0d31cb..3a32551 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Ghim"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Dạng tự do"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Máy tính"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Chuyển sang màn hình ngoài"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Máy tính"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Không có mục gần đây nào"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Cài đặt mức sử dụng ứng dụng"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Đóng tất cả"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"mở rộng <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"thu gọn <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Khoanh tròn để tìm kiếm"</string>
</resources>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 73121b4..eee46bb 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由窗口"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"桌面"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"移至外接显示屏"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"桌面设备"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"近期没有任何内容"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"应用使用设置"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"全部关闭"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"展开“<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>”"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"收起“<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>”"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"圈定即搜"</string>
</resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index b934dfc..c8d18eb 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"桌面"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"移至外部顯示屏"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"桌面"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"全部關閉"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"打開<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"收埋<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"一圈即搜"</string>
</resources>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 1cba819..fd132d2 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"桌面"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"移至外接螢幕"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"電腦"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"全部關閉"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"展開「<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>」"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"收合「<xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>」"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"畫圈搜尋"</string>
</resources>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index ee6b3b7..46dbbd5 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -22,8 +22,7 @@
<string name="recent_task_option_pin" msgid="7929860679018978258">"Phina"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"I-Freeform"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Ideskithophu"</string>
- <!-- no translation found for recent_task_option_external_display (4533840664313389484) -->
- <skip />
+ <string name="recent_task_option_external_display" msgid="4533840664313389484">"Hambisa esibonisini sangaphandle"</string>
<string name="recent_task_desktop" msgid="8081113562549637334">"Ideskithophu"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Azikho izinto zakamuva"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Izilungiselelo zokusetshenziswa kohlelo lokusebenza"</string>
@@ -156,6 +155,5 @@
<string name="bubble_bar_action_dismiss_all" msgid="3290722022983403060">"Chitha konke"</string>
<string name="bubble_bar_accessibility_announce_expand" msgid="1503192695527477102">"nweba <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
<string name="bubble_bar_accessibility_announce_collapse" msgid="928284600086798791">"goqa <xliff:g id="BUBBLE_DESCRIPTION">%1$s</xliff:g>"</string>
- <!-- no translation found for search_gesture_feature_title (1294044108313175306) -->
- <skip />
+ <string name="search_gesture_feature_title" msgid="1294044108313175306">"Khethela Ukusesha"</string>
</resources>
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index db5ff19..3ae2b89 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -38,7 +38,6 @@
<string name="nav_handle_long_press_handler_class" translatable="false"></string>
<string name="contextual_search_invoker_class" translatable="false"></string>
<string name="contextual_search_state_manager_class" translatable="false"></string>
- <string name="api_wrapper_class" translatable="false">com.android.launcher3.uioverrides.SystemApiWrapper</string>
<!-- The number of thumbnails and icons to keep in the cache. The thumbnail cache size also
determines how many thumbnails will be fetched in the background. -->
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 5f35007..451ba55 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -360,6 +360,7 @@
<dimen name="taskbar_running_app_indicator_width">12dp</dimen>
<dimen name="taskbar_running_app_indicator_top_margin">4dp</dimen>
<dimen name="taskbar_minimized_app_indicator_width">6dp</dimen>
+ <dimen name="taskbar_overflow_button_preview_stroke">2dp</dimen>
<!-- Transient taskbar -->
<dimen name="transient_taskbar_padding">12dp</dimen>
@@ -502,6 +503,7 @@
<dimen name="keyboard_quick_switch_recents_icon_size">20dp</dimen>
<dimen name="keyboard_quick_switch_desktop_icon_size">32dp</dimen>
<dimen name="keyboard_quick_switch_margin_top">56dp</dimen>
+ <dimen name="keyboard_quick_switch_margin_bottom">24dp</dimen>
<dimen name="keyboard_quick_switch_margin_ends">16dp</dimen>
<dimen name="keyboard_quick_switch_view_spacing">16dp</dimen>
<dimen name="keyboard_quick_switch_view_small_spacing">4dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 29e1f4e..2f4c6f6 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -59,7 +59,6 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
@@ -156,9 +155,6 @@
state.containerId);
FixedContainerItems fci = new FixedContainerItems(state.containerId,
state.storage.read(mApp.getContext(), factory, ums.allUsers::get));
- if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
- bindPredictionItems(callbacks, fci);
- }
mDataModel.extraItems.put(state.containerId, fci);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
index 50a253c..05d34b5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchView.java
@@ -131,6 +131,15 @@
}
@Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+
+ if (mViewCallbacks != null) {
+ mViewCallbacks.onViewDetchedFromWindow();
+ }
+ }
+
+ @Override
protected void onFinishInflate() {
super.onFinishInflate();
mNoRecentItemsPane = findViewById(R.id.no_recent_items_pane);
@@ -281,6 +290,10 @@
return mDesktopTaskIndex;
}
+ void resetViewCallbacks() {
+ mViewCallbacks = null;
+ }
+
protected Animator getCloseAnimation() {
AnimatorSet closeAnimation = new AnimatorSet();
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index fbbdc45..3f71870 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -20,6 +20,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.content.res.Resources;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -30,6 +31,7 @@
import androidx.annotation.Nullable;
import com.android.internal.jank.Cuj;
+import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.desktop.DesktopAppLaunchTransition;
@@ -69,6 +71,8 @@
private boolean mWasDesktopTaskFilteredOut;
private boolean mWasOpenedFromTaskbar;
+ private boolean mDetachingFromWindow = false;
+
protected KeyboardQuickSwitchViewController(
@NonNull TaskbarControllers controllers,
@NonNull TaskbarOverlayContext overlayContext,
@@ -121,6 +125,12 @@
BaseDragLayer.LayoutParams lp = new BaseDragLayer.LayoutParams(
mKeyboardQuickSwitchView.getLayoutParams());
+ final Resources resources = mKeyboardQuickSwitchView.getResources();
+ final int marginHorizontal = resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_margin_ends);
+ final int marginBottom = resources.getDimensionPixelSize(
+ R.dimen.keyboard_quick_switch_margin_bottom);
+ lp.setMargins(marginHorizontal, 0, marginHorizontal, marginBottom);
lp.width = BaseDragLayer.LayoutParams.WRAP_CONTENT;
lp.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
mKeyboardQuickSwitchView.setLayoutParams(lp);
@@ -235,7 +245,12 @@
private void onCloseComplete() {
mCloseAnimation = null;
- mOverlayContext.getDragLayer().removeView(mKeyboardQuickSwitchView);
+ // Reset the view callbacks to prevent `onDetachedFromWindow` getting called in response to
+ // the `removeView(mKeyboardQuickSwitchView)` call.
+ mKeyboardQuickSwitchView.resetViewCallbacks();
+ if (!mDetachingFromWindow) {
+ mOverlayContext.getDragLayer().removeView(mKeyboardQuickSwitchView);
+ }
mControllerCallbacks.onCloseComplete();
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_CLOSE);
}
@@ -326,5 +341,11 @@
boolean isAspectRatioSquare() {
return mControllerCallbacks.isAspectRatioSquare();
}
+
+ void onViewDetchedFromWindow() {
+ mDetachingFromWindow = true;
+ closeQuickSwitchView(false);
+ mDetachingFromWindow = false;
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 042bc9a..09dbeb6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -36,7 +36,6 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.data.ItemInfo;
@@ -69,17 +68,14 @@
public static final int ALL_APPS_PAGE_PROGRESS_INDEX = 1;
public static final int WIDGETS_PAGE_PROGRESS_INDEX = 2;
public static final int SYSUI_SURFACE_PROGRESS_INDEX = 3;
- public static final int LAUNCHER_PAUSE_PROGRESS_INDEX = 4;
- public static final int DISPLAY_PROGRESS_COUNT = 5;
+ public static final int DISPLAY_PROGRESS_COUNT = 4;
private final AnimatedFloat mTaskbarInAppDisplayProgress = new AnimatedFloat(
this::onInAppDisplayProgressChanged);
private final MultiPropertyFactory<AnimatedFloat> mTaskbarInAppDisplayProgressMultiProp =
new MultiPropertyFactory<>(mTaskbarInAppDisplayProgress,
AnimatedFloat.VALUE, DISPLAY_PROGRESS_COUNT, Float::max);
- private final AnimatedFloat mLauncherPauseProgress = new AnimatedFloat(
- this::launcherPauseProgressUpdate);
private final QuickstepLauncher mLauncher;
private final HomeVisibilityState mHomeState;
@@ -195,33 +191,6 @@
}
/**
- * Called when Launcher Activity is paused/resumed.
- * <p>
- * To avoid UI clash between taskbar & bottom sheet, shift nav buttons down on launcher
- * pause/resume at home.
- * @param paused if launcher is currently paused.
- */
- public void onLauncherPausedOrResumed(boolean paused) {
- if (!FeatureFlags.enableHomeTransitionListener()) {
- onLauncherVisibilityChanged(mLauncher.hasBeenResumed());
- return;
- }
-
- // Animate navbar iff pause/resume from home, NOT to/from app (avoid overriding existing
- // animations).
- boolean launcherPauseOrResumeFromHome = mHomeState.isHomeVisible() && mControllers
- .taskbarAutohideSuspendController.isSuspendedForTransientTaskbarInLauncher();
- if (launcherPauseOrResumeFromHome) {
- mLauncherPauseProgress.animateToValue(paused ? 1.0f : 0.0f).start();
- }
- }
-
- private void launcherPauseProgressUpdate() {
- onTaskbarInAppDisplayProgressUpdate(
- mLauncherPauseProgress.value, LAUNCHER_PAUSE_PROGRESS_INDEX);
- }
-
- /**
* Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
*/
@Override
@@ -395,20 +364,18 @@
}
if (mControllers.uiController.isIconAlignedWithHotseat()
&& !mTaskbarLauncherStateController.isAnimatingToLauncher()) {
- // Only animate nav button position while home and not animating home, otherwise let
+ // Only animate the nav buttons while home and not animating home, otherwise let
// the TaskbarViewController handle it.
mControllers.navbarButtonsViewController
- .getNavButtonTranslationYForInAppDisplay()
+ .getTaskbarNavButtonTranslationYForInAppDisplay()
.updateValue(mLauncher.getDeviceProfile().getTaskbarOffsetY()
* mTaskbarInAppDisplayProgress.value);
- if (!mLauncher.isPaused()) {
- mControllers.navbarButtonsViewController
- .getOnTaskbarBackgroundNavButtonColorOverride().updateValue(progress);
- }
+ mControllers.navbarButtonsViewController
+ .getOnTaskbarBackgroundNavButtonColorOverride().updateValue(progress);
}
}
- @Override
+ /** Returns true iff any in-app display progress > 0. */
public boolean shouldUseInAppLayout() {
return mTaskbarInAppDisplayProgress.value > 0;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index cfcbd2f..7d8e93c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -183,7 +183,7 @@
private final AnimatedFloat mTaskbarNavButtonTranslationY = new AnimatedFloat(
this::updateNavButtonTranslationY);
- private final AnimatedFloat mNavButtonTranslationYForInAppDisplay = new AnimatedFloat(
+ private final AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay = new AnimatedFloat(
this::updateNavButtonTranslationY);
private final AnimatedFloat mTaskbarNavButtonTranslationYForIme = new AnimatedFloat(
this::updateNavButtonTranslationY);
@@ -704,8 +704,8 @@
}
/** Use to set the translationY for the all nav+contextual buttons when in Launcher */
- public AnimatedFloat getNavButtonTranslationYForInAppDisplay() {
- return mNavButtonTranslationYForInAppDisplay;
+ public AnimatedFloat getTaskbarNavButtonTranslationYForInAppDisplay() {
+ return mTaskbarNavButtonTranslationYForInAppDisplay;
}
/** Use to set the dark intensity for the all nav+contextual buttons */
@@ -751,20 +751,18 @@
if (mContext.isPhoneButtonNavMode()) {
return;
}
- mLastSetNavButtonTranslationY = calculateNavButtonTranslationY();
- mNavButtonsView.setTranslationY(mLastSetNavButtonTranslationY);
- }
+ final float normalTranslationY = mTaskbarNavButtonTranslationY.value;
+ final float imeAdjustmentTranslationY = mTaskbarNavButtonTranslationYForIme.value;
+ TaskbarUIController uiController = mControllers.uiController;
+ final float inAppDisplayAdjustmentTranslationY =
+ (uiController instanceof LauncherTaskbarUIController
+ && ((LauncherTaskbarUIController) uiController).shouldUseInAppLayout())
+ ? mTaskbarNavButtonTranslationYForInAppDisplay.value : 0;
- /**
- * Calculates the translationY of the nav buttons based on the current device state.
- */
- private float calculateNavButtonTranslationY() {
- float translationY =
- mTaskbarNavButtonTranslationY.value + mTaskbarNavButtonTranslationYForIme.value;
- if (mControllers.uiController.shouldUseInAppLayout()) {
- translationY += mNavButtonTranslationYForInAppDisplay.value;
- }
- return translationY;
+ mLastSetNavButtonTranslationY = normalTranslationY
+ + imeAdjustmentTranslationY
+ + inAppDisplayAdjustmentTranslationY;
+ mNavButtonsView.setTranslationY(mLastSetNavButtonTranslationY);
}
/**
@@ -1164,7 +1162,7 @@
pw.println(prefix + "\t\tmTaskbarNavButtonTranslationY="
+ mTaskbarNavButtonTranslationY.value);
pw.println(prefix + "\t\tmTaskbarNavButtonTranslationYForInAppDisplay="
- + mNavButtonTranslationYForInAppDisplay.value);
+ + mTaskbarNavButtonTranslationYForInAppDisplay.value);
pw.println(prefix + "\t\tmTaskbarNavButtonTranslationYForIme="
+ mTaskbarNavButtonTranslationYForIme.value);
pw.println(prefix + "\t\tmTaskbarNavButtonDarkIntensity="
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index f3741b2..e22de06 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -29,7 +29,6 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY;
import static com.android.launcher3.Flags.enableCursorHoverStates;
-import static com.android.launcher3.Flags.taskbarOverflow;
import static com.android.launcher3.Utilities.calculateTextHeight;
import static com.android.launcher3.Utilities.isRunningInTestHarness;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
@@ -297,6 +296,7 @@
BubbleStashController bubbleStashController = isTransientTaskbar
? new TransientBubbleStashController(dimensionsProvider, this)
: new PersistentBubbleStashController(dimensionsProvider);
+ bubbleStashController.setHotseatVerticalCenter(launcherDp.getHotseatVerticalCenter());
bubbleControllersOptional = Optional.of(new BubbleControllers(
new BubbleBarController(this, bubbleBarView),
new BubbleBarViewController(this, bubbleBarView, bubbleBarContainer),
@@ -362,8 +362,11 @@
/** Updates {@link DeviceProfile} instances for any Taskbar windows. */
public void updateDeviceProfile(DeviceProfile launcherDp) {
applyDeviceProfile(launcherDp);
-
mControllers.taskbarOverlayController.updateLauncherDeviceProfile(launcherDp);
+ mControllers.bubbleControllers.ifPresent(bubbleControllers -> {
+ int hotseatVertCenter = launcherDp.getHotseatVerticalCenter();
+ bubbleControllers.bubbleStashController.setHotseatVerticalCenter(hotseatVertCenter);
+ });
AbstractFloatingView.closeAllOpenViewsExcept(this, false, TYPE_REBIND_SAFE);
// Reapply fullscreen to take potential new screen size into account.
setTaskbarWindowFullscreen(mIsFullscreen);
@@ -1213,9 +1216,7 @@
boolean shouldCloseAllOpenViews = true;
Object tag = view.getTag();
- if (taskbarOverflow()) {
- mControllers.keyboardQuickSwitchController.closeQuickSwitchView(false);
- }
+ mControllers.keyboardQuickSwitchController.closeQuickSwitchView(false);
if (tag instanceof GroupTask groupTask) {
handleGroupTaskLaunch(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index ade8f8c..a89bc3a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -265,7 +265,8 @@
!DisplayController.isPinnedTaskbar(activityContext) ||
!isTooltipEnabled ||
!shouldShowSearchEdu ||
- userHasSeenSearchEdu
+ userHasSeenSearchEdu ||
+ !controllers.taskbarStashController.isTaskbarVisibleAndNotStashing
) {
return
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 058dd07..325a0d3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -145,11 +145,12 @@
// if bubble bar is visible or animating new bubble, add bar bounds to the touch region
if (isBubbleBarVisible || isAnimatingNewBubble) {
defaultTouchableRegion.addBoundsToRegion(bubbleBarViewController.bubbleBarBounds)
+ defaultTouchableRegion.addBoundsToRegion(bubbleBarViewController.flyoutBounds)
}
}
if (
taskbarStashController.isInApp ||
- taskbarStashController.isInOverview ||
+ controllers.uiController.isInOverviewUi ||
DisplayController.showLockedTaskbarOnHome(context)
) {
// only add the taskbar touch region if not on home
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
new file mode 100644
index 0000000..fad5ca3
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarOverflowView.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+
+import com.android.launcher3.R;
+import com.android.launcher3.Reorderable;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.util.MultiTranslateDelegate;
+import com.android.systemui.shared.recents.model.Task;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * View used as overflow icon within task bar, when the list of recent/running apps overflows the
+ * available display bounds - if display is not wide enough to show all running apps in the taskbar,
+ * this icon is added to the taskbar as an entry point to open UI that surfaces all running apps.
+ * The icon contains icon representations of up to 4 more recent tasks in overflow, stacked on top
+ * each other in counter clockwise manner (icons of tasks partially overlapping with each other).
+ */
+public class TaskbarOverflowView extends FrameLayout implements Reorderable {
+ private final List<Task> mItems = new ArrayList<Task>();
+ private int mIconSize;
+ private int mPadding;
+ private Paint mItemBackgroundPaint;
+ private final MultiTranslateDelegate mTranslateDelegate = new MultiTranslateDelegate(this);
+ private float mScaleForReorderBounce = 1f;
+
+ public TaskbarOverflowView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init();
+ }
+
+ public TaskbarOverflowView(Context context) {
+ super(context);
+ init();
+ }
+
+ /**
+ * Inflates the taskbar overflow button view.
+ * @param resId The resource to inflate the view from.
+ * @param group The parent view.
+ * @param iconSize The size of the overflow button icon.
+ * @param padding The internal padding of the overflow view.
+ * @return A taskbar overflow button.
+ */
+ public static TaskbarOverflowView inflateIcon(int resId, ViewGroup group, int iconSize,
+ int padding) {
+ LayoutInflater inflater = LayoutInflater.from(group.getContext());
+ TaskbarOverflowView icon = (TaskbarOverflowView) inflater.inflate(resId, group, false);
+
+ icon.mIconSize = iconSize;
+ icon.mPadding = padding;
+ return icon;
+ }
+
+ private void init() {
+ mItemBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+ mItemBackgroundPaint.setColor(getContext().getColor(R.color.taskbar_background));
+
+ setWillNotDraw(false);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+
+ boolean isRtlLayout = Utilities.isRtl(getResources());
+ float radius = mIconSize / 2.0f - mPadding;
+ float itemPreviewStrokeWidth =
+ getResources().getDimension(R.dimen.taskbar_overflow_button_preview_stroke);
+
+ int itemsToShow = Math.min(mItems.size(), 4);
+ for (int i = itemsToShow - 1; i >= 0; --i) {
+ Drawable icon = mItems.get(mItems.size() - i - 1).icon;
+ if (icon == null) {
+ continue;
+ }
+
+ // Set the item icon size so two items fit within the overflow icon with stroke width
+ // included, and overlap of 4 stroke width sizes between base item preview items.
+ // 2 * strokeWidth + 2 * itemIconSize - 4 * strokeWidth = iconSize = 2 * radius.
+ float itemIconSize = radius + itemPreviewStrokeWidth;
+ // Offset item icon from center so item icon stroke edge mateches the parent icon edge.
+ float itemCenterOffset = radius - itemIconSize / 2 - itemPreviewStrokeWidth;
+
+ float itemCenterX = getItemXOffset(itemCenterOffset, isRtlLayout, i, itemsToShow);
+ float itemCenterY = getItemYOffset(itemCenterOffset, i, itemsToShow);
+
+ Drawable iconCopy = icon.getConstantState().newDrawable().mutate();
+ iconCopy.setBounds(0, 0, (int) itemIconSize, (int) itemIconSize);
+
+ canvas.save();
+ float itemIconRadius = itemIconSize / 2;
+ canvas.translate(
+ mPadding + itemCenterX + radius - itemIconRadius,
+ mPadding + itemCenterY + radius - itemIconRadius);
+ canvas.drawCircle(itemIconRadius, itemIconRadius,
+ itemIconRadius + itemPreviewStrokeWidth, mItemBackgroundPaint);
+ iconCopy.draw(canvas);
+ canvas.restore();
+ }
+ }
+
+ /**
+ * Clears the list of tasks tracked by the view.
+ */
+ public void clearItems() {
+ mItems.clear();
+ invalidate();
+ }
+
+ /**
+ * Update the view to represent a new list of recent tasks.
+ * @param items Items to be shown in the view.
+ */
+ public void setItems(List<Task> items) {
+ mItems.clear();
+ mItems.addAll(items);
+ invalidate();
+ }
+
+ /**
+ * Called when a task is updated. If the task is contained within the view, it's cached value
+ * gets updated. If the task is shown within the icon, invalidates the view, so the task icon
+ * gets updated.
+ * @param task The updated task.
+ */
+ public void updateTaskIsShown(Task task) {
+ for (int i = 0; i < mItems.size(); ++i) {
+ if (mItems.get(i).key.id == task.key.id) {
+ mItems.set(i, task);
+ if (i >= mItems.size() - 4) {
+ invalidate();
+ }
+ break;
+ }
+ }
+ }
+
+ @Override
+ public MultiTranslateDelegate getTranslateDelegate() {
+ return mTranslateDelegate;
+ }
+
+ @Override
+ public float getReorderBounceScale() {
+ return mScaleForReorderBounce;
+ }
+
+ @Override
+ public void setReorderBounceScale(float scale) {
+ mScaleForReorderBounce = scale;
+ super.setScaleX(scale);
+ super.setScaleY(scale);
+ }
+
+ private float getItemXOffset(float baseOffset, boolean isRtl, int itemIndex, int itemCount) {
+ // Item with index 1 is on the left in all cases.
+ if (itemIndex == 1) {
+ return (isRtl ? 1 : -1) * baseOffset;
+ }
+
+ // First item is centered if total number of items shown is 3, on the right otherwise.
+ if (itemIndex == 0) {
+ if (itemCount == 3) {
+ return 0;
+ }
+ return (isRtl ? -1 : 1) * baseOffset;
+ }
+
+ // Last item is on the right when there are more than 2 items (case which is already handled
+ // as `itemIndex == 1`).
+ if (itemIndex == itemCount - 1) {
+ return (isRtl ? -1 : 1) * baseOffset;
+ }
+
+ return (isRtl ? 1 : -1) * baseOffset;
+ }
+
+ private float getItemYOffset(float baseOffset, int itemIndex, int itemCount) {
+ // If icon contains two items, they are both centered vertically.
+ if (itemCount == 2) {
+ return 0;
+ }
+ // First half of items is on top, later half is on bottom.
+ return (itemIndex + 1 <= itemCount / 2 ? -1 : 1) * baseOffset;
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
index 7848b7e..bcfc718 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -30,6 +30,7 @@
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_UNPINNED
import com.android.launcher3.taskbar.TaskbarDividerPopupView.Companion.createAndPopulate
import java.io.PrintWriter
+import kotlin.jvm.optionals.getOrNull
/** Controls taskbar pinning through a popup view. */
class TaskbarPinningController(private val context: TaskbarActivityContext) :
@@ -119,7 +120,11 @@
taskbarViewController.taskbarIconScaleForPinning.animateToValue(animateToValue),
taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue),
)
-
+ controllers.bubbleControllers.getOrNull()?.bubbleBarViewController?.let {
+ // if bubble bar is not visible no need to add it`s animations
+ if (!it.isBubbleBarVisible) return@let
+ animatorSet.playTogether(it.bubbleBarPinning.animateToValue(animateToValue))
+ }
animatorSet.interpolator = Interpolators.EMPHASIZED
return animatorSet
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index b19da6b..c1dd216 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -410,12 +410,20 @@
return mIsStashed;
}
- /** Sets the hotseat stashed. */
+ /**
+ * Sets the hotseat stashed.
+ * b/373429249 - we might change this behavior if we remove the scrim, that's why we're keeping
+ * this method
+ */
public void stashHotseat(boolean stash) {
mControllers.uiController.stashHotseat(stash);
}
- /** Instantly un-stashes the hotseat. */
+ /**
+ * Instantly un-stashes the hotseat.
+ * * b/373429249 - we might change this behavior if we remove the scrim, that's why we're
+ * keeping this method
+ */
public void unStashHotseatInstantly() {
mControllers.uiController.unStashHotseatInstantly();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 7030088..f7f5cf6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -91,14 +91,6 @@
protected void onStashedInAppChanged() { }
/**
- * Whether the Taskbar should use in-app layout.
- * @return {@code true} iff in-app display progress > 0 or Launcher Activity paused.
- */
- public boolean shouldUseInAppLayout() {
- return false;
- }
-
- /**
* Called when taskbar icon layout bounds change.
*/
protected void onIconLayoutBoundsChanged() { }
@@ -126,6 +118,8 @@
* Manually closes the overlay window.
*/
public void hideOverlayWindow() {
+ mControllers.keyboardQuickSwitchController.closeQuickSwitchView();
+
if (!DisplayController.isTransientTaskbar(mControllers.taskbarActivityContext)
|| mControllers.taskbarAllAppsController.isOpen()) {
mControllers.taskbarOverlayController.hideWindow();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index fcb583a..55bcb23 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -64,12 +64,12 @@
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.IconButtonView;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.views.TaskViewType;
import com.android.systemui.shared.recents.model.Task;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
+import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;
@@ -106,7 +106,7 @@
@Nullable private TaskbarDividerContainer mTaskbarDividerContainer;
// Only non-null when device supports having a Taskbar Overflow button.
- @Nullable private IconButtonView mTaskbarOverflowView;
+ @Nullable private TaskbarOverflowView mTaskbarOverflowView;
/**
* Whether the divider is between Hotseat icons and Recents,
@@ -122,6 +122,8 @@
private final int mMaxNumIcons;
+ private final int mAllAppsButtonTranslationOffset;
+
public TaskbarView(@NonNull Context context) {
this(context, null);
}
@@ -141,8 +143,6 @@
mActivityContext = ActivityContext.lookupContext(context);
mIconLayoutBounds = mActivityContext.getTransientTaskbarBounds();
Resources resources = getResources();
- boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivityContext)
- && !mActivityContext.isPhoneMode();
mIsRtl = Utilities.isRtl(resources);
mTransientTaskbarMinWidth = resources.getDimension(R.dimen.transient_taskbar_min_width);
@@ -173,18 +173,19 @@
setWillNotDraw(false);
mAllAppsButtonContainer = new TaskbarAllAppsButtonContainer(context);
+ mAllAppsButtonTranslationOffset = (int) getResources().getDimension(
+ mAllAppsButtonContainer.getAllAppsButtonTranslationXOffset(isTransientTaskbar()));
if (enableTaskbarPinning() || enableRecentsInTaskbar()) {
mTaskbarDividerContainer = new TaskbarDividerContainer(context);
}
if (Flags.taskbarOverflow()) {
- mTaskbarOverflowView = (IconButtonView) LayoutInflater.from(context)
- .inflate(R.layout.taskbar_overflow_button, this, false);
- mTaskbarOverflowView.setIconDrawable(
- resources.getDrawable(R.drawable.taskbar_overflow_icon));
- mTaskbarOverflowView.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
+ mTaskbarOverflowView = TaskbarOverflowView.inflateIcon(
+ R.layout.taskbar_overflow_view, this,
+ mIconTouchSize, mItemPadding);
}
+
// TODO: Disable touch events on QSB otherwise it can crash.
mQsb = LayoutInflater.from(context).inflate(R.layout.search_container_hotseat, this, false);
@@ -197,11 +198,13 @@
private int calculateMaxNumIcons() {
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
int availableWidth = deviceProfile.widthPx;
+ int defaultEdgeMargin =
+ (int) getResources().getDimension(deviceProfile.inv.inlineNavButtonsEndSpacing);
// Reserve space required for edge margins, or for navbar if shown. If task bar needs to be
// center aligned with nav bar shown, reserve space on both sides.
- availableWidth -= Math.max(deviceProfile.edgeMarginPx, deviceProfile.hotseatBarEndOffset);
- availableWidth -= Math.max(deviceProfile.edgeMarginPx,
+ availableWidth -= Math.max(defaultEdgeMargin, deviceProfile.hotseatBarEndOffset);
+ availableWidth -= Math.max(defaultEdgeMargin,
mShouldTryStartAlign ? 0 : deviceProfile.hotseatBarEndOffset);
// The space taken by an item icon used during layout.
@@ -222,9 +225,7 @@
enableTaskbarPinning() && !mActivityContext.isThreeButtonNav();
availableWidth -= iconSize - (int) getResources().getDimension(
mAllAppsButtonContainer.getAllAppsButtonTranslationXOffset(
- forceTransientTaskbarSize || (
- DisplayController.isTransientTaskbar(mActivityContext)
- && !mActivityContext.isPhoneMode())));
+ forceTransientTaskbarSize || isTransientTaskbar()));
++additionalIcons;
return Math.floorDiv(availableWidth, iconSize) + additionalIcons;
@@ -449,24 +450,47 @@
int nonTaskIconsToBeAdded = 1;
boolean supportsOverflow = Flags.taskbarOverflow();
+ int overflowSize = 0;
if (supportsOverflow) {
int numberOfSupportedRecents = 0;
for (GroupTask task : recentTasks) {
// TODO(b/343289567 and b/316004172): support app pairs and desktop mode.
- if (!task.hasMultipleTasks()) {
+ if (!task.supportsMultipleTasks()) {
++numberOfSupportedRecents;
}
}
- if (nextViewIndex + numberOfSupportedRecents + nonTaskIconsToBeAdded > mMaxNumIcons
- && mTaskbarOverflowView != null) {
+
+ overflowSize =
+ nextViewIndex + numberOfSupportedRecents + nonTaskIconsToBeAdded - mMaxNumIcons;
+ if (overflowSize > 0 && mTaskbarOverflowView != null) {
addView(mTaskbarOverflowView, nextViewIndex++);
+ } else if (mTaskbarOverflowView != null) {
+ mTaskbarOverflowView.clearItems();
}
}
+ List<Task> overflownTasks = null;
+ // An extra item needs to be added to overflow button to account for the space taken up by
+ // the overflow button.
+ final int itemsToAddToOverflow = overflowSize > 0 ? overflowSize + 1 : 0;
+ if (overflowSize > 0) {
+ overflownTasks = new ArrayList<Task>(itemsToAddToOverflow);
+ }
+
// Add Recent/Running icons.
for (GroupTask task : recentTasks) {
- if (supportsOverflow && nextViewIndex + nonTaskIconsToBeAdded >= mMaxNumIcons) {
- break;
+ if (mTaskbarOverflowView != null && overflownTasks != null
+ && overflownTasks.size() < itemsToAddToOverflow) {
+ // TODO(b/343289567 and b/316004172): support app pairs and desktop mode.
+ if (task.supportsMultipleTasks()) {
+ continue;
+ }
+
+ overflownTasks.add(task.task1);
+ if (overflownTasks.size() == itemsToAddToOverflow) {
+ mTaskbarOverflowView.setItems(overflownTasks);
+ }
+ continue;
}
// Replace any Recent views with the appropriate type if it's not already that type.
@@ -668,6 +692,15 @@
mIconLayoutBounds.right = iconEnd;
mIconLayoutBounds.top = (bottom - top - mIconTouchSize) / 2;
mIconLayoutBounds.bottom = mIconLayoutBounds.top + mIconTouchSize;
+
+ // With rtl layout, the all apps button will be translated by `allAppsButtonOffset` after
+ // layout completion (by `TaskbarViewController`). Offset the icon end by the same amount
+ // when laying out icons, so the taskbar content remains centered after all apps button
+ // translation.
+ if (layoutRtl) {
+ iconEnd += mAllAppsButtonTranslationOffset;
+ }
+
int count = getChildCount();
for (int i = count; i > 0; i--) {
View child = getChildAt(i - 1);
@@ -699,6 +732,15 @@
mIconLayoutBounds.left = iconEnd;
+ // Adjust the icon layout bounds by the amount by which all apps button will be translated
+ // post layout to maintain margin between all apps button and the edge of the transient
+ // taskbar background. Done for ltr layout only - for rtl layout, the offset needs to be
+ // adjusted on the right, which is done by offsetting `iconEnd` after setting
+ // `mIconLayoutBounds.right`.
+ if (!layoutRtl) {
+ mIconLayoutBounds.left += mAllAppsButtonTranslationOffset;
+ }
+
if (mIconLayoutBounds.right - mIconLayoutBounds.left < mTransientTaskbarMinWidth) {
int center = mIconLayoutBounds.centerX();
int distanceFromCenter = (int) mTransientTaskbarMinWidth / 2;
@@ -741,12 +783,13 @@
/**
* Returns the space used by the icons
*/
- public int getIconLayoutWidth() {
+ private int getIconLayoutWidth() {
int countExcludingQsb = getChildCount();
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
if (deviceProfile.isQsbInline) {
countExcludingQsb--;
}
+
int iconLayoutBoundsWidth =
countExcludingQsb * (mItemMarginLeftRight * 2 + mIconTouchSize);
@@ -755,17 +798,28 @@
// All Apps icon, divider icon, and first app icon in taskbar
iconLayoutBoundsWidth -= mItemMarginLeftRight * 4;
}
+
+ // The all apps button container gets offset horizontally, reducing the overall taskbar
+ // view size.
+ iconLayoutBoundsWidth -= mAllAppsButtonTranslationOffset;
+
return iconLayoutBoundsWidth;
}
/**
- * Returns the app icons currently shown in the taskbar.
+ * Returns the app icons currently shown in the taskbar. The returned list does not include qsb,
+ * but it includes all apps button and icon divider views.
*/
public View[] getIconViews() {
final int count = getChildCount();
- View[] icons = new View[count];
+ if (count == 0) {
+ return new View[0];
+ }
+ View[] icons = new View[count - (mActivityContext.getDeviceProfile().isQsbInline ? 1 : 0)];
+ int insertionPoint = 0;
for (int i = 0; i < count; i++) {
- icons[i] = getChildAt(i);
+ if (getChildAt(i) == mQsb) continue;
+ icons[insertionPoint++] = getChildAt(i);
}
return icons;
}
@@ -789,7 +843,7 @@
* Returns the taskbar overflow view in the taskbar.
*/
@Nullable
- public IconButtonView getTaskbarOverflowView() {
+ public TaskbarOverflowView getTaskbarOverflowView() {
return mTaskbarOverflowView;
}
@@ -847,12 +901,25 @@
// Ignore, we just implement Insettable to draw behind system insets.
}
+ private boolean isTransientTaskbar() {
+ return DisplayController.isTransientTaskbar(mActivityContext)
+ && !mActivityContext.isPhoneMode();
+ }
+
public boolean areIconsVisible() {
// Consider the overall visibility
return getVisibility() == VISIBLE;
}
/**
+ * @return The all apps button horizontal offset used to calculate the taskbar contents width
+ * during layout.
+ */
+ public int getAllAppsButtonTranslationXOffsetUsedForLayout() {
+ return mAllAppsButtonTranslationOffset;
+ }
+
+ /**
* Maps {@code op} over all the child views.
*/
public void mapOverItems(LauncherBindableItemsContainer.ItemOperator op) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 253d025..87e19be 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -233,7 +233,7 @@
mTaskbarNavButtonTranslationY =
controllers.navbarButtonsViewController.getTaskbarNavButtonTranslationY();
mTaskbarNavButtonTranslationYForInAppDisplay = controllers.navbarButtonsViewController
- .getNavButtonTranslationYForInAppDisplay();
+ .getTaskbarNavButtonTranslationYForInAppDisplay();
mActivity.addOnDeviceProfileChangeListener(mDeviceProfileChangeListener);
@@ -359,10 +359,6 @@
return mTaskbarView.getIconLayoutBounds();
}
- public int getIconLayoutWidth() {
- return mTaskbarView.getIconLayoutWidth();
- }
-
public View[] getIconViews() {
return mTaskbarView.getIconViews();
}
@@ -442,6 +438,19 @@
float allAppIconTranslateRange = mapRange(scale, transientTaskbarAllAppsOffset,
persistentTaskbarAllAppsOffset);
+ // Task icons are laid out so the taskbar content is centered. The taskbar width (used for
+ // centering taskbar icons) depends on the all apps button X translation, and is different
+ // for persistent and transient taskbar. If the offset used for current taskbar layout is
+ // different than the offset used in final taskbar state, the icons may jump when the
+ // animation completes, and the taskbar is replaced. Adjust item transform to account for
+ // this mismatch.
+ float sizeDiffTranslationRange =
+ mapRange(scale,
+ (mTaskbarView.getAllAppsButtonTranslationXOffsetUsedForLayout()
+ - transientTaskbarAllAppsOffset) / 2,
+ (mTaskbarView.getAllAppsButtonTranslationXOffsetUsedForLayout()
+ - persistentTaskbarAllAppsOffset) / 2);
+
// no x translation required when all apps button is the only icon in taskbar.
if (iconViews.length <= 1) {
allAppIconTranslateRange = 0f;
@@ -449,6 +458,7 @@
if (mIsRtl) {
allAppIconTranslateRange *= -1;
+ sizeDiffTranslationRange *= -1;
}
if (mActivity.isThreeButtonNav()) {
@@ -457,25 +467,18 @@
return;
}
- float taskbarCenterX =
- mTaskbarView.getLeft() + (mTaskbarView.getRight() - mTaskbarView.getLeft()) / 2.0f;
-
float finalMarginScale = mapRange(scale, 0f, mTransientIconSize - mPersistentIconSize);
- float halfIconCount = iconViews.length / 2.0f;
+ // The index of the "middle" icon which will be used as a index from which the icon margins
+ // will be scaled. If number of icons is even, using the middle point between indices of two
+ // central icons.
+ float middleIndex = (iconViews.length - 1) / 2.0f;
for (int iconIndex = 0; iconIndex < iconViews.length; iconIndex++) {
View iconView = iconViews[iconIndex];
MultiTranslateDelegate translateDelegate =
((Reorderable) iconView).getTranslateDelegate();
- float iconCenterX =
- iconView.getLeft() + (iconView.getRight() - iconView.getLeft()) / 2.0f;
- if (iconCenterX <= taskbarCenterX) {
- translateDelegate.getTranslationX(INDEX_TASKBAR_PINNING_ANIM).setValue(
- finalMarginScale * (halfIconCount - iconIndex));
- } else {
- translateDelegate.getTranslationX(INDEX_TASKBAR_PINNING_ANIM).setValue(
- -finalMarginScale * (iconIndex - halfIconCount));
- }
+ translateDelegate.getTranslationX(INDEX_TASKBAR_PINNING_ANIM).setValue(
+ finalMarginScale * (middleIndex - iconIndex) + sizeDiffTranslationRange);
if (iconView.equals(mTaskbarView.getAllAppsButtonContainer())) {
mTaskbarView.getAllAppsButtonContainer().setTranslationXForTaskbarAllAppsIcon(
@@ -488,18 +491,14 @@
* Calculates visual taskbar view width.
*/
public float getCurrentVisualTaskbarWidth() {
- if (mTaskbarView.getIconViews().length == 0) {
+ View[] iconViews = mTaskbarView.getIconViews();
+ if (iconViews.length == 0) {
return 0;
}
- View[] iconViews = mTaskbarView.getIconViews();
+ float left = iconViews[0].getX();
- int leftIndex = mActivity.getDeviceProfile().isQsbInline && !mIsRtl ? 1 : 0;
- int rightIndex = mActivity.getDeviceProfile().isQsbInline && mIsRtl
- ? iconViews.length - 2
- : iconViews.length - 1;
-
- float left = iconViews[leftIndex].getX();
+ int rightIndex = iconViews.length - 1;
float right = iconViews[rightIndex].getRight() + iconViews[rightIndex].getTranslationX();
return right - left + (2 * mTaskbarLeftRightMargin);
@@ -1090,6 +1089,8 @@
if (groupTask.containsTask(task.key.id)) {
mTaskbarView.applyGroupTaskToBubbleTextView(btv, groupTask);
}
+ } else if (view instanceof TaskbarOverflowView overflowButton) {
+ overflowButton.updateTaskIsShown(task);
}
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index c5d649e..d91d10a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -38,6 +38,7 @@
import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
+import com.android.app.animation.Interpolators;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.taskbar.BarsLocationAnimatorHelper;
@@ -86,7 +87,7 @@
private static final int MAX_BUBBLES = 5;
private static final int MAX_VISIBLE_BUBBLES_COLLAPSED = 2;
private static final int ARROW_POSITION_ANIMATION_DURATION_MS = 200;
- private static final int WIDTH_ANIMATION_DURATION_MS = 200;
+ private static final int WIDTH_ANIMATION_DURATION_MS = 400;
private static final int SCALE_ANIMATION_DURATION_MS = 200;
/**
@@ -143,7 +144,7 @@
// An animator that represents the expansion state of the bubble bar, where 0 corresponds to the
// collapsed state and 1 to the fully expanded state.
- private final ValueAnimator mWidthAnimator = ValueAnimator.ofFloat(0, 1);
+ private ValueAnimator mWidthAnimator = createExpansionAnimator(/* expanding = */ false);
/** An animator used for animating individual bubbles in the bubble bar while expanded. */
@Nullable
@@ -207,35 +208,6 @@
mBubbleBarBackground = new BubbleBarBackground(context, getBubbleBarExpandedHeight());
setBackgroundDrawable(mBubbleBarBackground);
-
- mWidthAnimator.setDuration(WIDTH_ANIMATION_DURATION_MS);
-
- addAnimationCallBacks(mWidthAnimator,
- /* onStart= */ () -> mBubbleBarBackground.showArrow(true),
- /* onEnd= */ () -> {
- mBubbleBarBackground.showArrow(mIsBarExpanded);
- if (!mIsBarExpanded && mReorderRunnable != null) {
- mReorderRunnable.run();
- mReorderRunnable = null;
- }
- // If the bar was just collapsed and the overflow was the last bubble that was
- // selected, set the first bubble as selected.
- if (!mIsBarExpanded && mUpdateSelectedBubbleAfterCollapse != null
- && mSelectedBubbleView != null
- && mSelectedBubbleView.getBubble() instanceof BubbleBarOverflow) {
- BubbleView firstBubble = (BubbleView) getChildAt(0);
- mUpdateSelectedBubbleAfterCollapse.accept(firstBubble.getBubble().getKey());
- }
- // If the bar was just expanded, remove the dot from the selected bubble.
- if (mIsBarExpanded && mSelectedBubbleView != null) {
- mSelectedBubbleView.markSeen();
- }
- updateLayoutParams();
- },
- /* onUpdate= */ animator -> {
- updateBubblesLayoutProperties(mBubbleBarLocation);
- invalidate();
- });
}
@@ -332,6 +304,17 @@
}
/**
+ * Set the bubble icons size and spacing between the bubbles and the borders of the bubble
+ * bar.
+ */
+ public void setIconSizeAndPaddingForPinning(float newIconSize, float newBubbleBarPadding) {
+ mBubbleBarPadding = newBubbleBarPadding;
+ mIconScale = newIconSize / mIconSize;
+ updateBubblesLayoutProperties(mBubbleBarLocation);
+ invalidate();
+ }
+
+ /**
* Sets new icon sizes and newBubbleBarPadding between icons and bubble bar borders.
*
* @param newIconSize new icon size
@@ -1251,11 +1234,8 @@
mIsBarExpanded = isBarExpanded;
updateArrowForSelected(/* shouldAnimate= */ false);
setOrUnsetClickListener();
- if (isBarExpanded) {
- mWidthAnimator.start();
- } else {
- mWidthAnimator.reverse();
- }
+ mWidthAnimator = createExpansionAnimator(isBarExpanded);
+ mWidthAnimator.start();
updateBubbleAccessibilityStates();
announceExpandedStateChange();
}
@@ -1492,6 +1472,46 @@
return bubbles;
}
+ /** Creates an animator based on the expanding or collapsing action. */
+ private ValueAnimator createExpansionAnimator(boolean expanding) {
+ float startValue = expanding ? 0 : 1;
+ if ((mWidthAnimator != null && mWidthAnimator.isRunning())) {
+ startValue = (float) mWidthAnimator.getAnimatedValue();
+ mWidthAnimator.cancel();
+ }
+ float endValue = expanding ? 1 : 0;
+ ValueAnimator animator = ValueAnimator.ofFloat(startValue, endValue);
+ animator.setDuration(WIDTH_ANIMATION_DURATION_MS);
+ animator.setInterpolator(Interpolators.EMPHASIZED);
+ addAnimationCallBacks(animator,
+ /* onStart= */ () -> mBubbleBarBackground.showArrow(true),
+ /* onEnd= */ () -> {
+ mBubbleBarBackground.showArrow(mIsBarExpanded);
+ if (!mIsBarExpanded && mReorderRunnable != null) {
+ mReorderRunnable.run();
+ mReorderRunnable = null;
+ }
+ // If the bar was just collapsed and the overflow was the last bubble that was
+ // selected, set the first bubble as selected.
+ if (!mIsBarExpanded && mUpdateSelectedBubbleAfterCollapse != null
+ && mSelectedBubbleView != null
+ && mSelectedBubbleView.getBubble() instanceof BubbleBarOverflow) {
+ BubbleView firstBubble = (BubbleView) getChildAt(0);
+ mUpdateSelectedBubbleAfterCollapse.accept(firstBubble.getBubble().getKey());
+ }
+ // If the bar was just expanded, remove the dot from the selected bubble.
+ if (mIsBarExpanded && mSelectedBubbleView != null) {
+ mSelectedBubbleView.markSeen();
+ }
+ updateLayoutParams();
+ },
+ /* onUpdate= */ anim -> {
+ updateBubblesLayoutProperties(mBubbleBarLocation);
+ invalidate();
+ });
+ return animator;
+ }
+
/**
* Returns the distance between the top left corner of the bubble bar to the center of the dot
* of the selected bubble.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 76d3606..31b1ea0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -18,6 +18,10 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
+import static com.android.launcher3.Utilities.mapRange;
+import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT;
+import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
+
import android.animation.Animator;
import android.animation.AnimatorSet;
import android.content.res.Resources;
@@ -34,6 +38,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
@@ -41,11 +46,14 @@
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.taskbar.TaskbarInsetsController;
+import com.android.launcher3.taskbar.TaskbarSharedState;
import com.android.launcher3.taskbar.TaskbarStashController;
import com.android.launcher3.taskbar.bubbles.animation.BubbleBarViewAnimator;
import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutController;
import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutPositioner;
+import com.android.launcher3.taskbar.bubbles.flyout.FlyoutCallbacks;
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.SystemUiProxy;
@@ -68,6 +76,9 @@
private static final float APP_ICON_LARGE_DP = 52f;
/** The dot size is defined as a percentage of the icon size. */
private static final float DOT_TO_BUBBLE_SIZE_RATIO = 0.228f;
+ public static final int TASKBAR_FADE_IN_DURATION_MS = 150;
+ public static final int TASKBAR_FADE_IN_DELAY_MS = 50;
+ public static final int TASKBAR_FADE_OUT_DURATION_MS = 100;
private final SystemUiProxy mSystemUiProxy;
private final TaskbarActivityContext mActivity;
private final BubbleBarView mBarView;
@@ -101,6 +112,10 @@
this::updateTranslationY);
private final AnimatedFloat mBubbleOffsetY = new AnimatedFloat(
this::updateBubbleOffsetY);
+ private final AnimatedFloat mBubbleBarPinning = new AnimatedFloat(pinningProgress -> {
+ updateTranslationY();
+ setBubbleBarScaleAndPadding(pinningProgress);
+ });
// Modified when swipe up is happening on the bubble bar or task bar.
private float mBubbleBarSwipeUpTranslationY;
@@ -120,8 +135,9 @@
private BubbleBarViewAnimator mBubbleBarViewAnimator;
private final FrameLayout mBubbleBarContainer;
private BubbleBarFlyoutController mBubbleBarFlyoutController;
-
+ private TaskbarSharedState mTaskbarSharedState;
private final TimeSource mTimeSource = System::currentTimeMillis;
+ private final int mTaskbarTranslationDelta;
@Nullable
private BubbleBarBoundsChangeListener mBoundsChangeListener;
@@ -135,18 +151,20 @@
mBubbleBarAlpha = new MultiValueAlpha(mBarView, 1 /* num alpha channels */);
mIconSize = activity.getResources().getDimensionPixelSize(
R.dimen.bubblebar_icon_size);
+ mTaskbarTranslationDelta = getBubbleBarTranslationDeltaForTaskbar(activity);
}
/** Initializes controller. */
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers,
TaskbarViewPropertiesProvider taskbarViewPropertiesProvider) {
+ mTaskbarSharedState = controllers.getSharedState();
mBubbleStashController = bubbleControllers.bubbleStashController;
mBubbleBarController = bubbleControllers.bubbleBarController;
mBubbleDragController = bubbleControllers.bubbleDragController;
mTaskbarStashController = controllers.taskbarStashController;
mTaskbarInsetsController = controllers.taskbarInsetsController;
mBubbleBarFlyoutController = new BubbleBarFlyoutController(
- mBubbleBarContainer, createFlyoutPositioner(), createFlyoutTopBoundaryListener());
+ mBubbleBarContainer, createFlyoutPositioner(), createFlyoutCallbacks());
mBubbleBarViewAnimator = new BubbleBarViewAnimator(
mBarView, mBubbleStashController, mBubbleBarFlyoutController,
mBubbleBarController::showExpandedView);
@@ -167,6 +185,10 @@
mBoundsChangeListener.onBoundsChanged();
}
});
+ float pinningValue = DisplayController.isTransientTaskbar(mActivity)
+ ? PINNING_TRANSIENT
+ : PINNING_PERSISTENT;
+ mBubbleBarPinning.updateValue(pinningValue);
mBarView.setController(new BubbleBarView.Controller() {
@Override
public float getBubbleBarTranslationY() {
@@ -175,7 +197,9 @@
@Override
public void onBubbleBarTouched() {
- BubbleBarViewController.this.onBubbleBarTouched();
+ if (isAnimatingNewBubble()) {
+ interruptAnimationForTouch();
+ }
}
@Override
@@ -220,6 +244,11 @@
};
}
+ /** Returns animated float property responsible for pinning transition animation. */
+ public AnimatedFloat getBubbleBarPinning() {
+ return mBubbleBarPinning;
+ }
+
private BubbleBarFlyoutPositioner createFlyoutPositioner() {
return new BubbleBarFlyoutPositioner() {
@@ -273,8 +302,8 @@
};
}
- private BubbleBarFlyoutController.TopBoundaryListener createFlyoutTopBoundaryListener() {
- return new BubbleBarFlyoutController.TopBoundaryListener() {
+ private FlyoutCallbacks createFlyoutCallbacks() {
+ return new FlyoutCallbacks() {
@Override
public void extendTopBoundary(int space) {
int defaultSize = mActivity.getDefaultTaskbarWindowSize();
@@ -285,6 +314,12 @@
public void resetTopBoundary() {
mActivity.setTaskbarWindowSize(mActivity.getDefaultTaskbarWindowSize());
}
+
+ @Override
+ public void flyoutClicked() {
+ interruptAnimationForTouch();
+ expandBubbleBar();
+ }
};
}
@@ -304,12 +339,10 @@
}
}
- private void onBubbleBarTouched() {
- if (isAnimatingNewBubble()) {
- mBubbleBarViewAnimator.onBubbleBarTouchedWhileAnimating();
- mBubbleStashController.onNewBubbleAnimationInterrupted(false,
- mBarView.getTranslationY());
- }
+ /** Interrupts the running animation for a touch event on the bubble bar or flyout. */
+ private void interruptAnimationForTouch() {
+ mBubbleBarViewAnimator.interruptForTouch();
+ mBubbleStashController.onNewBubbleAnimationInterrupted(false, mBarView.getTranslationY());
}
private void expandBubbleBar() {
@@ -463,6 +496,12 @@
return mBarView.getBubbleBarBounds();
}
+ /** Returns the bounds of the flyout view if it exists, or {@code null} otherwise. */
+ @Nullable
+ public Rect getFlyoutBounds() {
+ return mBubbleBarFlyoutController.getFlyoutBounds();
+ }
+
/** Checks that bubble bar is visible and that the motion event is within bounds. */
public boolean isEventOverBubbleBar(MotionEvent event) {
if (!isBubbleBarVisible()) return false;
@@ -588,9 +627,11 @@
updateBubbleBarIconSizeAndPadding(newIconSize, newPadding, animate);
}
-
private int getBubbleBarIconSizeFromDeviceProfile(Resources res) {
- DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+ return getBubbleBarIconSizeFromDeviceProfile(res, mActivity.getDeviceProfile());
+ }
+
+ private int getBubbleBarIconSizeFromDeviceProfile(Resources res, DeviceProfile deviceProfile) {
DisplayMetrics dm = res.getDisplayMetrics();
float smallIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
APP_ICON_SMALL_DP, dm);
@@ -605,7 +646,10 @@
}
private int getBubbleBarPaddingFromDeviceProfile(Resources res) {
- DeviceProfile deviceProfile = mActivity.getDeviceProfile();
+ return getBubbleBarPaddingFromDeviceProfile(res, mActivity.getDeviceProfile());
+ }
+
+ private int getBubbleBarPaddingFromDeviceProfile(Resources res, DeviceProfile deviceProfile) {
DisplayMetrics dm = res.getDisplayMetrics();
float mediumIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
APP_ICON_MEDIUM_DP, dm);
@@ -646,7 +690,53 @@
private void updateTranslationY() {
mBarView.setTranslationY(mBubbleBarTranslationY.value + mBubbleBarSwipeUpTranslationY
- + mBubbleBarStashTranslationY);
+ + mBubbleBarStashTranslationY + getBubbleBarTranslationYForTaskbarPinning());
+ }
+
+ /** Computes translation y for taskbar pinning. */
+ private float getBubbleBarTranslationYForTaskbarPinning() {
+ if (mTaskbarSharedState == null) return 0f;
+ float pinningProgress = mBubbleBarPinning.value;
+ if (mTaskbarSharedState.startTaskbarVariantIsTransient) {
+ return mapRange(pinningProgress, /* min = */ 0f, mTaskbarTranslationDelta);
+ } else {
+ return mapRange(pinningProgress, -mTaskbarTranslationDelta, /* max = */ 0f);
+ }
+ }
+
+ private void setBubbleBarScaleAndPadding(float pinningProgress) {
+ Resources res = mActivity.getResources();
+ // determine icon scale for pinning
+ int persistentIconSize = res.getDimensionPixelSize(
+ R.dimen.bubblebar_icon_size_persistent_taskbar);
+ int transientIconSize = getBubbleBarIconSizeFromDeviceProfile(res,
+ mActivity.getTransientTaskbarDeviceProfile());
+ float pinningIconSize = mapRange(pinningProgress, transientIconSize, persistentIconSize);
+
+ // determine bubble bar padding for pinning
+ int persistentPadding = res.getDimensionPixelSize(
+ R.dimen.bubblebar_icon_spacing_persistent_taskbar);
+ int transientPadding = getBubbleBarPaddingFromDeviceProfile(res,
+ mActivity.getTransientTaskbarDeviceProfile());
+ float pinningPadding = mapRange(pinningProgress, transientPadding, persistentPadding);
+ mBarView.setIconSizeAndPaddingForPinning(pinningIconSize, pinningPadding);
+ }
+
+ /**
+ * Calculates the vertical difference in the bubble bar positions for pinned and transient
+ * taskbar modes.
+ */
+ private int getBubbleBarTranslationDeltaForTaskbar(TaskbarActivityContext activity) {
+ Resources res = activity.getResources();
+ int persistentBubbleSize = res
+ .getDimensionPixelSize(R.dimen.bubblebar_icon_size_persistent_taskbar);
+ int persistentSpacingSize = res
+ .getDimensionPixelSize(R.dimen.bubblebar_icon_spacing_persistent_taskbar);
+ int persistentBubbleBarSize = persistentBubbleSize + persistentSpacingSize * 2;
+ int persistentTaskbarHeight = activity.getPersistentTaskbarDeviceProfile().taskbarHeight;
+ int persistentBubbleBarY = (persistentTaskbarHeight - persistentBubbleBarSize) / 2;
+ int transientBubbleBarY = activity.getTransientTaskbarDeviceProfile().taskbarBottomMargin;
+ return transientBubbleBarY - persistentBubbleBarY;
}
private void updateScaleX(float scale) {
@@ -843,22 +933,21 @@
/**
* Hides the persistent taskbar if it is going to intersect with the expanded bubble bar if in
- * app or overview. Set the hotseat stashed state if on launcher home screen. If not on launcher
- * home screen and hotseat is stashed immediately un-stashes the hotseat.
+ * app or overview.
*/
private void adjustTaskbarAndHotseatToBubbleBarState(boolean isBubbleBarExpanded) {
- if (mBubbleStashController.isBubblesShowingOnHome()) {
- mTaskbarStashController.stashHotseat(isBubbleBarExpanded);
- } else if (!mBubbleStashController.isTransientTaskBar()) {
- boolean hideTaskbar = isBubbleBarExpanded && isIntersectingTaskbar();
- mTaskbarViewPropertiesProvider
- .getIconsAlpha()
- .animateToValue(hideTaskbar ? 0 : 1)
- .start();
- }
if (!mBubbleStashController.isBubblesShowingOnHome()
- && mTaskbarStashController.isHiddenForBubbles()) {
- mTaskbarStashController.unStashHotseatInstantly();
+ && !mBubbleStashController.isTransientTaskBar()) {
+ boolean hideTaskbar = isBubbleBarExpanded && isIntersectingTaskbar();
+ Animator taskbarAlphaAnimator = mTaskbarViewPropertiesProvider.getIconsAlpha()
+ .animateToValue(hideTaskbar ? 0 : 1);
+ taskbarAlphaAnimator.setDuration(hideTaskbar
+ ? TASKBAR_FADE_OUT_DURATION_MS : TASKBAR_FADE_IN_DURATION_MS);
+ if (!hideTaskbar) {
+ taskbarAlphaAnimator.setStartDelay(TASKBAR_FADE_IN_DELAY_MS);
+ }
+ taskbarAlphaAnimator.setInterpolator(Interpolators.LINEAR);
+ taskbarAlphaAnimator.start();
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
index 8a52ca9..78e5dbd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -471,8 +471,8 @@
bubbleStashController.updateTaskbarTouchRegion()
}
- /** Handles touching the animating bubble bar. */
- fun onBubbleBarTouchedWhileAnimating() {
+ /** Interrupts the animation due to touching the bubble bar or flyout. */
+ fun interruptForTouch() {
PhysicsAnimator.getInstance(bubbleBarView).cancelIfRunning()
bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
cancelFlyout()
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
index d6400bb..f389d7e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutController.kt
@@ -16,13 +16,13 @@
package com.android.launcher3.taskbar.bubbles.flyout
+import android.graphics.Rect
import android.view.Gravity
import android.view.ViewGroup
import android.widget.FrameLayout
import androidx.core.animation.ValueAnimator
import com.android.launcher3.R
import com.android.systemui.util.addListener
-import com.android.systemui.util.doOnEnd
/** Creates and manages the visibility of the [BubbleBarFlyoutView]. */
class BubbleBarFlyoutController
@@ -30,7 +30,7 @@
constructor(
private val container: FrameLayout,
private val positioner: BubbleBarFlyoutPositioner,
- private val topBoundaryListener: TopBoundaryListener,
+ private val callbacks: FlyoutCallbacks,
private val flyoutScheduler: FlyoutScheduler = HandlerScheduler(container),
) {
@@ -47,6 +47,15 @@
FADE,
}
+ /** The bounds of the flyout. */
+ val flyoutBounds: Rect?
+ get() {
+ val flyout = this.flyout ?: return null
+ val rect = Rect(flyout.bounds)
+ rect.offset(0, flyout.translationY.toInt())
+ return rect
+ }
+
fun setUpAndShowFlyout(message: BubbleBarFlyoutMessage, onEnd: () -> Unit) {
flyout?.let(container::removeView)
val flyout = BubbleBarFlyoutView(container.context, positioner, flyoutScheduler)
@@ -63,29 +72,63 @@
lp.marginEnd = horizontalMargin
container.addView(flyout, lp)
+ this.flyout = flyout
+ flyout.showFromCollapsed(message) { showFlyout(AnimationType.COLLAPSE, onEnd) }
+ }
+
+ private fun showFlyout(animationType: AnimationType, endAction: () -> Unit) {
+ val flyout = this.flyout ?: return
val animator = ValueAnimator.ofFloat(0f, 1f).setDuration(ANIMATION_DURATION_MS)
- animator.addUpdateListener { _ ->
- flyout.updateExpansionProgress(animator.animatedValue as Float)
+ when (animationType) {
+ AnimationType.FADE ->
+ animator.addUpdateListener { _ -> flyout.alpha = animator.animatedValue as Float }
+ AnimationType.COLLAPSE ->
+ animator.addUpdateListener { _ ->
+ flyout.updateExpansionProgress(animator.animatedValue as Float)
+ }
}
animator.addListener(
- onStart = {
- val flyoutTop = flyout.top + flyout.translationY
- // If the top position of the flyout is negative, then it's bleeding over the
- // top boundary of its parent view
- if (flyoutTop < 0) topBoundaryListener.extendTopBoundary(space = -flyoutTop.toInt())
+ onStart = { extendTopBoundary() },
+ onEnd = {
+ endAction()
+ flyout.setOnClickListener { callbacks.flyoutClicked() }
},
- onEnd = { onEnd() },
)
- flyout.showFromCollapsed(message) { animator.start() }
- this.flyout = flyout
+ animator.start()
+ }
+
+ fun updateFlyoutFullyExpanded(message: BubbleBarFlyoutMessage, onEnd: () -> Unit) {
+ val flyout = flyout ?: return
+ hideFlyout(AnimationType.FADE) {
+ flyout.updateData(message) { showFlyout(AnimationType.FADE, onEnd) }
+ }
+ }
+
+ fun updateFlyoutWhileExpanding(message: BubbleBarFlyoutMessage) {
+ val flyout = flyout ?: return
+ flyout.updateData(message) { extendTopBoundary() }
+ }
+
+ private fun extendTopBoundary() {
+ val flyout = flyout ?: return
+ val flyoutTop = flyout.top + flyout.translationY
+ // If the top position of the flyout is negative, then it's bleeding over the
+ // top boundary of its parent view
+ if (flyoutTop < 0) callbacks.extendTopBoundary(space = -flyoutTop.toInt())
}
fun cancelFlyout(endAction: () -> Unit) {
- hideFlyout(AnimationType.FADE, endAction)
+ hideFlyout(AnimationType.FADE) {
+ cleanupFlyoutView()
+ endAction()
+ }
}
fun collapseFlyout(endAction: () -> Unit) {
- hideFlyout(AnimationType.COLLAPSE, endAction)
+ hideFlyout(AnimationType.COLLAPSE) {
+ cleanupFlyoutView()
+ endAction()
+ }
}
private fun hideFlyout(animationType: AnimationType, endAction: () -> Unit) {
@@ -100,21 +143,15 @@
flyout.updateExpansionProgress(animator.animatedValue as Float)
}
}
- animator.doOnEnd {
- container.removeView(flyout)
- this@BubbleBarFlyoutController.flyout = null
- topBoundaryListener.resetTopBoundary()
- endAction()
- }
+ animator.addListener(onStart = { flyout.setOnClickListener(null) }, onEnd = { endAction() })
animator.start()
}
- /** Notifies when the top boundary of the flyout view changes. */
- interface TopBoundaryListener {
- /** Requests to extend the top boundary of the parent to fully include the flyout. */
- fun extendTopBoundary(space: Int)
-
- /** Resets the top boundary of the parent. */
- fun resetTopBoundary()
+ private fun cleanupFlyoutView() {
+ container.removeView(flyout)
+ this@BubbleBarFlyoutController.flyout = null
+ callbacks.resetTopBoundary()
}
+
+ fun hasFlyout() = flyout != null
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
index 6903c87..af8aaf8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutView.kt
@@ -24,6 +24,7 @@
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PointF
+import android.graphics.Rect
import android.graphics.RectF
import android.view.LayoutInflater
import android.view.View
@@ -138,6 +139,9 @@
*/
private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG or Paint.FILTER_BITMAP_FLAG)
+ /** The bounds of the flyout relative to the parent view. */
+ val bounds = Rect()
+
init {
LayoutInflater.from(context).inflate(R.layout.bubblebar_flyout, this, true)
id = R.id.bubble_bar_flyout_view
@@ -174,6 +178,14 @@
applyConfigurationColors(resources.configuration)
}
+ override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
+ super.onLayout(changed, left, top, right, bottom)
+ bounds.left = left
+ bounds.top = top
+ bounds.right = right
+ bounds.bottom = bottom
+ }
+
/** Sets the data for the flyout and starts playing the expand animation. */
fun showFromCollapsed(flyoutMessage: BubbleBarFlyoutMessage, expandAnimation: () -> Unit) {
icon.alpha = 0f
@@ -186,6 +198,8 @@
} else {
-positioner.distanceToCollapsedPosition.x
}
+ // TODO: b/277815200 - before collapsing, recalculate translationToCollapsedPosition because
+ // the collapsed position may have changed
val tyToCollapsedPosition =
positioner.distanceToCollapsedPosition.y + triangleHeight - triangleOverlap
translationToCollapsedPosition = PointF(txToCollapsedPosition, tyToCollapsedPosition)
@@ -205,6 +219,12 @@
scheduler.runAfterLayout(expandAnimation)
}
+ /** Updates the content of the flyout and schedules [afterLayout] to run after a layout pass. */
+ fun updateData(flyoutMessage: BubbleBarFlyoutMessage, afterLayout: () -> Unit) {
+ setData(flyoutMessage)
+ scheduler.runAfterLayout(afterLayout)
+ }
+
private fun setData(flyoutMessage: BubbleBarFlyoutMessage) {
if (flyoutMessage.icon != null) {
icon.visibility = VISIBLE
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/FlyoutCallbacks.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/FlyoutCallbacks.kt
new file mode 100644
index 0000000..e2f010a
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/flyout/FlyoutCallbacks.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.bubbles.flyout
+
+/** Callbacks that the flyout uses to notify of events. */
+interface FlyoutCallbacks {
+ /** Requests to extend the top boundary of the parent to fully include the flyout. */
+ fun extendTopBoundary(space: Int)
+
+ /** Resets the top boundary of the parent. */
+ fun resetTopBoundary()
+
+ /** The flyout was clicked. */
+ fun flyoutClicked()
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
index a78890b..831faa1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
@@ -42,12 +42,6 @@
/** Provides taskbar height in pixels. */
fun getTaskbarHeight(): Int
-
- /** Provides hotseat bottom space in pixels. */
- fun getHotseatBottomSpace(): Int
-
- /** Provides hotseat height in pixels. */
- fun getHotseatHeight(): Int
}
/** Execute passed action only after controllers are initiated. */
@@ -94,7 +88,7 @@
taskbarInsetsController: TaskbarInsetsController,
bubbleBarViewController: BubbleBarViewController,
bubbleStashedHandleViewController: BubbleStashedHandleViewController?,
- controllersAfterInitAction: ControllersAfterInitAction
+ controllersAfterInitAction: ControllersAfterInitAction,
)
/** Shows the bubble bar at [bubbleBarTranslationY] position immediately without animation. */
@@ -127,6 +121,9 @@
/** Set a bubble bar location */
fun setBubbleBarLocation(bubbleBarLocation: BubbleBarLocation)
+ /** Set the hotseat vertical center that bubble bar will align with. */
+ fun setHotseatVerticalCenter(hotseatVerticalCenter: Int)
+
/**
* Stashes the bubble bar (transform to the handle view), or just shrink width of the expanded
* bubble bar based on the controller implementation.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/DeviceProfileDimensionsProviderAdapter.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/DeviceProfileDimensionsProviderAdapter.kt
index a55763b..886b9f0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/DeviceProfileDimensionsProviderAdapter.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/DeviceProfileDimensionsProviderAdapter.kt
@@ -27,13 +27,9 @@
class DeviceProfileDimensionsProviderAdapter(
private val taskbarActivityContext: TaskbarActivityContext
) : TaskbarHotseatDimensionsProvider {
- override fun getTaskbarBottomSpace(): Int = deviceProfile().taskbarBottomMargin
+ override fun getTaskbarBottomSpace(): Int = taskbarDp().taskbarBottomMargin
- override fun getTaskbarHeight(): Int = deviceProfile().taskbarHeight
+ override fun getTaskbarHeight(): Int = taskbarDp().taskbarHeight
- override fun getHotseatBottomSpace(): Int = deviceProfile().hotseatBarBottomSpacePx
-
- override fun getHotseatHeight(): Int = deviceProfile().hotseatCellHeightPx
-
- private fun deviceProfile(): DeviceProfile = taskbarActivityContext.deviceProfile
+ private fun taskbarDp(): DeviceProfile = taskbarActivityContext.deviceProfile
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
index 722dfe7..c117ad4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
@@ -36,7 +36,7 @@
import com.android.wm.shell.shared.bubbles.BubbleBarLocation
class PersistentBubbleStashController(
- private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider,
+ private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider
) : BubbleStashController {
private lateinit var taskbarInsetsController: TaskbarInsetsController
@@ -45,6 +45,7 @@
private lateinit var bubbleBarAlphaAnimator: MultiPropertyFactory<View>.MultiProperty
private lateinit var bubbleBarScaleAnimator: AnimatedFloat
private lateinit var controllersAfterInitAction: ControllersAfterInitAction
+ private var hotseatVerticalCenter: Int = 0
override var launcherState: BubbleLauncherState = BubbleLauncherState.IN_APP
set(state) {
@@ -92,17 +93,15 @@
override val bubbleBarTranslationYForHotseat: Float
get() {
- val hotseatBottomSpace = taskbarHotseatDimensionsProvider.getHotseatBottomSpace()
- val hotseatCellHeight = taskbarHotseatDimensionsProvider.getHotseatHeight()
- val bubbleBarHeight: Float = bubbleBarViewController.bubbleBarCollapsedHeight
- return -hotseatBottomSpace - (hotseatCellHeight - bubbleBarHeight) / 2
+ val bubbleBarHeight = bubbleBarViewController.bubbleBarCollapsedHeight
+ return -hotseatVerticalCenter + bubbleBarHeight / 2
}
override fun init(
taskbarInsetsController: TaskbarInsetsController,
bubbleBarViewController: BubbleBarViewController,
bubbleStashedHandleViewController: BubbleStashedHandleViewController?,
- controllersAfterInitAction: ControllersAfterInitAction
+ controllersAfterInitAction: ControllersAfterInitAction,
) {
this.taskbarInsetsController = taskbarInsetsController
this.bubbleBarViewController = bubbleBarViewController
@@ -119,13 +118,17 @@
animatorSet.playTogether(
bubbleBarScaleAnimator.animateToValue(1f),
bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY),
- bubbleBarAlphaAnimator.animateToValue(1f)
+ bubbleBarAlphaAnimator.animateToValue(1f),
)
}
updateTouchRegionOnAnimationEnd(animatorSet)
animatorSet.setDuration(BAR_STASH_DURATION).start()
}
+ override fun setHotseatVerticalCenter(hotseatVerticalCenter: Int) {
+ this.hotseatVerticalCenter = hotseatVerticalCenter
+ }
+
override fun showBubbleBarImmediate() = showBubbleBarImmediate(bubbleBarTranslationY)
override fun showBubbleBarImmediate(bubbleBarTranslationY: Float) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index 9e7d1c4..fbeecaa 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -78,6 +78,7 @@
context.resources.getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f
private var animator: AnimatorSet? = null
+ private var hotseatVerticalCenter: Int = 0
override var isStashed: Boolean = false
@VisibleForTesting set
@@ -118,10 +119,8 @@
override val bubbleBarTranslationYForHotseat: Float
get() {
- val hotseatBottomSpace = taskbarHotseatDimensionsProvider.getHotseatBottomSpace()
- val hotseatCellHeight = taskbarHotseatDimensionsProvider.getHotseatHeight()
- val bubbleBarHeight: Float = bubbleBarViewController.bubbleBarCollapsedHeight
- return -hotseatBottomSpace - (hotseatCellHeight - bubbleBarHeight) / 2
+ val bubbleBarHeight = bubbleBarViewController.bubbleBarCollapsedHeight
+ return -hotseatVerticalCenter + bubbleBarHeight / 2
}
override val bubbleBarTranslationYForTaskbar: Float =
@@ -176,6 +175,10 @@
.start()
}
+ override fun setHotseatVerticalCenter(hotseatVerticalCenter: Int) {
+ this.hotseatVerticalCenter = hotseatVerticalCenter
+ }
+
override fun showBubbleBarImmediate() {
showBubbleBarImmediate(bubbleBarTranslationY)
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 4ad65e1..228dc91 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -419,8 +419,10 @@
mDepthController.setActivityStarted(isStarted());
}
- if ((changeBits & ACTIVITY_STATE_RESUMED) != 0 && mTaskbarUIController != null) {
- mTaskbarUIController.onLauncherPausedOrResumed(isPaused());
+ if ((changeBits & ACTIVITY_STATE_RESUMED) != 0) {
+ if (!FeatureFlags.enableHomeTransitionListener() && mTaskbarUIController != null) {
+ mTaskbarUIController.onLauncherVisibilityChanged(hasBeenResumed());
+ }
}
super.onActivityFlagsChanged(changeBits);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
index f542b8c..374db6a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
+++ b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
@@ -41,15 +41,20 @@
import com.android.launcher3.Flags.privateSpaceSysAppsSeparation
import com.android.launcher3.R
import com.android.launcher3.Utilities
+import com.android.launcher3.dagger.ApplicationContext
+import com.android.launcher3.dagger.LauncherAppSingleton
import com.android.launcher3.proxy.ProxyActivityStarter
import com.android.launcher3.util.ApiWrapper
import com.android.launcher3.util.Executors
import com.android.launcher3.util.StartActivityParams
import com.android.launcher3.util.UserIconInfo
import com.android.quickstep.util.FadeOutRemoteTransition
+import javax.inject.Inject
/** A wrapper for the hidden API calls */
-open class SystemApiWrapper(context: Context?) : ApiWrapper(context) {
+@LauncherAppSingleton
+open class SystemApiWrapper @Inject constructor(@ApplicationContext context: Context?) :
+ ApiWrapper(context) {
override fun getPersons(si: ShortcutInfo) = si.persons ?: Utilities.EMPTY_PERSON_ARRAY
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index e87ac2f..ca388c6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.uioverrides.states;
+import static com.android.launcher3.Flags.enableDesktopWindowingCarouselDetach;
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
@@ -91,7 +92,7 @@
@Override
public boolean detachDesktopCarousel() {
- return true;
+ return enableDesktopWindowingCarouselDetach();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 015a449..cff352c 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -309,7 +309,9 @@
* changes in the WM hierarchy (ie. starting recents transition when you are already over home).
*/
public boolean useSyntheticRecentsTransition() {
- return mRunningTask.isHomeTask() && Flags.enableFallbackOverviewInWindow();
+ return mRunningTask.isHomeTask()
+ && (Flags.enableFallbackOverviewInWindow()
+ || Flags.enableLauncherOverviewInWindow());
}
/**
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 66112c1..1f6c671 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -155,7 +155,7 @@
mContainerInterface.onAssistantVisibilityChanged(0.f);
}
- if (SEPARATE_RECENTS_ACTIVITY.get()) {
+ if (SEPARATE_RECENTS_ACTIVITY.get() || Flags.enableLauncherOverviewInWindow()) {
mIsDefaultHome = false;
if (defaultHome == null) {
defaultHome = mMyHomeIntent.getComponent();
@@ -179,7 +179,7 @@
} else {
// The default home app is a different launcher. Use the fallback Overview instead.
- if (Flags.enableFallbackOverviewInWindow()) {
+ if (Flags.enableLauncherOverviewInWindow() || Flags.enableFallbackOverviewInWindow()) {
mContainerInterface = FallbackWindowInterface.getInstance();
} else {
mContainerInterface = FallbackActivityInterface.INSTANCE;
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 324ca1b..b19f651 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -196,6 +196,7 @@
@Override
public void onHandleConfigurationChanged() {
+ Trace.instant(Trace.TRACE_TAG_APP, "recentsActivity_onHandleConfigurationChanged");
initDeviceProfile();
AbstractFloatingView.closeOpenViews(this, true,
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index 7d5bd37..8fc1a78 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -109,7 +109,8 @@
boolean isOpeningHome = Arrays.stream(appTargets).filter(app -> app.mode == MODE_OPENING
&& app.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME)
.count() > 0;
- if (appCount == 0 && (!Flags.enableFallbackOverviewInWindow() || isOpeningHome)) {
+ if (appCount == 0 && (!(Flags.enableFallbackOverviewInWindow()
+ || Flags.enableLauncherOverviewInWindow()) || isOpeningHome)) {
ActiveGestureProtoLogProxy.logOnRecentsAnimationStartCancelled();
// Edge case, if there are no closing app targets, then Launcher has nothing to handle
notifyAnimationCanceled();
diff --git a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
index 8adc11a..06b2972 100644
--- a/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
+++ b/quickstep/src/com/android/quickstep/RemoteTargetGluer.java
@@ -94,7 +94,7 @@
RemoteTargetHandle[] handles = new RemoteTargetHandle[numHandles];
for (int i = 0; i < numHandles; i++) {
TaskViewSimulator tvs = new TaskViewSimulator(context, sizingStrategy);
- tvs.setIsDesktopTask(forDesktop);
+ tvs.setIsDesktopTask(forDesktop , i);
TransformParams transformParams = new TransformParams();
handles[i] = new RemoteTargetHandle(tvs, transformParams);
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 56c978a..0b6794c 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -295,7 +295,8 @@
// TODO:(b/365777482) if flag is enabled, but on launcher it will crash.
if(containerInterface.getCreatedContainer() instanceof RecentsWindowManager
- && Flags.enableFallbackOverviewInWindow()){
+ && (Flags.enableFallbackOverviewInWindow()
+ || Flags.enableLauncherOverviewInWindow())) {
mRecentsAnimationStartPending = getSystemUiProxy().startRecentsActivity(intent, options,
mCallbacks, gestureState.useSyntheticRecentsTransition());
mRecentsWindowsManager.startRecentsWindow(mCallbacks);
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 1481ef2..032e755 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -675,7 +675,7 @@
mDesktopVisibilityController = new DesktopVisibilityController(this);
mTaskbarManager = new TaskbarManager(
this, mAllAppsActionManager, mNavCallbacks, mDesktopVisibilityController);
- if(Flags.enableFallbackOverviewInWindow()) {
+ if (Flags.enableLauncherOverviewInWindow() || Flags.enableFallbackOverviewInWindow()) {
mRecentsWindowManager = new RecentsWindowManager(this);
}
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
@@ -927,9 +927,6 @@
BubbleControllers bubbleControllers = tac != null ? tac.getBubbleControllers() : null;
boolean isOnBubbles = bubbleControllers != null
&& BubbleBarInputConsumer.isEventOnBubbles(tac, event);
- if (isInSwipeUpTouchRegion && tac != null) {
- tac.closeKeyboardQuickSwitchView();
- }
if (mDeviceState.isButtonNavMode()
&& mDeviceState.supportsAssistantGestureInButtonNav()) {
reasonString.append("in three button mode which supports Assistant gesture");
@@ -1410,8 +1407,10 @@
}
public AbsSwipeUpHandler.Factory getSwipeUpHandlerFactory() {
+ boolean recentsInWindow =
+ Flags.enableFallbackOverviewInWindow() || Flags.enableLauncherOverviewInWindow();
return mOverviewComponentObserver.isHomeAndOverviewSame()
- ? mLauncherSwipeHandlerFactory : (Flags.enableFallbackOverviewInWindow()
+ ? mLauncherSwipeHandlerFactory : (recentsInWindow
? mRecentsWindowSwipeHandlerFactory : mFallbackSwipeHandlerFactory);
}
diff --git a/quickstep/src/com/android/quickstep/ViewUtils.java b/quickstep/src/com/android/quickstep/ViewUtils.java
index 3b58dfc..cf6b04e 100644
--- a/quickstep/src/com/android/quickstep/ViewUtils.java
+++ b/quickstep/src/com/android/quickstep/ViewUtils.java
@@ -23,6 +23,7 @@
import com.android.launcher3.Utilities;
+import java.util.ArrayList;
import java.util.function.BooleanSupplier;
/**
@@ -129,4 +130,18 @@
}
}
}
+
+ /**
+ * Adds the view to the list of accessible children.
+ *
+ * @param view The view to add.
+ * @param outChildren The list of accessible children.
+ */
+ public static void addAccessibleChildToList(View view, ArrayList<View> outChildren) {
+ if (view.includeForAccessibility()) {
+ outChildren.add(view);
+ } else {
+ view.addChildrenForAccessibility(outChildren);
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
index ab77a7f..3870b9b 100644
--- a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
+++ b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
@@ -15,7 +15,9 @@
*/
package com.android.quickstep.dagger;
+import com.android.launcher3.uioverrides.SystemApiWrapper;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl;
+import com.android.launcher3.util.ApiWrapper;
import com.android.launcher3.util.PluginManagerWrapper;
import dagger.Binds;
@@ -25,4 +27,5 @@
public abstract class QuickStepModule {
@Binds abstract PluginManagerWrapper bindPluginManagerWrapper(PluginManagerWrapperImpl impl);
+ @Binds abstract ApiWrapper bindApiWrapper(SystemApiWrapper systemApiWrapper);
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 5a4c769..daad6b7 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -78,7 +78,7 @@
}
private static BaseContainerInterface<RecentsState, ?> getContainerInterface() {
- return Flags.enableFallbackOverviewInWindow()
+ return (Flags.enableFallbackOverviewInWindow() || Flags.enableLauncherOverviewInWindow())
? FallbackWindowInterface.getInstance()
: FallbackActivityInterface.INSTANCE;
}
@@ -294,7 +294,8 @@
}
// disabling this so app icons aren't drawn on top of recent tasks.
- if (isOverlayEnabled && !Flags.enableFallbackOverviewInWindow()) {
+ if (isOverlayEnabled && !(Flags.enableFallbackOverviewInWindow()
+ || Flags.enableLauncherOverviewInWindow())) {
runActionOnRemoteHandles(remoteTargetHandle ->
remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true));
}
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsState.java b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
index 082b96c..34783c7 100644
--- a/quickstep/src/com/android/quickstep/fallback/RecentsState.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsState.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep.fallback;
+import static com.android.launcher3.Flags.enableDesktopWindowingCarouselDetach;
import static com.android.launcher3.LauncherState.FLAG_CLOSE_POPUPS;
import static com.android.launcher3.uioverrides.states.BackgroundAppState.getOverviewScaleAndOffsetForBackgroundState;
import static com.android.launcher3.uioverrides.states.OverviewModalTaskState.getOverviewScaleAndOffsetForModalState;
@@ -152,7 +153,7 @@
@Override
public boolean detachDesktopCarousel() {
- return hasFlag(FLAG_DETACH_DESKTOP_CAROUSEL);
+ return hasFlag(FLAG_DETACH_DESKTOP_CAROUSEL) && enableDesktopWindowingCarouselDetach();
}
/**
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index e19b338..c4198db 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -157,6 +157,7 @@
mStartDisplacement = continuingPreviousGesture ? 0 : -mTouchSlop;
mDisableHorizontalSwipe = !mPassedPilferInputSlop && disableHorizontalSwipe;
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
+
}
@Override
@@ -426,8 +427,9 @@
notifyGestureStarted(true /*isLikelyToStartNewTask*/);
} else {
// todo differentiate intent based on if we are on home or in app for overview in window
- Intent intent = new Intent(Flags.enableFallbackOverviewInWindow()
- ? mInteractionHandler.getHomeIntent()
+ boolean useHomeIntentForWindow = Flags.enableFallbackOverviewInWindow()
+ || Flags.enableLauncherOverviewInWindow();
+ Intent intent = new Intent(useHomeIntentForWindow ? mInteractionHandler.getHomeIntent()
: mInteractionHandler.getLaunchIntent());
intent.putExtra(INTENT_EXTRA_LOG_TRACE_ID, mGestureState.getGestureId());
mActiveCallbacks = mTaskAnimationManager.startRecentsAnimation(mGestureState, intent,
diff --git a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
index 44b8b8d..f2b9976 100644
--- a/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
+++ b/quickstep/src/com/android/quickstep/recents/di/RecentsDependencies.kt
@@ -113,6 +113,10 @@
instance =
factory?.invoke(extras) as T ?: createDependency(modelClass, scopeId, extras)
scope[modelClass.simpleName] = instance!!
+ log(
+ "instance of $modelClass" +
+ " (${instance.hashCode()}) added to scope ${scope.scopeId}"
+ )
}
}
return instance!!
@@ -148,6 +152,13 @@
fun getScope(scopeId: RecentsScopeId): RecentsDependenciesScope =
scopes[scopeId] ?: createScope(scopeId)
+ fun removeScope(scope: Any) {
+ val scopeId: RecentsScopeId = scope as? RecentsScopeId ?: scope.hashCode().toString()
+ scopes[scopeId]?.close()
+ scopes.remove(scopeId)
+ log("Scope $scopeId removed")
+ }
+
// TODO(b/353912757): Create a factory so we can prevent this method of growing indefinitely.
// Each class should be responsible for providing a factory function to create a new instance.
@Suppress("UNCHECKED_CAST")
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index e7416ec..eb9c047 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -32,6 +32,7 @@
import com.android.launcher3.Utilities
import com.android.launcher3.util.ViewPool
import com.android.quickstep.recents.di.RecentsDependencies
+import com.android.quickstep.recents.di.get
import com.android.quickstep.recents.di.inject
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
@@ -54,7 +55,7 @@
class TaskThumbnailView : ConstraintLayout, ViewPool.Reusable {
private val viewData: TaskThumbnailViewData by RecentsDependencies.inject(this)
- private val viewModel: TaskThumbnailViewModel by RecentsDependencies.inject(this)
+ private lateinit var viewModel: TaskThumbnailViewModel
private lateinit var viewAttachedScope: CoroutineScope
@@ -91,6 +92,7 @@
super.onAttachedToWindow()
viewAttachedScope =
CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("TaskThumbnailView"))
+ viewModel = RecentsDependencies.get(this)
viewModel.uiState
.onEach { viewModelUiState ->
Log.d(TAG, "viewModelUiState changed from $uiState to: $viewModelUiState")
diff --git a/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt b/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
index 9253dbf..c82ed9a 100644
--- a/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
+++ b/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
@@ -17,6 +17,7 @@
package com.android.quickstep.task.util
import android.util.Log
+import android.view.View.OnLayoutChangeListener
import com.android.quickstep.TaskOverlayFactory
import com.android.quickstep.recents.di.RecentsDependencies
import com.android.quickstep.recents.di.get
@@ -41,31 +42,35 @@
private lateinit var overlayInitializedScope: CoroutineScope
private var uiState: TaskOverlayUiState = Disabled
- private val viewModel: TaskOverlayViewModel by lazy {
- TaskOverlayViewModel(
- task = task,
- recentsViewData = RecentsDependencies.get(),
- getThumbnailPositionUseCase = RecentsDependencies.get(),
- recentTasksRepository = RecentsDependencies.get()
- )
- }
+ private lateinit var viewModel: TaskOverlayViewModel
// TODO(b/331753115): TaskOverlay should listen for state changes and react.
val enabledState: Enabled
get() = uiState as Enabled
+ private val snapshotLayoutChangeListener = OnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
+ (uiState as? Enabled)?.let { initOverlay(it) }
+ }
+
fun getThumbnailMatrix() = getThumbnailPositionState().matrix
private fun getThumbnailPositionState() =
viewModel.getThumbnailPositionState(
overlay.snapshotView.width,
overlay.snapshotView.height,
- overlay.snapshotView.isLayoutRtl
+ overlay.snapshotView.isLayoutRtl,
)
fun init() {
overlayInitializedScope =
CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("TaskOverlayHelper"))
+ viewModel =
+ TaskOverlayViewModel(
+ task = task,
+ recentsViewData = RecentsDependencies.get(),
+ getThumbnailPositionUseCase = RecentsDependencies.get(),
+ recentTasksRepository = RecentsDependencies.get(),
+ )
viewModel.overlayState
.onEach {
uiState = it
@@ -76,9 +81,7 @@
}
}
.launchIn(overlayInitializedScope)
- overlay.snapshotView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
- (uiState as? Enabled)?.let { initOverlay(it) }
- }
+ overlay.snapshotView.addOnLayoutChangeListener(snapshotLayoutChangeListener)
}
private fun initOverlay(enabledState: Enabled) {
@@ -96,6 +99,7 @@
fun destroy() {
overlayInitializedScope.cancel()
uiState = Disabled
+ overlay.snapshotView.removeOnLayoutChangeListener(snapshotLayoutChangeListener)
reset()
}
diff --git a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
index 2f0a6df..db02f55 100644
--- a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
+++ b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
@@ -16,10 +16,13 @@
package com.android.quickstep.util
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
import android.animation.AnimatorSet
import android.graphics.Matrix
import android.graphics.Path
import android.graphics.RectF
+import android.util.Log
import android.view.View
import android.view.animation.PathInterpolator
import androidx.core.graphics.transform
@@ -41,6 +44,8 @@
import com.android.launcher3.uioverrides.QuickstepLauncher
import com.android.quickstep.views.RecentsView
+const val TAG = "ScalingWorkspaceRevealAnim"
+
/**
* Creates an animation where the workspace and hotseat fade in while revealing from the center of
* the screen outwards radially. This is used in conjunction with the swipe up to home animation.
@@ -197,6 +202,19 @@
workspace.setLayerType(View.LAYER_TYPE_HARDWARE, null)
hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null)
animation.addListener(
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationCancel(animation: Animator) {
+ super.onAnimationCancel(animation)
+ Log.d(TAG, "onAnimationCancel")
+ }
+
+ override fun onAnimationPause(animation: Animator) {
+ super.onAnimationPause(animation)
+ Log.d(TAG, "onAnimationPause")
+ }
+ }
+ )
+ animation.addListener(
AnimatorListeners.forEndCallback(
Runnable {
workspace.setLayerType(View.LAYER_TYPE_NONE, null)
@@ -207,6 +225,8 @@
Animations.setOngoingAnimation(workspace, animation = null)
Animations.setOngoingAnimation(hotseat, animation = null)
}
+
+ Log.d(TAG, "alpha of workspace at the end of animation: ${workspace.alpha}")
}
)
)
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index f5be103..a4b8fec 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -120,6 +120,7 @@
private boolean mScaleToCarouselTaskSize = false;
private int mTaskRectTranslationX;
private int mTaskRectTranslationY;
+ private int mDesktopTaskIndex = 0;
public TaskViewSimulator(Context context, BaseContainerInterface sizeStrategy) {
mContext = context;
@@ -290,8 +291,9 @@
/**
* Sets whether this task is part of desktop tasks in overview.
*/
- public void setIsDesktopTask(boolean desktop) {
+ public void setIsDesktopTask(boolean desktop, int index) {
mIsDesktopTask = desktop;
+ mDesktopTaskIndex = index;
}
/**
@@ -545,9 +547,9 @@
// In shell transitions, the animation leashes are reparented to an animation container
// so we can bump layers as needed.
builder.setLayer(mDrawsBelowRecents
- ? Integer.MIN_VALUE + app.prefixOrderIndex
// 1000 is an arbitrary number to give room for multiple layers.
- : Integer.MAX_VALUE - 1000 + app.prefixOrderIndex);
+ ? Integer.MIN_VALUE + 1000 + app.prefixOrderIndex - mDesktopTaskIndex
+ : Integer.MAX_VALUE - 1000 + app.prefixOrderIndex - mDesktopTaskIndex);
}
}
diff --git a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
index 0a97793..32e0e13 100644
--- a/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
+++ b/quickstep/src/com/android/quickstep/util/WorkspaceRevealAnim.java
@@ -30,6 +30,7 @@
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.util.FloatProperty;
+import android.util.Log;
import android.view.View;
import com.android.app.animation.Interpolators;
@@ -51,6 +52,8 @@
*/
public class WorkspaceRevealAnim {
+ private static final String TAG = "WorkspaceRevealAnim";
+
// Should be used for animations running alongside this WorkspaceRevealAnim.
public static final int DURATION_MS = 350;
private static final FloatProperty<Workspace<?>> WORKSPACE_SCALE_PROPERTY =
@@ -97,6 +100,19 @@
mAnimators.setDuration(DURATION_MS);
mAnimators.setInterpolator(Interpolators.DECELERATED_EASE);
+ mAnimators.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ super.onAnimationCancel(animation);
+ Log.d(TAG, "onAnimationCancel");
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ Log.d(TAG, "onAnimationEnd: workspace alpha = " + workspace.getAlpha());
+ }
+ });
}
private <T extends View> void addRevealAnimatorsForView(T v, FloatProperty<T> scaleProperty) {
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 8c854e7..15b0a6b 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -25,7 +25,6 @@
import android.util.AttributeSet
import android.util.Log
import android.view.Gravity
-import android.view.LayoutInflater
import android.view.View
import androidx.core.content.res.ResourcesCompat
import androidx.core.view.updateLayoutParams
@@ -40,6 +39,8 @@
import com.android.launcher3.util.rects.set
import com.android.quickstep.BaseContainerInterface
import com.android.quickstep.TaskOverlayFactory
+import com.android.quickstep.ViewUtils
+import com.android.quickstep.task.thumbnail.TaskThumbnailView
import com.android.quickstep.util.RecentsOrientedState
import com.android.systemui.shared.recents.model.Task
@@ -53,14 +54,29 @@
override fun computeTaskCornerRadius(context: Context) =
computeWindowCornerRadius(context)
}
+
private val taskThumbnailViewDeprecatedPool =
- ViewPool<TaskThumbnailViewDeprecated>(
- context,
- this,
- R.layout.task_thumbnail_deprecated,
- VIEW_POOL_MAX_SIZE,
- VIEW_POOL_INITIAL_SIZE,
- )
+ if (!enableRefactorTaskThumbnail()) {
+ ViewPool<TaskThumbnailViewDeprecated>(
+ context,
+ this,
+ R.layout.task_thumbnail_deprecated,
+ VIEW_POOL_MAX_SIZE,
+ VIEW_POOL_INITIAL_SIZE,
+ )
+ } else null
+
+ private val taskThumbnailViewPool =
+ if (enableRefactorTaskThumbnail()) {
+ ViewPool<TaskThumbnailView>(
+ context,
+ this,
+ R.layout.task_thumbnail,
+ VIEW_POOL_MAX_SIZE,
+ VIEW_POOL_INITIAL_SIZE,
+ )
+ } else null
+
private val tempPointF = PointF()
private val tempRect = Rect()
private lateinit var backgroundView: View
@@ -117,9 +133,9 @@
tasks.map { task ->
val snapshotView =
if (enableRefactorTaskThumbnail()) {
- LayoutInflater.from(context).inflate(R.layout.task_thumbnail, this, false)
+ taskThumbnailViewPool!!.view
} else {
- taskThumbnailViewDeprecatedPool.view
+ taskThumbnailViewDeprecatedPool!!.view
}
addView(
@@ -148,9 +164,11 @@
super.onRecycle()
visibility = VISIBLE
taskContainers.forEach {
- if (!enableRefactorTaskThumbnail()) {
- removeView(it.thumbnailViewDeprecated)
- taskThumbnailViewDeprecatedPool.recycle(it.thumbnailViewDeprecated)
+ removeView(it.snapshotView)
+ if (enableRefactorTaskThumbnail()) {
+ taskThumbnailViewPool!!.recycle(it.thumbnailView)
+ } else {
+ taskThumbnailViewDeprecatedPool!!.recycle(it.thumbnailViewDeprecated)
}
}
}
@@ -296,10 +314,15 @@
override fun getThumbnailFullscreenParams() = snapshotDrawParams
+ override fun addChildrenForAccessibility(outChildren: ArrayList<View>) {
+ super.addChildrenForAccessibility(outChildren)
+ ViewUtils.addAccessibleChildToList(backgroundView, outChildren)
+ }
+
companion object {
private const val TAG = "DesktopTaskView"
private const val DEBUG = false
- private const val VIEW_POOL_MAX_SIZE = 10
+ private const val VIEW_POOL_MAX_SIZE = 5
// As DesktopTaskView is inflated in background, use initialSize=0 to avoid initPool.
private const val VIEW_POOL_INITIAL_SIZE = 0
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index b38d0d7..2d0f15e 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -5058,7 +5058,8 @@
mSplitHiddenTaskViewIndex = indexOfChild(mSplitHiddenTaskView);
mSplitSelectStateController
.setAnimateCurrentTaskDismissal(splitSelectSource.animateCurrentTaskDismissal
- && mSplitHiddenTaskView != null);
+ && mSplitHiddenTaskView != null
+ && !(mSplitHiddenTaskView instanceof DesktopTaskView));
// Prevent dismissing whole task if we're only initiating from one of 2 tasks in split pair
mSplitSelectStateController.setDismissingFromSplitPair(mSplitHiddenTaskView != null
diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
index 6cb7741..959516f 100644
--- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
@@ -29,6 +29,7 @@
import com.android.launcher3.util.TransformingTouchDelegate
import com.android.quickstep.TaskOverlayFactory
import com.android.quickstep.TaskUtils
+import com.android.quickstep.ViewUtils.addAccessibleChildToList
import com.android.quickstep.recents.di.RecentsDependencies
import com.android.quickstep.recents.di.get
import com.android.quickstep.recents.di.getScope
@@ -157,12 +158,13 @@
fun destroy() {
digitalWellBeingToast?.destroy()
- if (enableRefactorTaskThumbnail()) {
- taskView.removeView(thumbnailView)
- }
snapshotView.scaleX = 1f
snapshotView.scaleY = 1f
overlay.destroy()
+ if (enableRefactorTaskThumbnail()) {
+ RecentsDependencies.getInstance().removeScope(snapshotView)
+ RecentsDependencies.getInstance().removeScope(this)
+ }
}
fun bindThumbnailView() {
@@ -181,12 +183,4 @@
showWindowsView?.let { addAccessibleChildToList(it, outChildren) }
digitalWellBeingToast?.let { addAccessibleChildToList(it, outChildren) }
}
-
- private fun addAccessibleChildToList(view: View, outChildren: ArrayList<View>) {
- if (view.includeForAccessibility()) {
- outChildren.add(view)
- } else {
- view.addChildrenForAccessibility(outChildren)
- }
- }
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index cc64dba..28ecf96 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -82,6 +82,7 @@
import com.android.quickstep.orientation.RecentsPagedOrientationHandler
import com.android.quickstep.recents.di.RecentsDependencies
import com.android.quickstep.recents.di.get
+import com.android.quickstep.task.thumbnail.TaskThumbnailView
import com.android.quickstep.task.viewmodel.TaskViewModel
import com.android.quickstep.util.ActiveGestureErrorDetector
import com.android.quickstep.util.ActiveGestureLog
@@ -723,20 +724,23 @@
@StagePosition stagePosition: Int,
taskOverlayFactory: TaskOverlayFactory,
): TaskContainer {
- val thumbnailViewDeprecated: TaskThumbnailViewDeprecated = findViewById(thumbnailViewId)!!
+ val existingThumbnailView: View = findViewById(thumbnailViewId)!!
val snapshotView =
- if (enableRefactorTaskThumbnail()) {
- thumbnailViewDeprecated.visibility = GONE
- val indexOfSnapshotView = indexOfChild(thumbnailViewDeprecated)
- LayoutInflater.from(context).inflate(R.layout.task_thumbnail, this, false).also {
- it.id = thumbnailViewId
- addView(it, indexOfSnapshotView, thumbnailViewDeprecated.layoutParams)
+ when {
+ !enableRefactorTaskThumbnail() -> existingThumbnailView
+ existingThumbnailView is TaskThumbnailView -> existingThumbnailView
+ else -> {
+ val indexOfSnapshotView = indexOfChild(existingThumbnailView)
+ LayoutInflater.from(context)
+ .inflate(R.layout.task_thumbnail, this, false)
+ .also {
+ it.id = thumbnailViewId
+ addView(it, indexOfSnapshotView, existingThumbnailView.layoutParams)
+ removeView(existingThumbnailView)
+ }
}
- } else {
- thumbnailViewDeprecated
}
val iconView = getOrInflateIconView(iconViewId)
- val digitalWellBeingToast = findViewById<DigitalWellBeingToast>(digitalWellbeingBannerId)!!
return TaskContainer(
this,
task,
@@ -744,7 +748,7 @@
iconView,
TransformingTouchDelegate(iconView.asView()),
stagePosition,
- digitalWellBeingToast,
+ findViewById(digitalWellbeingBannerId)!!,
findViewById(showWindowViewId)!!,
taskOverlayFactory,
)
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index b37048a..b0d01d3 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -40,6 +40,7 @@
import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutController
import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutMessage
import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutPositioner
+import com.android.launcher3.taskbar.bubbles.flyout.FlyoutCallbacks
import com.android.launcher3.taskbar.bubbles.flyout.FlyoutScheduler
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.wm.shell.shared.animation.PhysicsAnimator
@@ -179,9 +180,7 @@
// verify the hide bubble animation is pending
assertThat(animatorScheduler.delayedBlock).isNotNull()
- InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animator.onBubbleBarTouchedWhileAnimating()
- }
+ InstrumentationRegistry.getInstrumentation().runOnMainSync { animator.interruptForTouch() }
waitForFlyoutToHide()
@@ -992,18 +991,20 @@
override val collapsedElevation = 1f
override val distanceToRevealTriangle = 10f
}
- val topBoundaryListener =
- object : BubbleBarFlyoutController.TopBoundaryListener {
+ val flyoutCallbacks =
+ object : FlyoutCallbacks {
override fun extendTopBoundary(space: Int) {}
override fun resetTopBoundary() {}
+
+ override fun flyoutClicked() {}
}
val flyoutScheduler = FlyoutScheduler { block -> block.invoke() }
flyoutController =
BubbleBarFlyoutController(
flyoutContainer,
flyoutPositioner,
- topBoundaryListener,
+ flyoutCallbacks,
flyoutScheduler,
)
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
index 527bdaa..50bb9bc 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/flyout/BubbleBarFlyoutControllerTest.kt
@@ -44,7 +44,7 @@
private lateinit var flyoutController: BubbleBarFlyoutController
private lateinit var flyoutContainer: FrameLayout
- private lateinit var topBoundaryListener: FakeTopBoundaryListener
+ private lateinit var flyoutCallbacks: FakeFlyoutCallbacks
private val context = ApplicationProvider.getApplicationContext<Context>()
private val flyoutMessage = BubbleBarFlyoutMessage(icon = null, "sender name", "message")
private var onLeft = true
@@ -67,15 +67,10 @@
override val collapsedElevation = 1f
override val distanceToRevealTriangle = 50f
}
- topBoundaryListener = FakeTopBoundaryListener()
+ flyoutCallbacks = FakeFlyoutCallbacks()
val flyoutScheduler = FlyoutScheduler { block -> block.invoke() }
flyoutController =
- BubbleBarFlyoutController(
- flyoutContainer,
- positioner,
- topBoundaryListener,
- flyoutScheduler,
- )
+ BubbleBarFlyoutController(flyoutContainer, positioner, flyoutCallbacks, flyoutScheduler)
}
@Test
@@ -120,11 +115,13 @@
fun hideFlyout_removedFromContainer() {
InstrumentationRegistry.getInstrumentation().runOnMainSync {
flyoutController.setUpAndShowFlyout(flyoutMessage) {}
+ assertThat(flyoutController.hasFlyout()).isTrue()
assertThat(flyoutContainer.childCount).isEqualTo(1)
flyoutController.collapseFlyout {}
animatorTestRule.advanceTimeBy(300)
}
assertThat(flyoutContainer.childCount).isEqualTo(0)
+ assertThat(flyoutController.hasFlyout()).isFalse()
}
@Test
@@ -140,7 +137,7 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animatorTestRule.advanceTimeBy(300)
}
- assertThat(topBoundaryListener.topBoundaryExtendedSpace).isEqualTo(50)
+ assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(50)
}
@Test
@@ -153,7 +150,7 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync {
animatorTestRule.advanceTimeBy(300)
}
- assertThat(topBoundaryListener.topBoundaryExtendedSpace).isEqualTo(0)
+ assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(0)
}
@Test
@@ -164,7 +161,7 @@
flyoutController.collapseFlyout {}
animatorTestRule.advanceTimeBy(300)
}
- assertThat(topBoundaryListener.topBoundaryReset).isTrue()
+ assertThat(flyoutCallbacks.topBoundaryReset).isTrue()
}
@Test
@@ -178,13 +175,82 @@
animatorTestRule.advanceTimeBy(300)
assertThat(flyoutView.alpha).isEqualTo(0f)
}
- assertThat(topBoundaryListener.topBoundaryReset).isTrue()
+ assertThat(flyoutCallbacks.topBoundaryReset).isTrue()
}
- class FakeTopBoundaryListener : BubbleBarFlyoutController.TopBoundaryListener {
+ @Test
+ fun clickFlyout_notifiesCallback() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ flyoutController.setUpAndShowFlyout(flyoutMessage) {}
+ assertThat(flyoutContainer.childCount).isEqualTo(1)
+ val flyoutView = flyoutContainer.findViewById<View>(R.id.bubble_bar_flyout_view)
+ assertThat(flyoutView.alpha).isEqualTo(1f)
+ animatorTestRule.advanceTimeBy(300)
+ flyoutView.performClick()
+ }
+ assertThat(flyoutCallbacks.flyoutClicked).isTrue()
+ }
+
+ @Test
+ fun updateFlyoutWhileExpanding() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ flyoutController.setUpAndShowFlyout(flyoutMessage) {}
+ assertThat(flyoutController.hasFlyout()).isTrue()
+ val flyout = flyoutContainer.findViewById<View>(R.id.bubble_bar_flyout_view)
+ assertThat(flyout.findViewById<TextView>(R.id.bubble_flyout_text).text)
+ .isEqualTo("message")
+ // advance the animation about halfway
+ animatorTestRule.advanceTimeBy(100)
+ }
+ assertThat(flyoutController.hasFlyout()).isTrue()
+
+ val newFlyoutMessage = flyoutMessage.copy(message = "new message")
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ val flyout = flyoutContainer.findViewById<View>(R.id.bubble_bar_flyout_view)
+ // set negative translation to verify that the top boundary extends as a result of
+ // updating while expanding
+ flyout.translationY = -50f
+ flyoutController.updateFlyoutWhileExpanding(newFlyoutMessage)
+ assertThat(flyout.findViewById<TextView>(R.id.bubble_flyout_text).text)
+ .isEqualTo("new message")
+ }
+ assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(50)
+ }
+
+ @Test
+ fun updateFlyoutFullyExpanded() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ flyoutController.setUpAndShowFlyout(flyoutMessage) {}
+ animatorTestRule.advanceTimeBy(300)
+ }
+ assertThat(flyoutController.hasFlyout()).isTrue()
+
+ val newFlyoutMessage = flyoutMessage.copy(message = "new message")
+ InstrumentationRegistry.getInstrumentation().runOnMainSync {
+ val flyout = flyoutContainer.findViewById<View>(R.id.bubble_bar_flyout_view)
+ // set negative translation to verify that the top boundary extends as a result of
+ // updating while fully expanded
+ flyout.translationY = -50f
+ flyoutController.updateFlyoutFullyExpanded(newFlyoutMessage) {}
+
+ // advance the timer so that the fade out animation plays
+ animatorTestRule.advanceTimeBy(250)
+ assertThat(flyout.alpha).isEqualTo(0)
+ assertThat(flyout.findViewById<TextView>(R.id.bubble_flyout_text).text)
+ .isEqualTo("new message")
+
+ // advance the timer so that the fade in animation plays
+ animatorTestRule.advanceTimeBy(250)
+ assertThat(flyout.alpha).isEqualTo(1)
+ }
+ assertThat(flyoutCallbacks.topBoundaryExtendedSpace).isEqualTo(50)
+ }
+
+ class FakeFlyoutCallbacks : FlyoutCallbacks {
var topBoundaryExtendedSpace = 0
var topBoundaryReset = false
+ var flyoutClicked = false
override fun extendTopBoundary(space: Int) {
topBoundaryExtendedSpace = space
@@ -193,5 +259,9 @@
override fun resetTopBoundary() {
topBoundaryReset = true
}
+
+ override fun flyoutClicked() {
+ flyoutClicked = true
+ }
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
index 5dc78a9..00b42bc 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
@@ -48,6 +48,7 @@
companion object {
const val BUBBLE_BAR_HEIGHT = 100f
+ const val HOTSEAT_VERTICAL_CENTER = 95
const val HOTSEAT_TRANSLATION_Y = -45f
const val TASK_BAR_TRANSLATION_Y = -5f
}
@@ -74,11 +75,12 @@
PersistentBubbleStashController(DefaultDimensionsProvider())
setUpBubbleBarView()
setUpBubbleBarController()
+ persistentTaskBarStashController.setHotseatVerticalCenter(HOTSEAT_VERTICAL_CENTER)
persistentTaskBarStashController.init(
taskbarInsetsController,
bubbleBarViewController,
null,
- ImmediateAction()
+ ImmediateAction(),
)
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt
index 0f8a2c3..96c2f45 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt
@@ -23,21 +23,13 @@
class DefaultDimensionsProvider(
private val taskBarBottomSpace: Int = TASKBAR_BOTTOM_SPACE,
private val taskBarHeight: Int = TASKBAR_HEIGHT,
- private val hotseatBottomSpace: Int = HOTSEAT_BOTTOM_SPACE,
- private val hotseatHeight: Int = HOTSEAT_HEIGHT
) : BubbleStashController.TaskbarHotseatDimensionsProvider {
override fun getTaskbarBottomSpace(): Int = taskBarBottomSpace
override fun getTaskbarHeight(): Int = taskBarHeight
- override fun getHotseatBottomSpace(): Int = hotseatBottomSpace
-
- override fun getHotseatHeight(): Int = hotseatHeight
-
companion object {
const val TASKBAR_BOTTOM_SPACE = 0
const val TASKBAR_HEIGHT = 110
- const val HOTSEAT_BOTTOM_SPACE = 20
- const val HOTSEAT_HEIGHT = 150
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
index 8b277e7..64416dd 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashControllerTest.kt
@@ -60,6 +60,7 @@
companion object {
const val TASKBAR_BOTTOM_SPACE = 5
+ const val HOTSEAT_VERTICAL_CENTER = 95
const val BUBBLE_BAR_WIDTH = 200
const val BUBBLE_BAR_HEIGHT = 100
const val HOTSEAT_TRANSLATION_Y = -45f
@@ -108,6 +109,7 @@
setUpStashedHandleView()
setUpBubbleStashedHandleViewController()
PhysicsAnimatorTestUtils.prepareForTest()
+ mTransientBubbleStashController.setHotseatVerticalCenter(HOTSEAT_VERTICAL_CENTER)
mTransientBubbleStashController.init(
taskbarInsetsController,
bubbleBarViewController,
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index 9bc1c59..2c275f4 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -22,7 +22,7 @@
import android.platform.test.annotations.PlatinumTest;
import com.android.launcher3.tapl.Overview;
-import com.android.launcher3.tapl.OverviewTask.OverviewSplitTask;
+import com.android.launcher3.tapl.OverviewTask.OverviewTaskContainer;
import com.android.launcher3.tapl.OverviewTaskMenu;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.uioverrides.QuickstepLauncher;
@@ -76,7 +76,7 @@
taskMenu.touchOutsideTaskMenuToDismiss();
OverviewTaskMenu splitMenu = overview.getCurrentTask().tapMenu(
- OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT);
+ OverviewTaskContainer.SPLIT_BOTTOM_OR_RIGHT);
assertTrue("App info item not appearing in expanded split task's menu.",
splitMenu.hasMenuItem("App info"));
splitMenu.touchOutsideTaskMenuToDismiss();
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
index 694a382..2a8afbf 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsOverviewDesktop.kt
@@ -21,6 +21,8 @@
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Until
import com.android.launcher3.BuildConfig
+import com.android.launcher3.tapl.LaunchedAppState
+import com.android.launcher3.tapl.OverviewTask
import com.android.launcher3.ui.AbstractLauncherUiTest
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape
import com.android.launcher3.uioverrides.QuickstepLauncher
@@ -45,22 +47,16 @@
@Test
@PortraitLandscape
fun enterDesktopViaOverviewMenu() {
- // Move last launched TEST_ACTIVITY_2 into Desktop
- mLauncher.workspace
- .switchToOverview()
- .getTestActivityTask(TEST_ACTIVITY_2)
- .tapMenu()
- .tapDesktopMenuItem()
- assertTestAppLaunched(TEST_ACTIVITY_2)
+ mLauncher.workspace.switchToOverview()
+ moveTaskToDesktop(TEST_ACTIVITY_2) // Move last launched TEST_ACTIVITY_2 into Desktop
// Scroll back to TEST_ACTIVITY_1, then move it into Desktop
mLauncher
.goHome()
.switchToOverview()
.apply { flingForward() }
- .getTestActivityTask(TEST_ACTIVITY_1)
- .tapMenu()
- .tapDesktopMenuItem()
+ .also { moveTaskToDesktop(TEST_ACTIVITY_1) }
+
TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) }
// Launch static DesktopTaskView
@@ -73,6 +69,83 @@
TEST_ACTIVITIES.forEach { assertTestAppLaunched(it) }
}
+ @Test
+ @PortraitLandscape
+ fun dismissFocusedTasks_thenDesktopIsCentered() {
+ // Create DesktopTaskView
+ mLauncher.goHome().switchToOverview()
+ moveTaskToDesktop(TEST_ACTIVITY_2)
+
+ // Create a new task activity to be the focused task
+ mLauncher.goHome()
+ startTestActivity(TEST_ACTIVITY_EXTRA)
+
+ val overview = mLauncher.goHome().switchToOverview()
+
+ // Dismiss focused task
+ val focusedTask1 = overview.currentTask
+ assertTaskContentDescription(focusedTask1, TEST_ACTIVITY_EXTRA)
+ focusedTask1.dismiss()
+
+ // Dismiss new focused task
+ val focusedTask2 = overview.currentTask
+ assertTaskContentDescription(focusedTask2, TEST_ACTIVITY_1)
+ focusedTask2.dismiss()
+
+ // Dismiss DesktopTaskView
+ val desktopTask = overview.currentTask
+ assertWithMessage("The current task is not a Desktop.").that(desktopTask.isDesktop).isTrue()
+ desktopTask.dismiss()
+
+ assertWithMessage("Still have tasks after dismissing all the tasks")
+ .that(mLauncher.workspace.switchToOverview().hasTasks())
+ .isFalse()
+ }
+
+ @Test
+ @PortraitLandscape
+ fun dismissFocusedTask_thenDesktopTask_thenFocusedTaskIsCentered() {
+ // Create extra activity to be DesktopTaskView
+ startTestActivity(TEST_ACTIVITY_EXTRA)
+ mLauncher.goHome().switchToOverview()
+ val desktop = moveTaskToDesktop(TEST_ACTIVITY_EXTRA)
+
+ val overview = desktop.switchToOverview()
+
+ // Dismiss focused task
+ val focusedTask1 = overview.getTestActivityTask(TEST_ACTIVITY_2)
+ assertTaskContentDescription(focusedTask1, TEST_ACTIVITY_2)
+ focusedTask1.dismiss()
+
+ // Dismiss DesktopTaskView
+ val desktopTask = overview.currentTask
+ assertWithMessage("The current task is not a Desktop.").that(desktopTask.isDesktop).isTrue()
+ desktopTask.dismiss()
+
+ // Dismiss focused task
+ val focusedTask2 = overview.currentTask
+ assertTaskContentDescription(focusedTask2, TEST_ACTIVITY_1)
+ focusedTask2.dismiss()
+
+ assertWithMessage("Still have tasks after dismissing all the tasks")
+ .that(mLauncher.workspace.switchToOverview().hasTasks())
+ .isFalse()
+ }
+
+ private fun assertTaskContentDescription(task: OverviewTask, activityIndex: Int) {
+ assertWithMessage("The current task content description is not TestActivity$activityIndex.")
+ .that(task.containsContentDescription("TestActivity$activityIndex"))
+ .isTrue()
+ }
+
+ private fun moveTaskToDesktop(activityIndex: Int): LaunchedAppState {
+ return mLauncher.overview
+ .getTestActivityTask(activityIndex)
+ .tapMenu()
+ .tapDesktopMenuItem()
+ .also { assertTestAppLaunched(activityIndex) }
+ }
+
private fun startTestAppsWithCheck() {
TEST_ACTIVITIES.forEach {
startTestActivity(it)
@@ -91,7 +164,7 @@
.that(
mDevice.wait(
Until.hasObject(By.pkg(getAppPackageName()).text("TestActivity$index")),
- DEFAULT_UI_TIMEOUT
+ DEFAULT_UI_TIMEOUT,
)
)
.isTrue()
@@ -100,6 +173,7 @@
companion object {
const val TEST_ACTIVITY_1 = 2
const val TEST_ACTIVITY_2 = 3
+ const val TEST_ACTIVITY_EXTRA = 4
val TEST_ACTIVITIES = listOf(TEST_ACTIVITY_1, TEST_ACTIVITY_2)
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt b/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt
index 82361aa..99c74be 100644
--- a/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/SplitScreenTestUtils.kt
@@ -43,11 +43,11 @@
val currentTask = overviewWithSplitPair.currentTask
currentTask.containsContentDescription(
By.pkg(AbstractLauncherUiTest.getAppPackageName()).text("TestActivity3").toString(),
- OverviewTask.OverviewSplitTask.SPLIT_TOP_OR_LEFT
+ OverviewTask.OverviewTaskContainer.SPLIT_TOP_OR_LEFT,
)
currentTask.containsContentDescription(
By.pkg(AbstractLauncherUiTest.getAppPackageName()).text("TestActivity2").toString(),
- OverviewTask.OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT
+ OverviewTask.OverviewTaskContainer.SPLIT_BOTTOM_OR_RIGHT,
)
return overviewWithSplitPair
}
diff --git a/res/layout/widgets_two_pane_sheet_paged_view.xml b/res/layout/widgets_two_pane_sheet_paged_view.xml
index 71c77b5..33a50b0 100644
--- a/res/layout/widgets_two_pane_sheet_paged_view.xml
+++ b/res/layout/widgets_two_pane_sheet_paged_view.xml
@@ -15,7 +15,7 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <FrameLayout
+ <LinearLayout
android:id="@+id/widgets_two_pane_sheet_paged_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
@@ -23,40 +23,17 @@
android:layout_gravity="start"
android:clipChildren="false"
android:clipToPadding="false"
- android:layout_alignParentStart="true">
- <!-- Note: the paddingHorizontal has to be on WidgetPagedView level so that talkback
- correctly orders the lists to be after the search and suggestions header. See b/209579563.
- -->
- <com.android.launcher3.widget.picker.WidgetPagedView
- android:id="@+id/widgets_view_pager"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipToPadding="false"
- android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
- android:descendantFocusability="afterDescendants"
- launcher:pageIndicator="@+id/tabs" >
-
- <com.android.launcher3.widget.picker.WidgetsRecyclerView
- android:id="@+id/primary_widgets_list_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipToPadding="false" />
-
- <com.android.launcher3.widget.picker.WidgetsRecyclerView
- android:id="@+id/work_widgets_list_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:clipToPadding="false" />
-
- </com.android.launcher3.widget.picker.WidgetPagedView>
-
+ android:layout_alignParentStart="true"
+ android:orientation="vertical">
<!-- SearchAndRecommendationsView without the tab layout as well -->
<!-- Note: the horizontal padding matches with the WidgetPagedView -->
- <com.android.launcher3.views.StickyHeaderLayout
+ <LinearLayout
android:id="@+id/search_and_recommendations_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToOutline="true"
+ android:elevation="1dp"
+ android:background="?attr/widgetPickerPrimarySurfaceColor"
android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
android:orientation="vertical">
@@ -67,6 +44,7 @@
android:orientation="horizontal"
android:background="?attr/widgetPickerPrimarySurfaceColor"
android:gravity="center_vertical"
+ android:layout_marginBottom="8dp"
launcher:layout_sticky="true">
<FrameLayout
android:layout_width="0dp"
@@ -98,7 +76,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/suggestions_header"
- android:layout_marginTop="8dp"
android:orientation="horizontal"
android:background="?attr/widgetPickerPrimarySurfaceColor"
launcher:layout_sticky="true">
@@ -140,6 +117,31 @@
style="?android:attr/borderlessButtonStyle" />
</com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip>
- </com.android.launcher3.views.StickyHeaderLayout>
- </FrameLayout>
+ </LinearLayout>
+ <!-- Note: the paddingHorizontal has to be on WidgetPagedView level so that talkback
+ correctly orders the lists to be after the search and suggestions header. See b/209579563.
+ -->
+ <com.android.launcher3.widget.picker.WidgetPagedView
+ android:id="@+id/widgets_view_pager"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false"
+ android:paddingHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
+ android:descendantFocusability="afterDescendants"
+ launcher:pageIndicator="@+id/tabs" >
+
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/primary_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false" />
+
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/work_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:clipToPadding="false" />
+
+ </com.android.launcher3.widget.picker.WidgetPagedView>
+ </LinearLayout>
</merge>
diff --git a/res/layout/widgets_two_pane_sheet_recyclerview.xml b/res/layout/widgets_two_pane_sheet_recyclerview.xml
index c6b3b74..94f141b 100644
--- a/res/layout/widgets_two_pane_sheet_recyclerview.xml
+++ b/res/layout/widgets_two_pane_sheet_recyclerview.xml
@@ -15,28 +15,22 @@
<merge xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto">
- <FrameLayout
+ <LinearLayout
android:id="@+id/widgets_two_pane_sheet_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="start"
android:layout_gravity="start"
android:clipChildren="false"
- android:layout_alignParentStart="true">
-
- <com.android.launcher3.widget.picker.WidgetsRecyclerView
- android:id="@+id/primary_widgets_list_view"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
- android:clipToPadding="false" />
-
+ android:layout_alignParentStart="true"
+ android:orientation="vertical">
<!-- SearchAndRecommendationsView without the tab layout as well -->
- <com.android.launcher3.views.StickyHeaderLayout
+ <LinearLayout
android:id="@+id/search_and_recommendations_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:clipToOutline="true"
+ android:background="?attr/widgetPickerPrimarySurfaceColor"
android:orientation="vertical">
<LinearLayout
@@ -83,6 +77,13 @@
android:background="?attr/widgetPickerPrimarySurfaceColor"
launcher:layout_sticky="true">
</FrameLayout>
- </com.android.launcher3.views.StickyHeaderLayout>
- </FrameLayout>
+ </LinearLayout>
+
+ <com.android.launcher3.widget.picker.WidgetsRecyclerView
+ android:id="@+id/primary_widgets_list_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin_two_pane"
+ android:clipToPadding="false" />
+ </LinearLayout>
</merge>
\ No newline at end of file
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 7c6e373..17dd851 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -102,7 +102,7 @@
<string name="permdesc_write_settings" msgid="726859348127868466">"به برنامه اجازه میدهد تنظیمات و میانبرهای صفحه اصلی را تغییر دهد."</string>
<string name="gadget_error_text" msgid="740356548025791839">"ابزاره را نمیتوان بار کرد"</string>
<string name="gadget_setup_text" msgid="8348374825537681407">"تنظیمات ابزاره"</string>
- <string name="gadget_complete_setup_text" msgid="309040266978007925">"برای تکمیل راهاندازی تکضرب بزنید"</string>
+ <string name="gadget_complete_setup_text" msgid="309040266978007925">"برای تمام کردن راهاندازی تکضرب بزنید"</string>
<string name="uninstall_system_app_text" msgid="4172046090762920660">"این برنامه سیستمی است و حذف نصب نمیشود."</string>
<string name="folder_hint_text" msgid="5174843001373488816">"ویرایش نام"</string>
<string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> غیرفعال شد"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 5ddf8a2..6941139 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -189,7 +189,7 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Nyahjeda"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Tapis"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
- <string name="private_space_label" msgid="2359721649407947001">"Ruang privasi"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Ruang persendirian"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Ketik untuk menyediakan atau membuka"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Persendirian"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Tetapan Ruang Peribadi"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 504218b..b0b7aa2 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -79,7 +79,6 @@
<string name="contextual_edu_manager_class" translatable="false"></string>
<!-- Used for determining category of a widget presented in widget recommendations. -->
<string name="widget_recommendation_category_provider_class" translatable="false"></string>
- <string name="api_wrapper_class" translatable="false"></string>
<!-- Default packages -->
<string name="wallpaper_picker_package" translatable="false"></string>
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 3774ae3..2e75261 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -306,10 +306,6 @@
removeActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_DEFERRED_RESUMED);
}
- public boolean isPaused() {
- return !hasBeenResumed() && (mActivityFlags & ACTIVITY_STATE_DEFERRED_RESUMED) == 0;
- }
-
/**
* Sets the activity to appear as resumed.
*/
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 177b28c..50e78ac 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -80,7 +80,7 @@
updateTheme();
}
- private void updateTheme() {
+ protected void updateTheme() {
if (mThemeRes != Themes.getActivityThemeRes(this)) {
recreate();
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 8862550..4305703 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -24,6 +24,7 @@
import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_LANDSCAPE;
import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_PORTRAIT;
import static com.android.launcher3.Utilities.dpiFromPx;
+import static com.android.launcher3.Utilities.isEnglishLanguage;
import static com.android.launcher3.Utilities.pxFromSp;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.ICON_OVERLAP_FACTOR;
import static com.android.launcher3.icons.GraphicsUtils.getShapePath;
@@ -1344,8 +1345,14 @@
}
if ((Flags.enableTwolineToggle()
&& LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(context))) {
- // Add extra textHeight to the existing allAppsCellHeight.
- allAppsCellHeightPx += Utilities.calculateTextHeight(allAppsIconTextSizePx);
+ if (!isEnglishLanguage(context)) {
+ // Set toggle preference value to false if not english here as it's possible the
+ // preference is stale after language change.
+ LauncherPrefs.get(context).put(LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE, false);
+ } else {
+ // Add extra textHeight to the existing allAppsCellHeight.
+ allAppsCellHeightPx += Utilities.calculateTextHeight(allAppsIconTextSizePx);
+ }
}
updateHotseatSizes(iconSizePx);
@@ -2019,6 +2026,18 @@
}
/**
+ * Returns the number of pixels the hotseat icons vertical center is translated from the bottom
+ * of the screen.
+ */
+ public int getHotseatVerticalCenter() {
+ return hotseatBarSizePx
+ - (isQsbInline ? 0 : hotseatQsbVisualHeight)
+ - hotseatQsbSpace
+ - (hotseatCellHeightPx / 2)
+ + ((hotseatCellHeightPx - iconSizePx) / 2);
+ }
+
+ /**
* Returns the number of pixels the taskbar is translated from the bottom of the screen.
*/
public int getTaskbarOffsetY() {
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 6b478be..27602af 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -186,9 +186,6 @@
*/
public void adjustForBubbleBar(boolean isBubbleBarVisible) {
DeviceProfile dp = mActivity.getDeviceProfile();
- if (!dp.shouldAdjustHotseatForBubbleBar(getContext(), isBubbleBarVisible)) {
- return;
- }
ShortcutAndWidgetContainer icons = getShortcutsAndWidgets();
AnimatorSet animatorSet = new AnimatorSet();
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 5ea7bd9..ece6540 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -34,6 +34,7 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Trace;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
@@ -497,7 +498,11 @@
public void setCurrentGrid(Context context, String gridName) {
LauncherPrefs.get(context).put(GRID_NAME, gridName);
- MAIN_EXECUTOR.execute(() -> onConfigChanged(context.getApplicationContext()));
+ MAIN_EXECUTOR.execute(() -> {
+ Trace.beginSection("InvariantDeviceProfile#setCurrentGrid");
+ onConfigChanged(context.getApplicationContext());
+ Trace.endSection();
+ });
}
private Object[] toModelState() {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8547eb4..983cf8d 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1345,7 +1345,8 @@
if (requestArgs != null) {
setWaitingForResult(requestArgs);
}
- mPendingActivityRequestCode = savedState.getInt(RUNTIME_STATE_PENDING_REQUEST_CODE);
+ mPendingActivityRequestCode = savedState.getInt(
+ RUNTIME_STATE_PENDING_REQUEST_CODE, mPendingActivityRequestCode);
mPendingActivityResult = savedState.getParcelable(RUNTIME_STATE_PENDING_ACTIVITY_RESULT);
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 42a28d6..b6da164 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -163,8 +163,7 @@
LockedUserState.get(context).runOnUserUnlocked(() -> {
CustomWidgetManager cwm = CustomWidgetManager.INSTANCE.get(mContext);
- cwm.setWidgetRefreshCallback(mModel::refreshAndBindWidgetsAndShortcuts);
- mOnTerminateCallback.add(() -> cwm.setWidgetRefreshCallback(null));
+ mOnTerminateCallback.add(cwm.addWidgetRefreshCallback(mModel::rebindCallbacks)::close);
IconObserver observer = new IconObserver();
SafeCloseable iconChangeTracker = mIconProvider.registerIconChangeListener(
diff --git a/src/com/android/launcher3/LauncherApplication.java b/src/com/android/launcher3/LauncherApplication.java
index 4c82e56..678901b 100644
--- a/src/com/android/launcher3/LauncherApplication.java
+++ b/src/com/android/launcher3/LauncherApplication.java
@@ -26,15 +26,25 @@
*/
public class LauncherApplication extends Application {
- private LauncherBaseAppComponent mAppComponent;
+ private volatile LauncherBaseAppComponent mAppComponent;
@Override
public void onCreate() {
super.onCreate();
MainProcessInitializer.initialize(this);
- initDagger();
}
public LauncherAppComponent getAppComponent() {
+ if (mAppComponent == null) {
+ synchronized (this) {
+ // Check for null again, as it may have been assigned on a different thread. This
+ // avoids holding synchronization locks everytime.
+ if (mAppComponent == null) {
+ // Initialize the dagger component on demand as content providers can get
+ // accessed before the Launcher application (b/36917845#comment4)
+ initDaggerComponent(DaggerLauncherAppComponent.builder());
+ }
+ }
+ }
// Since supertype setters will return a supertype.builder and @Component.Builder types
// must not have any generic types.
// We need to cast mAppComponent to {@link LauncherAppComponent} since appContext()
@@ -42,7 +52,10 @@
return (LauncherAppComponent) mAppComponent;
}
- protected void initDagger() {
- mAppComponent = DaggerLauncherAppComponent.builder().appContext(this).build();
+ /**
+ * Init with the desired dagger component.
+ */
+ public void initDaggerComponent(LauncherAppComponent.Builder componentBuilder) {
+ mAppComponent = componentBuilder.appContext(this).build();
}
}
diff --git a/src/com/android/launcher3/LauncherBackupAgent.java b/src/com/android/launcher3/LauncherBackupAgent.java
index 2617b93..a96495d 100644
--- a/src/com/android/launcher3/LauncherBackupAgent.java
+++ b/src/com/android/launcher3/LauncherBackupAgent.java
@@ -1,5 +1,7 @@
package com.android.launcher3;
+import static com.android.launcher3.LauncherPrefs.NO_DB_FILES_RESTORED;
+
import android.app.backup.BackupAgent;
import android.app.backup.BackupDataInput;
import android.app.backup.BackupDataOutput;
@@ -10,10 +12,13 @@
import java.io.File;
import java.io.IOException;
+import java.util.Arrays;
+import java.util.stream.Collectors;
public class LauncherBackupAgent extends BackupAgent {
-
private static final String TAG = "LauncherBackupAgent";
+ private static final String DB_FILE_PREFIX = "launcher";
+ private static final String DB_FILE_SUFFIX = ".db";
@Override
public void onCreate() {
@@ -47,7 +52,34 @@
@Override
public void onRestoreFinished() {
- FileLog.d(TAG, "onRestoreFinished: set pending for RestoreDbTask");
RestoreDbTask.setPending(this);
+ FileLog.d(TAG, "onRestoreFinished: set pending for RestoreDbTask");
+ markIfFilesWereNotActuallyRestored();
+ }
+
+ /**
+ * When restore is finished, we check to see if any db files were successfully restored. If not,
+ * our restore will fail later, but will report a different cause. This is important to split
+ * out the metric failures that are launcher's fault, and those that are due to bugs in the
+ * backup/restore code itself.
+ */
+ private void markIfFilesWereNotActuallyRestored() {
+ File directory = new File(getDatabasePath(InvariantDeviceProfile.INSTANCE.get(this).dbFile)
+ .getParent());
+ if (!directory.exists()) {
+ FileLog.e(TAG, "restore failed as target database directory doesn't exist");
+ } else {
+ // Check for any db file that was restored, and collect as list
+ String fileNames = Arrays.stream(directory.listFiles())
+ .map(File::getName)
+ .filter(n -> n.startsWith(DB_FILE_PREFIX) && n.endsWith(DB_FILE_SUFFIX))
+ .collect(Collectors.joining(", "));
+ if (fileNames.isBlank()) {
+ FileLog.e(TAG, "no database files were successfully restored");
+ LauncherPrefs.get(this).putSync(NO_DB_FILES_RESTORED.to(true));
+ } else {
+ FileLog.d(TAG, "database files successfully restored: " + fileNames);
+ }
+ }
}
}
diff --git a/src/com/android/launcher3/LauncherModel.kt b/src/com/android/launcher3/LauncherModel.kt
index a013eaa..85ecd58 100644
--- a/src/com/android/launcher3/LauncherModel.kt
+++ b/src/com/android/launcher3/LauncherModel.kt
@@ -25,7 +25,6 @@
import android.util.Pair
import androidx.annotation.WorkerThread
import com.android.launcher3.celllayout.CellPosMapper
-import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.icons.IconCache
import com.android.launcher3.model.AddWorkspaceItemsTask
import com.android.launcher3.model.AllAppsList
@@ -67,8 +66,8 @@
private val context: Context,
private val mApp: LauncherAppState,
private val iconCache: IconCache,
- private val appFilter: AppFilter,
- private val mPmHelper: PackageManagerHelper,
+ appFilter: AppFilter,
+ mPmHelper: PackageManagerHelper,
isPrimaryInstance: Boolean,
) {
@@ -304,9 +303,6 @@
launcherBinder.bindAllApps()
launcherBinder.bindDeepShortcuts()
launcherBinder.bindWidgets()
- if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
- this.modelDelegate.bindAllModelExtras(callbacksList)
- }
return true
} else {
mLoaderTask =
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 7ebfc18..5c03644 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -126,6 +126,9 @@
EncryptionType.ENCRYPTED,
)
@JvmField
+ val NO_DB_FILES_RESTORED =
+ nonRestorableItem("no_db_files_restored", false, EncryptionType.DEVICE_PROTECTED)
+ @JvmField
val IS_FIRST_LOAD_AFTER_RESTORE =
nonRestorableItem(FIRST_LOAD_AFTER_RESTORE_KEY, false, EncryptionType.ENCRYPTED)
@JvmField val APP_WIDGET_IDS = backedUpItem(RestoreDbTask.APPWIDGET_IDS, "")
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index 9192e13..71a2589 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -616,6 +616,14 @@
}
/**
+ * Utility method to know if a device's primary language is English.
+ */
+ public static boolean isEnglishLanguage(Context context) {
+ return context.getResources().getConfiguration().locale.getLanguage()
+ .equals(Locale.ENGLISH.getLanguage());
+ }
+
+ /**
* Returns the full drawable for info as multiple layers of AdaptiveIconDrawable. The second
* drawable in the Pair is the badge used with the icon.
*
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 1094768..0dd2791 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -296,6 +296,10 @@
// Add the search box above everything else in this container (if the flag is enabled,
// it's added to drag layer in onAttach instead).
addView(mSearchContainer);
+ // The search container is visually at the top of the all apps UI, and should thus be
+ // focused by default. It's added to end of the children list, so it needs to be
+ // explicitly marked as focused by default.
+ mSearchContainer.setFocusedByDefault(true);
}
mSearchUiManager = (SearchUiManager) mSearchContainer;
}
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 9c36dc2..21dce14 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -220,7 +220,7 @@
* when animation is not running.
*/
public void reset() {
- // Ensure the state of the header views is what it should be before animating.
+ // Ensure the state of the header view is what it should be before animating.
updateView();
getMainRecyclerView().setChildAttachedConsumer(null);
int previousState = getCurrentState();
@@ -435,6 +435,7 @@
lockPill.setVisibility(GONE);
}
}
+ mPSHeader.invalidate();
}
/** Sets the enablement of the profile when header or button is clicked. */
diff --git a/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt b/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt
index e6654b1..b05539a 100644
--- a/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt
+++ b/src/com/android/launcher3/backuprestore/LauncherRestoreEventLogger.kt
@@ -24,9 +24,10 @@
RestoreError.WIDGETS_DISABLED,
RestoreError.PROFILE_NOT_RESTORED,
RestoreError.WIDGET_REMOVED,
+ RestoreError.DATABASE_FILE_NOT_RESTORED,
RestoreError.GRID_MIGRATION_FAILURE,
RestoreError.NO_SEARCH_WIDGET,
- RestoreError.INVALID_WIDGET_ID
+ RestoreError.INVALID_WIDGET_ID,
)
annotation class RestoreError {
companion object {
@@ -38,6 +39,7 @@
const val APP_NOT_INSTALLED = "app_not_installed"
const val WIDGETS_DISABLED = "widgets_disabled"
const val PROFILE_NOT_RESTORED = "profile_not_restored"
+ const val DATABASE_FILE_NOT_RESTORED = "db_file_not_restored"
const val WIDGET_REMOVED = "widget_not_found"
const val GRID_MIGRATION_FAILURE = "grid_migration_failed"
const val NO_SEARCH_WIDGET = "no_search_widget"
@@ -52,7 +54,7 @@
return ResourceBasedOverride.Overrides.getObject(
LauncherRestoreEventLogger::class.java,
context,
- R.string.launcher_restore_event_logger_class
+ R.string.launcher_restore_event_logger_class,
)
}
}
@@ -117,7 +119,7 @@
open fun logFavoritesItemsRestoreFailed(
favoritesId: Int,
count: Int,
- @RestoreError error: String?
+ @RestoreError error: String?,
) {
// no-op
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 8fe1b34..9e38824 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -62,17 +62,6 @@
* and set a default value for the flag. This will be the default value on Debug builds.
* <p>
*/
- // TODO(Block 3): Clean up flags
- public static final BooleanFlag ENABLE_WORKSPACE_LOADING_OPTIMIZATION = getDebugFlag(251502424,
- "ENABLE_WORKSPACE_LOADING_OPTIMIZATION", DISABLED,
- "load the current workspace screen visible to the user before the rest rather than "
- + "loading all of them at once.");
-
- public static final BooleanFlag CHANGE_MODEL_DELEGATE_LOADING_ORDER = getDebugFlag(251502424,
- "CHANGE_MODEL_DELEGATE_LOADING_ORDER", DISABLED,
- "changes the timing of the loading and binding of delegate items during "
- + "data preparation for loading the home screen");
-
// TODO(Block 6): Clean up flags
public static final BooleanFlag SECONDARY_DRAG_N_DROP_TO_PIN = getDebugFlag(270395140,
"SECONDARY_DRAG_N_DROP_TO_PIN", DISABLED,
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index 4537785..ecc5bb2 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -19,6 +19,7 @@
import android.content.Context;
import com.android.launcher3.pm.InstallSessionHelper;
+import com.android.launcher3.util.ApiWrapper;
import com.android.launcher3.util.DaggerSingletonTracker;
import com.android.launcher3.util.PluginManagerWrapper;
import com.android.launcher3.util.ScreenOnTracker;
@@ -40,6 +41,7 @@
DaggerSingletonTracker getDaggerSingletonTracker();
RefreshRateTracker getRefreshRateTracker();
InstallSessionHelper getInstallSessionHelper();
+ ApiWrapper getApiWrapper();
ScreenOnTracker getScreenOnTracker();
SettingsCache getSettingsCache();
CustomWidgetManager getCustomWidgetManager();
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
index 259e543..bc51a66 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProvider.java
@@ -36,18 +36,24 @@
import android.text.TextUtils;
import android.util.Log;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.InvariantDeviceProfile.GridOption;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.model.BgDataModel;
+import com.android.launcher3.shapes.AppShape;
+import com.android.launcher3.shapes.AppShapesProvider;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.RunnableList;
import com.android.systemui.shared.Flags;
import java.util.Collections;
+import java.util.List;
+import java.util.Optional;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ExecutionException;
@@ -55,31 +61,44 @@
/**
* Exposes various launcher grid options and allows the caller to change them.
* APIs:
- * /list_options: List the various available grip options, has following columns
- * name: name of the grid
+ * /shape_options: List of various available shape options, where each has following fields
+ * shape_key: key of the shape option
+ * title: translated title of the shape option
+ * path: path of the shape, assuming drawn on 100x100 view port
+ * is_default: true if this shape option is currently set to the system
+ *
+ * /grid_options: List the various available grid options, where each has following fields
+ * name: key of the grid option
* rows: number of rows in the grid
* cols: number of columns in the grid
* preview_count: number of previews available for this grid option. The preview uri
* looks like /preview/<grid-name>/<preview index starting with 0>
- * is_default: true if this grid is currently active
+ * is_default: true if this grid option is currently set to the system
*
- * /preview: Opens a file stream for the grid preview
+ * /get_preview: Open a file stream for the grid preview
*
- * /default_grid: Call update to set the current grid, with values
- * name: name of the grid to apply
+ * /default_grid: Call update to set the current shape and grid, with values
+ * shape_key: key of the shape to apply
+ * name: key of the grid to apply
*/
public class GridCustomizationsProvider extends ContentProvider {
private static final String TAG = "GridCustomizationsProvider";
- private static final String KEY_NAME = "name";
+ private static final String KEY_SHAPE_KEY = "shape_key";
+ private static final String KEY_TITLE = "title";
+ private static final String KEY_PATH = "path";
+ // is_default means if a certain option is currently set to the system
+ private static final String KEY_IS_DEFAULT = "is_default";
+ // Key of grid option. We do not change the name to grid_key for backward compatibility
+ private static final String KEY_GRID_KEY = "name";
private static final String KEY_ROWS = "rows";
private static final String KEY_COLS = "cols";
private static final String KEY_PREVIEW_COUNT = "preview_count";
- private static final String KEY_IS_DEFAULT = "is_default";
- private static final String KEY_LIST_OPTIONS = "/list_options";
- private static final String KEY_DEFAULT_GRID = "/default_grid";
+ private static final String KEY_SHAPE_OPTIONS = "/shape_options";
+ private static final String KEY_GRID_OPTIONS = "/grid_options";
+ private static final String KEY_SHAPE_GRID = "/default_grid";
private static final String METHOD_GET_PREVIEW = "get_preview";
@@ -91,9 +110,9 @@
private static final String KEY_SURFACE_PACKAGE = "surface_package";
private static final String KEY_CALLBACK = "callback";
public static final String KEY_HIDE_BOTTOM_ROW = "hide_bottom_row";
- public static final String KEY_GRID_NAME = "grid_name";
private static final int MESSAGE_ID_UPDATE_PREVIEW = 1337;
+ private static final int MESSAGE_ID_UPDATE_SHAPE = 2586;
private static final int MESSAGE_ID_UPDATE_GRID = 7414;
private static final int MESSAGE_ID_UPDATE_COLOR = 856;
@@ -109,14 +128,39 @@
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
- switch (uri.getPath()) {
- case KEY_LIST_OPTIONS: {
+ Context context = getContext();
+ String path = uri.getPath();
+ if (context == null || path == null) {
+ return null;
+ }
+ switch (path) {
+ case KEY_SHAPE_OPTIONS: {
+ if (Flags.newCustomizationPickerUi()) {
+ MatrixCursor cursor = new MatrixCursor(new String[]{
+ KEY_SHAPE_KEY, KEY_TITLE, KEY_PATH, KEY_IS_DEFAULT});
+ List<AppShape> shapes = AppShapesProvider.INSTANCE.getShapes();
+ for (int i = 0; i < shapes.size(); i++) {
+ AppShape shape = shapes.get(i);
+ cursor.newRow()
+ .add(KEY_SHAPE_KEY, shape.getKey())
+ .add(KEY_TITLE, shape.getTitle())
+ .add(KEY_PATH, shape.getPath())
+ // TODO (b/348664593): We should fetch the currently-set shape
+ // option from the preferences.
+ .add(KEY_IS_DEFAULT, i == 0);
+ }
+ return cursor;
+ } else {
+ return null;
+ }
+ }
+ case KEY_GRID_OPTIONS: {
MatrixCursor cursor = new MatrixCursor(new String[]{
- KEY_NAME, KEY_ROWS, KEY_COLS, KEY_PREVIEW_COUNT, KEY_IS_DEFAULT});
- InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(getContext());
- for (GridOption gridOption : idp.parseAllGridOptions(getContext())) {
+ KEY_GRID_KEY, KEY_ROWS, KEY_COLS, KEY_PREVIEW_COUNT, KEY_IS_DEFAULT});
+ InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context);
+ for (GridOption gridOption : idp.parseAllGridOptions(context)) {
cursor.newRow()
- .add(KEY_NAME, gridOption.name)
+ .add(KEY_GRID_KEY, gridOption.name)
.add(KEY_ROWS, gridOption.numRows)
.add(KEY_COLS, gridOption.numColumns)
.add(KEY_PREVIEW_COUNT, 1)
@@ -159,14 +203,22 @@
return 0;
}
switch (path) {
- case KEY_DEFAULT_GRID: {
- String gridName = values.getAsString(KEY_NAME);
+ case KEY_SHAPE_GRID: {
+ if (Flags.newCustomizationPickerUi()) {
+ String shapeKey = values.getAsString(KEY_SHAPE_KEY);
+ Optional<AppShape> optionalShape = AppShapesProvider.INSTANCE.getShapes()
+ .stream().filter(shape -> shape.getKey().equals(shapeKey)).findFirst();
+ String pathToSet = optionalShape.map(AppShape::getPath).orElse(null);
+ // TODO (b/348664593): Apply shapeName to the system. This needs to be a
+ // synchronous call.
+ }
+ String gridKey = values.getAsString(KEY_GRID_KEY);
InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(context);
// Verify that this is a valid grid option
GridOption match = null;
for (GridOption option : idp.parseAllGridOptions(context)) {
String name = option.name;
- if (name != null && name.equals(gridName)) {
+ if (name != null && name.equals(gridKey)) {
match = option;
break;
}
@@ -175,7 +227,7 @@
return 0;
}
- idp.setCurrentGrid(context, gridName);
+ idp.setCurrentGrid(context, gridKey);
if (Flags.newCustomizationPickerUi()) {
try {
// Wait for device profile to be fully reloaded and applied to the launcher
@@ -217,20 +269,30 @@
}
@Override
- public Bundle call(String method, String arg, Bundle extras) {
- if (getContext().checkPermission("android.permission.BIND_WALLPAPER",
+ public Bundle call(@NonNull String method, String arg, Bundle extras) {
+ Context context = getContext();
+ if (context == null) {
+ return null;
+ }
+
+ if (context.checkPermission("android.permission.BIND_WALLPAPER",
Binder.getCallingPid(), Binder.getCallingUid())
!= PackageManager.PERMISSION_GRANTED) {
return null;
}
- if (!METHOD_GET_PREVIEW.equals(method)) {
+ if (METHOD_GET_PREVIEW.equals(method)) {
+ return getPreview(extras);
+ } else {
return null;
}
- return getPreview(extras);
}
private synchronized Bundle getPreview(Bundle request) {
+ Context context = getContext();
+ if (context == null) {
+ return null;
+ }
RunnableList lifeCycleTracker = new RunnableList();
try {
PreviewSurfaceRenderer renderer = new PreviewSurfaceRenderer(
@@ -268,7 +330,9 @@
public final PreviewSurfaceRenderer renderer;
public boolean destroyed = false;
- PreviewLifecycleObserver(RunnableList lifeCycleTracker, PreviewSurfaceRenderer renderer) {
+ PreviewLifecycleObserver(
+ RunnableList lifeCycleTracker,
+ PreviewSurfaceRenderer renderer) {
this.lifeCycleTracker = lifeCycleTracker;
this.renderer = renderer;
lifeCycleTracker.add(() -> destroyed = true);
@@ -284,10 +348,21 @@
case MESSAGE_ID_UPDATE_PREVIEW:
renderer.hideBottomRow(message.getData().getBoolean(KEY_HIDE_BOTTOM_ROW));
break;
+ case MESSAGE_ID_UPDATE_SHAPE:
+ if (Flags.newCustomizationPickerUi()) {
+ String shapeKey = message.getData().getString(KEY_SHAPE_KEY);
+ Optional<AppShape> optionalShape = AppShapesProvider.INSTANCE.getShapes()
+ .stream()
+ .filter(shape -> shape.getKey().equals(shapeKey))
+ .findFirst();
+ String pathToSet = optionalShape.map(AppShape::getPath).orElse(null);
+ // TODO (b/348664593): Update launcher preview with the given shape
+ }
+ break;
case MESSAGE_ID_UPDATE_GRID:
- String gridName = message.getData().getString(KEY_GRID_NAME);
- if (!TextUtils.isEmpty(gridName)) {
- renderer.updateGrid(gridName);
+ String gridKey = message.getData().getString(KEY_GRID_KEY);
+ if (!TextUtils.isEmpty(gridKey)) {
+ renderer.updateGrid(gridKey);
}
break;
case MESSAGE_ID_UPDATE_COLOR:
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index e3c2d36..1dd7d45 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -55,7 +55,7 @@
import com.android.launcher3.model.BaseLauncherBinder;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.model.GridSizeMigrationUtil;
+import com.android.launcher3.model.GridSizeMigrationDBController;
import com.android.launcher3.model.LoaderTask;
import com.android.launcher3.model.ModelDbController;
import com.android.launcher3.provider.LauncherDbUtils;
@@ -284,7 +284,7 @@
private void loadModelData() {
final Context inflationContext = getPreviewContext();
final InvariantDeviceProfile idp = new InvariantDeviceProfile(inflationContext, mGridName);
- if (GridSizeMigrationUtil.needsToMigrate(inflationContext, idp)) {
+ if (GridSizeMigrationDBController.needsToMigrate(inflationContext, idp)) {
// Start the migration
PreviewContext previewContext = new PreviewContext(inflationContext, idp);
// Copy existing data to preview DB
diff --git a/src/com/android/launcher3/model/BaseLauncherBinder.java b/src/com/android/launcher3/model/BaseLauncherBinder.java
index 5faa2b8..b51f855 100644
--- a/src/com/android/launcher3/model/BaseLauncherBinder.java
+++ b/src/com/android/launcher3/model/BaseLauncherBinder.java
@@ -36,7 +36,6 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel.CallbackTask;
import com.android.launcher3.LauncherSettings;
-import com.android.launcher3.Workspace;
import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.BgDataModel.Callbacks;
@@ -59,11 +58,9 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
-import java.util.Set;
import java.util.concurrent.Executor;
import java.util.stream.Collectors;
@@ -100,13 +97,29 @@
public void bindWorkspace(boolean incrementBindId, boolean isBindSync) {
Trace.beginSection("BaseLauncherBinder#bindWorkspace");
try {
- if (FeatureFlags.ENABLE_WORKSPACE_LOADING_OPTIMIZATION.get()) {
- DisjointWorkspaceBinder workspaceBinder =
- initWorkspaceBinder(incrementBindId, mBgDataModel.collectWorkspaceScreens());
- workspaceBinder.bindCurrentWorkspacePages(isBindSync);
- workspaceBinder.bindOtherWorkspacePages();
- } else {
- bindWorkspaceAllAtOnce(incrementBindId, isBindSync);
+ // Save a copy of all the bg-thread collections
+ ArrayList<ItemInfo> workspaceItems = new ArrayList<>();
+ ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>();
+ final IntArray orderedScreenIds = new IntArray();
+ ArrayList<FixedContainerItems> extraItems = new ArrayList<>();
+ final int workspaceItemCount;
+ synchronized (mBgDataModel) {
+ workspaceItems.addAll(mBgDataModel.workspaceItems);
+ appWidgets.addAll(mBgDataModel.appWidgets);
+ orderedScreenIds.addAll(mBgDataModel.collectWorkspaceScreens());
+ mBgDataModel.extraItems.forEach(extraItems::add);
+ if (incrementBindId) {
+ mBgDataModel.lastBindId++;
+ mBgDataModel.lastLoadId = mApp.getModel().getLastLoadId();
+ }
+ mMyBindingId = mBgDataModel.lastBindId;
+ workspaceItemCount = mBgDataModel.itemsIdMap.size();
+ }
+
+ for (Callbacks cb : mCallbacksList) {
+ new UnifiedWorkspaceBinder(cb, mUiExecutor, mApp, mBgDataModel, mMyBindingId,
+ workspaceItems, appWidgets, extraItems, orderedScreenIds)
+ .bind(isBindSync, workspaceItemCount);
}
} finally {
Trace.endSection();
@@ -114,53 +127,6 @@
}
/**
- * Initializes the WorkspaceBinder for binding.
- *
- * @param incrementBindId this is used to stop previously started binding tasks that are
- * obsolete but still queued.
- * @param workspacePages this allows the Launcher to add the correct workspace screens.
- */
- public DisjointWorkspaceBinder initWorkspaceBinder(boolean incrementBindId,
- IntArray workspacePages) {
-
- synchronized (mBgDataModel) {
- if (incrementBindId) {
- mBgDataModel.lastBindId++;
- mBgDataModel.lastLoadId = mApp.getModel().getLastLoadId();
- }
- mMyBindingId = mBgDataModel.lastBindId;
- return new DisjointWorkspaceBinder(workspacePages);
- }
- }
-
- private void bindWorkspaceAllAtOnce(boolean incrementBindId, boolean isBindSync) {
- // Save a copy of all the bg-thread collections
- ArrayList<ItemInfo> workspaceItems = new ArrayList<>();
- ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>();
- final IntArray orderedScreenIds = new IntArray();
- ArrayList<FixedContainerItems> extraItems = new ArrayList<>();
- final int workspaceItemCount;
- synchronized (mBgDataModel) {
- workspaceItems.addAll(mBgDataModel.workspaceItems);
- appWidgets.addAll(mBgDataModel.appWidgets);
- orderedScreenIds.addAll(mBgDataModel.collectWorkspaceScreens());
- mBgDataModel.extraItems.forEach(extraItems::add);
- if (incrementBindId) {
- mBgDataModel.lastBindId++;
- mBgDataModel.lastLoadId = mApp.getModel().getLastLoadId();
- }
- mMyBindingId = mBgDataModel.lastBindId;
- workspaceItemCount = mBgDataModel.itemsIdMap.size();
- }
-
- for (Callbacks cb : mCallbacksList) {
- new UnifiedWorkspaceBinder(cb, mUiExecutor, mApp, mBgDataModel, mMyBindingId,
- workspaceItems, appWidgets, extraItems, orderedScreenIds)
- .bind(isBindSync, workspaceItemCount);
- }
- }
-
- /**
* BindDeepShortcuts is abstract because it is a no-op for the go launcher.
*/
public void bindDeepShortcuts() {
@@ -347,10 +313,8 @@
bindItemsInChunks(currentWorkspaceItems, ITEMS_CHUNK, mUiExecutor);
bindItemsInChunks(currentAppWidgets, 1, mUiExecutor);
}
- if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
- mExtraItems.forEach(item ->
- executeCallbacksTask(c -> c.bindExtraContainerItems(item), mUiExecutor));
- }
+ mExtraItems.forEach(item ->
+ executeCallbacksTask(c -> c.bindExtraContainerItems(item), mUiExecutor));
RunnableList pendingTasks = new RunnableList();
Executor pendingExecutor = pendingTasks::add;
@@ -440,126 +404,4 @@
});
}
}
-
- private class DisjointWorkspaceBinder {
- private final IntArray mOrderedScreenIds;
- private final IntSet mCurrentScreenIds = new IntSet();
- private final Set<Integer> mBoundItemIds = new HashSet<>();
-
- protected DisjointWorkspaceBinder(IntArray orderedScreenIds) {
- mOrderedScreenIds = orderedScreenIds;
-
- for (Callbacks cb : mCallbacksList) {
- mCurrentScreenIds.addAll(cb.getPagesToBindSynchronously(orderedScreenIds));
- }
- if (mCurrentScreenIds.size() == 0) {
- mCurrentScreenIds.add(Workspace.FIRST_SCREEN_ID);
- }
- }
-
- /**
- * Binds the currently loaded items in the Data Model. Also signals to the Callbacks[]
- * that these items have been bound and their respective screens are ready to be shown.
- *
- * If this method is called after all the items on the workspace screen have already been
- * loaded, it will bind all workspace items immediately, and bindOtherWorkspacePages() will
- * not bind any items.
- */
- protected void bindCurrentWorkspacePages(boolean isBindSync) {
- // Save a copy of all the bg-thread collections
- ArrayList<ItemInfo> workspaceItems;
- ArrayList<LauncherAppWidgetInfo> appWidgets;
- ArrayList<FixedContainerItems> fciList = new ArrayList<>();
- final int workspaceItemCount;
- synchronized (mBgDataModel) {
- workspaceItems = new ArrayList<>(mBgDataModel.workspaceItems);
- appWidgets = new ArrayList<>(mBgDataModel.appWidgets);
- if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
- mBgDataModel.extraItems.forEach(fciList::add);
- }
- workspaceItemCount = mBgDataModel.itemsIdMap.size();
- }
-
- workspaceItems.forEach(it -> mBoundItemIds.add(it.id));
- appWidgets.forEach(it -> mBoundItemIds.add(it.id));
- if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
- fciList.forEach(item ->
- executeCallbacksTask(c -> c.bindExtraContainerItems(item), mUiExecutor));
- }
-
- sortWorkspaceItemsSpatially(mApp.getInvariantDeviceProfile(), workspaceItems);
-
- // Tell the workspace that we're about to start binding items
- executeCallbacksTask(c -> {
- c.clearPendingBinds();
- c.startBinding();
- }, mUiExecutor);
-
- // Bind workspace screens
- executeCallbacksTask(c -> c.bindScreens(mOrderedScreenIds), mUiExecutor);
-
- bindWorkspaceItems(workspaceItems);
- bindAppWidgets(appWidgets);
- executeCallbacksTask(c -> {
- MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
-
- RunnableList onCompleteSignal = new RunnableList();
- onCompleteSignal.executeAllAndDestroy();
- c.onInitialBindComplete(mCurrentScreenIds, new RunnableList(), onCompleteSignal,
- workspaceItemCount, isBindSync);
- }, mUiExecutor);
- }
-
- protected void bindOtherWorkspacePages() {
- // Save a copy of all the bg-thread collections
- ArrayList<ItemInfo> workspaceItems;
- ArrayList<LauncherAppWidgetInfo> appWidgets;
-
- synchronized (mBgDataModel) {
- workspaceItems = new ArrayList<>(mBgDataModel.workspaceItems);
- appWidgets = new ArrayList<>(mBgDataModel.appWidgets);
- }
-
- workspaceItems.removeIf(it -> mBoundItemIds.contains(it.id));
- appWidgets.removeIf(it -> mBoundItemIds.contains(it.id));
-
- sortWorkspaceItemsSpatially(mApp.getInvariantDeviceProfile(), workspaceItems);
-
- bindWorkspaceItems(workspaceItems);
- bindAppWidgets(appWidgets);
-
- executeCallbacksTask(c -> c.finishBindingItems(mCurrentScreenIds), mUiExecutor);
- mUiExecutor.execute(() -> {
- MODEL_EXECUTOR.setThreadPriority(Process.THREAD_PRIORITY_DEFAULT);
- ItemInstallQueue.INSTANCE.get(mApp.getContext())
- .resumeModelPush(FLAG_LOADER_RUNNING);
- });
-
- StringCache cacheClone = mBgDataModel.stringCache.clone();
- executeCallbacksTask(c -> c.bindStringCache(cacheClone), mUiExecutor);
- }
-
- private void bindWorkspaceItems(final ArrayList<ItemInfo> workspaceItems) {
- // Bind the workspace items
- int count = workspaceItems.size();
- for (int i = 0; i < count; i += ITEMS_CHUNK) {
- final int start = i;
- final int chunkSize = (i + ITEMS_CHUNK <= count) ? ITEMS_CHUNK : (count - i);
- executeCallbacksTask(
- c -> c.bindItems(workspaceItems.subList(start, start + chunkSize), false),
- mUiExecutor);
- }
- }
-
- private void bindAppWidgets(List<LauncherAppWidgetInfo> appWidgets) {
- // Bind the widgets, one at a time
- int count = appWidgets.size();
- for (int i = 0; i < count; i++) {
- final ItemInfo widget = appWidgets.get(i);
- executeCallbacksTask(
- c -> c.bindItems(Collections.singletonList(widget), false),
- mUiExecutor);
- }
- }
- }
}
diff --git a/src/com/android/launcher3/model/DbEntry.java b/src/com/android/launcher3/model/DbEntry.java
new file mode 100644
index 0000000..c0c51da
--- /dev/null
+++ b/src/com/android/launcher3/model/DbEntry.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model;
+
+import android.content.ContentValues;
+import android.content.Intent;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.ContentWriter;
+
+import java.net.URISyntaxException;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class DbEntry extends ItemInfo implements Comparable<DbEntry> {
+
+ private static final String TAG = "DbEntry";
+
+ String mIntent;
+ String mProvider;
+ Map<String, Set<Integer>> mFolderItems = new HashMap<>();
+
+ /**
+ * Id of the specific widget.
+ */
+ public int appWidgetId = NO_ID;
+
+ /** Comparator according to the reading order */
+ @Override
+ public int compareTo(DbEntry another) {
+ if (screenId != another.screenId) {
+ return Integer.compare(screenId, another.screenId);
+ }
+ if (cellY != another.cellY) {
+ return Integer.compare(cellY, another.cellY);
+ }
+ return Integer.compare(cellX, another.cellX);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) return true;
+ if (!(o instanceof DbEntry)) return false;
+ DbEntry entry = (DbEntry) o;
+ return Objects.equals(getEntryMigrationId(), entry.getEntryMigrationId());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(getEntryMigrationId());
+ }
+
+ /**
+ * Puts the updated DbEntry values into ContentValues which we then use to insert the
+ * entry to the DB.
+ */
+ public void updateContentValues(ContentValues values) {
+ values.put(LauncherSettings.Favorites.SCREEN, screenId);
+ values.put(LauncherSettings.Favorites.CELLX, cellX);
+ values.put(LauncherSettings.Favorites.CELLY, cellY);
+ values.put(LauncherSettings.Favorites.SPANX, spanX);
+ values.put(LauncherSettings.Favorites.SPANY, spanY);
+ }
+
+ @Override
+ public void writeToValues(@NonNull ContentWriter writer) {
+ super.writeToValues(writer);
+ writer.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
+ }
+
+ @Override
+ public void readFromValues(@NonNull ContentValues values) {
+ super.readFromValues(values);
+ appWidgetId = values.getAsInteger(LauncherSettings.Favorites.APPWIDGET_ID);
+ }
+
+ /**
+ * This id is not used in the DB is only used while doing the migration and it identifies
+ * an entry on each workspace. For example two calculator icons would have the same
+ * migration id even thought they have different database ids.
+ */
+ public String getEntryMigrationId() {
+ switch (itemType) {
+ case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
+ case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
+ return getFolderMigrationId();
+ case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
+ // mProvider is the app the widget belongs to and appWidgetId it's the unique
+ // is of the widget, we need both because if you remove a widget and then add it
+ // again, then it can change and the WidgetProvider would not know the widget.
+ return mProvider + appWidgetId;
+ case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
+ final String intentStr = cleanIntentString(mIntent);
+ try {
+ Intent i = Intent.parseUri(intentStr, 0);
+ return Objects.requireNonNull(i.getComponent()).toString();
+ } catch (Exception e) {
+ return intentStr;
+ }
+ default:
+ return cleanIntentString(mIntent);
+ }
+ }
+
+ /**
+ * This method should return an id that should be the same for two folders containing the
+ * same elements.
+ */
+ @NonNull
+ private String getFolderMigrationId() {
+ return mFolderItems.keySet().stream()
+ .map(intentString -> mFolderItems.get(intentString).size()
+ + cleanIntentString(intentString))
+ .sorted()
+ .collect(Collectors.joining(","));
+ }
+
+ /**
+ * This is needed because sourceBounds can change and make the id of two equal items
+ * different.
+ */
+ @NonNull
+ private String cleanIntentString(@NonNull String intentStr) {
+ try {
+ Intent i = Intent.parseUri(intentStr, 0);
+ i.setSourceBounds(null);
+ return i.toURI();
+ } catch (URISyntaxException e) {
+ Log.e(TAG, "Unable to parse Intent string", e);
+ return intentStr;
+ }
+
+ }
+}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationDBController.java
similarity index 83%
rename from src/com/android/launcher3/model/GridSizeMigrationUtil.java
rename to src/com/android/launcher3/model/GridSizeMigrationDBController.java
index 4c017e9..d8ca095 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationDBController.java
@@ -28,7 +28,6 @@
import android.content.ComponentName;
import android.content.ContentValues;
import android.content.Context;
-import android.content.Intent;
import android.database.Cursor;
import android.database.DatabaseUtils;
import android.database.sqlite.SQLiteDatabase;
@@ -45,15 +44,12 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
-import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.GridOccupancy;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetManagerHelper;
-import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
@@ -61,7 +57,6 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;
@@ -69,12 +64,12 @@
* This class takes care of shrinking the workspace (by maximum of one row and one column), as a
* result of restoring from a larger device or device density change.
*/
-public class GridSizeMigrationUtil {
+public class GridSizeMigrationDBController {
- private static final String TAG = "GridSizeMigrationUtil";
+ private static final String TAG = "GridSizeMigrationDBController";
private static final boolean DEBUG = true;
- private GridSizeMigrationUtil() {
+ private GridSizeMigrationDBController() {
// Util class should not be instantiated
}
@@ -85,7 +80,7 @@
return needsToMigrate(new DeviceGridState(context), new DeviceGridState(idp));
}
- private static boolean needsToMigrate(
+ static boolean needsToMigrate(
DeviceGridState srcDeviceState, DeviceGridState destDeviceState) {
boolean needsToMigrate = !destDeviceState.isCompatible(srcDeviceState);
if (needsToMigrate) {
@@ -95,6 +90,9 @@
return needsToMigrate;
}
+ /**
+ * @return all the workspace and hotseat entries in the db.
+ */
@VisibleForTesting
public static List<DbEntry> readAllEntries(SQLiteDatabase db, String tableName,
Context context) {
@@ -198,7 +196,7 @@
Collectors.joining(",\n", "[", "]"))
+ "\n Removing Items:"
+ dstWorkspaceItems.stream().filter(entry ->
- toBeRemoved.contains(entry.id)).map(DbEntry::toString).collect(
+ toBeRemoved.contains(entry.id)).map(DbEntry::toString).collect(
Collectors.joining(",\n", "[", "]"))
+ "\n Adding Workspace Items:"
+ workspaceToBeAdded.stream().map(DbEntry::toString).collect(
@@ -291,7 +289,7 @@
});
}
- private static void insertEntryInDb(DatabaseHelper helper, DbEntry entry,
+ static void insertEntryInDb(DatabaseHelper helper, DbEntry entry,
String srcTableName, String destTableName, List<Integer> idsInUse) {
int id = copyEntryAndUpdate(helper, entry, srcTableName, destTableName, idsInUse);
if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER
@@ -330,10 +328,9 @@
} else {
values.put(LauncherSettings.Favorites.CONTAINER, folderId);
}
- newId = helper.generateNewItemId();
- while (idsInUse.contains(newId)) {
+ do {
newId = helper.generateNewItemId();
- }
+ } while (idsInUse.contains(newId));
values.put(LauncherSettings.Favorites._ID, newId);
helper.getWritableDatabase().insert(destTableName, null, values);
}
@@ -341,7 +338,7 @@
return newId;
}
- private static void removeEntryFromDb(SQLiteDatabase db, String tableName, IntArray entryIds) {
+ static void removeEntryFromDb(SQLiteDatabase db, String tableName, IntArray entryIds) {
db.delete(tableName,
Utilities.createDbSelectionQuery(LauncherSettings.Favorites._ID, entryIds), null);
}
@@ -387,7 +384,7 @@
private static boolean findPlacementForEntry(@NonNull final DbEntry entry,
@NonNull final Point next, @NonNull final Point trg,
@NonNull final GridOccupancy occupied, final int screenId) {
- for (int y = next.y; y < trg.y; y++) {
+ for (int y = next.y; y < trg.y; y++) {
for (int x = next.x; x < trg.x; x++) {
boolean fits = occupied.isRegionVacant(x, y, entry.spanX, entry.spanY);
boolean minFits = occupied.isRegionVacant(x, y, entry.minSpanX,
@@ -413,7 +410,7 @@
private static void solveHotseatPlacement(
@NonNull final DatabaseHelper helper, final int hotseatSize,
@NonNull final DbReader srcReader, @NonNull final DbReader destReader,
- @NonNull final List<DbEntry> placedHotseatItems,
+ @NonNull final List<DbEntry> placedHotseatItems,
@NonNull final List<DbEntry> itemsToPlace, List<Integer> idsInUse) {
final boolean[] occupied = new boolean[hotseatSize];
@@ -436,15 +433,26 @@
}
}
- @VisibleForTesting
+ static void copyCurrentGridToNewGrid(
+ @NonNull Context context,
+ @NonNull DeviceGridState destDeviceState,
+ @NonNull DatabaseHelper target,
+ @NonNull SQLiteDatabase source) {
+ // Only use this strategy when comparing the previous grid to the new grid and the
+ // columns are the same and the destination has more rows
+ copyTable(source, TABLE_NAME, target.getWritableDatabase(), TABLE_NAME, context);
+ destDeviceState.writeToPrefs(context);
+ }
+
+ @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)
public static class DbReader {
- private final SQLiteDatabase mDb;
- private final String mTableName;
- private final Context mContext;
- private int mLastScreenId = -1;
+ final SQLiteDatabase mDb;
+ final String mTableName;
+ final Context mContext;
+ int mLastScreenId = -1;
- private final Map<Integer, ArrayList<DbEntry>> mWorkspaceEntriesByScreenId =
+ final Map<Integer, ArrayList<DbEntry>> mWorkspaceEntriesByScreenId =
new ArrayMap<>();
public DbReader(SQLiteDatabase db, String tableName, Context context) {
@@ -529,7 +537,7 @@
LauncherSettings.Favorites.INTENT, // 7
LauncherSettings.Favorites.APPWIDGET_PROVIDER, // 8
LauncherSettings.Favorites.APPWIDGET_ID}, // 9
- LauncherSettings.Favorites.CONTAINER + " = "
+ LauncherSettings.Favorites.CONTAINER + " = "
+ LauncherSettings.Favorites.CONTAINER_DESKTOP);
final int indexId = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
final int indexItemType = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
@@ -648,118 +656,4 @@
return mDb.query(mTableName, columns, where, null, null, null, null);
}
}
-
- public static class DbEntry extends ItemInfo implements Comparable<DbEntry> {
-
- private String mIntent;
- private String mProvider;
- private Map<String, Set<Integer>> mFolderItems = new HashMap<>();
-
- /**
- * Id of the specific widget.
- */
- public int appWidgetId = NO_ID;
-
- /** Comparator according to the reading order */
- @Override
- public int compareTo(DbEntry another) {
- if (screenId != another.screenId) {
- return Integer.compare(screenId, another.screenId);
- }
- if (cellY != another.cellY) {
- return Integer.compare(cellY, another.cellY);
- }
- return Integer.compare(cellX, another.cellX);
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- DbEntry entry = (DbEntry) o;
- return Objects.equals(getEntryMigrationId(), entry.getEntryMigrationId());
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(getEntryMigrationId());
- }
-
- public void updateContentValues(ContentValues values) {
- values.put(LauncherSettings.Favorites.SCREEN, screenId);
- values.put(LauncherSettings.Favorites.CELLX, cellX);
- values.put(LauncherSettings.Favorites.CELLY, cellY);
- values.put(LauncherSettings.Favorites.SPANX, spanX);
- values.put(LauncherSettings.Favorites.SPANY, spanY);
- }
-
- @Override
- public void writeToValues(@NonNull ContentWriter writer) {
- super.writeToValues(writer);
- writer.put(LauncherSettings.Favorites.APPWIDGET_ID, appWidgetId);
- }
-
- @Override
- public void readFromValues(@NonNull ContentValues values) {
- super.readFromValues(values);
- appWidgetId = values.getAsInteger(LauncherSettings.Favorites.APPWIDGET_ID);
- }
-
- /** This id is not used in the DB is only used while doing the migration and it identifies
- * an entry on each workspace. For example two calculator icons would have the same
- * migration id even thought they have different database ids.
- */
- public String getEntryMigrationId() {
- switch (itemType) {
- case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
- case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
- return getFolderMigrationId();
- case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET:
- // mProvider is the app the widget belongs to and appWidgetId it's the unique
- // is of the widget, we need both because if you remove a widget and then add it
- // again, then it can change and the WidgetProvider would not know the widget.
- return mProvider + appWidgetId;
- case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- final String intentStr = cleanIntentString(mIntent);
- try {
- Intent i = Intent.parseUri(intentStr, 0);
- return Objects.requireNonNull(i.getComponent()).toString();
- } catch (Exception e) {
- return intentStr;
- }
- default:
- return cleanIntentString(mIntent);
- }
- }
-
- /**
- * This method should return an id that should be the same for two folders containing the
- * same elements.
- */
- @NonNull
- private String getFolderMigrationId() {
- return mFolderItems.keySet().stream()
- .map(intentString -> mFolderItems.get(intentString).size()
- + cleanIntentString(intentString))
- .sorted()
- .collect(Collectors.joining(","));
- }
-
- /**
- * This is needed because sourceBounds can change and make the id of two equal items
- * different.
- */
- @NonNull
- private String cleanIntentString(@NonNull String intentStr) {
- try {
- Intent i = Intent.parseUri(intentStr, 0);
- i.setSourceBounds(null);
- return i.toURI();
- } catch (URISyntaxException e) {
- Log.e(TAG, "Unable to parse Intent string", e);
- return intentStr;
- }
-
- }
- }
}
diff --git a/src/com/android/launcher3/model/GridSizeMigrationLogic.java b/src/com/android/launcher3/model/GridSizeMigrationLogic.java
new file mode 100644
index 0000000..f8c8f77
--- /dev/null
+++ b/src/com/android/launcher3/model/GridSizeMigrationLogic.java
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model;
+
+import static com.android.launcher3.Flags.enableSmartspaceRemovalToggle;
+import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
+import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
+import static com.android.launcher3.LauncherSettings.Favorites.TMP_TABLE;
+import static com.android.launcher3.Utilities.SHOULD_SHOW_FIRST_PAGE_WIDGET;
+import static com.android.launcher3.model.GridSizeMigrationDBController.copyCurrentGridToNewGrid;
+import static com.android.launcher3.model.GridSizeMigrationDBController.insertEntryInDb;
+import static com.android.launcher3.model.GridSizeMigrationDBController.needsToMigrate;
+import static com.android.launcher3.model.GridSizeMigrationDBController.removeEntryFromDb;
+import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN;
+import static com.android.launcher3.provider.LauncherDbUtils.copyTable;
+import static com.android.launcher3.provider.LauncherDbUtils.dropTable;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Point;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.VisibleForTesting;
+
+import com.android.launcher3.Flags;
+import com.android.launcher3.LauncherPrefs;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.provider.LauncherDbUtils;
+import com.android.launcher3.util.CellAndSpan;
+import com.android.launcher3.util.GridOccupancy;
+import com.android.launcher3.util.IntArray;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+public class GridSizeMigrationLogic {
+
+ private static final String TAG = "GridSizeMigrationLogic";
+ private static final boolean DEBUG = true;
+
+ /**
+ * Migrates the grid size from srcDeviceState to destDeviceState and make those changes
+ * in the target DB, using the source DB to determine what to add/remove/move/resize
+ * in the destination DB.
+ */
+ public void migrateGrid(
+ @NonNull Context context,
+ @NonNull DeviceGridState srcDeviceState,
+ @NonNull DeviceGridState destDeviceState,
+ @NonNull DatabaseHelper target,
+ @NonNull SQLiteDatabase source) {
+ if (!needsToMigrate(srcDeviceState, destDeviceState)) {
+ return;
+ }
+
+ boolean isFirstLoad = LauncherPrefs.get(context).get(IS_FIRST_LOAD_AFTER_RESTORE);
+ Log.d(TAG, "Begin grid migration. First load: " + isFirstLoad);
+
+ // This is a special case where if the grid is the same amount of columns but a larger
+ // amount of rows we simply copy over the source grid to the destination grid, rather
+ // than undergoing the general grid migration.
+ if (shouldMigrateToStrictlyTallerGrid(isFirstLoad, srcDeviceState, destDeviceState)) {
+ copyCurrentGridToNewGrid(context, destDeviceState, target, source);
+ return;
+ }
+ copyTable(source, TABLE_NAME, target.getWritableDatabase(), TMP_TABLE, context);
+
+ long migrationStartTime = System.currentTimeMillis();
+ try (LauncherDbUtils.SQLiteTransaction t =
+ new LauncherDbUtils.SQLiteTransaction(target.getWritableDatabase())) {
+ GridSizeMigrationDBController.DbReader srcReader = new GridSizeMigrationDBController
+ .DbReader(t.getDb(), TMP_TABLE, context);
+ GridSizeMigrationDBController.DbReader destReader =
+ new GridSizeMigrationDBController.DbReader(
+ t.getDb(), TABLE_NAME, context);
+
+ Point targetSize = new Point(destDeviceState.getColumns(), destDeviceState.getRows());
+
+ // Here we keep all the DB ids we have in the destination DB such that we don't assign
+ // an item that we want to add to the destination DB the same id as an already existing
+ // item.
+ List<Integer> idsInUse = new ArrayList<>();
+
+ // Migrate hotseat.
+ migrateHotseat(destDeviceState.getNumHotseat(), srcReader, destReader, target,
+ idsInUse);
+ // Migrate workspace.
+ migrateWorkspace(srcReader, destReader, target, targetSize, idsInUse);
+
+ dropTable(t.getDb(), TMP_TABLE);
+ t.commit();
+ } catch (Exception e) {
+ Log.e(TAG, "Error during grid migration", e);
+ } finally {
+ Log.v(TAG, "Workspace migration completed in "
+ + (System.currentTimeMillis() - migrationStartTime));
+
+ // Save current configuration, so that the migration does not run again.
+ destDeviceState.writeToPrefs(context);
+ }
+ }
+
+ /**
+ * Handles hotseat migration.
+ */
+ @VisibleForTesting
+ public void migrateHotseat(int destHotseatSize,
+ GridSizeMigrationDBController.DbReader srcReader,
+ GridSizeMigrationDBController.DbReader destReader,
+ DatabaseHelper helper, List<Integer> idsInUse) {
+ final List<DbEntry> srcHotseatItems =
+ srcReader.loadHotseatEntries();
+ final List<DbEntry> dstHotseatItems =
+ destReader.loadHotseatEntries();
+
+ final List<DbEntry> hotseatToBeAdded =
+ getItemsToBeAdded(srcHotseatItems, dstHotseatItems);
+
+ final IntArray toBeRemoved = new IntArray();
+ toBeRemoved.addAll(getItemsToBeRemoved(srcHotseatItems, dstHotseatItems));
+
+ if (DEBUG) {
+ Log.d(TAG, "Start hotseat migration:"
+ + "\n Removing Hotseat Items:"
+ + dstHotseatItems.stream().filter(entry -> toBeRemoved
+ .contains(entry.id)).map(DbEntry::toString)
+ .collect(Collectors.joining(",\n", "[", "]"))
+ + "\n Adding Hotseat Items:"
+ + hotseatToBeAdded.stream().map(DbEntry::toString)
+ .collect(Collectors.joining(",\n", "[", "]"))
+ );
+ }
+
+ // Removes the items that we need to remove from the destination DB.
+ if (!toBeRemoved.isEmpty()) {
+ removeEntryFromDb(destReader.mDb, destReader.mTableName, toBeRemoved);
+ }
+
+ placeHotseatItems(hotseatToBeAdded, dstHotseatItems, destHotseatSize, helper, srcReader,
+ destReader, idsInUse);
+ }
+
+ private void placeHotseatItems(List<DbEntry> hotseatToBeAdded,
+ List<DbEntry> dstHotseatItems, int destHotseatSize,
+ DatabaseHelper helper, GridSizeMigrationDBController.DbReader srcReader,
+ GridSizeMigrationDBController.DbReader destReader, List<Integer> idsInUse) {
+ if (hotseatToBeAdded.isEmpty()) {
+ return;
+ }
+
+ idsInUse.addAll(dstHotseatItems.stream().map(entry -> entry.id).toList());
+
+ Collections.sort(hotseatToBeAdded);
+
+ List<DbEntry> placementSolutionHotseat =
+ solveHotseatPlacement(destHotseatSize, dstHotseatItems, hotseatToBeAdded);
+ for (DbEntry entryToPlace: placementSolutionHotseat) {
+ insertEntryInDb(helper, entryToPlace, srcReader.mTableName, destReader.mTableName,
+ idsInUse);
+ }
+ }
+
+
+ /**
+ * Handles workspace migration.
+ */
+ @VisibleForTesting
+ public void migrateWorkspace(GridSizeMigrationDBController.DbReader srcReader,
+ GridSizeMigrationDBController.DbReader destReader, DatabaseHelper helper,
+ Point targetSize, List<Integer> idsInUse) {
+ final List<DbEntry> srcWorkspaceItems =
+ srcReader.loadAllWorkspaceEntries();
+
+ final List<DbEntry> dstWorkspaceItems =
+ destReader.loadAllWorkspaceEntries();
+
+ final IntArray toBeRemoved = new IntArray();
+
+ List<DbEntry> workspaceToBeAdded =
+ getItemsToBeAdded(srcWorkspaceItems, dstWorkspaceItems);
+ toBeRemoved.addAll(getItemsToBeRemoved(srcWorkspaceItems, dstWorkspaceItems));
+
+ if (DEBUG) {
+ Log.d(TAG, "Start workspace migration:"
+ + "\n Source Device:"
+ + srcWorkspaceItems.stream().map(
+ DbEntry::toString)
+ .collect(Collectors.joining(",\n", "[", "]"))
+ + "\n Target Device:"
+ + dstWorkspaceItems.stream().map(
+ DbEntry::toString)
+ .collect(Collectors.joining(",\n", "[", "]"))
+ + "\n Removing Workspace Items:"
+ + dstWorkspaceItems.stream().filter(entry -> toBeRemoved
+ .contains(entry.id)).map(
+ DbEntry::toString)
+ .collect(Collectors.joining(",\n", "[", "]"))
+ + "\n Adding Workspace Items:"
+ + workspaceToBeAdded.stream().map(
+ DbEntry::toString)
+ .collect(Collectors.joining(",\n", "[", "]"))
+ );
+ }
+
+ // Removes the items that we need to remove from the destination DB.
+ if (!toBeRemoved.isEmpty()) {
+ removeEntryFromDb(destReader.mDb, destReader.mTableName, toBeRemoved);
+ }
+
+ placeWorkspaceItems(workspaceToBeAdded, dstWorkspaceItems, targetSize.x, targetSize.y,
+ helper, srcReader, destReader, idsInUse);
+ }
+
+ private void placeWorkspaceItems(
+ List<DbEntry> workspaceToBeAdded,
+ List<DbEntry> dstWorkspaceItems,
+ int trgX, int trgY, DatabaseHelper helper,
+ GridSizeMigrationDBController.DbReader srcReader,
+ GridSizeMigrationDBController.DbReader destReader, List<Integer> idsInUse) {
+ if (workspaceToBeAdded.isEmpty()) {
+ return;
+ }
+
+ idsInUse.addAll(dstWorkspaceItems.stream().map(entry -> entry.id).toList());
+
+ Collections.sort(workspaceToBeAdded);
+
+
+ // First we create a collection of the screens
+ List<Integer> screens = new ArrayList<>();
+ for (int screenId = 0; screenId <= destReader.mLastScreenId; screenId++) {
+ screens.add(screenId);
+ }
+
+ // Then we place the items on the screens
+ WorkspaceItemsToPlace itemsToPlace =
+ new WorkspaceItemsToPlace(workspaceToBeAdded);
+ for (int screenId : screens) {
+ if (DEBUG) {
+ Log.d(TAG, "Migrating " + screenId);
+ }
+ itemsToPlace = solveGridPlacement(
+ destReader.mContext, screenId, trgX, trgY, itemsToPlace.mRemainingItemsToPlace,
+ destReader.mWorkspaceEntriesByScreenId.get(screenId));
+ placeItems(itemsToPlace, helper, srcReader, destReader, idsInUse);
+ while (!itemsToPlace.mPlacementSolution.isEmpty()) {
+ insertEntryInDb(helper, itemsToPlace.mPlacementSolution.remove(0),
+ srcReader.mTableName, destReader.mTableName, idsInUse);
+ }
+ if (itemsToPlace.mRemainingItemsToPlace.isEmpty()) {
+ break;
+ }
+ }
+
+ // In case the new grid is smaller, there might be some leftover items that don't fit on
+ // any of the screens, in this case we add them to new screens until all of them are placed.
+ int screenId = destReader.mLastScreenId + 1;
+ while (!itemsToPlace.mRemainingItemsToPlace.isEmpty()) {
+ itemsToPlace = solveGridPlacement(destReader.mContext, screenId,
+ trgX, trgY, itemsToPlace.mRemainingItemsToPlace,
+ destReader.mWorkspaceEntriesByScreenId.get(screenId));
+ placeItems(itemsToPlace, helper, srcReader, destReader, idsInUse);
+ screenId++;
+ }
+ }
+
+ private void placeItems(WorkspaceItemsToPlace itemsToPlace, DatabaseHelper helper,
+ GridSizeMigrationDBController.DbReader srcReader,
+ GridSizeMigrationDBController.DbReader destReader, List<Integer> idsInUse) {
+ while (!itemsToPlace.mPlacementSolution.isEmpty()) {
+ insertEntryInDb(helper, itemsToPlace.mPlacementSolution.remove(0),
+ srcReader.mTableName, destReader.mTableName, idsInUse);
+ }
+ }
+
+
+ /**
+ * Only migrate the grid in this manner if the target grid is taller and not wider.
+ */
+ private boolean shouldMigrateToStrictlyTallerGrid(boolean isFirstLoad,
+ @NonNull DeviceGridState srcDeviceState,
+ @NonNull DeviceGridState destDeviceState) {
+ if (isFirstLoad
+ && Flags.enableGridMigrationFix()
+ && srcDeviceState.getColumns().equals(destDeviceState.getColumns())
+ && srcDeviceState.getRows() < destDeviceState.getRows()) {
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Finds all the items that are in the old grid which aren't in the new grid, meaning they
+ * need to be added to the new grid.
+ *
+ * @return a list of DbEntry's which we need to add.
+ */
+ private List<DbEntry> getItemsToBeAdded(
+ @NonNull final List<DbEntry> src,
+ @NonNull final List<DbEntry> dest) {
+ Map<DbEntry, Integer> entryCountDiff =
+ calcDiff(src, dest);
+ List<DbEntry> toBeAdded = new ArrayList<>();
+ src.forEach(entry -> {
+ if (entryCountDiff.get(entry) > 0) {
+ toBeAdded.add(entry);
+ entryCountDiff.put(entry, entryCountDiff.get(entry) - 1);
+ }
+ });
+ return toBeAdded;
+ }
+
+ /**
+ * Finds all the items that are in the new grid which aren't in the old grid, meaning they
+ * need to be removed from the new grid.
+ *
+ * @return an IntArray of item id's which we need to remove.
+ */
+ private IntArray getItemsToBeRemoved(
+ @NonNull final List<DbEntry> src,
+ @NonNull final List<DbEntry> dest) {
+ Map<DbEntry, Integer> entryCountDiff =
+ calcDiff(src, dest);
+ IntArray toBeRemoved = new IntArray();
+ dest.forEach(entry -> {
+ if (entryCountDiff.get(entry) < 0) {
+ toBeRemoved.add(entry.id);
+ if (entry.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
+ entry.mFolderItems.values().forEach(ids -> ids.forEach(toBeRemoved::add));
+ }
+ entryCountDiff.put(entry, entryCountDiff.get(entry) + 1);
+ }
+ });
+ return toBeRemoved;
+ }
+
+ /**
+ * Calculates the difference between the old and new grid items in terms of how many of each
+ * item there are. E.g. if the old grid had 2 Calculator icons but the new grid has 0, then the
+ * difference there would be 2. While if the old grid has 0 Calculator icons and the
+ * new grid has 1, then the difference would be -1.
+ *
+ * @return a Map with each DbEntry as a key and the count of said entry as the value.
+ */
+ private Map<DbEntry, Integer> calcDiff(
+ @NonNull final List<DbEntry> src,
+ @NonNull final List<DbEntry> dest) {
+ Map<DbEntry, Integer> entryCountDiff = new HashMap<>();
+ src.forEach(entry ->
+ entryCountDiff.put(entry, entryCountDiff.getOrDefault(entry, 0) + 1));
+ dest.forEach(entry ->
+ entryCountDiff.put(entry, entryCountDiff.getOrDefault(entry, 0) - 1));
+ return entryCountDiff;
+ }
+
+ private List<DbEntry> solveHotseatPlacement(final int hotseatSize,
+ @NonNull final List<DbEntry> placedHotseatItems,
+ @NonNull final List<DbEntry> itemsToPlace) {
+ List<DbEntry> placementSolution = new ArrayList<>();
+ List<DbEntry> remainingItemsToPlace =
+ new ArrayList<>(itemsToPlace);
+ final boolean[] occupied = new boolean[hotseatSize];
+ for (DbEntry entry : placedHotseatItems) {
+ occupied[entry.screenId] = true;
+ }
+
+ for (int i = 0; i < occupied.length; i++) {
+ if (!occupied[i] && !remainingItemsToPlace.isEmpty()) {
+ DbEntry entry = remainingItemsToPlace.remove(0);
+ entry.screenId = i;
+ // These values does not affect the item position, but we should set them
+ // to something other than -1.
+ entry.cellX = i;
+ entry.cellY = 0;
+
+ placementSolution.add(entry);
+ occupied[entry.screenId] = true;
+ }
+ }
+ return placementSolution;
+ }
+
+ private WorkspaceItemsToPlace solveGridPlacement(
+ Context context,
+ final int screenId, final int trgX, final int trgY,
+ @NonNull final List<DbEntry> sortedItemsToPlace,
+ List<DbEntry> existedEntries) {
+ WorkspaceItemsToPlace itemsToPlace = new WorkspaceItemsToPlace(sortedItemsToPlace);
+ final GridOccupancy occupied = new GridOccupancy(trgX, trgY);
+ final Point trg = new Point(trgX, trgY);
+ final Point next = new Point(0, screenId == 0
+ && (FeatureFlags.QSB_ON_FIRST_SCREEN
+ && (!enableSmartspaceRemovalToggle() || LauncherPrefs.getPrefs(context)
+ .getBoolean(SMARTSPACE_ON_HOME_SCREEN, true))
+ && !SHOULD_SHOW_FIRST_PAGE_WIDGET)
+ ? 1 /* smartspace */ : 0);
+ if (existedEntries != null) {
+ for (DbEntry entry : existedEntries) {
+ occupied.markCells(entry, true);
+ }
+ }
+ Iterator<DbEntry> iterator =
+ itemsToPlace.mRemainingItemsToPlace.iterator();
+ while (iterator.hasNext()) {
+ final DbEntry entry = iterator.next();
+ if (entry.minSpanX > trgX || entry.minSpanY > trgY) {
+ iterator.remove();
+ continue;
+ }
+ CellAndSpan placement = findPlacementForEntry(
+ entry, next.x, next.y, trg, occupied);
+ if (placement != null) {
+ entry.screenId = screenId;
+ entry.cellX = placement.cellX;
+ entry.cellY = placement.cellY;
+ entry.spanX = placement.spanX;
+ entry.spanY = placement.spanY;
+ occupied.markCells(entry, true);
+ next.set(entry.cellX + entry.spanX, entry.cellY);
+ itemsToPlace.mPlacementSolution.add(entry);
+ iterator.remove();
+ }
+ }
+ return itemsToPlace;
+ }
+
+ /**
+ * Search for the next possible placement of an item. (mNextStartX, mNextStartY) serves as
+ * a memoization of last placement, we can start our search for next placement from there
+ * to speed up the search.
+ *
+ * @return NewEntryPlacement object if we found a valid placement, null if we didn't.
+ */
+ private CellAndSpan findPlacementForEntry(
+ @NonNull final DbEntry entry,
+ int startPosX, int startPosY, @NonNull final Point trg,
+ @NonNull final GridOccupancy occupied) {
+ for (int y = startPosY; y < trg.y; y++) {
+ for (int x = startPosX; x < trg.x; x++) {
+ boolean minFits = occupied.isRegionVacant(x, y, entry.minSpanX, entry.minSpanY);
+ if (minFits) {
+ return (new CellAndSpan(x, y, entry.minSpanX, entry.minSpanY));
+ }
+ }
+ startPosX = 0;
+ }
+ return null;
+ }
+
+ private static class WorkspaceItemsToPlace {
+ List<DbEntry> mRemainingItemsToPlace;
+ List<DbEntry> mPlacementSolution;
+
+ WorkspaceItemsToPlace(List<DbEntry> sortedItemsToPlace) {
+ mRemainingItemsToPlace = new ArrayList<>(sortedItemsToPlace);
+ mPlacementSolution = new ArrayList<>();
+ }
+
+ }
+}
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 09d1146..06d8b59 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -287,11 +287,6 @@
}
logASplit("loadAllApps");
- if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
- mModelDelegate.loadAndBindAllAppsItems(mUserManagerState,
- mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts);
- logASplit("allAppsDelegateItems");
- }
verifyNotStopped();
mLauncherBinder.bindAllApps();
logASplit("bindAllApps");
@@ -356,12 +351,6 @@
prefs.putSync(SHOULD_SHOW_SMARTSPACE.to(true));
}
- if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
- mModelDelegate.loadAndBindOtherItems(mLauncherBinder.mCallbacksList);
- logASplit("otherDelegateItems");
- verifyNotStopped();
- }
-
updateHandler.updateIcons(allWidgetsList,
CachedObjectCachingLogic.INSTANCE,
mApp.getModel()::onWidgetLabelsUpdated);
@@ -413,13 +402,6 @@
}
logASplit("loadWorkspace");
- if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
- verifyNotStopped();
- mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState,
- mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts);
- mModelDelegate.markActive();
- logASplit("workspaceDelegateItems");
- }
mBgDataModel.isFirstPagePinnedItemEnabled = FeatureFlags.QSB_ON_FIRST_SCREEN
&& (!enableSmartspaceRemovalToggle() || LauncherPrefs.getPrefs(
mApp.getContext()).getBoolean(SMARTSPACE_ON_HOME_SCREEN, true));
@@ -435,7 +417,15 @@
final WidgetInflater widgetInflater = new WidgetInflater(context);
ModelDbController dbController = mApp.getModel().getModelDbController();
- dbController.tryMigrateDB(restoreEventLogger);
+ if (Flags.gridMigrationRefactor()) {
+ try {
+ dbController.attemptMigrateDb(restoreEventLogger);
+ } catch (Exception e) {
+ FileLog.e(TAG, "Failed to migrate grid", e);
+ }
+ } else {
+ dbController.tryMigrateDB(restoreEventLogger);
+ }
Log.d(TAG, "loadWorkspace: loading default favorites");
dbController.loadDefaultFavoritesIfNecessary();
@@ -482,14 +472,12 @@
IOUtils.closeSilently(c);
}
- if (!FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) {
- mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState,
- mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts);
- mModelDelegate.loadAndBindAllAppsItems(mUserManagerState,
- mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts);
- mModelDelegate.loadAndBindOtherItems(mLauncherBinder.mCallbacksList);
- mModelDelegate.markActive();
- }
+ mModelDelegate.loadAndBindWorkspaceItems(mUserManagerState,
+ mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts);
+ mModelDelegate.loadAndBindAllAppsItems(mUserManagerState,
+ mLauncherBinder.mCallbacksList, mShortcutKeyToPinnedShortcuts);
+ mModelDelegate.loadAndBindOtherItems(mLauncherBinder.mCallbacksList);
+ mModelDelegate.markActive();
// Break early if we've stopped loading
if (mStopped) {
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index 5d66d16..8c3e860 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -20,15 +20,16 @@
import static android.util.Base64.NO_WRAP;
import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT;
+import static com.android.launcher3.LauncherPrefs.NO_DB_FILES_RESTORED;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb;
import static com.android.launcher3.LauncherSettings.Settings.BLOB_KEY_PREFIX;
-import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_PROVIDER_KEY;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_TAG;
+import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_PROVIDER_KEY;
import static com.android.launcher3.provider.LauncherDbUtils.tableExists;
import android.app.blob.BlobHandle;
@@ -97,6 +98,7 @@
private static final String EMPTY_DATABASE_CREATED = "EMPTY_DATABASE_CREATED";
public static final String EXTRA_DB_NAME = "db_name";
+ public static final String DATA_TYPE_DB_FILE = "database_file";
protected DatabaseHelper mOpenHelper;
@@ -289,13 +291,115 @@
/**
+ * Resets the launcher DB if we should reset it.
+ */
+ public void resetLauncherDb(@Nullable LauncherRestoreEventLogger restoreEventLogger) {
+ if (restoreEventLogger != null) {
+ sendMetricsForFailedMigration(restoreEventLogger, getDb());
+ }
+ FileLog.d(TAG, "Migration failed: resetting launcher database");
+ createEmptyDB();
+ LauncherPrefs.get(mContext).putSync(
+ getEmptyDbCreatedKey(mOpenHelper.getDatabaseName()).to(true));
+
+ // Write the grid state to avoid another migration
+ new DeviceGridState(LauncherAppState.getIDP(mContext)).writeToPrefs(mContext);
+ }
+
+ /**
+ * Determines if we should reset the DB.
+ */
+ private boolean shouldResetDb() {
+ if (isThereExistingDb()) {
+ return true;
+ }
+ if (!isGridMigrationNecessary()) {
+ return false;
+ }
+ if (isCurrentDbSameAsTarget()) {
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isThereExistingDb() {
+ if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) {
+ // If we already have a new DB, ignore migration
+ FileLog.d(TAG, "migrateGridIfNeeded: new DB already created, skipping migration");
+ return true;
+ }
+ return false;
+ }
+
+ private boolean isGridMigrationNecessary() {
+ InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
+ if (GridSizeMigrationDBController.needsToMigrate(mContext, idp)) {
+ return true;
+ }
+ FileLog.d(TAG, "migrateGridIfNeeded: no grid migration needed");
+ return false;
+ }
+
+ private boolean isCurrentDbSameAsTarget() {
+ InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
+ String targetDbName = new DeviceGridState(idp).getDbFile();
+ if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) {
+ FileLog.e(TAG, "migrateGridIfNeeded: target db is same as current: " + targetDbName);
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Migrates the DB. If the migration failed, it clears the DB.
+ */
+ public void attemptMigrateDb(LauncherRestoreEventLogger restoreEventLogger) throws Exception {
+ createDbIfNotExists();
+
+ if (shouldResetDb()) {
+ resetLauncherDb(restoreEventLogger);
+ return;
+ }
+
+ InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
+ DatabaseHelper oldHelper = mOpenHelper;
+ mOpenHelper = (mContext instanceof SandboxContext) ? oldHelper
+ : createDatabaseHelper(true /* forMigration */);
+ try {
+ // This is the current grid we have, given by the mContext
+ DeviceGridState srcDeviceState = new DeviceGridState(mContext);
+ // This is the state we want to migrate to that is given by the idp
+ DeviceGridState destDeviceState = new DeviceGridState(idp);
+
+ GridSizeMigrationLogic gridSizeMigrationLogic = new GridSizeMigrationLogic();
+ gridSizeMigrationLogic.migrateGrid(mContext, srcDeviceState, destDeviceState,
+ mOpenHelper, oldHelper.getWritableDatabase());
+ } catch (Exception e) {
+ resetLauncherDb(restoreEventLogger);
+ throw new Exception("Failed to migrate grid", e);
+ } finally {
+ if (mOpenHelper != oldHelper) {
+ oldHelper.close();
+ }
+ }
+ }
+
+ /**
* Migrates the DB if needed. If the migration failed, it clears the DB.
*/
public void tryMigrateDB(@Nullable LauncherRestoreEventLogger restoreEventLogger) {
if (!migrateGridIfNeeded()) {
if (restoreEventLogger != null) {
- sendMetricsForFailedMigration(restoreEventLogger, getDb());
+ if (LauncherPrefs.get(mContext).get(NO_DB_FILES_RESTORED)) {
+ restoreEventLogger.logLauncherItemsRestoreFailed(DATA_TYPE_DB_FILE, 1,
+ RestoreError.DATABASE_FILE_NOT_RESTORED);
+ LauncherPrefs.get(mContext).put(NO_DB_FILES_RESTORED, false);
+ FileLog.d(TAG, "There is no data to migrate: resetting launcher database");
+ } else {
+ restoreEventLogger.logLauncherItemsRestored(DATA_TYPE_DB_FILE, 1);
+ sendMetricsForFailedMigration(restoreEventLogger, getDb());
+ }
}
FileLog.d(TAG, "Migration failed: resetting launcher database");
createEmptyDB();
@@ -304,6 +408,8 @@
// Write the grid state to avoid another migration
new DeviceGridState(LauncherAppState.getIDP(mContext)).writeToPrefs(mContext);
+ } else if (restoreEventLogger != null) {
+ restoreEventLogger.logLauncherItemsRestored(DATA_TYPE_DB_FILE, 1);
}
}
@@ -317,17 +423,17 @@
createDbIfNotExists();
if (LauncherPrefs.get(mContext).get(getEmptyDbCreatedKey())) {
// If we have already create a new DB, ignore migration
- Log.d(TAG, "migrateGridIfNeeded: new DB already created, skipping migration");
+ FileLog.d(TAG, "migrateGridIfNeeded: new DB already created, skipping migration");
return false;
}
InvariantDeviceProfile idp = LauncherAppState.getIDP(mContext);
- if (!GridSizeMigrationUtil.needsToMigrate(mContext, idp)) {
- Log.d(TAG, "migrateGridIfNeeded: no grid migration needed");
+ if (!GridSizeMigrationDBController.needsToMigrate(mContext, idp)) {
+ FileLog.d(TAG, "migrateGridIfNeeded: no grid migration needed");
return true;
}
String targetDbName = new DeviceGridState(idp).getDbFile();
if (TextUtils.equals(targetDbName, mOpenHelper.getDatabaseName())) {
- Log.e(TAG, "migrateGridIfNeeded: target db is same as current: " + targetDbName);
+ FileLog.e(TAG, "migrateGridIfNeeded: target db is same as current: " + targetDbName);
return false;
}
DatabaseHelper oldHelper = mOpenHelper;
@@ -338,7 +444,7 @@
DeviceGridState srcDeviceState = new DeviceGridState(mContext);
// This is the state we want to migrate to that is given by the idp
DeviceGridState destDeviceState = new DeviceGridState(idp);
- return GridSizeMigrationUtil.migrateGridIfNeeded(mContext, srcDeviceState,
+ return GridSizeMigrationDBController.migrateGridIfNeeded(mContext, srcDeviceState,
destDeviceState, mOpenHelper, oldHelper.getWritableDatabase());
} catch (Exception e) {
FileLog.e(TAG, "Failed to migrate grid", e);
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
deleted file mode 100644
index 3ae643e..0000000
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (C) 2016 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.provider;
-
-import static com.android.launcher3.LauncherSettings.Favorites.getColumns;
-import static com.android.launcher3.icons.IconCache.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE;
-
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ResolveInfo;
-import android.content.pm.ShortcutInfo;
-import android.database.Cursor;
-import android.database.sqlite.SQLiteDatabase;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.drawable.Icon;
-import android.os.PersistableBundle;
-import android.os.Process;
-import android.os.UserManager;
-import android.text.TextUtils;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.model.LoaderCursor;
-import com.android.launcher3.model.UserManagerState;
-import com.android.launcher3.pm.PinRequestHelper;
-import com.android.launcher3.pm.UserCache;
-import com.android.launcher3.shortcuts.ShortcutKey;
-import com.android.launcher3.util.IntArray;
-import com.android.launcher3.util.IntSet;
-import com.android.launcher3.util.PackageManagerHelper;
-
-/**
- * A set of utility methods for Launcher DB used for DB updates and migration.
- */
-public class LauncherDbUtils {
- /**
- * Returns a string which can be used as a where clause for DB query to match the given itemId
- */
- public static String itemIdMatch(int itemId) {
- return "_id=" + itemId;
- }
-
- 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(distinct, tableName, new String[] { columnName }, selection, null,
- groupBy, null, orderBy, null)) {
- while (c.moveToNext()) {
- out.add(c.getInt(0));
- }
- }
- return out;
- }
-
- public static boolean tableExists(SQLiteDatabase db, String tableName) {
- try (Cursor c = db.query(true, "sqlite_master", new String[] {"tbl_name"},
- "tbl_name = ?", new String[] {tableName},
- null, null, null, null, null)) {
- return c.getCount() > 0;
- }
- }
-
- public static void dropTable(SQLiteDatabase db, String tableName) {
- db.execSQL("DROP TABLE IF EXISTS " + tableName);
- }
-
- /** Copy fromTable in fromDb to toTable in toDb. */
- public static void copyTable(SQLiteDatabase fromDb, String fromTable, SQLiteDatabase toDb,
- String toTable, Context context) {
- long userSerial = UserCache.INSTANCE.get(context).getSerialNumberForUser(
- Process.myUserHandle());
- dropTable(toDb, toTable);
- Favorites.addTableToDb(toDb, userSerial, false, toTable);
- if (fromDb != toDb) {
- toDb.execSQL("ATTACH DATABASE '" + fromDb.getPath() + "' AS from_db");
- toDb.execSQL(
- "INSERT INTO " + toTable + " SELECT " + getColumns(userSerial)
- + " FROM from_db." + fromTable);
- toDb.execSQL("DETACH DATABASE 'from_db'");
- } else {
- toDb.execSQL("INSERT INTO " + toTable + " SELECT " + getColumns(userSerial) + " FROM "
- + fromTable);
- }
- }
-
- /**
- * Migrates the legacy shortcuts to deep shortcuts pinned under Launcher.
- * Removes any invalid shortcut or any shortcut which requires some permission to launch
- */
- public static void migrateLegacyShortcuts(Context context, SQLiteDatabase db) {
- Cursor c = db.query(
- Favorites.TABLE_NAME, null, "itemType = 1", null, null, null, null);
- UserManagerState ums = new UserManagerState();
- PackageManagerHelper pmHelper = PackageManagerHelper.INSTANCE.get(context);
- ums.init(UserCache.INSTANCE.get(context),
- context.getSystemService(UserManager.class));
- LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums, pmHelper,
- null);
- IntSet deletedShortcuts = new IntSet();
-
- while (lc.moveToNext()) {
- if (lc.user != Process.myUserHandle()) {
- deletedShortcuts.add(lc.id);
- continue;
- }
- Intent intent = lc.parseIntent();
- if (intent == null) {
- deletedShortcuts.add(lc.id);
- continue;
- }
- if (TextUtils.isEmpty(lc.getTitle())) {
- deletedShortcuts.add(lc.id);
- continue;
- }
-
- // Make sure the target intent can be launched without any permissions. Otherwise remove
- // the shortcut
- ResolveInfo ri = context.getPackageManager().resolveActivity(intent, 0);
- if (ri == null || !TextUtils.isEmpty(ri.activityInfo.permission)) {
- deletedShortcuts.add(lc.id);
- continue;
- }
- PersistableBundle extras = new PersistableBundle();
- extras.putString(EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE, ri.activityInfo.packageName);
- ShortcutInfo.Builder infoBuilder = new ShortcutInfo.Builder(
- context, "migrated_shortcut-" + lc.id)
- .setIntent(intent)
- .setExtras(extras)
- .setShortLabel(lc.getTitle());
-
- Bitmap bitmap = null;
- byte[] iconData = lc.getIconBlob();
- if (iconData != null) {
- bitmap = BitmapFactory.decodeByteArray(iconData, 0, iconData.length);
- }
- if (bitmap != null) {
- infoBuilder.setIcon(Icon.createWithBitmap(bitmap));
- }
-
- ShortcutInfo info = infoBuilder.build();
- try {
- if (!PinRequestHelper.createRequestForShortcut(context, info).accept()) {
- deletedShortcuts.add(lc.id);
- continue;
- }
- } catch (Exception e) {
- deletedShortcuts.add(lc.id);
- continue;
- }
- ContentValues update = new ContentValues();
- update.put(Favorites.ITEM_TYPE, Favorites.ITEM_TYPE_DEEP_SHORTCUT);
- update.put(Favorites.INTENT,
- ShortcutKey.makeIntent(info.getId(), context.getPackageName()).toUri(0));
- db.update(Favorites.TABLE_NAME, update, "_id = ?",
- new String[] {Integer.toString(lc.id)});
- }
- lc.close();
- if (!deletedShortcuts.isEmpty()) {
- db.delete(Favorites.TABLE_NAME,
- Utilities.createDbSelectionQuery(Favorites._ID, deletedShortcuts.getArray()),
- null);
- }
-
- // Drop the unused columns
- db.execSQL("ALTER TABLE " + Favorites.TABLE_NAME + " DROP COLUMN iconPackage;");
- db.execSQL("ALTER TABLE " + Favorites.TABLE_NAME + " DROP COLUMN iconResource;");
- }
-
- /**
- * Utility class to simplify managing sqlite transactions
- */
- public static class SQLiteTransaction implements AutoCloseable {
- private final SQLiteDatabase mDb;
-
- public SQLiteTransaction(SQLiteDatabase db) {
- mDb = db;
- db.beginTransaction();
- }
-
- public void commit() {
- mDb.setTransactionSuccessful();
- }
-
- @Override
- public void close() {
- mDb.endTransaction();
- }
-
- public SQLiteDatabase getDb() {
- return mDb;
- }
- }
-}
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.kt b/src/com/android/launcher3/provider/LauncherDbUtils.kt
new file mode 100644
index 0000000..3c68e46
--- /dev/null
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.kt
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2016 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.provider
+
+import android.content.ContentValues
+import android.content.Context
+import android.content.pm.ShortcutInfo
+import android.database.sqlite.SQLiteDatabase
+import android.graphics.Bitmap
+import android.graphics.BitmapFactory
+import android.graphics.drawable.Icon
+import android.os.PersistableBundle
+import android.os.Process
+import android.os.UserManager
+import android.text.TextUtils
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.Utilities
+import com.android.launcher3.icons.IconCache
+import com.android.launcher3.model.LoaderCursor
+import com.android.launcher3.model.UserManagerState
+import com.android.launcher3.pm.PinRequestHelper
+import com.android.launcher3.pm.UserCache
+import com.android.launcher3.shortcuts.ShortcutKey
+import com.android.launcher3.util.IntArray
+import com.android.launcher3.util.IntSet
+import com.android.launcher3.util.PackageManagerHelper
+
+/** A set of utility methods for Launcher DB used for DB updates and migration. */
+object LauncherDbUtils {
+ /**
+ * Returns a string which can be used as a where clause for DB query to match the given itemId
+ */
+ @JvmStatic fun itemIdMatch(itemId: Int): String = "_id=$itemId"
+
+ @JvmStatic
+ fun queryIntArray(
+ distinct: Boolean,
+ db: SQLiteDatabase,
+ tableName: String,
+ columnName: String,
+ selection: String?,
+ groupBy: String?,
+ orderBy: String?,
+ ): IntArray {
+ val out = IntArray()
+ db.query(
+ distinct,
+ tableName,
+ arrayOf(columnName),
+ selection,
+ null,
+ groupBy,
+ null,
+ orderBy,
+ null,
+ )
+ .use { c ->
+ while (c.moveToNext()) {
+ out.add(c.getInt(0))
+ }
+ }
+ return out
+ }
+
+ @JvmStatic
+ fun tableExists(db: SQLiteDatabase, tableName: String): Boolean =
+ db.query(
+ /* distinct = */ true,
+ /* table = */ "sqlite_master",
+ /* columns = */ arrayOf("tbl_name"),
+ /* selection = */ "tbl_name = ?",
+ /* selectionArgs = */ arrayOf(tableName),
+ /* groupBy = */ null,
+ /* having = */ null,
+ /* orderBy = */ null,
+ /* limit = */ null,
+ /* cancellationSignal = */ null,
+ )
+ .use { c ->
+ return c.count > 0
+ }
+
+ @JvmStatic
+ fun dropTable(db: SQLiteDatabase, tableName: String) =
+ db.execSQL("DROP TABLE IF EXISTS $tableName")
+
+ /** Copy fromTable in fromDb to toTable in toDb. */
+ @JvmStatic
+ fun copyTable(
+ fromDb: SQLiteDatabase,
+ fromTable: String,
+ toDb: SQLiteDatabase,
+ toTable: String,
+ context: Context,
+ ) {
+ val userSerial = UserCache.INSTANCE[context].getSerialNumberForUser(Process.myUserHandle())
+ dropTable(toDb, toTable)
+ LauncherSettings.Favorites.addTableToDb(toDb, userSerial, false, toTable)
+ if (fromDb != toDb) {
+ toDb.run {
+ execSQL("ATTACH DATABASE '${fromDb.path}' AS from_db")
+ execSQL(
+ "INSERT INTO $toTable SELECT ${LauncherSettings.Favorites.getColumns(userSerial)} FROM from_db.$fromTable"
+ )
+ execSQL("DETACH DATABASE 'from_db'")
+ }
+ } else {
+ toDb.run {
+ execSQL(
+ "INSERT INTO $toTable SELECT ${
+ LauncherSettings.Favorites.getColumns(
+ userSerial
+ )
+ } FROM $fromTable"
+ )
+ }
+ }
+ }
+
+ /**
+ * Migrates the legacy shortcuts to deep shortcuts pinned under Launcher. Removes any invalid
+ * shortcut or any shortcut which requires some permission to launch
+ */
+ @JvmStatic
+ fun migrateLegacyShortcuts(context: Context, db: SQLiteDatabase) {
+ val c =
+ db.query(
+ LauncherSettings.Favorites.TABLE_NAME,
+ null,
+ "itemType = 1",
+ null,
+ null,
+ null,
+ null,
+ )
+ val pmHelper = PackageManagerHelper.INSTANCE[context]
+ val ums = UserManagerState()
+ ums.run {
+ init(UserCache.INSTANCE[context], context.getSystemService(UserManager::class.java))
+ }
+ val lc = LoaderCursor(c, LauncherAppState.getInstance(context), ums, pmHelper, null)
+ val deletedShortcuts = IntSet()
+
+ while (lc.moveToNext()) {
+ if (lc.user !== Process.myUserHandle()) {
+ deletedShortcuts.add(lc.id)
+ continue
+ }
+ val intent = lc.parseIntent()
+ if (intent == null) {
+ deletedShortcuts.add(lc.id)
+ continue
+ }
+ if (TextUtils.isEmpty(lc.title)) {
+ deletedShortcuts.add(lc.id)
+ continue
+ }
+
+ // Make sure the target intent can be launched without any permissions. Otherwise remove
+ // the shortcut
+ val ri = context.packageManager.resolveActivity(intent, 0)
+ if (ri == null || !TextUtils.isEmpty(ri.activityInfo.permission)) {
+ deletedShortcuts.add(lc.id)
+ continue
+ }
+ val extras =
+ PersistableBundle().apply {
+ putString(
+ IconCache.EXTRA_SHORTCUT_BADGE_OVERRIDE_PACKAGE,
+ ri.activityInfo.packageName,
+ )
+ }
+ val infoBuilder =
+ ShortcutInfo.Builder(context, "migrated_shortcut-${lc.id}")
+ .setIntent(intent)
+ .setExtras(extras)
+ .setShortLabel(lc.title)
+
+ var bitmap: Bitmap? = null
+ val iconData = lc.iconBlob
+ if (iconData != null) {
+ bitmap = BitmapFactory.decodeByteArray(iconData, 0, iconData.size)
+ }
+ if (bitmap != null) {
+ infoBuilder.setIcon(Icon.createWithBitmap(bitmap))
+ }
+
+ val info = infoBuilder.build()
+ try {
+ if (!PinRequestHelper.createRequestForShortcut(context, info).accept()) {
+ deletedShortcuts.add(lc.id)
+ continue
+ }
+ } catch (e: Exception) {
+ deletedShortcuts.add(lc.id)
+ continue
+ }
+ val update =
+ ContentValues().apply {
+ put(
+ LauncherSettings.Favorites.ITEM_TYPE,
+ LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT,
+ )
+ put(
+ LauncherSettings.Favorites.INTENT,
+ ShortcutKey.makeIntent(info.id, context.packageName).toUri(0),
+ )
+ }
+ db.update(
+ LauncherSettings.Favorites.TABLE_NAME,
+ update,
+ "_id = ?",
+ arrayOf(lc.id.toString()),
+ )
+ }
+ lc.close()
+ if (deletedShortcuts.isEmpty.not()) {
+ db.delete(
+ /* table = */ LauncherSettings.Favorites.TABLE_NAME,
+ /* whereClause = */ Utilities.createDbSelectionQuery(
+ LauncherSettings.Favorites._ID,
+ deletedShortcuts.array,
+ ),
+ /* whereArgs = */ null,
+ )
+ }
+
+ // Drop the unused columns
+ db.run {
+ execSQL("ALTER TABLE ${LauncherSettings.Favorites.TABLE_NAME} DROP COLUMN iconPackage;")
+ execSQL(
+ "ALTER TABLE ${LauncherSettings.Favorites.TABLE_NAME} DROP COLUMN iconResource;"
+ )
+ }
+ }
+
+ /** Utility class to simplify managing sqlite transactions */
+ class SQLiteTransaction(val db: SQLiteDatabase) : AutoCloseable {
+ init {
+ db.beginTransaction()
+ }
+
+ fun commit() = db.setTransactionSuccessful()
+
+ override fun close() = db.endTransaction()
+ }
+}
diff --git a/src/com/android/launcher3/shapes/AppShape.kt b/src/com/android/launcher3/shapes/AppShape.kt
new file mode 100644
index 0000000..68200a0
--- /dev/null
+++ b/src/com/android/launcher3/shapes/AppShape.kt
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.shapes
+
+class AppShape(val key: String, val title: String, val path: String)
diff --git a/src/com/android/launcher3/shapes/AppShapesProvider.kt b/src/com/android/launcher3/shapes/AppShapesProvider.kt
new file mode 100644
index 0000000..41bac6a
--- /dev/null
+++ b/src/com/android/launcher3/shapes/AppShapesProvider.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.shapes
+
+object AppShapesProvider {
+
+ val shapes =
+ listOf(
+ AppShape(
+ "arch",
+ "arch",
+ "M100 83.46C100 85.471 100 86.476 99.9 87.321 99.116 93.916 93.916 99.116 87.321 99.9 86.476 100 85.471 100 83.46 100H16.54C14.529 100 13.524 100 12.679 99.9 6.084 99.116.884 93.916.1 87.321 0 86.476 0 85.471 0 83.46L0 50C0 22.386 22.386 0 50 0 77.614 0 100 22.386 100 50V83.46Z",
+ ),
+ AppShape(
+ "4_sided_cookie",
+ "4 sided cookie",
+ "M63.605 3C84.733-6.176 106.176 15.268 97 36.395L95.483 39.888C92.681 46.338 92.681 53.662 95.483 60.112L97 63.605C106.176 84.732 84.733 106.176 63.605 97L60.112 95.483C53.662 92.681 46.338 92.681 39.888 95.483L36.395 97C15.267 106.176-6.176 84.732 3 63.605L4.517 60.112C7.319 53.662 7.319 46.338 4.517 39.888L3 36.395C-6.176 15.268 15.267-6.176 36.395 3L39.888 4.517C46.338 7.319 53.662 7.319 60.112 4.517L63.605 3Z",
+ ),
+ AppShape(
+ "seven_sided_cookie",
+ "7 sided cookie",
+ "M35.209 4.878C36.326 3.895 36.884 3.404 37.397 3.006 44.82-2.742 55.18-2.742 62.603 3.006 63.116 3.404 63.674 3.895 64.791 4.878 65.164 5.207 65.351 5.371 65.539 5.529 68.167 7.734 71.303 9.248 74.663 9.932 74.902 9.981 75.147 10.025 75.637 10.113 77.1 10.375 77.831 10.506 78.461 10.66 87.573 12.893 94.032 21.011 94.176 30.412 94.186 31.062 94.151 31.805 94.08 33.293 94.057 33.791 94.045 34.04 94.039 34.285 93.958 37.72 94.732 41.121 96.293 44.18 96.404 44.399 96.522 44.618 96.759 45.056 97.467 46.366 97.821 47.021 98.093 47.611 102.032 56.143 99.727 66.266 92.484 72.24 91.983 72.653 91.381 73.089 90.177 73.961 89.774 74.254 89.572 74.4 89.377 74.548 86.647 76.626 84.477 79.353 83.063 82.483 82.962 82.707 82.865 82.936 82.671 83.395 82.091 84.766 81.8 85.451 81.51 86.033 77.31 94.44 67.977 98.945 58.801 96.994 58.166 96.859 57.451 96.659 56.019 96.259 55.54 96.125 55.3 96.058 55.063 95.998 51.74 95.154 48.26 95.154 44.937 95.998 44.699 96.058 44.46 96.125 43.981 96.259 42.549 96.659 41.834 96.859 41.199 96.994 32.023 98.945 22.69 94.44 18.49 86.033 18.2 85.451 17.909 84.766 17.329 83.395 17.135 82.936 17.038 82.707 16.937 82.483 15.523 79.353 13.353 76.626 10.623 74.548 10.428 74.4 10.226 74.254 9.823 73.961 8.619 73.089 8.017 72.653 7.516 72.24.273 66.266-2.032 56.143 1.907 47.611 2.179 47.021 2.533 46.366 3.241 45.056 3.478 44.618 3.596 44.399 3.707 44.18 5.268 41.121 6.042 37.72 5.961 34.285 5.955 34.04 5.943 33.791 5.92 33.293 5.849 31.805 5.814 31.062 5.824 30.412 5.968 21.011 12.427 12.893 21.539 10.66 22.169 10.506 22.9 10.375 24.363 10.113 24.853 10.025 25.098 9.981 25.337 9.932 28.697 9.248 31.833 7.734 34.461 5.529 34.649 5.371 34.836 5.207 35.209 4.878Z",
+ ),
+ AppShape(
+ "sunny",
+ "sunny",
+ "M42.846 4.873C46.084-.531 53.916-.531 57.154 4.873L60.796 10.951C62.685 14.103 66.414 15.647 69.978 14.754L76.851 13.032C82.962 11.5 88.5 17.038 86.968 23.149L85.246 30.022C84.353 33.586 85.897 37.315 89.049 39.204L95.127 42.846C100.531 46.084 100.531 53.916 95.127 57.154L89.049 60.796C85.897 62.685 84.353 66.414 85.246 69.978L86.968 76.851C88.5 82.962 82.962 88.5 76.851 86.968L69.978 85.246C66.414 84.353 62.685 85.898 60.796 89.049L57.154 95.127C53.916 100.531 46.084 100.531 42.846 95.127L39.204 89.049C37.315 85.898 33.586 84.353 30.022 85.246L23.149 86.968C17.038 88.5 11.5 82.962 13.032 76.851L14.754 69.978C15.647 66.414 14.103 62.685 10.951 60.796L4.873 57.154C-.531 53.916-.531 46.084 4.873 42.846L10.951 39.204C14.103 37.315 15.647 33.586 14.754 30.022L13.032 23.149C11.5 17.038 17.038 11.5 23.149 13.032L30.022 14.754C33.586 15.647 37.315 14.103 39.204 10.951L42.846 4.873Z",
+ ),
+ AppShape(
+ "circle",
+ "circle",
+ "M99.18 50C99.18 77.162 77.162 99.18 50 99.18 22.838 99.18.82 77.162.82 50 .82 22.839 22.838.82 50 .82 77.162.82 99.18 22.839 99.18 50Z",
+ ),
+ AppShape(
+ "square",
+ "square",
+ "M99.18 53.689C99.18 67.434 99.18 74.306 97.022 79.758 93.897 87.649 87.649 93.897 79.758 97.022 74.306 99.18 67.434 99.18 53.689 99.18H46.311C32.566 99.18 25.694 99.18 20.242 97.022 12.351 93.897 6.103 87.649 2.978 79.758.82 74.306.82 67.434.82 53.689L.82 46.311C.82 32.566.82 25.694 2.978 20.242 6.103 12.351 12.351 6.103 20.242 2.978 25.694.82 32.566.82 46.311.82L53.689.82C67.434.82 74.306.82 79.758 2.978 87.649 6.103 93.897 12.351 97.022 20.242 99.18 25.694 99.18 32.566 99.18 46.311V53.689Z\n",
+ ),
+ )
+}
diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java
index 54b2eae..079191f 100644
--- a/src/com/android/launcher3/statemanager/StatefulActivity.java
+++ b/src/com/android/launcher3/statemanager/StatefulActivity.java
@@ -24,6 +24,7 @@
import android.content.res.Configuration;
import android.os.Bundle;
import android.os.Handler;
+import android.os.Trace;
import android.view.LayoutInflater;
import android.view.View;
@@ -176,8 +177,10 @@
@Override
public void onConfigurationChanged(Configuration newConfig) {
+ Trace.beginSection("statefulActivity#onConfigurationChanged");
handleConfigurationChanged(newConfig);
super.onConfigurationChanged(newConfig);
+ Trace.endSection();
}
/**
diff --git a/src/com/android/launcher3/util/ApiWrapper.java b/src/com/android/launcher3/util/ApiWrapper.java
index 21f91acd..467a7ec 100644
--- a/src/com/android/launcher3/util/ApiWrapper.java
+++ b/src/com/android/launcher3/util/ApiWrapper.java
@@ -17,7 +17,6 @@
package com.android.launcher3.util;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_HOME_ROLE;
-import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
import android.app.ActivityOptions;
import android.app.Person;
@@ -38,24 +37,30 @@
import com.android.launcher3.BuildConfig;
import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppComponent;
+import com.android.launcher3.dagger.LauncherAppSingleton;
import java.util.Collections;
import java.util.List;
import java.util.Map;
+import javax.inject.Inject;
+
/**
* A wrapper for the hidden API calls
*/
-public class ApiWrapper implements ResourceBasedOverride, SafeCloseable {
+@LauncherAppSingleton
+public class ApiWrapper {
- public static final MainThreadInitializedObject<ApiWrapper> INSTANCE =
- forOverride(ApiWrapper.class, R.string.api_wrapper_class);
+ public static final DaggerSingletonObject<ApiWrapper> INSTANCE = new DaggerSingletonObject<>(
+ LauncherAppComponent::getApiWrapper);
protected final Context mContext;
- public ApiWrapper(Context context) {
+ @Inject
+ public ApiWrapper(@ApplicationContext Context context) {
mContext = context;
}
@@ -166,9 +171,6 @@
return appInfo.sourceDir;
}
- @Override
- public void close() { }
-
private static class NoopDrawable extends ColorDrawable {
@Override
public int getIntrinsicHeight() {
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
index 9a70298..356a551 100644
--- a/src/com/android/launcher3/util/MainThreadInitializedObject.java
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -150,7 +150,6 @@
public SandboxContext(Context base) {
attachBaseContext(base);
- initDagger();
}
@Override
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
index 9dddc18..20cce8f 100644
--- a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
+++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
@@ -39,8 +39,8 @@
import com.android.launcher3.dagger.LauncherBaseAppComponent;
import com.android.launcher3.util.DaggerSingletonObject;
import com.android.launcher3.util.DaggerSingletonTracker;
-import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.PluginManagerWrapper;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.systemui.plugins.CustomWidgetPlugin;
@@ -51,7 +51,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.function.Consumer;
+import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Stream;
import javax.inject.Inject;
@@ -70,7 +70,7 @@
private final Context mContext;
private final HashMap<ComponentName, CustomWidgetPlugin> mPlugins;
private final List<CustomAppWidgetProviderInfo> mCustomWidgets;
- private Consumer<PackageUserKey> mWidgetRefreshCallback;
+ private final List<Runnable> mWidgetRefreshCallbacks = new CopyOnWriteArrayList<>();
private final @NonNull AppWidgetManager mAppWidgetManager;
@Inject
@@ -111,23 +111,20 @@
@Override
public void onPluginConnected(CustomWidgetPlugin plugin, Context context) {
- List<AppWidgetProviderInfo> providers = mAppWidgetManager
- .getInstalledProvidersForProfile(Process.myUserHandle());
- if (providers.isEmpty()) return;
- Parcel parcel = Parcel.obtain();
- providers.get(0).writeToParcel(parcel, 0);
- parcel.setDataPosition(0);
- CustomAppWidgetProviderInfo info = newInfo(plugin, parcel);
- parcel.recycle();
- mPlugins.put(info.provider, plugin);
- mCustomWidgets.add(info);
+ CustomAppWidgetProviderInfo info = getAndAddInfo(new ComponentName(
+ PLUGIN_PKG, CLS_CUSTOM_WIDGET_PREFIX + plugin.getClass().getName()));
+ if (info != null) {
+ plugin.updateWidgetInfo(info, mContext);
+ mPlugins.put(info.provider, plugin);
+ mWidgetRefreshCallbacks.forEach(MAIN_EXECUTOR::execute);
+ }
}
@Override
public void onPluginDisconnected(CustomWidgetPlugin plugin) {
- ComponentName cn = getWidgetProviderComponent(plugin);
- mPlugins.remove(cn);
- mCustomWidgets.removeIf(w -> w.getComponent().equals(cn));
+ // Leave the providerInfo as plugins can get disconnected/reconnected multiple times
+ mPlugins.values().remove(plugin);
+ mWidgetRefreshCallbacks.forEach(MAIN_EXECUTOR::execute);
}
@VisibleForTesting
@@ -138,9 +135,11 @@
/**
* Inject a callback function to refresh the widgets.
+ * @return a closeable to remove this callback
*/
- public void setWidgetRefreshCallback(Consumer<PackageUserKey> cb) {
- mWidgetRefreshCallback = cb;
+ public SafeCloseable addWidgetRefreshCallback(Runnable callback) {
+ mWidgetRefreshCallbacks.add(callback);
+ return () -> mWidgetRefreshCallbacks.remove(callback);
}
/**
@@ -149,8 +148,9 @@
public void onViewCreated(LauncherAppWidgetHostView view) {
CustomAppWidgetProviderInfo info = (CustomAppWidgetProviderInfo) view.getAppWidgetInfo();
CustomWidgetPlugin plugin = mPlugins.get(info.provider);
- if (plugin == null) return;
- plugin.onViewCreated(view);
+ if (plugin != null) {
+ plugin.onViewCreated(view);
+ }
}
/**
@@ -166,14 +166,13 @@
*/
@Nullable
public LauncherAppWidgetProviderInfo getWidgetProvider(ComponentName cn) {
- return mCustomWidgets.stream()
+ LauncherAppWidgetProviderInfo info = mCustomWidgets.stream()
.filter(w -> w.getComponent().equals(cn)).findAny().orElse(null);
- }
-
- private CustomAppWidgetProviderInfo newInfo(CustomWidgetPlugin plugin, Parcel parcel) {
- CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(parcel, false);
- info.provider = getWidgetProviderComponent(plugin);
- plugin.updateWidgetInfo(info, mContext);
+ if (info == null) {
+ // If the info is not present, add a placeholder info since the
+ // plugin might get loaded later
+ info = getAndAddInfo(cn);
+ }
return info;
}
@@ -184,8 +183,24 @@
return CUSTOM_WIDGET_ID - mCustomWidgets.indexOf(getWidgetProvider(componentName));
}
- private ComponentName getWidgetProviderComponent(CustomWidgetPlugin plugin) {
- return new ComponentName(
- PLUGIN_PKG, CLS_CUSTOM_WIDGET_PREFIX + plugin.getClass().getName());
+ @Nullable
+ private CustomAppWidgetProviderInfo getAndAddInfo(ComponentName cn) {
+ for (CustomAppWidgetProviderInfo info : mCustomWidgets) {
+ if (info.provider.equals(cn)) return info;
+ }
+
+ List<AppWidgetProviderInfo> providers = mAppWidgetManager
+ .getInstalledProvidersForProfile(Process.myUserHandle());
+ if (providers.isEmpty()) return null;
+ Parcel parcel = Parcel.obtain();
+ providers.get(0).writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+ CustomAppWidgetProviderInfo info = new CustomAppWidgetProviderInfo(parcel, false);
+ parcel.recycle();
+
+ info.provider = cn;
+ info.initialLayout = 0;
+ mCustomWidgets.add(info);
+ return info;
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index c8ad564..1860977 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -145,7 +145,9 @@
protected DeviceProfile mDeviceProfile;
protected TextView mNoWidgetsView;
- protected StickyHeaderLayout mSearchScrollView;
+ protected LinearLayout mSearchScrollView;
+ // Reference to the mSearchScrollView when it is is a sticky header.
+ private @Nullable StickyHeaderLayout mStickyHeaderLayout;
protected WidgetRecommendationsView mWidgetRecommendationsView;
protected LinearLayout mWidgetRecommendationsContainer;
protected View mTabBar;
@@ -220,7 +222,11 @@
protected void setupViews() {
mSearchScrollView = findViewById(R.id.search_and_recommendations_container);
- mSearchScrollView.setCurrentRecyclerView(findViewById(R.id.primary_widgets_list_view));
+ if (mSearchScrollView instanceof StickyHeaderLayout) {
+ mStickyHeaderLayout = (StickyHeaderLayout) mSearchScrollView;
+ mStickyHeaderLayout.setCurrentRecyclerView(
+ findViewById(R.id.primary_widgets_list_view));
+ }
mNoWidgetsView = findViewById(R.id.no_widgets_text);
mFastScroller = findViewById(R.id.fast_scroller);
mFastScroller.setPopupView(findViewById(R.id.fast_scroller_popup));
@@ -284,7 +290,9 @@
reset();
resetExpandedHeaders();
mCurrentWidgetsRecyclerView = recyclerView;
- mSearchScrollView.setCurrentRecyclerView(recyclerView);
+ if (mStickyHeaderLayout != null) {
+ mStickyHeaderLayout.setCurrentRecyclerView(recyclerView);
+ }
}
}
@@ -313,7 +321,9 @@
mAdapters.get(AdapterHolder.WORK).mWidgetsRecyclerView.scrollToTop();
}
mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView.scrollToTop();
- mSearchScrollView.reset(/* animate= */ true);
+ if (mStickyHeaderLayout != null) {
+ mStickyHeaderLayout.reset(/* animate= */ true);
+ }
}
@VisibleForTesting
@@ -1051,7 +1061,7 @@
}
private int getEmptySpaceHeight() {
- return mSearchScrollView.getHeaderHeight();
+ return mStickyHeaderLayout != null ? mStickyHeaderLayout.getHeaderHeight() : 0;
}
void setup(WidgetsRecyclerView recyclerView) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
index 8dd1de4..3d3a669 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListAdapter.java
@@ -396,15 +396,6 @@
LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
if (layoutManager == null) return;
- if (position == mVisibleEntries.size() - 2
- && mVisibleEntries.get(mVisibleEntries.size() - 1)
- instanceof WidgetsListContentEntry) {
- // If the selected header is in the last position and its content is showing, then
- // scroll to the final position so the last list of widgets will show.
- layoutManager.scrollToPosition(mVisibleEntries.size() - 1);
- return;
- }
-
// Scroll to the header view's current offset, accounting for the recycler view's padding.
// If the header view couldn't be found, then it will appear at the top of the list.
layoutManager.scrollToPositionWithOffset(
diff --git a/tests/Android.bp b/tests/Android.bp
index 9667277..35a2275 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -148,6 +148,7 @@
platform_apis: true,
test_config: "Launcher3Tests.xml",
data: [":Launcher3"],
+ plugins: ["dagger2-compiler"],
test_suites: ["general-tests"],
}
@@ -237,6 +238,7 @@
"truth",
],
instrumentation_for: "Launcher3",
+ plugins: ["dagger2-compiler"],
upstream: true,
strict_mode: false,
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/AutoInstallsLayoutTest.kt b/tests/multivalentTests/src/com/android/launcher3/AutoInstallsLayoutTest.kt
index b04bcca..f73a9d3 100644
--- a/tests/multivalentTests/src/com/android/launcher3/AutoInstallsLayoutTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/AutoInstallsLayoutTest.kt
@@ -41,6 +41,8 @@
import com.android.launcher3.LauncherSettings.Favorites.SPANX
import com.android.launcher3.LauncherSettings.Favorites.SPANY
import com.android.launcher3.LauncherSettings.Favorites._ID
+import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppSingleton
import com.android.launcher3.model.data.AppInfo
import com.android.launcher3.pm.UserCache
import com.android.launcher3.util.ApiWrapper
@@ -54,6 +56,8 @@
import com.android.launcher3.util.UserIconInfo.TYPE_WORK
import com.android.launcher3.widget.LauncherWidgetHolder
import com.google.common.truth.Truth.assertThat
+import dagger.BindsInstance
+import dagger.Component
import java.io.StringReader
import org.junit.After
import org.junit.Before
@@ -162,7 +166,9 @@
@Test
fun work_item_added_to_home() {
val apiWrapperMock = spy(ApiWrapper.INSTANCE[targetContext])
- targetContext.putObject(ApiWrapper.INSTANCE, apiWrapperMock)
+ targetContext.initDaggerComponent(
+ DaggerAutoInstallsLayoutTestComponent.builder().bindApiWrapper(apiWrapperMock)
+ )
doReturn(
mapOf(
myUserHandle() to UserIconInfo(myUserHandle(), TYPE_MAIN, 0),
@@ -198,7 +204,7 @@
callback,
SourceResources.wrap(targetContext.resources),
{ Xml.newPullParser().also { it.setInput(StringReader(build())) } },
- TAG_WORKSPACE
+ TAG_WORKSPACE,
)
class MyCallback : LayoutParserCallback {
@@ -214,3 +220,14 @@
}
}
}
+
+@LauncherAppSingleton
+@Component
+interface AutoInstallsLayoutTestComponent : LauncherAppComponent {
+ @Component.Builder
+ interface Builder : LauncherAppComponent.Builder {
+ @BindsInstance fun bindApiWrapper(wrapper: ApiWrapper): Builder
+
+ override fun build(): AutoInstallsLayoutTestComponent
+ }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
index 0c3081f..a9082e2 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
@@ -22,6 +22,7 @@
import android.content.Context;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
@@ -59,7 +60,11 @@
runOnExecutorSync(MODEL_EXECUTOR, () -> {
ModelDbController controller = model.getModelDbController();
// Migrate any previous data so that the DB state is correct
- controller.tryMigrateDB(null /* restoreEventLogger */);
+ if (Flags.gridMigrationRefactor()) {
+ controller.attemptMigrateDb(null /* restoreEventLogger */);
+ } else {
+ controller.tryMigrateDB(null /* restoreEventLogger */);
+ }
// Create DB again to load fresh data
controller.createEmptyDB();
diff --git a/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationTest.kt
similarity index 80%
rename from tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationTest.kt
index f57e8a1..7933331 100644
--- a/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/model/GridSizeMigrationTest.kt
@@ -22,13 +22,16 @@
import android.database.sqlite.SQLiteDatabase
import android.graphics.Point
import android.os.Process
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import com.android.launcher3.Flags
import com.android.launcher3.InvariantDeviceProfile
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherPrefs.Companion.WORKSPACE_SIZE
import com.android.launcher3.LauncherSettings.Favorites.*
-import com.android.launcher3.model.GridSizeMigrationUtil.DbReader
+import com.android.launcher3.model.GridSizeMigrationDBController.DbReader
import com.android.launcher3.pm.UserCache
import com.android.launcher3.provider.LauncherDbUtils
import com.android.launcher3.util.LauncherModelHelper
@@ -38,10 +41,10 @@
import org.junit.Test
import org.junit.runner.RunWith
-/** Unit tests for [GridSizeMigrationUtil] */
+/** Unit tests for [GridSizeMigrationDBController, GridSizeMigrationLogic] */
@SmallTest
@RunWith(AndroidJUnit4::class)
-class GridSizeMigrationUtilTest {
+class GridSizeMigrationTest {
private lateinit var modelHelper: LauncherModelHelper
private lateinit var context: Context
@@ -82,9 +85,22 @@
modelHelper.destroy()
}
- /** Old migration logic, should be modified once is not needed anymore */
@Test
@Throws(Exception::class)
+ @EnableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun testMigrationRefactorFlagOn() {
+ testMigration()
+ }
+
+ @Test
+ @Throws(Exception::class)
+ @DisableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun testMigrationRefactorFlagOff() {
+ testMigration()
+ }
+
+ /** Old migration logic, should be modified once is not needed anymore */
+ @Throws(Exception::class)
fun testMigration() {
// Src Hotseat icons
addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE)
@@ -113,15 +129,34 @@
idp.numRows = 4
val srcReader = DbReader(db, TMP_TABLE, context)
val destReader = DbReader(db, TABLE_NAME, context)
- GridSizeMigrationUtil.migrate(
- dbHelper,
- srcReader,
- destReader,
- idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp),
- )
+ if (Flags.gridMigrationRefactor()) {
+ var gridSizeMigrationLogic = GridSizeMigrationLogic()
+ val idsInUse = mutableListOf<Int>()
+ gridSizeMigrationLogic.migrateHotseat(
+ idp.numDatabaseHotseatIcons,
+ srcReader,
+ destReader,
+ dbHelper,
+ idsInUse,
+ )
+ gridSizeMigrationLogic.migrateWorkspace(
+ srcReader,
+ destReader,
+ dbHelper,
+ Point(idp.numColumns, idp.numRows),
+ idsInUse,
+ )
+ } else {
+ GridSizeMigrationDBController.migrate(
+ dbHelper,
+ srcReader,
+ destReader,
+ idp.numDatabaseHotseatIcons,
+ Point(idp.numColumns, idp.numRows),
+ DeviceGridState(context),
+ DeviceGridState(idp),
+ )
+ }
// Check hotseat items
var c =
@@ -187,9 +222,22 @@
assertThat(locMap[testPackage9]).isEqualTo(Point(0, 2))
}
- /** Old migration logic, should be modified once is not needed anymore */
@Test
@Throws(Exception::class)
+ @EnableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun testMigrationBackAndForthRefactorFlagOn() {
+ testMigrationBackAndForth()
+ }
+
+ @Test
+ @Throws(Exception::class)
+ @DisableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun testMigrationBackAndForthRefactorFlagOff() {
+ testMigrationBackAndForth()
+ }
+
+ /** Old migration logic, should be modified once is not needed anymore */
+ @Throws(Exception::class)
fun testMigrationBackAndForth() {
// Hotseat items in grid A
// 1 2 _ 3 4
@@ -224,15 +272,34 @@
val readerGridA = DbReader(db, TMP_TABLE, context)
val readerGridB = DbReader(db, TABLE_NAME, context)
// migrate from A -> B
- GridSizeMigrationUtil.migrate(
- dbHelper,
- readerGridA,
- readerGridB,
- idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp),
- )
+ if (Flags.gridMigrationRefactor()) {
+ var gridSizeMigrationLogic = GridSizeMigrationLogic()
+ val idsInUse = mutableListOf<Int>()
+ gridSizeMigrationLogic.migrateHotseat(
+ idp.numDatabaseHotseatIcons,
+ readerGridA,
+ readerGridB,
+ dbHelper,
+ idsInUse,
+ )
+ gridSizeMigrationLogic.migrateWorkspace(
+ readerGridA,
+ readerGridB,
+ dbHelper,
+ Point(idp.numColumns, idp.numRows),
+ idsInUse,
+ )
+ } else {
+ GridSizeMigrationDBController.migrate(
+ dbHelper,
+ readerGridA,
+ readerGridB,
+ idp.numDatabaseHotseatIcons,
+ Point(idp.numColumns, idp.numRows),
+ DeviceGridState(context),
+ DeviceGridState(idp),
+ )
+ }
// Check hotseat items in grid B
var c =
@@ -280,15 +347,8 @@
addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 0, 2, testPackage9)
// migrate from B -> A
- GridSizeMigrationUtil.migrate(
- dbHelper,
- readerGridB,
- readerGridA,
- 5,
- Point(5, 5),
- DeviceGridState(idp),
- DeviceGridState(context),
- )
+ migrateGrid(dbHelper, readerGridB, readerGridA, 5, 5, 5)
+
// Check hotseat items in grid A
c =
db.query(
@@ -339,14 +399,13 @@
db.delete(TMP_TABLE, "$_ID=7", null)
// migrate from A -> B
- GridSizeMigrationUtil.migrate(
+ migrateGrid(
dbHelper,
readerGridA,
readerGridB,
idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp),
+ idp.numColumns,
+ idp.numRows,
)
// Check hotseat items in grid B
@@ -392,6 +451,44 @@
assertThat(locMap[testPackage9]).isEqualTo(Triple(0, 0, 2))
}
+ private fun migrateGrid(
+ dbHelper: DatabaseHelper,
+ srcReader: DbReader,
+ destReader: DbReader,
+ destHotseatSize: Int,
+ pointX: Int,
+ pointY: Int,
+ ) {
+ if (Flags.gridMigrationRefactor()) {
+ var gridSizeMigrationLogic = GridSizeMigrationLogic()
+ val idsInUse = mutableListOf<Int>()
+ gridSizeMigrationLogic.migrateHotseat(
+ idp.numDatabaseHotseatIcons,
+ srcReader,
+ destReader,
+ dbHelper,
+ idsInUse,
+ )
+ gridSizeMigrationLogic.migrateWorkspace(
+ srcReader,
+ destReader,
+ dbHelper,
+ Point(idp.numColumns, idp.numRows),
+ idsInUse,
+ )
+ } else {
+ GridSizeMigrationDBController.migrate(
+ dbHelper,
+ srcReader,
+ destReader,
+ destHotseatSize,
+ Point(pointX, pointY),
+ DeviceGridState(idp),
+ DeviceGridState(context),
+ )
+ }
+ }
+
private fun verifyHotseat(c: Cursor, idp: InvariantDeviceProfile, expected: List<String?>) {
assertThat(c.count).isEqualTo(idp.numDatabaseHotseatIcons)
val screenIndex = c.getColumnIndex(SCREEN)
@@ -421,6 +518,17 @@
}
@Test
+ @EnableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun migrateToLargerHotseatRefactorFlagOn() {
+ migrateToLargerHotseat()
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun migrateToLargerHotseatRefactorFlagOff() {
+ migrateToLargerHotseat()
+ }
+
fun migrateToLargerHotseat() {
val srcHotseatItems =
intArrayOf(
@@ -471,14 +579,13 @@
idp.numRows = 4
val srcReader = DbReader(db, TMP_TABLE, context)
val destReader = DbReader(db, TABLE_NAME, context)
- GridSizeMigrationUtil.migrate(
+ migrateGrid(
dbHelper,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp),
+ idp.numColumns,
+ idp.numRows,
)
// Check hotseat items
@@ -516,6 +623,17 @@
}
@Test
+ @EnableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun migrateFromLargerHotseatRefactorFlagOn() {
+ migrateFromLargerHotseat()
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun migrateFromLargerHotseatRefactorFlagOff() {
+ migrateFromLargerHotseat()
+ }
+
fun migrateFromLargerHotseat() {
addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_HOTSEAT, 0, 0, testPackage1, 1, TMP_TABLE)
addItem(ITEM_TYPE_DEEP_SHORTCUT, 2, CONTAINER_HOTSEAT, 0, 0, testPackage2, 2, TMP_TABLE)
@@ -528,14 +646,13 @@
idp.numRows = 4
val srcReader = DbReader(db, TMP_TABLE, context)
val destReader = DbReader(db, TABLE_NAME, context)
- GridSizeMigrationUtil.migrate(
+ migrateGrid(
dbHelper,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp),
+ idp.numColumns,
+ idp.numRows,
)
// Check hotseat items
@@ -573,11 +690,24 @@
c.close()
}
+ @Test
+ @Throws(Exception::class)
+ @EnableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun migrateFromSmallerGridBigDifferenceRefactorFlagOn() {
+ migrateFromSmallerGridBigDifference()
+ }
+
+ @Test
+ @Throws(Exception::class)
+ @DisableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun migrateFromSmallerGridBigDifferenceRefactorFlagOff() {
+ migrateFromSmallerGridBigDifference()
+ }
+
/**
* Migrating from a smaller grid to a large one should reflow the pages if the column difference
* is more than 2
*/
- @Test
@Throws(Exception::class)
fun migrateFromSmallerGridBigDifference() {
enableNewMigrationLogic("2,2")
@@ -594,14 +724,13 @@
idp.numRows = 5
val srcReader = DbReader(db, TMP_TABLE, context)
val destReader = DbReader(db, TABLE_NAME, context)
- GridSizeMigrationUtil.migrate(
+ migrateGrid(
dbHelper,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp),
+ idp.numColumns,
+ idp.numRows,
)
// Get workspace items
@@ -636,9 +765,22 @@
assertThat(locMap[testPackage5]).isEqualTo(0)
}
- /** Migrating from a larger grid to a smaller, we reflow from page 0 */
@Test
@Throws(Exception::class)
+ @EnableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun migrateFromLargerGridRefactorFlagOn() {
+ migrateFromLargerGrid()
+ }
+
+ @Test
+ @Throws(Exception::class)
+ @DisableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun migrateFromLargerGridRefactorFlagOff() {
+ migrateFromLargerGrid()
+ }
+
+ /** Migrating from a larger grid to a smaller, we reflow from page 0 */
+ @Throws(Exception::class)
fun migrateFromLargerGrid() {
enableNewMigrationLogic("5,5")
@@ -654,14 +796,13 @@
idp.numRows = 4
val srcReader = DbReader(db, TMP_TABLE, context)
val destReader = DbReader(db, TABLE_NAME, context)
- GridSizeMigrationUtil.migrate(
+ migrateGrid(
dbHelper,
srcReader,
destReader,
idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp),
+ idp.numColumns,
+ idp.numRows,
)
// Get workspace items
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt b/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt
index 6bd182b..8d072d8 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/ModelTestExtensions.kt
@@ -1,6 +1,7 @@
package com.android.launcher3.util
import android.content.ContentValues
+import com.android.launcher3.Flags
import com.android.launcher3.LauncherModel
import com.android.launcher3.LauncherSettings.Favorites
import com.android.launcher3.LauncherSettings.Favorites.APPWIDGET_ID
@@ -30,7 +31,8 @@
loadModelSync()
TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
modelDbController.run {
- tryMigrateDB(null /* restoreEventLogger */)
+ if (Flags.gridMigrationRefactor()) attemptMigrateDb(null /* restoreEventLogger */)
+ else tryMigrateDB(null /* restoreEventLogger */)
createEmptyDB()
clearEmptyDbFlag()
}
@@ -67,12 +69,12 @@
tableName: String = Favorites.TABLE_NAME,
appWidgetId: Int = -1,
appWidgetSource: Int = -1,
- appWidgetProvider: String? = null
+ appWidgetProvider: String? = null,
) {
loadModelSync()
TestUtil.runOnExecutorSync(Executors.MODEL_EXECUTOR) {
val controller: ModelDbController = modelDbController
- controller.tryMigrateDB(null /* restoreEventLogger */)
+ controller.attemptMigrateDb(null /* restoreEventLogger */)
modelDbController.newTransaction().use { transaction ->
val values =
ContentValues().apply {
diff --git a/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
index 35ac0a1..b4ee090 100644
--- a/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
+++ b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
@@ -16,6 +16,8 @@
package com.android.launcher3.backuprestore
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.MediumTest
@@ -52,10 +54,24 @@
setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_NARROW_GRID_RESTORE)
}
+ @EnableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun oldDatabasesNotPresentAfterRestoreRefactorFlagEnabled() {
+ oldDatabasesNotPresentAfterRestore()
+ }
+
+ @DisableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun oldDatabasesNotPresentAfterRestoreRefactorFlagDisabled() {
+ oldDatabasesNotPresentAfterRestore()
+ }
+
@Test
fun oldDatabasesNotPresentAfterRestore() {
val dbController = ModelDbController(getInstrumentation().targetContext)
- dbController.tryMigrateDB(null)
+ if (Flags.gridMigrationRefactor()) {
+ dbController.attemptMigrateDb(null)
+ } else {
+ dbController.tryMigrateDB(null)
+ }
TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
assert(backAndRestoreRule.getDatabaseFiles().size == 1) {
"There should only be one database after restoring, the last one used. Actual databases ${backAndRestoreRule.getDatabaseFiles()}"
diff --git a/tests/src/com/android/launcher3/model/GridMigrationTest.kt b/tests/src/com/android/launcher3/model/GridMigrationTest.kt
index 15222a4..666ec16 100644
--- a/tests/src/com/android/launcher3/model/GridMigrationTest.kt
+++ b/tests/src/com/android/launcher3/model/GridMigrationTest.kt
@@ -52,11 +52,15 @@
phoneContext,
dbFileName,
{ UserCache.INSTANCE.get(phoneContext).getSerialNumberForUser(it) },
- {}
+ {},
)
- fun readEntries(): List<GridSizeMigrationUtil.DbEntry> =
- GridSizeMigrationUtil.readAllEntries(dbHelper.readableDatabase, TABLE_NAME, phoneContext)
+ fun readEntries(): List<DbEntry> =
+ GridSizeMigrationDBController.readAllEntries(
+ dbHelper.readableDatabase,
+ TABLE_NAME,
+ phoneContext,
+ )
}
/**
@@ -80,7 +84,7 @@
TestToPhoneFileCopier(
src = "databases/GridMigrationTest/$DB_FILE",
dest = "databases/$DB_FILE",
- removeOnFinish = true
+ removeOnFinish = true,
)
@Before
@@ -89,13 +93,24 @@
}
private fun migrate(src: GridMigrationData, dst: GridMigrationData) {
- GridSizeMigrationUtil.migrateGridIfNeeded(
- phoneContext,
- src.gridState,
- dst.gridState,
- dst.dbHelper,
- src.dbHelper.readableDatabase
- )
+ if (Flags.gridMigrationRefactor()) {
+ val gridSizeMigrationLogic = GridSizeMigrationLogic()
+ gridSizeMigrationLogic.migrateGrid(
+ phoneContext,
+ src.gridState,
+ dst.gridState,
+ dst.dbHelper,
+ src.dbHelper.readableDatabase,
+ )
+ } else {
+ GridSizeMigrationDBController.migrateGridIfNeeded(
+ phoneContext,
+ src.gridState,
+ dst.gridState,
+ dst.dbHelper,
+ src.dbHelper.readableDatabase,
+ )
+ }
}
/**
@@ -115,10 +130,8 @@
}
private fun compare(dst: GridMigrationData, target: GridMigrationData) {
- val sort = compareBy<GridSizeMigrationUtil.DbEntry>({ it.cellX }, { it.cellY })
- val mapF = { it: GridSizeMigrationUtil.DbEntry ->
- EntryData(it.cellX, it.cellY, it.spanX, it.spanY, it.rank)
- }
+ val sort = compareBy<DbEntry>({ it.cellX }, { it.cellY })
+ val mapF = { it: DbEntry -> EntryData(it.cellX, it.cellY, it.spanX, it.spanY, it.rank) }
val entriesDst = dst.readEntries().sortedWith(sort).map(mapF)
val entriesTarget = target.readEntries().sortedWith(sort).map(mapF)
@@ -149,7 +162,7 @@
TestToPhoneFileCopier(
src = "databases/GridMigrationTest/result5x5to3x3.db",
dest = "databases/result5x5to3x3.db",
- removeOnFinish = true
+ removeOnFinish = true,
)
@Test
@@ -160,10 +173,10 @@
GridMigrationData(
null, // in memory db, to download a new db change null for the filename of the
// db name to store it. Do not use existing names.
- DeviceGridState(3, 3, 3, TYPE_PHONE, "")
+ DeviceGridState(3, 3, 3, TYPE_PHONE, ""),
),
target =
- GridMigrationData("result5x5to3x3.db", DeviceGridState(3, 3, 3, TYPE_PHONE, ""))
+ GridMigrationData("result5x5to3x3.db", DeviceGridState(3, 3, 3, TYPE_PHONE, "")),
)
@JvmField
@@ -172,7 +185,7 @@
TestToPhoneFileCopier(
src = "databases/GridMigrationTest/result5x5to4x7.db",
dest = "databases/result5x5to4x7.db",
- removeOnFinish = true
+ removeOnFinish = true,
)
@Test
@@ -183,10 +196,10 @@
GridMigrationData(
null, // in memory db, to download a new db change null for the filename of the
// db name to store it. Do not use existing names.
- DeviceGridState(4, 7, 4, TYPE_PHONE, "")
+ DeviceGridState(4, 7, 4, TYPE_PHONE, ""),
),
target =
- GridMigrationData("result5x5to4x7.db", DeviceGridState(4, 7, 4, TYPE_PHONE, ""))
+ GridMigrationData("result5x5to4x7.db", DeviceGridState(4, 7, 4, TYPE_PHONE, "")),
)
@JvmField
@@ -195,7 +208,7 @@
TestToPhoneFileCopier(
src = "databases/GridMigrationTest/result5x5to5x8.db",
dest = "databases/result5x5to5x8.db",
- removeOnFinish = true
+ removeOnFinish = true,
)
@Test
@@ -206,10 +219,10 @@
GridMigrationData(
null, // in memory db, to download a new db change null for the filename of the
// db name to store it. Do not use existing names.
- DeviceGridState(5, 8, 5, TYPE_PHONE, "")
+ DeviceGridState(5, 8, 5, TYPE_PHONE, ""),
),
target =
- GridMigrationData("result5x5to5x8.db", DeviceGridState(5, 8, 5, TYPE_PHONE, ""))
+ GridMigrationData("result5x5to5x8.db", DeviceGridState(5, 8, 5, TYPE_PHONE, "")),
)
@JvmField
@@ -218,7 +231,7 @@
TestToPhoneFileCopier(
src = "databases/GridMigrationTest/flagged_result5x5to5x8.db",
dest = "databases/flagged_result5x5to5x8.db",
- removeOnFinish = true
+ removeOnFinish = true,
)
@Test
@@ -230,13 +243,13 @@
GridMigrationData(
null, // in memory db, to download a new db change null for the filename of the
// db name to store it. Do not use existing names.
- DeviceGridState(5, 8, 5, TYPE_PHONE, "")
+ DeviceGridState(5, 8, 5, TYPE_PHONE, ""),
),
target =
GridMigrationData(
"flagged_result5x5to5x8.db",
- DeviceGridState(5, 8, 5, TYPE_PHONE, "")
- )
+ DeviceGridState(5, 8, 5, TYPE_PHONE, ""),
+ ),
)
}
}
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index b17cd4d..ef7242f 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -3,6 +3,8 @@
import android.appwidget.AppWidgetManager
import android.content.Intent
import android.os.UserHandle
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.platform.test.flag.junit.SetFlagsRule
import android.provider.Settings
import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -203,7 +205,8 @@
}
@Test
- fun `When launcher_broadcast_installed_apps and is restore then send installed item broadcast`() {
+ @DisableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
+ fun `When secure setting true and is restore then send installed item broadcast`() {
// Given
val spyContext = spy(context)
`when`(app.context).thenReturn(spyContext)
@@ -271,6 +274,76 @@
}
@Test
+ @EnableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
+ fun `When broadcast flag true and is restore then send installed item broadcast`() {
+ // Given
+ val spyContext = spy(context)
+ `when`(app.context).thenReturn(spyContext)
+ whenever(
+ FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
+ any(),
+ any(),
+ any(),
+ any(),
+ )
+ )
+ .thenReturn(listOf(expectedBroadcastModel))
+
+ whenever(
+ FirstScreenBroadcastHelper.sendBroadcastsForModels(
+ spyContext,
+ listOf(expectedBroadcastModel),
+ )
+ )
+ .thenCallRealMethod()
+
+ Settings.Secure.putInt(spyContext.contentResolver, "launcher_broadcast_installed_apps", 0)
+ RestoreDbTask.setPending(spyContext)
+
+ // When
+ LoaderTask(app, bgAllAppsList, BgDataModel(), modelDelegate, launcherBinder)
+ .runSyncOnBackgroundThread()
+
+ // Then
+ val argumentCaptor = ArgumentCaptor.forClass(Intent::class.java)
+ verify(spyContext).sendBroadcast(argumentCaptor.capture())
+ val actualBroadcastIntent = argumentCaptor.value
+ assertEquals(expectedBroadcastModel.installerPackage, actualBroadcastIntent.`package`)
+ assertEquals(
+ ArrayList(expectedBroadcastModel.installedWorkspaceItems),
+ actualBroadcastIntent.getStringArrayListExtra("workspaceInstalledItems"),
+ )
+ assertEquals(
+ ArrayList(expectedBroadcastModel.installedHotseatItems),
+ actualBroadcastIntent.getStringArrayListExtra("hotseatInstalledItems"),
+ )
+ assertEquals(
+ ArrayList(
+ expectedBroadcastModel.firstScreenInstalledWidgets +
+ expectedBroadcastModel.secondaryScreenInstalledWidgets
+ ),
+ actualBroadcastIntent.getStringArrayListExtra("widgetInstalledItems"),
+ )
+ assertEquals(
+ ArrayList(expectedBroadcastModel.pendingCollectionItems),
+ actualBroadcastIntent.getStringArrayListExtra("folderItem"),
+ )
+ assertEquals(
+ ArrayList(expectedBroadcastModel.pendingWorkspaceItems),
+ actualBroadcastIntent.getStringArrayListExtra("workspaceItem"),
+ )
+ assertEquals(
+ ArrayList(expectedBroadcastModel.pendingHotseatItems),
+ actualBroadcastIntent.getStringArrayListExtra("hotseatItem"),
+ )
+ assertEquals(
+ ArrayList(expectedBroadcastModel.pendingWidgetItems),
+ actualBroadcastIntent.getStringArrayListExtra("widgetItem"),
+ )
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
fun `When not a restore then installed item broadcast not sent`() {
// Given
val spyContext = spy(context)
@@ -304,7 +377,8 @@
}
@Test
- fun `When launcher_broadcast_installed_apps false then installed item broadcast not sent`() {
+ @DisableFlags(Flags.FLAG_ENABLE_FIRST_SCREEN_BROADCAST_ARCHIVING_EXTRAS)
+ fun `When broadcast flag and secure setting false then installed item broadcast not sent`() {
// Given
val spyContext = spy(context)
`when`(app.context).thenReturn(spyContext)
diff --git a/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt b/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
index 03d0195..b96dbcd 100644
--- a/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
+++ b/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
@@ -20,17 +20,21 @@
import android.database.sqlite.SQLiteDatabase
import android.graphics.Point
import android.os.Process
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
import android.util.Log
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.Flags
import com.android.launcher3.InvariantDeviceProfile
import com.android.launcher3.LauncherSettings.Favorites
import com.android.launcher3.celllayout.testgenerator.ValidGridMigrationTestCaseGenerator
import com.android.launcher3.celllayout.testgenerator.generateItemsForTest
import com.android.launcher3.model.DatabaseHelper
import com.android.launcher3.model.DeviceGridState
-import com.android.launcher3.model.GridSizeMigrationUtil
+import com.android.launcher3.model.GridSizeMigrationDBController
+import com.android.launcher3.model.GridSizeMigrationLogic
import com.android.launcher3.pm.UserCache
import com.android.launcher3.provider.LauncherDbUtils
import com.android.launcher3.util.rule.TestStabilityRule
@@ -130,22 +134,52 @@
addItemsToDb(dbHelper.writableDatabase, dstGrid)
LauncherDbUtils.SQLiteTransaction(dbHelper.writableDatabase).use {
- GridSizeMigrationUtil.migrate(
- dbHelper,
- GridSizeMigrationUtil.DbReader(it.db, srcGrid.tableName, context),
- GridSizeMigrationUtil.DbReader(it.db, dstGrid.tableName, context),
- dstGrid.size.x,
- dstGrid.size,
- srcGrid.toGridState(),
- dstGrid.toGridState(),
- )
+ if (Flags.gridMigrationRefactor()) {
+ val gridSizeMigrationLogic = GridSizeMigrationLogic()
+ val idsInUse = mutableListOf<Int>()
+ gridSizeMigrationLogic.migrateHotseat(
+ dstGrid.size.x,
+ GridSizeMigrationDBController.DbReader(it.db, srcGrid.tableName, context),
+ GridSizeMigrationDBController.DbReader(it.db, dstGrid.tableName, context),
+ dbHelper,
+ idsInUse,
+ )
+ gridSizeMigrationLogic.migrateWorkspace(
+ GridSizeMigrationDBController.DbReader(it.db, srcGrid.tableName, context),
+ GridSizeMigrationDBController.DbReader(it.db, dstGrid.tableName, context),
+ dbHelper,
+ dstGrid.size,
+ idsInUse,
+ )
+ } else {
+ GridSizeMigrationDBController.migrate(
+ dbHelper,
+ GridSizeMigrationDBController.DbReader(it.db, srcGrid.tableName, context),
+ GridSizeMigrationDBController.DbReader(it.db, dstGrid.tableName, context),
+ dstGrid.size.x,
+ dstGrid.size,
+ srcGrid.toGridState(),
+ dstGrid.toGridState(),
+ )
+ }
it.commit()
}
return readDb(dstGrid.tableName, dbHelper.readableDatabase)
}
@Test
- fun runTestCase() {
+ @EnableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun runTestCaseRefactorFlagEnabled() {
+ runTestCase()
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun runTestCaseRefactorFlagDisabled() {
+ runTestCase()
+ }
+
+ private fun runTestCase() {
val caseGenerator = ValidGridMigrationTestCaseGenerator(Random(SEED.toLong()))
for (i in 0..SMALL_TEST_SIZE) {
val testCase = caseGenerator.generateTestCase(isDestEmpty = true)
@@ -163,7 +197,18 @@
}
@Test
- fun mergeBoards() {
+ @EnableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun mergeBoardsRefactorFlagEnabled() {
+ mergeBoards()
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun mergeBoardsRefactorFlagDisabled() {
+ mergeBoards()
+ }
+
+ private fun mergeBoards() {
val caseGenerator = ValidGridMigrationTestCaseGenerator(Random(SEED.toLong()))
for (i in 0..SMALL_TEST_SIZE) {
val testCase = caseGenerator.generateTestCase(isDestEmpty = false)
@@ -187,7 +232,20 @@
// This test takes about 4 minutes, there is no need to run it in presubmit.
@Stability(flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT)
@Test
- fun runExtensiveTestCases() {
+ @EnableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun runExtensiveTestCasesRefactorFlagEnabled() {
+ runExtensiveTestCases()
+ }
+
+ // This test takes about 4 minutes, there is no need to run it in presubmit.
+ @Stability(flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT)
+ @Test
+ @DisableFlags(Flags.FLAG_GRID_MIGRATION_REFACTOR)
+ fun runExtensiveTestCasesRefactorFlagDisabled() {
+ runExtensiveTestCases()
+ }
+
+ private fun runExtensiveTestCases() {
val caseGenerator = ValidGridMigrationTestCaseGenerator(Random(SEED.toLong()))
for (i in 0..LARGE_TEST_SIZE) {
val testCase = caseGenerator.generateTestCase(isDestEmpty = true)
diff --git a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
index f54668c..ae54e95 100644
--- a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
+++ b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
@@ -62,6 +62,8 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.R;
import com.android.launcher3.allapps.PrivateProfileManager;
+import com.android.launcher3.dagger.LauncherAppComponent;
+import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.data.AppInfo;
@@ -79,6 +81,9 @@
import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
import com.android.launcher3.widget.picker.model.data.WidgetPickerData;
+import dagger.BindsInstance;
+import dagger.Component;
+
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
@@ -115,8 +120,10 @@
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
+ mSandboxContext.initDaggerComponent(
+ DaggerSystemShortcutTest_TestComponent.builder().bindApiWrapper(
+ ApiWrapper.INSTANCE.get(mSandboxContext)));
mSandboxContext.putObject(UserCache.INSTANCE, mUserCache);
- mSandboxContext.putObject(ApiWrapper.INSTANCE, mApiWrapper);
mTestContext = new TestSandboxModelContextWrapper(mSandboxContext) {
@Override
public StatsLogManager getStatsLogManager() {
@@ -405,4 +412,16 @@
systemShortcut.onClick(mView);
verify(mSandboxContext).startActivity(any());
}
+
+ @LauncherAppSingleton
+ @Component
+ interface TestComponent extends LauncherAppComponent {
+ @Component.Builder
+ interface Builder extends LauncherAppComponent.Builder {
+ @BindsInstance Builder bindApiWrapper(ApiWrapper wrapper);
+
+ @Override
+ TestComponent build();
+ }
+ }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 0edcfea..1002ca4 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -369,7 +369,6 @@
}
}
-
int getTaskCount() {
return getTasks().size();
}
@@ -441,7 +440,7 @@
"Not expecting an actions bar: device is tablet and task is not centered");
return false;
}
- if (task.isTaskSplit() && (!mLauncher.isAppPairsEnabled() || !isTablet)) {
+ if (task.isGrouped() && (!mLauncher.isAppPairsEnabled() || !isTablet)) {
testLogD(TAG, "Not expecting an actions bar: device is phone and task is split");
// Overview actions aren't visible for split screen tasks, except for save app pair
// button on tablets.
@@ -504,11 +503,11 @@
"want to assert overview actions view visibility="
+ isActionsViewVisible()
+ ", focused task is "
- + (task == null ? "null" : (task.isTaskSplit() ? "split" : "not split"))
+ + (task == null ? "null" : (task.isGrouped() ? "split" : "not split"))
)) {
if (isActionsViewVisible()) {
- if (task.isTaskSplit()) {
+ if (task.isGrouped()) {
mLauncher.waitForOverviewObject("action_save_app_pair");
} else {
mLauncher.waitForOverviewObject("action_buttons");
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 9a8d952..5fd4dac 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -16,9 +16,10 @@
package com.android.launcher3.tapl;
-import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.DEFAULT;
-import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT;
-import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.SPLIT_TOP_OR_LEFT;
+import static com.android.launcher3.tapl.OverviewTask.OverviewTaskContainer.DEFAULT;
+import static com.android.launcher3.tapl.OverviewTask.OverviewTaskContainer.DESKTOP;
+import static com.android.launcher3.tapl.OverviewTask.OverviewTaskContainer.SPLIT_BOTTOM_OR_RIGHT;
+import static com.android.launcher3.tapl.OverviewTask.OverviewTaskContainer.SPLIT_TOP_OR_LEFT;
import android.graphics.Rect;
@@ -69,11 +70,11 @@
* divider between.
*/
int getVisibleHeight() {
- if (isTaskSplit()) {
+ if (isGrouped()) {
return getCombinedSplitTaskHeight();
}
- UiObject2 taskSnapshot1 = findObjectInTask(DEFAULT.snapshotRes);
+ UiObject2 taskSnapshot1 = findObjectInTask((isDesktop() ? DESKTOP : DEFAULT).snapshotRes);
return taskSnapshot1.getVisibleBounds().height();
}
@@ -102,7 +103,7 @@
* divider between.
*/
int getVisibleWidth() {
- if (isTaskSplit()) {
+ if (isGrouped()) {
return getCombinedSplitTaskWidth();
}
@@ -164,8 +165,11 @@
dismissBySwipingUp();
+ long numNonDesktopTasks = mOverview.getCurrentTasksForTablet()
+ .stream().filter(t -> !t.isDesktop()).count();
+
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer("dismissed")) {
- if (taskWasFocused) {
+ if (taskWasFocused && numNonDesktopTasks > 0) {
mLauncher.assertNotNull("No task became focused",
mOverview.getFocusedTaskForTablet());
}
@@ -256,7 +260,7 @@
/** Taps the task menu of the split task. Returns the split task's menu object. */
@NonNull
- public OverviewTaskMenu tapMenu(OverviewSplitTask task) {
+ public OverviewTaskMenu tapMenu(OverviewTaskContainer task) {
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"want to tap the task menu")) {
@@ -270,10 +274,6 @@
}
}
- boolean isTaskSplit() {
- return findObjectInTask(SPLIT_BOTTOM_OR_RIGHT.snapshotRes) != null;
- }
-
private UiObject2 findObjectInTask(String resName) {
return mTask.findObject(mLauncher.getOverviewObjectSelector(resName));
}
@@ -285,8 +285,8 @@
* TODO(b/342627272): remove Nullable support once the bug causing it to be null is fixed.
*/
public boolean containsContentDescription(@Nullable String expected,
- OverviewSplitTask overviewSplitTask) {
- String actual = findObjectInTask(overviewSplitTask.snapshotRes).getContentDescription();
+ OverviewTaskContainer overviewTaskContainer) {
+ String actual = findObjectInTask(overviewTaskContainer.snapshotRes).getContentDescription();
if (actual == null && expected == null) {
return true;
}
@@ -315,21 +315,31 @@
}
}
+ boolean isGrouped() {
+ return mType == TaskViewType.GROUPED;
+ }
+
+ public boolean isDesktop() {
+ return mType == TaskViewType.DESKTOP;
+ }
+
/**
- * Enum used to specify which task is retrieved when it is a split task.
+ * Enum used to specify which resource name should be used depending on the type of the task.
*/
- public enum OverviewSplitTask {
+ public enum OverviewTaskContainer {
// The main task when the task is not split.
DEFAULT("snapshot", "icon"),
// The first task in split task.
SPLIT_TOP_OR_LEFT("snapshot", "icon"),
// The second task in split task.
- SPLIT_BOTTOM_OR_RIGHT("bottomright_snapshot", "bottomRight_icon");
+ SPLIT_BOTTOM_OR_RIGHT("bottomright_snapshot", "bottomRight_icon"),
+ // The desktop task.
+ DESKTOP("background", "icon");
public final String snapshotRes;
public final String iconAppRes;
- OverviewSplitTask(String snapshotRes, String iconAppRes) {
+ OverviewTaskContainer(String snapshotRes, String iconAppRes) {
this.snapshotRes = snapshotRes;
this.iconAppRes = iconAppRes;
}