Merge "Update KQS to better support desktop tasks" into main
diff --git a/Android.bp b/Android.bp
index eed67f5..13a926b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -141,6 +141,7 @@
static_libs: [
"LauncherPluginLib",
"launcher_quickstep_log_protos_lite",
+ "android.os.flags-aconfig-java",
"androidx-constraintlayout_constraintlayout",
"androidx.recyclerview_recyclerview",
"androidx.dynamicanimation_dynamicanimation",
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index a31ee80..edbea88 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -52,18 +52,18 @@
name in the permissions. eq com.mypackage.permission.READ_SETTINGS
-->
<permission
- android:name="${packageName}.permission.READ_SETTINGS"
+ android:name="${applicationId}.permission.READ_SETTINGS"
android:protectionLevel="signatureOrSystem"
android:label="@string/permlab_read_settings"
android:description="@string/permdesc_read_settings"/>
<permission
- android:name="${packageName}.permission.WRITE_SETTINGS"
+ android:name="${applicationId}.permission.WRITE_SETTINGS"
android:protectionLevel="signatureOrSystem"
android:label="@string/permlab_write_settings"
android:description="@string/permdesc_write_settings"/>
- <uses-permission android:name="${packageName}.permission.READ_SETTINGS" />
- <uses-permission android:name="${packageName}.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="${applicationId}.permission.READ_SETTINGS" />
+ <uses-permission android:name="${applicationId}.permission.WRITE_SETTINGS" />
<application
android:backupAgent="com.android.launcher3.LauncherBackupAgent"
@@ -126,10 +126,10 @@
-->
<provider
android:name="com.android.launcher3.LauncherProvider"
- android:authorities="${packageName}.settings"
+ android:authorities="${applicationId}.settings"
android:exported="true"
- android:writePermission="${packageName}.permission.WRITE_SETTINGS"
- android:readPermission="${packageName}.permission.READ_SETTINGS" />
+ android:writePermission="${applicationId}.permission.WRITE_SETTINGS"
+ android:readPermission="${applicationId}.permission.READ_SETTINGS" />
<!--
The content provider for exposing various launcher grid options.
@@ -137,7 +137,7 @@
-->
<provider
android:name="com.android.launcher3.graphics.GridCustomizationsProvider"
- android:authorities="${packageName}.grid_control"
+ android:authorities="${applicationId}.grid_control"
android:exported="true" />
<!--
@@ -157,7 +157,7 @@
<provider
android:name="com.android.launcher3.testing.TestInformationProvider"
- android:authorities="${packageName}.TestInfo"
+ android:authorities="${applicationId}.TestInfo"
android:readPermission="android.permission.WRITE_SECURE_SETTINGS"
android:writePermission="android.permission.WRITE_SECURE_SETTINGS"
android:exported="true"
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 2d2fb97..bf198b6 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -50,7 +50,7 @@
<uses-permission android:name="android.permission.ACCESS_HIDDEN_PROFILES_FULL" />
<!-- Permission required to start a WidgetPickerActivity. -->
- <permission android:name="${packageName}.permission.START_WIDGET_PICKER_ACTIVITY"
+ <permission android:name="${applicationId}.permission.START_WIDGET_PICKER_ACTIVITY"
android:protectionLevel="signature|privileged" />
<application android:backupAgent="com.android.launcher3.LauncherBackupAgent"
@@ -88,7 +88,7 @@
<!-- Content provider to settings search. The autority should be same as the packageName -->
<provider android:name="com.android.quickstep.LauncherSearchIndexablesProvider"
- android:authorities="${packageName}"
+ android:authorities="${applicationId}"
android:grantUriPermissions="true"
android:multiprocess="true"
android:permission="android.permission.READ_SEARCH_INDEXABLES"
@@ -100,7 +100,7 @@
<!-- FileProvider used for sharing images. -->
<provider android:name="androidx.core.content.FileProvider"
- android:authorities="${packageName}.overview.fileprovider"
+ android:authorities="${applicationId}.overview.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data android:name="android.support.FILE_PROVIDER_PATHS"
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index e1f52e7..6a749d1 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Speld vas"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Vormvry"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Rekenaar"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Geen onlangse items nie"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programgebruikinstellings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vee alles uit"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 72482ff..c483fb1 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"পিন"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ডেস্কটপ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"কোনো শেহতীয়া বস্তু নাই"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"এপে ব্যৱহাৰ কৰা ডেটাৰ ছেটিং"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"আটাইবোৰ মচক"</string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 68fcb3c..1500e82 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sancın"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Sərbəst rejim"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
<string name="recents_clear_all" msgid="5328176793634888831">"Hamısını silin"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 6fb8f01..9529776 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Zakači"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Slobodni oblik"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Računar"</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>
<string name="recents_clear_all" msgid="5328176793634888831">"Obriši sve"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index a13e943..62ae01b 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixa"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format lliure"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinador"</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>
<string name="recents_clear_all" msgid="5328176793634888831">"Esborra-ho tot"</string>
@@ -119,7 +118,7 @@
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostra sempre la Barra de tasques"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Perquè es mostri sempre la Barra de tasques a la part inferior de la pantalla, mantén premut el separador"</string>
<string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Mantén premuda la tecla d\'acció per cercar què es mostra a la pantalla"</string>
- <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Aquest producte utilitza la part seleccionada de la pantalla per fer cerques. S\'apliquen la <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>política de privadesa<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> i les <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>condicions del servei de Google<xliff:g id="END_TOS_LINK"></a></xliff:g>."</string>
+ <string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Aquest producte utilitza la part seleccionada de la pantalla per fer cerques. S\'apliquen la <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>política de privadesa<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> i les <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>condicions del servei<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Tanca"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Fet"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Inici"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 30c4dc8..55e535b 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Καρφίτσωμα"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Ελεύθερη μορφή"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Υπολογιστής"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Δεν υπάρχουν πρόσφατα στοιχεία"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ρυθμίσεις χρήσης εφαρμογής"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Διαγραφή όλων"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 33536b7..10aa359 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forme libre"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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\'application"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index bf89f83..457d425 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Épingler"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format libre"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
<string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index b4eb026..4306f1f 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ჩამაგრება"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"თავისუფალი ფორმა"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"დესკტოპი"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ბოლოს გამოყენებული ერთეულები არ არის"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"აპების გამოყენების პარამეტრები"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ყველას გასუფთავება"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index a8bbdf5..2a12452 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -118,7 +118,7 @@
<string name="taskbar_edu_features" msgid="3320337287472848162">"Тапсырмалар жолағында мүмкіндік көп"</string>
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Тапсырмалар жолағын әрдайым көрсету"</string>
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Экранның төменгі жағында тапсырмалар жолағы әрдайым көрсетілуі үшін, бөлгішті басып тұрыңыз."</string>
- <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Экраннан іздеу үшін әрекет пернесін басып тұрыңыз."</string>
+ <string name="taskbar_edu_circle_to_search_title" msgid="4322780398403949508">"Экраннан іздеу үшін әрекет пернесін басып тұрыңыз"</string>
<string name="taskbar_edu_circle_to_search_disclosure" msgid="5841648785867787221">"Бұл өнім іздеу үшін экранның таңдалған бөлігін пайдаланады. Google <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Құпиялық саясаты<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> мен <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Қызмет көрсету шарттары<xliff:g id="END_TOS_LINK"></a></xliff:g> қолданылады."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Жабу"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Дайын"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 3b7180c..bcec955 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ខ្ទាស់"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"មុខងារទម្រង់សេរី"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"កុំព្យូទ័រ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"មិនមានធាតុថ្មីៗទេ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ការកំណត់ការប្រើប្រាស់កម្មវិធី"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"សម្អាតទាំងអស់"</string>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 211e9ed..9496dd5 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ປັກໝຸດ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ຮູບແບບອິດສະຫລະ"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ເດັສທັອບ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ບໍ່ມີລາຍການຫຼ້າສຸດ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ການຕັ້ງຄ່າການນຳໃຊ້ແອັບ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ລຶບລ້າງທັງໝົດ"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 87c6e24..d998176 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Semat"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Bentuk bebas"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
<string name="recents_clear_all" msgid="5328176793634888831">"Kosongkan semua"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index acfa2ce..f6668c1 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन गर्नुहोस्"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रिफर्म"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटप"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"हालसालैको कुनै पनि वस्तु छैन"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"एपको उपयोगका सेटिङहरू"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"सबै मेटाउनुहोस्"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index a67cff9..a7c5d44 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -128,7 +128,7 @@
<string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME ସ୍ୱିଚର"</string>
<string name="taskbar_button_recents" msgid="7273376136216613134">"ବର୍ତ୍ତମାନର"</string>
<string name="taskbar_button_notifications" msgid="7471740351507357318">"ବିଜ୍ଞପ୍ତିଗୁଡ଼ିକ"</string>
- <string name="taskbar_button_quick_settings" msgid="227662894293189391">"କ୍ୱିକ ସେଟିଂସ"</string>
+ <string name="taskbar_button_quick_settings" msgid="227662894293189391">"କୁଇକ ସେଟିଂସ"</string>
<string name="taskbar_a11y_title" msgid="6432169809852243110">"ଟାସ୍କବାର"</string>
<string name="taskbar_a11y_shown_title" msgid="6842833581088937713">"ଟାସ୍କବାର ଦେଖାଯାଇଛି"</string>
<string name="taskbar_a11y_hidden_title" msgid="9154903639589659284">"ଟାସ୍କବାର ଲୁଚାଯାଇଛି"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 202813b..5af1bf6 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fixar"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma livre"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
<string name="recents_clear_all" msgid="5328176793634888831">"Limpar tudo"</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 65dde9d..3b7598b 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"අමුණන්න"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ඩෙස්ක්ටොපය"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"මෑත අයිතම නැත"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"යෙදුම් භාවිත සැකසීම්"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"සියල්ල හිස් කරන්න"</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 0164d67..2a7239e 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закачи"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Слободни облик"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Рачунар"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Нема недавних ставки"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Подешавања коришћења апликације"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Обриши све"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 9d925a5..ba960ec 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Bandika"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Muundo huru"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"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>
<string name="recents_clear_all" msgid="5328176793634888831">"Ondoa zote"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 5f1feff..f2c06b4 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"పిన్ చేయండి"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"సంప్రదాయేతర"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"డెస్క్టాప్"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ఇటీవలి ఐటెమ్లు ఏవీ లేవు"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"యాప్ వినియోగ సెట్టింగ్లు"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"అన్నీ తీసివేయండి"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index ea6a285..c5f0b3e 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ปักหมุด"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"รูปแบบอิสระ"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"เดสก์ท็อป"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ไม่มีรายการล่าสุด"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"การตั้งค่าการใช้แอป"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ล้างทั้งหมด"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index c006c59..45cf781 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"電腦"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index e793df6..ef811c4 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"自由形式"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"電腦"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近沒有任何項目"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"應用程式使用情況設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"全部清除"</string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 69e07f2..dc28614 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -427,11 +427,14 @@
<dimen name="bubblebar_drag_elevation">2dp</dimen>
<dimen name="bubblebar_hotseat_adjustment_threshold">90dp</dimen>
- <dimen name="bubblebar_icon_size">50dp</dimen>
+ <dimen name="bubblebar_icon_size_small">32dp</dimen>
+ <dimen name="bubblebar_icon_size">36dp</dimen>
<dimen name="bubblebar_badge_size">24dp</dimen>
<dimen name="bubblebar_icon_overlap">12dp</dimen>
- <dimen name="bubblebar_overflow_inset">24dp</dimen>
- <dimen name="bubblebar_icon_spacing">3dp</dimen>
+ <dimen name="bubblebar_overflow_inset">16dp</dimen>
+ <dimen name="bubblebar_icon_spacing">6dp</dimen>
+ <dimen name="bubblebar_icon_spacing_large">8dp</dimen>
+ <dimen name="bubblebar_expanded_icon_spacing">12dp</dimen>
<dimen name="bubblebar_icon_elevation">1dp</dimen>
<!-- Bubble bar dismiss view -->
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 07e9d00..489102f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -227,11 +227,7 @@
}
mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, isVisible);
- // TODO(b/308851855): Skip animation for launching split from home, will refine later
- boolean skipAnimForSplit = enableSplitContextually() &&
- mLauncher.areBothSplitAppsConfirmed() &&
- mLauncher.getStateManager().getState() == LauncherState.NORMAL;
- if (skipAnimForSplit || fromInit) {
+ if (fromInit) {
duration = 0;
}
return mTaskbarLauncherStateController.applyState(duration, startAnimation);
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 6ceec3e..8e05686 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -207,13 +207,6 @@
}
@Override
- protected void onUserSwipeToDismissProgressChanged() {
- super.onUserSwipeToDismissProgressChanged();
- mAppsView.setClipChildren(!mIsDismissInProgress);
- mAppsView.getAppsRecyclerViewContainer().setClipChildren(!mIsDismissInProgress);
- }
-
- @Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
setTranslationShift(mTranslationShift);
@@ -259,12 +252,28 @@
return getPopupContainer().isEventOverView(mAppsView.getVisibleContainerView(), ev);
}
+ /**
+ * In taskbar all apps search mode, we should scale down content inside all apps, rather
+ * than the whole all apps bottom sheet, to indicate we will navigate back within the all apps.
+ */
+ @Override
+ public boolean shouldAnimateContentViewInBackSwipe() {
+ return mAllAppsCallbacks.canHandleSearchBackInvoked();
+ }
+
+ @Override
+ protected void onUserSwipeToDismissProgressChanged() {
+ super.onUserSwipeToDismissProgressChanged();
+ mAppsView.setClipChildren(!mIsDismissInProgress);
+ mAppsView.getAppsRecyclerViewContainer().setClipChildren(!mIsDismissInProgress);
+ }
+
@Override
public void onBackInvoked() {
if (mAllAppsCallbacks.handleSearchBackInvoked()) {
// We need to scale back taskbar all apps if we navigate back within search inside all
// apps
- animateSwipeToDismissProgressToStart();
+ post(this::animateSwipeToDismissProgressToStart);
} else {
super.onBackInvoked();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index ba4fa45..52f7176 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -143,6 +143,11 @@
}
}
+ /** Check if search session can handle back. This check doesn't perform any action. */
+ boolean canHandleSearchBackInvoked() {
+ return mSearchSessionController.canHandleBackInvoked();
+ }
+
/** Invoked on back press, returning {@code true} if the search session handled it. */
boolean handleSearchBackInvoked() {
return mSearchSessionController.handleBackInvoked();
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
index 3d15fbd..4d0b376 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarSearchSessionController.kt
@@ -49,6 +49,8 @@
/** Creates a [PreDragCondition] for [view], if it is a search result that requires one. */
open fun createPreDragConditionForSearch(view: View): PreDragCondition? = null
+ open fun canHandleBackInvoked(): Boolean = false
+
open fun handleBackInvoked(): Boolean = false
open fun onAllAppsAnimationPending(
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index 8eeb055..9799349 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -31,7 +31,7 @@
import com.android.wm.shell.common.TriangleShape
/** Drawable for the background of the bubble bar. */
-class BubbleBarBackground(context: Context, private val backgroundHeight: Float) : Drawable() {
+class BubbleBarBackground(context: Context, private var backgroundHeight: Float) : Drawable() {
private val DARK_THEME_SHADOW_ALPHA = 51f
private val LIGHT_THEME_SHADOW_ALPHA = 25f
@@ -171,4 +171,8 @@
fun setArrowAlpha(alpha: Int) {
arrowDrawable.paint.alpha = alpha
}
+
+ fun setHeight(newHeight: Float) {
+ backgroundHeight = newHeight
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index a2c1b07..981c9f9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -313,8 +313,11 @@
|| (!update.expandedChanged && !mBubbleBarViewController.isExpanded());
final boolean isExpanding = update.expandedChanged && update.expanded;
// don't animate bubbles if this is the initial state because we may be unfolding or
- // enabling gesture nav
- final boolean suppressAnimation = update.initialState;
+ // enabling gesture nav. also suppress animation if the bubble bar is hidden for sysui e.g.
+ // the shade is open, or we're locked.
+ final boolean suppressAnimation =
+ update.initialState || mBubbleBarViewController.isHiddenForSysui();
+
BubbleBarItem previouslySelectedBubble = mSelectedBubble;
BubbleBarBubble bubbleToSelect = null;
if (!update.removedBubbles.isEmpty()) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 711ba62..1003c3f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -106,10 +106,12 @@
private final Rect mBubbleBarBounds = new Rect();
// The amount the bubbles overlap when they are stacked in the bubble bar
private final float mIconOverlapAmount;
- // The spacing between the bubbles when they are expanded in the bubble bar
- private final float mIconSpacing;
+ // The spacing between the bubbles when bubble bar is expanded
+ private final float mExpandedBarIconsSpacing;
+ // The spacing between the bubbles and the borders of the bubble bar
+ private float mBubbleBarPadding;
// The size of a bubble in the bar
- private final float mIconSize;
+ private float mIconSize;
// The elevation of the bubbles within the bar
private final float mBubbleElevation;
private final float mDragElevation;
@@ -169,16 +171,17 @@
setAlpha(0);
setVisibility(INVISIBLE);
mIconOverlapAmount = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_overlap);
- mIconSpacing = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
+ mBubbleBarPadding = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
mIconSize = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
+ mExpandedBarIconsSpacing = getResources().getDimensionPixelSize(
+ R.dimen.bubblebar_expanded_icon_spacing);
mBubbleElevation = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_elevation);
mDragElevation = getResources().getDimensionPixelSize(R.dimen.bubblebar_drag_elevation);
mPointerSize = getResources().getDimensionPixelSize(R.dimen.bubblebar_pointer_size);
setClipToPadding(false);
- mBubbleBarBackground = new BubbleBarBackground(context,
- getResources().getDimensionPixelSize(R.dimen.bubblebar_size));
+ mBubbleBarBackground = new BubbleBarBackground(context, getBubbleBarHeight());
setBackgroundDrawable(mBubbleBarBackground);
mWidthAnimator.setDuration(WIDTH_ANIMATION_DURATION_MS);
@@ -219,6 +222,29 @@
});
}
+ /**
+ * Sets new icon size and spacing between icons and bubble bar borders.
+ *
+ * @param newIconSize new icon size
+ * @param spacing spacing between icons and bubble bar borders.
+ */
+ // TODO(b/335575529): animate bubble bar icons size change
+ public void setIconSizeAndPadding(float newIconSize, float spacing) {
+ // TODO(b/335457839): handle new bubble animation during the size change
+ mBubbleBarPadding = spacing;
+ mIconSize = newIconSize;
+ int childCount = getChildCount();
+ for (int i = 0; i < childCount; i++) {
+ View childView = getChildAt(i);
+ FrameLayout.LayoutParams params = (LayoutParams) childView.getLayoutParams();
+ params.height = (int) mIconSize;
+ params.width = (int) mIconSize;
+ childView.setLayoutParams(params);
+ }
+ mBubbleBarBackground.setHeight(getBubbleBarHeight());
+ updateLayoutParams();
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -516,6 +542,13 @@
setLayoutParams(lp);
}
+ private void updateLayoutParams() {
+ LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+ lp.height = getBubbleBarHeight();
+ lp.width = (int) (mIsBarExpanded ? expandedWidth() : collapsedWidth());
+ setLayoutParams(lp);
+ }
+
/** @return the horizontal margin between the bubble bar and the edge of the screen. */
int getHorizontalMargin() {
LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
@@ -551,12 +584,12 @@
final float collapsedX;
if (onLeft) {
// If bar is on the left, bubbles are ordered right to left
- expandedX = (bubbleCount - i - 1) * (mIconSize + mIconSpacing);
+ expandedX = (bubbleCount - i - 1) * (mIconSize + mExpandedBarIconsSpacing);
// Shift the first bubble only if there are more bubbles in addition to overflow
collapsedX = i == 0 && bubbleCount > 2 ? mIconOverlapAmount : 0;
} else {
// Bubbles ordered left to right, don't move the first bubble
- expandedX = i * (mIconSize + mIconSpacing);
+ expandedX = i * (mIconSize + mExpandedBarIconsSpacing);
collapsedX = i == 0 ? 0 : mIconOverlapAmount;
}
@@ -599,14 +632,14 @@
final float interpolatedWidth =
widthState * (expandedWidth - collapsedWidth) + collapsedWidth;
final float arrowPosition;
+
+ float interpolatedShift = (expandedArrowPosition - collapsedArrowPosition) * widthState;
if (onLeft) {
- float interpolatedShift = (expandedArrowPosition - collapsedArrowPosition) * widthState;
arrowPosition = collapsedArrowPosition + interpolatedShift;
} else {
if (mIsBarExpanded) {
- // when the bar is expanding, the selected bubble is always the first, so the arrow
- // always shifts with the interpolated width.
- arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition;
+ arrowPosition = currentWidth - interpolatedWidth + collapsedArrowPosition
+ + interpolatedShift;
} else {
final float targetPosition = currentWidth - collapsedWidth + collapsedArrowPosition;
arrowPosition =
@@ -709,7 +742,8 @@
} else {
bubblePosition = index;
}
- return getPaddingStart() + bubblePosition * (mIconSize + mIconSpacing) + mIconSize / 2f;
+ return getPaddingStart() + bubblePosition * (mIconSize + mExpandedBarIconsSpacing)
+ + mIconSize / 2f;
}
private float arrowPositionForSelectedWhenCollapsed() {
@@ -770,7 +804,9 @@
public float expandedWidth() {
final int childCount = getChildCount();
final int horizontalPadding = getPaddingStart() + getPaddingEnd();
- return childCount * (mIconSize + mIconSpacing) + horizontalPadding;
+ // spaces amount is less than child count by 1, or 0 if no child views
+ int spacesCount = Math.max(childCount - 1, 0);
+ return childCount * mIconSize + spacesCount * mExpandedBarIconsSpacing + horizontalPadding;
}
private float collapsedWidth() {
@@ -783,6 +819,10 @@
: mIconSize + horizontalPadding;
}
+ private int getBubbleBarHeight() {
+ return (int) (mIconSize + mBubbleBarPadding * 2 + mPointerSize);
+ }
+
/**
* Returns whether the given MotionEvent, *in screen coordinates*, is within bubble bar
* touch bounds.
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index aa1b4df..a1a2898 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -18,9 +18,12 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
+import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
+import android.util.DisplayMetrics;
import android.util.Log;
+import android.util.TypedValue;
import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
@@ -52,12 +55,13 @@
public class BubbleBarViewController {
private static final String TAG = BubbleBarViewController.class.getSimpleName();
-
+ private static final float APP_ICON_SMALL_DP = 44f;
+ private static final float APP_ICON_MEDIUM_DP = 48f;
+ private static final float APP_ICON_LARGE_DP = 52f;
private final SystemUiProxy mSystemUiProxy;
private final TaskbarActivityContext mActivity;
private final BubbleBarView mBarView;
- private final int mIconSize;
- private final int mPointerSize;
+ private int mIconSize;
// Initialized in init.
private BubbleStashController mBubbleStashController;
@@ -96,9 +100,8 @@
mSystemUiProxy = SystemUiProxy.INSTANCE.get(mActivity);
mBubbleBarAlpha = new MultiValueAlpha(mBarView, 1 /* num alpha channels */);
mBubbleBarAlpha.setUpdateVisibility(true);
- mIconSize = activity.getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
- mPointerSize = activity.getResources().getDimensionPixelSize(
- R.dimen.bubblebar_pointer_size);
+ mIconSize = activity.getResources().getDimensionPixelSize(
+ R.dimen.bubblebar_icon_size);
}
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
@@ -108,12 +111,8 @@
mTaskbarStashController = controllers.taskbarStashController;
mTaskbarInsetsController = controllers.taskbarInsetsController;
- mActivity.addOnDeviceProfileChangeListener(dp ->
- mBarView.getLayoutParams().height =
- mActivity.getDeviceProfile().taskbarHeight + mPointerSize
- );
- mBarView.getLayoutParams().height =
- mActivity.getDeviceProfile().taskbarHeight + mPointerSize;
+ mActivity.addOnDeviceProfileChangeListener(dp -> setBubbleBarIconSize(dp.taskbarIconSize));
+ setBubbleBarIconSize(mActivity.getDeviceProfile().taskbarIconSize);
mBubbleBarScale.updateValue(1f);
mBubbleClickListener = v -> onBubbleClicked(v);
mBubbleBarClickListener = v -> onBubbleBarClicked();
@@ -260,12 +259,44 @@
}
}
+ private void setBubbleBarIconSize(int newIconSize) {
+ if (newIconSize == mIconSize) {
+ return;
+ }
+ Resources res = mActivity.getResources();
+ DisplayMetrics dm = res.getDisplayMetrics();
+ float smallIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ APP_ICON_SMALL_DP, dm);
+ float mediumIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ APP_ICON_MEDIUM_DP, dm);
+ float largeIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ APP_ICON_LARGE_DP, dm);
+ float smallMediumThreshold = (smallIconSize + mediumIconSize) / 2f;
+ float mediumLargeThreshold = (mediumIconSize + largeIconSize) / 2f;
+ mIconSize = newIconSize <= smallMediumThreshold
+ ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_size_small) :
+ res.getDimensionPixelSize(R.dimen.bubblebar_icon_size);
+ float bubbleBarPadding = newIconSize >= mediumLargeThreshold
+ ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing_large) :
+ res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
+
+ mBarView.setIconSizeAndPadding(mIconSize, bubbleBarPadding);
+ mBarView.setPadding((int) bubbleBarPadding, mBarView.getPaddingTop(),
+ (int) bubbleBarPadding,
+ mBarView.getPaddingBottom());
+ }
+
/** Sets a callback that updates the selected bubble after the bubble bar collapses. */
public void setUpdateSelectedBubbleAfterCollapse(
Consumer<String> updateSelectedBubbleAfterCollapse) {
mBarView.setUpdateSelectedBubbleAfterCollapse(updateSelectedBubbleAfterCollapse);
}
+ /** Returns whether the bubble bar should be hidden because of the current sysui state. */
+ boolean isHiddenForSysui() {
+ return mHiddenForSysui;
+ }
+
/**
* Sets whether the bubble bar should be hidden due to SysUI state (e.g. on lockscreen).
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
index 61a2e22..76d86de 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
@@ -23,6 +23,7 @@
import android.annotation.Nullable;
import android.view.InsetsController;
import android.view.MotionEvent;
+import android.view.View;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.taskbar.StashedHandleViewController;
@@ -32,6 +33,7 @@
import com.android.launcher3.taskbar.TaskbarStashController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.animation.PhysicsAnimator;
/**
* Coordinates between controllers such as BubbleBarView and BubbleHandleViewController to
@@ -51,15 +53,6 @@
*/
private static final float STASHED_BAR_SCALE = 0.5f;
- /** The duration of hiding and showing the stashed handle as part of a new bubble animation. */
- private static final long NEW_BUBBLE_HANDLE_ANIMATION_DURATION_MS = 200;
-
- /** The translation Y value the handle animates to when hiding it for a new bubble. */
- private static final int NEW_BUBBLE_HIDE_HANDLE_ANIMATION_TRANSLATION_Y = -20;
-
- /** The alpha value the handle animates to when hiding it for a new bubble. */
- public static final float NEW_BUBBLE_HIDE_HANDLE_ANIMATION_ALPHA = 0.5f;
-
protected final TaskbarActivityContext mActivity;
// Initialized in init.
@@ -73,7 +66,6 @@
private AnimatedFloat mIconScaleForStash;
private AnimatedFloat mIconTranslationYForStash;
private MultiPropertyFactory.MultiProperty mBubbleStashedHandleAlpha;
- private AnimatedFloat mBubbleStashedHandleTranslationY;
private boolean mRequestedStashState;
private boolean mRequestedExpandedState;
@@ -105,7 +97,6 @@
mBubbleStashedHandleAlpha = mHandleViewController.getStashedHandleAlpha().get(
StashedHandleViewController.ALPHA_INDEX_STASHED);
- mBubbleStashedHandleTranslationY = mHandleViewController.getStashedHandleTranslationY();
mStashedHeight = mHandleViewController.getStashedHeight();
mUnstashedHeight = mHandleViewController.getUnstashedHeight();
@@ -379,29 +370,8 @@
return mHandleViewController.getStashedHandleCenterX();
}
- /** Returns the animation for hiding the handle before a new bubble animates in. */
- public AnimatorSet buildHideHandleAnimationForNewBubble() {
- AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.playTogether(
- mBubbleStashedHandleTranslationY.animateToValue(
- NEW_BUBBLE_HIDE_HANDLE_ANIMATION_TRANSLATION_Y),
- mBubbleStashedHandleAlpha.animateToValue(NEW_BUBBLE_HIDE_HANDLE_ANIMATION_ALPHA));
- animatorSet.setDuration(NEW_BUBBLE_HANDLE_ANIMATION_DURATION_MS);
- return animatorSet;
- }
-
- /** Sets the alpha value of the stashed handle. */
- public void setStashAlpha(float alpha) {
- mBubbleStashedHandleAlpha.setValue(alpha);
- }
-
- /** Returns the animation for showing the handle after a new bubble animated in. */
- public AnimatorSet buildShowHandleAnimationForNewBubble() {
- AnimatorSet animatorSet = new AnimatorSet();
- animatorSet.playTogether(
- mBubbleStashedHandleTranslationY.animateToValue(0),
- mBubbleStashedHandleAlpha.animateToValue(1));
- animatorSet.setDuration(NEW_BUBBLE_HANDLE_ANIMATION_DURATION_MS);
- return animatorSet;
+ /** Returns the [PhysicsAnimator] for the stashed handle view. */
+ public PhysicsAnimator<View> getStashedHandlePhysicsAnimator() {
+ return mHandleViewController.getPhysicsAnimator();
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
index 2a5912a..6f1a093 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashedHandleViewController.java
@@ -29,7 +29,6 @@
import android.view.ViewOutlineProvider;
import com.android.launcher3.R;
-import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.taskbar.StashedHandleView;
@@ -40,6 +39,7 @@
import com.android.launcher3.util.MultiValueAlpha;
import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.shared.animation.PhysicsAnimator;
/**
* Handles properties/data collection, then passes the results to our stashed handle View to render.
@@ -59,12 +59,6 @@
private int mStashedHandleWidth;
private int mStashedHandleHeight;
- private final AnimatedFloat mStashedHandleTranslationY =
- new AnimatedFloat(this::updateTranslationY);
-
- // Modified when swipe up is happening on the stashed handle or task bar.
- private float mSwipeUpTranslationY;
-
// The bounds we want to clip to in the settled state when showing the stashed handle.
private final Rect mStashedHandleBounds = new Rect();
@@ -129,6 +123,11 @@
updateBounds(mBarViewController.getBubbleBarLocation()));
}
+ /** Returns the [PhysicsAnimator] for the stashed handle view. */
+ public PhysicsAnimator<View> getPhysicsAnimator() {
+ return PhysicsAnimator.getInstance(mStashedHandleView);
+ }
+
private void updateBounds(BubbleBarLocation bubbleBarLocation) {
// As more bubbles get added, the icon bounds become larger. To ensure a consistent
// handle bar position, we pin it to the edge of the screen.
@@ -238,21 +237,11 @@
}
}
- /** Returns an animator for translation Y. */
- public AnimatedFloat getStashedHandleTranslationY() {
- return mStashedHandleTranslationY;
- }
-
/**
* Sets the translation of the stashed handle during the swipe up gesture.
*/
public void setTranslationYForSwipe(float transY) {
- mSwipeUpTranslationY = transY;
- updateTranslationY();
- }
-
- private void updateTranslationY() {
- mStashedHandleView.setTranslationY(mStashedHandleTranslationY.value + mSwipeUpTranslationY);
+ mStashedHandleView.setTranslationY(transY);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS b/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS
index edabae2..3f947a0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/OWNERS
@@ -1,3 +1,5 @@
atsjenk@google.com
liranb@google.com
madym@google.com
+mpodolian@google.com
+
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 1db5103..2d8983f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimator.kt
@@ -18,16 +18,12 @@
import android.view.View
import android.view.View.VISIBLE
-import androidx.core.animation.AnimatorSet
-import androidx.core.animation.ObjectAnimator
-import androidx.core.animation.doOnEnd
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.SpringForce
import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleStashController
import com.android.launcher3.taskbar.bubbles.BubbleView
-import com.android.systemui.util.doOnEnd
import com.android.wm.shell.shared.animation.PhysicsAnimator
/** Handles animations for bubble bar bubbles. */
@@ -43,17 +39,19 @@
/** The time to show the flyout. */
const val FLYOUT_DELAY_MS: Long = 2500
/** The translation Y the new bubble will animate to. */
- const val BUBBLE_ANIMATION_FINAL_TRANSLATION_Y = -50f
+ const val BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y = -50f
/** The initial translation Y value the new bubble is set to before the animation starts. */
// TODO(liranb): get rid of this and calculate this based on the y-distance between the
// bubble and the stash handle.
- const val BUBBLE_ANIMATION_INITIAL_TRANSLATION_Y = 50f
+ const val BUBBLE_ANIMATION_TRANSLATION_Y_OFFSET = 50f
/** The initial scale Y value that the new bubble is set to before the animation starts. */
const val BUBBLE_ANIMATION_INITIAL_SCALE_Y = 0.3f
- /** The initial alpha value that the new bubble is set to before the animation starts. */
- const val BUBBLE_ANIMATION_INITIAL_ALPHA = 0.5f
- /** The duration of the hide bubble animation. */
- const val HIDE_BUBBLE_ANIMATION_DURATION_MS = 250L
+ /**
+ * The distance the stashed handle will travel as it gets hidden as part of the new bubble
+ * animation.
+ */
+ // TODO(liranb): calculate this based on the position of the views
+ const val BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y = -20f
}
/** An interface for scheduling jobs. */
@@ -91,7 +89,7 @@
if (animator.isRunning()) animator.cancel()
// the animation of a new bubble is divided into 2 parts. The first part shows the bubble
// and the second part hides it after a delay.
- val showAnimation = buildShowAnimation(bubbleView, b.key, animator)
+ val showAnimation = buildShowAnimation(bubbleView, b.key)
val hideAnimation = buildHideAnimation(bubbleView)
scheduler.post(showAnimation)
scheduler.postDelayed(FLYOUT_DELAY_MS, hideAnimation)
@@ -100,71 +98,139 @@
/**
* Returns a lambda that starts the animation that shows the new bubble.
*
- * The animation is divided into 2 parts. First the stash handle starts animating up and fades
- * out. When it ends the bubble starts fading in. The bubble and stashed handle are aligned to
- * give the impression of the stash handle morphing into the bubble.
+ * Visually, the animation is divided into 2 parts. The stash handle starts animating up and
+ * fading out and then the bubble starts animating up and fading in.
+ *
+ * To make the transition from the handle to the bubble smooth, the positions and movement of
+ * the 2 views must be synchronized. To do that we use a single spring path along the Y axis,
+ * starting from the handle's position to the eventual bubble's position. The path is split into
+ * 3 parts.
+ * 1. In the first part, we only animate the handle.
+ * 1. In the second part the handle is fully hidden, and the bubble is animating in.
+ * 1. The third part is the overshoot of the spring animation, where we make the bubble fully
+ * visible which helps avoiding further updates when we re-enter the second part.
*/
private fun buildShowAnimation(
bubbleView: BubbleView,
key: String,
- bubbleAnimator: PhysicsAnimator<BubbleView>
): () -> Unit = {
+ bubbleBarView.prepareForAnimatingBubbleWhileStashed(key)
// calculate the initial translation x the bubble should have in order to align it with the
// stash handle.
val initialTranslationX =
bubbleStashController.stashedHandleCenterX - bubbleView.centerXOnScreen
- bubbleBarView.prepareForAnimatingBubbleWhileStashed(key)
- bubbleAnimator.setDefaultSpringConfig(springConfig)
- bubbleAnimator
- .spring(DynamicAnimation.ALPHA, 1f)
- .spring(DynamicAnimation.TRANSLATION_Y, BUBBLE_ANIMATION_FINAL_TRANSLATION_Y)
- .spring(DynamicAnimation.SCALE_Y, 1f)
// prepare the bubble for the animation
bubbleView.alpha = 0f
bubbleView.translationX = initialTranslationX
- bubbleView.translationY = BUBBLE_ANIMATION_INITIAL_TRANSLATION_Y
bubbleView.scaleY = BUBBLE_ANIMATION_INITIAL_SCALE_Y
bubbleView.visibility = VISIBLE
- // start the stashed handle animation. when it ends, start the bubble animation.
- val stashedHandleAnimation = bubbleStashController.buildHideHandleAnimationForNewBubble()
- stashedHandleAnimation.doOnEnd {
- bubbleView.alpha = BUBBLE_ANIMATION_INITIAL_ALPHA
- bubbleAnimator.start()
- bubbleStashController.setStashAlpha(0f)
+
+ // this is the total distance that both the stashed handle and the bubble will be traveling
+ val totalTranslationY =
+ BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y + BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y
+ val animator = bubbleStashController.stashedHandlePhysicsAnimator
+ animator.setDefaultSpringConfig(springConfig)
+ animator.spring(DynamicAnimation.TRANSLATION_Y, totalTranslationY)
+ animator.addUpdateListener { target, values ->
+ val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
+ when {
+ ty >= BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y -> {
+ // we're in the first leg of the animation. only animate the handle. the bubble
+ // remains hidden during this part of the animation
+
+ // map the path [0, BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y] to [0,1]
+ val fraction = ty / BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y
+ target.alpha = 1 - fraction / 2
+ }
+ ty >= totalTranslationY -> {
+ // this is the second leg of the animation. the handle should be completely
+ // hidden and the bubble should start animating in.
+ // it's possible that we're re-entering this leg because this is a spring
+ // animation, so only set the alpha and scale for the bubble if we didn't
+ // already fully animate in.
+ target.alpha = 0f
+ bubbleView.translationY = ty + BUBBLE_ANIMATION_TRANSLATION_Y_OFFSET
+ if (bubbleView.alpha != 1f) {
+ // map the path
+ // [BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y, totalTranslationY]
+ // to [0, 1]
+ val fraction =
+ (ty - BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y) /
+ BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y
+ bubbleView.alpha = fraction
+ bubbleView.scaleY =
+ BUBBLE_ANIMATION_INITIAL_SCALE_Y +
+ (1 - BUBBLE_ANIMATION_INITIAL_SCALE_Y) * fraction
+ }
+ }
+ else -> {
+ // we're past the target animated value, set the alpha and scale for the bubble
+ // so that it's fully visible and no longer changing, but keep moving it along
+ // the animation path
+ bubbleView.alpha = 1f
+ bubbleView.scaleY = 1f
+ bubbleView.translationY = ty + BUBBLE_ANIMATION_TRANSLATION_Y_OFFSET
+ }
+ }
}
- stashedHandleAnimation.start()
+ animator.start()
}
/**
* Returns a lambda that starts the animation that hides the new bubble.
*
- * Similarly to the show animation, this is divided into 2 parts. We first animate the bubble
- * out, and then animate the stash handle in. At the end of the animation we reset the values of
- * the bubble.
+ * Similarly to the show animation, this is visually divided into 2 parts. We first animate the
+ * bubble out, and then animate the stash handle in. At the end of the animation we reset the
+ * values of the bubble.
+ *
+ * This is a spring animation that goes along the same path of the show animation in the
+ * opposite order, and is split into 3 parts:
+ * 1. In the first part the bubble animates out.
+ * 1. In the second part the bubble is fully hidden and the handle animates in.
+ * 1. The third part is the overshoot. The handle is made fully visible.
*/
private fun buildHideAnimation(bubbleView: BubbleView): () -> Unit = {
- val stashAnimation = bubbleStashController.buildShowHandleAnimationForNewBubble()
- val alphaAnimator =
- ObjectAnimator.ofFloat(bubbleView, View.ALPHA, BUBBLE_ANIMATION_INITIAL_ALPHA)
- val translationYAnimator =
- ObjectAnimator.ofFloat(
- bubbleView,
- View.TRANSLATION_Y,
- BUBBLE_ANIMATION_INITIAL_TRANSLATION_Y
- )
- val scaleYAnimator =
- ObjectAnimator.ofFloat(bubbleView, View.SCALE_Y, BUBBLE_ANIMATION_INITIAL_SCALE_Y)
- val hideBubbleAnimation = AnimatorSet()
- hideBubbleAnimation.playTogether(alphaAnimator, translationYAnimator, scaleYAnimator)
- hideBubbleAnimation.duration = HIDE_BUBBLE_ANIMATION_DURATION_MS
- hideBubbleAnimation.doOnEnd {
- // the bubble is now hidden, start the stash handle animation and reset bubble
- // properties
- bubbleStashController.setStashAlpha(
- BubbleStashController.NEW_BUBBLE_HIDE_HANDLE_ANIMATION_ALPHA
- )
+ // this is the total distance that both the stashed handle and the bubble will be traveling
+ val totalTranslationY =
+ BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y + BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y
+ val animator = bubbleStashController.stashedHandlePhysicsAnimator
+ animator.setDefaultSpringConfig(springConfig)
+ animator.spring(DynamicAnimation.TRANSLATION_Y, 0f)
+ animator.addUpdateListener { target, values ->
+ val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
+ when {
+ ty <= BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y -> {
+ // this is the first leg of the animation. only animate the bubble. the handle
+ // is hidden during this part
+ bubbleView.translationY = ty + BUBBLE_ANIMATION_TRANSLATION_Y_OFFSET
+ // map the path
+ // [totalTranslationY, BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y]
+ // to [0, 1]
+ val fraction = (totalTranslationY - ty) / BUBBLE_ANIMATION_BUBBLE_TRANSLATION_Y
+ bubbleView.alpha = 1 - fraction / 2
+ bubbleView.scaleY = 1 - (1 - BUBBLE_ANIMATION_INITIAL_SCALE_Y) * fraction
+ }
+ ty <= 0 -> {
+ // this is the second part of the animation. make the bubble invisible and
+ // start fading in the handle, but don't update the alpha if it's already fully
+ // visible
+ bubbleView.alpha = 0f
+ if (target.alpha != 1f) {
+ // map the path [BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y, 0] to [0, 1]
+ val fraction =
+ (BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y - ty) /
+ BUBBLE_ANIMATION_STASH_HANDLE_TRANSLATION_Y
+ target.alpha = fraction
+ }
+ }
+ else -> {
+ // we reached the target value. set the alpha of the handle to 1
+ target.alpha = 1f
+ }
+ }
+ }
+ animator.addEndListener { _, _, _, _, _, _, _ ->
bubbleView.alpha = 0f
- stashAnimation.start()
bubbleView.translationY = 0f
bubbleView.scaleY = 1f
if (bubbleStashController.isStashed) {
@@ -172,7 +238,7 @@
}
bubbleBarView.onAnimatingBubbleCompleted()
}
- hideBubbleAnimation.start()
+ animator.start()
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 543fd02..4acddee 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -1210,6 +1210,7 @@
switch (info.container) {
case Favorites.CONTAINER_DESKTOP:
case Favorites.CONTAINER_HOTSEAT:
+ case Favorites.CONTAINER_PRIVATESPACE:
// Fall through and continue it's on the workspace (we don't support swiping back
// to other containers like all apps or the hotseat predictions (which can change)
break;
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 2fedb6f..9e1addf 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -1254,10 +1254,12 @@
return LAST_TASK;
}
- if (((mRecentsView.getNextPageTaskView() != null
- && mRecentsView.getNextPageTaskView().isDesktopTask())
- || (mRecentsView.getCurrentPageTaskView() != null
- && mRecentsView.getCurrentPageTaskView().isDesktopTask()))
+ TaskView nextPageTaskView = mRecentsView != null
+ ? mRecentsView.getNextPageTaskView() : null;
+ TaskView currentPageTaskView = mRecentsView != null
+ ? mRecentsView.getCurrentPageTaskView() : null;
+ if (((nextPageTaskView != null && nextPageTaskView.isDesktopTask())
+ || (currentPageTaskView != null && currentPageTaskView.isDesktopTask()))
&& endTarget == NEW_TASK) {
// TODO(b/268075592): add support for quickswitch to/from desktop
return LAST_TASK;
diff --git a/quickstep/src/com/android/quickstep/DesktopModeStatus.java b/quickstep/src/com/android/quickstep/DesktopModeStatus.java
new file mode 100644
index 0000000..b1aae16
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/DesktopModeStatus.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep;
+
+import android.content.Context;
+import android.os.SystemProperties;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.window.flags.Flags;
+
+// TODO(b/335401172): Explore unifying logic across core and shell
+public class DesktopModeStatus {
+
+ /**
+ * Flag to indicate whether to restrict desktop mode to supported devices.
+ */
+ private static final boolean ENFORCE_DEVICE_RESTRICTIONS = SystemProperties.getBoolean(
+ "persist.wm.debug.desktop_mode_enforce_device_restrictions", true);
+
+ /**
+ * Return {@code true} if desktop mode should be restricted to supported devices.
+ */
+ @VisibleForTesting
+ public static boolean enforceDeviceRestrictions() {
+ return ENFORCE_DEVICE_RESTRICTIONS;
+ }
+
+ /**
+ * Return {@code true} if the current device supports desktop mode.
+ */
+ @VisibleForTesting
+ public static boolean isDesktopModeSupported(Context context) {
+ return context.getResources().getBoolean(
+ com.android.internal.R.bool.config_isDesktopModeSupported);
+ }
+
+ /**
+ * Return {@code true} if desktop mode can be entered on the current device.
+ */
+ public static boolean canEnterDesktopMode(Context context) {
+ return Flags.enableDesktopWindowingMode()
+ && (!enforceDeviceRestrictions() || isDesktopModeSupported(context));
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index aa0f728..f26d594 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -24,7 +24,6 @@
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
-import com.android.window.flags.Flags
/** A menu item, "Desktop", that allows the user to bring the current app into Desktop Windowing. */
class DesktopSystemShortcut(
@@ -52,7 +51,7 @@
}
companion object {
- /** Creates a factory for creating Desktop system shorcuts. */
+ /** Creates a factory for creating Desktop system shortcuts. */
@JvmOverloads
fun createFactory(
abstractFloatingViewHelper: AbstractFloatingViewHelper = AbstractFloatingViewHelper()
@@ -62,7 +61,7 @@
container: RecentsViewContainer,
taskContainer: TaskIdAttributeContainer
): List<DesktopSystemShortcut>? {
- return if (!Flags.enableDesktopWindowingMode()) null
+ return if (!DesktopModeStatus.canEnterDesktopMode(container.asContext())) null
else if (!taskContainer.task.isDockable) null
else
listOf(
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index a3935ce..af02ccf 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -122,6 +122,10 @@
float windowAlphaThreshold = 1f - SHAPE_PROGRESS_DURATION;
return new FloatingViewHomeAnimationFactory(floatingIconView) {
+ @Nullable
+ private RectF mTargetRect;
+ @Nullable
+ private RectFSpringAnim mSiblingAnimation;
@Nullable
@Override
@@ -138,15 +142,36 @@
@NonNull
@Override
public RectF getWindowTargetRect() {
- return iconLocation;
+ if (enableScalingRevealHomeAnimation()) {
+ if (mTargetRect == null) {
+ mTargetRect = new RectF(iconLocation);
+ }
+ return mTargetRect;
+ } else {
+ return iconLocation;
+ }
+ }
+
+ @Override
+ public void playAtomicAnimation(float velocity) {
+ if (enableScalingRevealHomeAnimation()) {
+ if (mContainer != null) {
+ new ScalingWorkspaceRevealAnim(
+ mContainer, mSiblingAnimation, getWindowTargetRect()).start();
+ }
+ } else {
+ super.playAtomicAnimation(velocity);
+ }
}
@Override
public void setAnimation(RectFSpringAnim anim) {
super.setAnimation(anim);
- anim.addAnimatorListener(floatingIconView);
- floatingIconView.setOnTargetChangeListener(anim::onTargetPositionChanged);
- floatingIconView.setFastFinishRunnable(anim::end);
+ mSiblingAnimation = anim;
+ mSiblingAnimation.addAnimatorListener(floatingIconView);
+ floatingIconView.setOnTargetChangeListener(
+ mSiblingAnimation::onTargetPositionChanged);
+ floatingIconView.setFastFinishRunnable(mSiblingAnimation::end);
}
@Override
@@ -301,15 +326,9 @@
@Override
public void playAtomicAnimation(float velocity) {
- if (enableScalingRevealHomeAnimation()) {
- if (mContainer != null) {
- new ScalingWorkspaceRevealAnim(mContainer).start();
- }
- } else {
- new StaggeredWorkspaceAnim(mContainer, velocity, true /* animateOverviewScrim */,
- getViewIgnoredInWorkspaceRevealAnimation())
- .start();
- }
+ new StaggeredWorkspaceAnim(mContainer, velocity, true /* animateOverviewScrim */,
+ getViewIgnoredInWorkspaceRevealAnimation())
+ .start();
}
}
}
diff --git a/quickstep/src/com/android/quickstep/util/AssistStateManager.java b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
index dcd3c6d..4a35c3b 100644
--- a/quickstep/src/com/android/quickstep/util/AssistStateManager.java
+++ b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
@@ -43,6 +43,11 @@
return false;
}
+ /** Whether search supports showing on the lockscreen. */
+ public boolean supportsShowWhenLocked() {
+ return false;
+ }
+
/** Whether CsHelper CtS invocation path is available. */
public Optional<Boolean> isCsHelperAvailable() {
return Optional.empty();
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
index c39056d..5505bb3 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -171,8 +171,13 @@
public void onTargetPositionChanged() {
if (enableScalingRevealHomeAnimation()) {
+ if (isEnded()) {
+ return;
+ }
+
if (mRectXSpring != null) {
mRectXSpring.animateToFinalPosition(mTargetRect.centerX());
+ mRectXAnimEnded = false;
}
if (mRectYSpring != null) {
@@ -187,6 +192,7 @@
mRectYSpring.animateToFinalPosition(mTargetRect.centerY());
break;
}
+ mRectYAnimEnded = false;
}
} else {
if (mRectXAnim != null && mRectXAnim.getTargetPosition() != mTargetRect.centerX()) {
@@ -297,6 +303,7 @@
.setStiffness(stiffnessZ)
.setDampingRatio(dampingZ))
.setStartVelocity(velocityPxPerMs.y * minVisibleChange)
+ .setMaxValue(1f)
.setMinimumVisibleChange(minVisibleChange)
.addEndListener((animation, canceled, value, velocity) -> {
mRectScaleAnimEnded = true;
diff --git a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
index 0c1ac25..1bf77f1 100644
--- a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
+++ b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
@@ -16,7 +16,10 @@
package com.android.quickstep.util
+import android.graphics.Matrix
+import android.graphics.RectF
import android.view.View
+import androidx.core.graphics.transform
import com.android.app.animation.Interpolators
import com.android.app.animation.Interpolators.EMPHASIZED
import com.android.app.animation.Interpolators.LINEAR
@@ -38,7 +41,11 @@
* 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.
*/
-class ScalingWorkspaceRevealAnim(launcher: QuickstepLauncher) {
+class ScalingWorkspaceRevealAnim(
+ launcher: QuickstepLauncher,
+ siblingAnimation: RectFSpringAnim?,
+ windowTargetRect: RectF?
+) {
companion object {
private const val FADE_DURATION_MS = 200L
private const val SCALE_DURATION_MS = 1000L
@@ -118,6 +125,41 @@
transitionConfig
)
+ // To avoid awkward jumps in icon position, we want the sibling animation to always be
+ // targeting the current position. Since we can't easily access this, instead we calculate
+ // it using the animation of the whole of home.
+ // We start by caching the final target position, as this is the base for the transforms.
+ val originalTarget = RectF(windowTargetRect)
+ animation.addOnFrameListener {
+ val transformed = RectF(originalTarget)
+
+ // First we scale down using the same pivot as the workspace scale, so we find the
+ // correct position AND size.
+ transformed.transform(
+ Matrix().apply {
+ setScale(workspace.scaleX, workspace.scaleY, workspace.pivotX, workspace.pivotY)
+ }
+ )
+ // Then we scale back up around the center of the current position. This is because the
+ // icon animation behaves poorly if it is given a target that is smaller than the size
+ // of the icon.
+ transformed.transform(
+ Matrix().apply {
+ setScale(
+ 1 / workspace.scaleX,
+ 1 / workspace.scaleY,
+ transformed.centerX(),
+ transformed.centerY()
+ )
+ }
+ )
+
+ if (transformed != windowTargetRect) {
+ windowTargetRect?.set(transformed)
+ siblingAnimation?.onTargetPositionChanged()
+ }
+ }
+
// Needed to avoid text artefacts during the scale animation.
workspace.setLayerType(View.LAYER_TYPE_HARDWARE, null)
hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null)
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 378a00d..021c455 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -929,11 +929,30 @@
}
}
+ if (splitRoot1 != null) {
+ // Set the highest level split root alpha; we could technically use the parent of
+ // either splitRoot1 or splitRoot2
+ val parentToken = splitRoot1.parent
+ var rootLayer: Change? = null
+ if (parentToken != null) {
+ rootLayer = transitionInfo.getChange(parentToken)
+ }
+ if (rootLayer != null && rootLayer.leash != null) {
+ openingTargets.add(rootLayer.leash)
+ }
+ }
+
val animTransaction = Transaction()
val animator = ValueAnimator.ofFloat(0f, 1f)
animator.setDuration(QuickstepTransitionManager.SPLIT_LAUNCH_DURATION.toLong())
animator.addUpdateListener { valueAnimator: ValueAnimator ->
- val progress = valueAnimator.animatedFraction
+ val progress =
+ Interpolators.clampToProgress(
+ Interpolators.LINEAR,
+ valueAnimator.animatedFraction,
+ 0.8f,
+ 1f
+ )
for (leash in openingTargets) {
animTransaction.setAlpha(leash, progress)
}
@@ -955,19 +974,6 @@
}
)
- if (splitRoot1 != null) {
- // Set the highest level split root alpha; we could technically use the parent of
- // either splitRoot1 or splitRoot2
- val parentToken = splitRoot1.parent
- var rootLayer: Change? = null
- if (parentToken != null) {
- rootLayer = transitionInfo.getChange(parentToken)
- }
- if (rootLayer != null && rootLayer.leash != null) {
- t.setAlpha(rootLayer.leash, 1f)
- }
- }
-
t.apply()
animator.start()
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index d07acd4..b6e6bf7 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -177,6 +177,11 @@
private boolean mIsCancelled = false;
@Override
+ public void onAnimationStart(Animator animation) {
+ mController.launchSplitTasks(aBoolean -> cleanUp());
+ }
+
+ @Override
public void onAnimationCancel(Animator animation) {
mIsCancelled = true;
cleanUp();
@@ -185,7 +190,6 @@
@Override
public void onAnimationEnd(Animator animation) {
if (!mIsCancelled) {
- mController.launchSplitTasks(aBoolean -> cleanUp());
InteractionJankMonitorWrapper.end(Cuj.CUJ_SPLIT_SCREEN_ENTER);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 791ef04..ae6f703 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -68,7 +68,6 @@
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_NO_TASKS;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_SPLIT_SCREEN;
import static com.android.quickstep.views.OverviewActionsView.HIDDEN_SPLIT_SELECT_ACTIVE;
-import static com.android.window.flags.Flags.enableDesktopWindowingMode;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -167,6 +166,7 @@
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.ViewPool;
import com.android.quickstep.BaseContainerInterface;
+import com.android.quickstep.DesktopModeStatus;
import com.android.quickstep.GestureState;
import com.android.quickstep.OverviewCommandHelper;
import com.android.quickstep.RecentsAnimationController;
@@ -2817,7 +2817,7 @@
}
private boolean hasDesktopTask(Task[] runningTasks) {
- if (!enableDesktopWindowingMode()) {
+ if (!DesktopModeStatus.canEnterDesktopMode(mContext)) {
return false;
}
for (Task task : runningTasks) {
@@ -6229,7 +6229,7 @@
*/
public void moveTaskToDesktop(TaskIdAttributeContainer taskContainer,
Runnable successCallback) {
- if (!enableDesktopWindowingMode()) {
+ if (!DesktopModeStatus.canEnterDesktopMode(mContext)) {
return;
}
switchToScreenshot(() -> finishRecentsAnimation(/* toRecents= */true, /* shouldPip= */false,
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 b478efa..d90e048 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
@@ -16,19 +16,15 @@
package com.android.launcher3.taskbar.bubbles.animation
-import android.animation.Animator
-import android.animation.AnimatorListenerAdapter
-import android.animation.AnimatorSet
import android.content.Context
import android.graphics.Color
import android.graphics.Path
import android.graphics.drawable.ColorDrawable
import android.view.LayoutInflater
+import android.view.View
import android.view.View.INVISIBLE
import android.view.View.VISIBLE
import android.widget.FrameLayout
-import androidx.core.animation.AnimatorTestRule
-import androidx.core.animation.doOnEnd
import androidx.core.graphics.drawable.toBitmap
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.test.core.app.ApplicationProvider
@@ -42,16 +38,13 @@
import com.android.launcher3.taskbar.bubbles.BubbleStashController
import com.android.launcher3.taskbar.bubbles.BubbleView
import com.android.wm.shell.common.bubbles.BubbleInfo
+import com.android.wm.shell.shared.animation.PhysicsAnimator
import com.android.wm.shell.shared.animation.PhysicsAnimatorTestUtils
import com.google.common.truth.Truth.assertThat
-import java.util.concurrent.Semaphore
-import java.util.concurrent.TimeUnit
import org.junit.Before
-import org.junit.ClassRule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
-import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@SmallTest
@@ -61,10 +54,6 @@
private val context = ApplicationProvider.getApplicationContext<Context>()
private val animatorScheduler = TestBubbleBarViewAnimatorScheduler()
- companion object {
- @JvmField @ClassRule val animatorTestRule = AnimatorTestRule()
- }
-
@Before
fun setUp() {
PhysicsAnimatorTestUtils.prepareForTest()
@@ -99,14 +88,9 @@
val bubbleStashController = mock<BubbleStashController>()
whenever(bubbleStashController.isStashed).thenReturn(true)
- val semaphore = Semaphore(0)
- val hideHandleAnimator = AnimatorSet()
- hideHandleAnimator.duration = 0
- whenever(bubbleStashController.buildHideHandleAnimationForNewBubble())
- .thenReturn(hideHandleAnimator)
- // add an end listener to the hide handle animation. we add it when the animation starts
- // to ensure that it gets called after all other end listeners.
- hideHandleAnimator.doOnStart { hideHandleAnimator.doOnEnd { semaphore.release() } }
+ val handle = View(context)
+ val handleAnimator = PhysicsAnimator.getInstance(handle)
+ whenever(bubbleStashController.stashedHandlePhysicsAnimator).thenReturn(handleAnimator)
val animator =
BubbleBarViewAnimator(bubbleBarView, bubbleStashController, animatorScheduler)
@@ -115,44 +99,26 @@
animator.animateBubbleInForStashed(bubble)
}
- // wait for the stash handle animation to complete
- assertThat(semaphore.tryAcquire(5, TimeUnit.SECONDS)).isTrue()
- // stash handle animation finished. verify that the stash handle is now hidden
- verify(bubbleStashController).setStashAlpha(0f)
-
+ // let the animation start and wait for it to complete
InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
+ assertThat(handle.alpha).isEqualTo(0)
+ assertThat(handle.translationY).isEqualTo(-70)
assertThat(overflowView.visibility).isEqualTo(INVISIBLE)
assertThat(bubbleBarView.visibility).isEqualTo(VISIBLE)
assertThat(bubbleView.visibility).isEqualTo(VISIBLE)
-
- // wait for the show bubble animation to complete
- PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(
- DynamicAnimation.ALPHA,
- DynamicAnimation.TRANSLATION_Y,
- DynamicAnimation.SCALE_Y,
- )
-
assertThat(bubbleView.alpha).isEqualTo(1)
- assertThat(bubbleView.translationY).isEqualTo(-50)
+ assertThat(bubbleView.translationY).isEqualTo(-20)
assertThat(bubbleView.scaleY).isEqualTo(1)
- val showHandleAnimator = AnimatorSet()
- showHandleAnimator.duration = 0
- whenever(bubbleStashController.buildShowHandleAnimationForNewBubble())
- .thenReturn(showHandleAnimator)
- var showHandleAnimationStarted = false
- showHandleAnimator.doOnStart { showHandleAnimationStarted = true }
-
// execute the hide bubble animation
assertThat(animatorScheduler.delayedBlock).isNotNull()
InstrumentationRegistry.getInstrumentation().runOnMainSync(animatorScheduler.delayedBlock!!)
- // finish the hide bubble animation
- InstrumentationRegistry.getInstrumentation().runOnMainSync {
- animatorTestRule.advanceTimeBy(250)
- }
- assertThat(showHandleAnimationStarted).isTrue()
+ // let the animation start and wait for it to complete
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+ PhysicsAnimatorTestUtils.blockUntilAnimationsEnd(DynamicAnimation.TRANSLATION_Y)
assertThat(bubbleView.alpha).isEqualTo(1)
assertThat(bubbleView.visibility).isEqualTo(VISIBLE)
@@ -160,16 +126,8 @@
assertThat(bubbleBarView.alpha).isEqualTo(0)
assertThat(overflowView.alpha).isEqualTo(1)
assertThat(overflowView.visibility).isEqualTo(VISIBLE)
- }
-
- private fun AnimatorSet.doOnStart(onStart: () -> Unit) {
- addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationStart(animator: Animator) {
- onStart()
- }
- }
- )
+ assertThat(handle.alpha).isEqualTo(1)
+ assertThat(handle.translationY).isEqualTo(0)
}
private class TestBubbleBarViewAnimatorScheduler : BubbleBarViewAnimator.Scheduler {
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/bubbles/OWNERS b/quickstep/tests/src/com/android/launcher3/taskbar/bubbles/OWNERS
new file mode 100644
index 0000000..3f947a0
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/bubbles/OWNERS
@@ -0,0 +1,5 @@
+atsjenk@google.com
+liranb@google.com
+madym@google.com
+mpodolian@google.com
+
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index 7dabbca..0f9d96c 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -16,12 +16,14 @@
package com.android.quickstep
+import com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn
+import com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession
+import com.android.dx.mockito.inline.extended.StaticMockitoSession
import android.content.ComponentName
import android.content.Intent
import android.platform.test.flag.junit.SetFlagsRule
import com.android.launcher3.AbstractFloatingView
import com.android.launcher3.AbstractFloatingViewHelper
-import com.android.launcher3.Launcher
import com.android.launcher3.logging.StatsLogManager
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
import com.android.launcher3.model.data.WorkspaceItemInfo
@@ -33,8 +35,11 @@
import com.android.systemui.shared.recents.model.Task.TaskKey
import com.android.window.flags.Flags
import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
import org.junit.Rule
import org.junit.Test
+import org.mockito.quality.Strictness
import org.mockito.kotlin.any
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
@@ -56,8 +61,23 @@
private val factory: TaskShortcutFactory =
DesktopSystemShortcut.createFactory(abstractFloatingViewHelper)
+ private lateinit var mockitoSession: StaticMockitoSession
+
+ @Before
+ fun setUp(){
+ mockitoSession = mockitoSession().strictness(Strictness.LENIENT)
+ .spyStatic(DesktopModeStatus::class.java).startMocking()
+ doReturn(true).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
+ doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+ }
+
+ @After
+ fun tearDown(){
+ mockitoSession.finishMocking()
+ }
+
@Test
- fun createDesktopTaskShortcutFactory_featureOff() {
+ fun createDesktopTaskShortcutFactory_desktopModeDisabled() {
setFlagsRule.disableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
val task =
@@ -77,6 +97,49 @@
}
@Test
+ fun createDesktopTaskShortcutFactory_desktopModeEnabled_DeviceNotSupported() {
+ setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+
+ val task =
+ Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+ isDockable = true
+ }
+ val taskContainer =
+ taskView.TaskIdAttributeContainer(
+ task,
+ null,
+ null,
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ )
+
+ val shortcuts = factory.getShortcuts(launcher, taskContainer)
+ assertThat(shortcuts).isNull()
+ }
+
+ @Test
+ fun createDesktopTaskShortcutFactory_desktopModeEnabled_DeviceNotSupported_OverrideEnabled() {
+ setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
+ doReturn(false).`when` { DesktopModeStatus.isDesktopModeSupported(any()) }
+ doReturn(false).`when` { DesktopModeStatus.enforceDeviceRestrictions() }
+
+ val task =
+ Task(TaskKey(1, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+ isDockable = true
+ }
+ val taskContainer =
+ taskView.TaskIdAttributeContainer(
+ task,
+ null,
+ null,
+ SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+ )
+
+ val shortcuts = factory.getShortcuts(launcher, taskContainer)
+ assertThat(shortcuts).isNotNull()
+ }
+
+ @Test
fun createDesktopTaskShortcutFactory_undockable() {
setFlagsRule.enableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
diff --git a/res/drawable/ic_private_profile_app_scroller_badge.xml b/res/drawable/ic_private_profile_app_scroller_badge.xml
new file mode 100644
index 0000000..b52a277
--- /dev/null
+++ b/res/drawable/ic_private_profile_app_scroller_badge.xml
@@ -0,0 +1,28 @@
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt"
+ android:viewportWidth="32"
+ android:viewportHeight="32"
+ android:width="32dp"
+ android:height="32dp">
+ <path
+ android:pathData="M16.0007 2.66602L5.33398 6.66602V14.786C5.33398 21.5194 9.88065 27.7993 16.0007 29.3327C22.1207 27.7993 26.6673 21.5194 26.6673 14.786V6.66602L16.0007 2.66602ZM20.0007 19.9993V22.666H17.334V23.9993H14.6673V17.1193C12.7473 16.546 11.334 14.786 11.334 12.666C11.334 10.0927 13.4273 7.99935 16.0007 7.99935C18.574 7.99935 20.6673 10.0927 20.6673 12.666C20.6673 14.7727 19.254 16.546 17.334 17.1193V19.9993H20.0007Z"
+ android:fillType="evenOdd"
+ android:fillColor="@android:color/white" />
+ <path
+ android:pathData="M16 14.666C17.1046 14.666 18 13.7706 18 12.666C18 11.5614 17.1046 10.666 16 10.666C14.8954 10.666 14 11.5614 14 12.666C14 13.7706 14.8954 14.666 16 14.666Z"
+ android:fillColor="@android:color/white" />
+</vector>
diff --git a/res/drawable/widget_picker_preview_pane_scroll_thumb.xml b/res/drawable/widget_picker_preview_pane_scroll_thumb.xml
new file mode 100644
index 0000000..24f90b0
--- /dev/null
+++ b/res/drawable/widget_picker_preview_pane_scroll_thumb.xml
@@ -0,0 +1,31 @@
+<?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.
+ -->
+<!--
+A variation of material's scrollbar_handle_material.xml that has paddings to make it smaller.
+ScrollView's "insideInsets" / "insideOverlay" styles don't consider corner radius applied to scroll
+views, so we apply matching padding to the thumb to align it.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item
+ android:bottom="@dimen/widget_list_top_bottom_corner_radius"
+ android:top="@dimen/widget_list_top_bottom_corner_radius">
+ <shape
+ android:shape="rectangle"
+ android:tint="?android:attr/colorControlNormal">
+ <solid android:color="#84ffffff" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/work_mode_fab_background.xml b/res/drawable/work_mode_fab_background.xml
index 478b887..6be33e8 100644
--- a/res/drawable/work_mode_fab_background.xml
+++ b/res/drawable/work_mode_fab_background.xml
@@ -19,9 +19,6 @@
<shape android:shape="rectangle">
<corners android:radius="@dimen/work_fab_radius" />
<solid android:color="@color/work_fab_bg_color" />
- <padding
- android:left="@dimen/work_profile_footer_padding"
- android:right="@dimen/work_profile_footer_padding" />
</shape>
</item>
</ripple>
diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml
index 185207b..65f1004 100644
--- a/res/layout/private_space_header.xml
+++ b/res/layout/private_space_header.xml
@@ -24,6 +24,7 @@
android:background="@drawable/bg_ps_header"
android:clipToOutline="true"
android:gravity="center_vertical"
+ android:textDirection="locale"
android:orientation="horizontal">
<LinearLayout
diff --git a/res/layout/widgets_two_pane_sheet.xml b/res/layout/widgets_two_pane_sheet.xml
index 6c4810c..bb2b7bd 100644
--- a/res/layout/widgets_two_pane_sheet.xml
+++ b/res/layout/widgets_two_pane_sheet.xml
@@ -94,42 +94,49 @@
</FrameLayout>
<FrameLayout
- android:id="@+id/right_pane_container"
android:layout_width="0dp"
android:layout_height="match_parent"
- android:layout_weight="0.67"
- android:layout_marginEnd="@dimen/widget_list_horizontal_margin_two_pane"
- android:paddingTop="@dimen/widget_list_horizontal_margin_two_pane"
- android:gravity="end"
- android:layout_gravity="end"
- android:orientation="horizontal">
- <ScrollView
- android:id="@+id/right_pane_scroll_view"
+ android:layout_weight="0.67">
+ <FrameLayout
+ android:id="@+id/right_pane_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:fillViewport="true">
- <LinearLayout
- android:orientation="vertical"
+ android:layout_marginVertical="@dimen/widget_picker_vertical_margin_right_pane"
+ android:layout_marginEnd="@dimen/widget_list_horizontal_margin_two_pane"
+ android:gravity="end"
+ android:layout_gravity="end"
+ android:orientation="horizontal">
+ <ScrollView
+ android:id="@+id/right_pane_scroll_view"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_vertical"
- android:clipToOutline="true"
- android:paddingBottom="36dp"
+ android:layout_height="match_parent"
android:background="@drawable/widgets_surface_background"
- android:importantForAccessibility="yes"
- android:id="@+id/right_pane">
- <!-- Shown when there are recommendations to display -->
+ android:scrollbarThumbVertical="@drawable/widget_picker_preview_pane_scroll_thumb"
+ android:clipToOutline="true"
+ android:fillViewport="true">
<LinearLayout
- android:id="@+id/widget_recommendations_container"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/widgets_surface_background"
android:orientation="vertical"
- android:visibility="gone">
- <include layout="@layout/widget_recommendations" />
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_vertical"
+ android:clipToOutline="true"
+ android:paddingBottom="36dp"
+ android:background="@drawable/widgets_surface_background"
+ android:importantForAccessibility="yes"
+ android:id="@+id/right_pane">
+ <!-- Shown when there are recommendations to display -->
+ <LinearLayout
+ android:id="@+id/widget_recommendations_container"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@drawable/widgets_surface_background"
+ android:orientation="vertical"
+ android:visibility="gone">
+ <include layout="@layout/widget_recommendations" />
+ </LinearLayout>
</LinearLayout>
- </LinearLayout>
- </ScrollView>
+ </ScrollView>
+ </FrameLayout>
</FrameLayout>
</LinearLayout>
</com.android.launcher3.views.SpringRelativeLayout>
diff --git a/res/layout/work_mode_fab.xml b/res/layout/work_mode_fab.xml
index 276d73e..b3484c9 100644
--- a/res/layout/work_mode_fab.xml
+++ b/res/layout/work_mode_fab.xml
@@ -24,12 +24,15 @@
android:background="@drawable/work_mode_fab_background"
android:forceHasOverlappingRendering="false"
android:contentDescription="@string/work_apps_pause_btn_text"
+ android:paddingStart="@dimen/work_mode_fab_background_start_padding"
+ android:paddingEnd="@dimen/work_mode_fab_background_end_padding"
android:animateLayoutChanges="true">
<ImageView
android:id="@+id/work_icon"
android:layout_width="@dimen/work_fab_icon_size"
android:layout_height="@dimen/work_fab_icon_size"
android:importantForAccessibility="no"
+ android:layout_marginEnd="@dimen/work_fab_icon_end_margin"
android:src="@drawable/ic_corp_off"
android:tint="@color/work_fab_icon_color"
android:scaleType="center"/>
@@ -43,7 +46,7 @@
android:includeFontPadding="false"
android:textDirection="locale"
android:text="@string/work_apps_pause_btn_text"
- android:layout_marginStart="@dimen/work_fab_text_start_margin"
+ android:layout_marginEnd="@dimen/work_fab_text_end_margin"
android:ellipsize="end"
android:maxLines="1"
style="@style/TextHeadline"/>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 07343d7..7db41c3 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -51,7 +51,7 @@
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"التواصل الاجتماعي"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"الصحة واللياقة البدنية"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"الطقس"</string>
- <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"محتوى مقترَح لك"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"اقتراحاتنا لك"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"تطبيقات \"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>\" المصغّرة على اليسار، والبحث والخيارات على اليمين"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{تطبيق مصغّر واحد}zero{# تطبيق مصغّر}two{تطبيقان مصغّران}few{# تطبيقات مصغّرة}many{# تطبيقًا مصغّرًا}other{# تطبيق مصغّر}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{اختصار واحد}zero{# اختصار}two{اختصاران}few{# اختصارات}many{# اختصارًا}other{# اختصار}}"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index c411783..b57de6b 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -51,7 +51,7 @@
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salut i fitnes"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Temps"</string>
- <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggeriments personalitzats"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggeriments per a tu"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> a la dreta, cerca i opcions a l\'esquerra"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# drecera}other{# dreceres}}"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 4cf1e8f..e9fef0c 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Přidat na plochu"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> byl přidán na plochu"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Návrhy"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Nezbytnosti"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Základní"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Zprávy a časopisy"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaše klidová zóna"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zábava"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 848ebee..163739a 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -44,14 +44,14 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"افزودن به صفحه اصلی"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g> به صفحه اصلی اضافه شد"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"پیشنهادها"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ضروریات"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"بایدها"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"اخبار و مجله"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"منطقه آرامش شما"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"سرگرمی"</string>
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"اجتماعی"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"سلامتی و تناسب اندام"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"آبوهوا"</string>
- <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"پیشنهادشده برای شما"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"پیشنهاداتی برای شما"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"ابزارکهای <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> در سمت چپ، جستجو و گزینهها در سمت راست"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ابزارک}one{# ابزارک}other{# ابزارک}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# میانبر}one{# میانبر}other{# میانبر}}"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 6d83820..600cde4 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -47,8 +47,8 @@
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ज़रूरी ऐप्लिकेशन"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"खबरों और पत्रिकाओं वाले ऐप्लिकेशन"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"आपके मनोरंजन के लिए"</string>
- <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"मनोरंजन वाले ऐप्लिकेशन"</string>
- <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"सोशल"</string>
+ <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"मनोरंजन से जुड़े ऐप्लिकेशन"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"सोशल मीडिया ऐप्लिकेशन"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"हेल्थ और फ़िटनेस वाले ऐप्लिकेशन"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"मौसम"</string>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"आपके लिए सुझाए गए ऐप्लिकेशन"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 72d23fa..03a30c4 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -45,7 +45,7 @@
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul hozzáadva a kezdőképernyőhöz"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Javaslatok"</string>
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Legfontosabbak"</string>
- <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Hírlapok és folyóiratok"</string>
+ <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Újságok és magazinok"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Az Ön relaxáló zónája"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Szórakozás"</string>
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Közösségi"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 0a1e4aa..215ac74 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -45,10 +45,10 @@
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджеті негізгі экранға енгізілді."</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Ұсыныстар"</string>
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Ең қажетті"</string>
- <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Газеттер мен журналдар"</string>
+ <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Жаңалықтар мен журналдар"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Жанға жайлы жер"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Ойын-сауық"</string>
- <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Әлеуметтік"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Қоғам"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Денсаулық және фитнес"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Ауа райы"</string>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Сізге ұсынылғандар"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index b2f307b..4ab4ada 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -88,7 +88,7 @@
<string name="all_apps_button_work_label" msgid="7270707118948892488">"ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್ಗಳ ಪಟ್ಟಿ"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"ತೆಗೆದುಹಾಕಿ"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ಅನ್ಇನ್ಸ್ಟಾಲ್"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"ಅಪ್ಲಿಕೇಶನ್ ಮಾಹಿತಿ"</string>
+ <string name="app_info_drop_target_label" msgid="692894985365717661">"ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ಖಾಸಗಿಯಾಗಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ಸ್ಥಾಪಿಸಿ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ಆ್ಯಪ್ ಅನ್ನು ಸೂಚಿಸಬೇಡಿ"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 9cecf07..d83a02b 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -45,7 +45,7 @@
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>ର ୱିଜେଟ ହୋମ ସ୍କ୍ରିନରେ ଯୋଡ଼ାଗଲା"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"ପରାମର୍ଶଗୁଡ଼ିକ"</string>
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"ଅତ୍ୟାବଶ୍ୟକୀୟ"</string>
- <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ନ୍ୟୁଜ ଓ ମେଗାଜିନ"</string>
+ <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ନ୍ୟୁଜ ଓ ମାଗାଜିନ"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"ଆପଣଙ୍କ ଚିଲ ଜୋନ"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"ମନୋରଞ୍ଜନ"</string>
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"ସୋସିଆଲ"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index fc70150..6d5c699 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -51,7 +51,7 @@
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociais"</string>
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Saúde e fitness"</string>
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Meteorologia"</string>
- <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerido para si"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugestões para si"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> à direita, pesquisa e opções à esquerda"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atalho}other{# atalhos}}"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index ee1caef..c0f3baa 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Добавить на главный экран"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Виджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\" добавлен на главный экран"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Подсказки"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Главное"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Основное"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Новости и журналы"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Развлечение и общение"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Развлечения"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 07672c7..a3f5625 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Lägg till på startskärmen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget för <xliff:g id="WIDGET_NAME">%1$s</xliff:g> har lagts till på startskärmen"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Förslag"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Favoriter"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Viktigt"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Nyheter och tidskrifter"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Koppla av"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Underhållning"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index daa90fa..4533fda 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"మొదటి స్క్రీన్కు జోడించండి"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"మొదటి స్క్రీన్కు <xliff:g id="WIDGET_NAME">%1$s</xliff:g> విడ్జెట్ జోడించబడింది"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"సూచనలు"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essentials"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"నిత్యావసరాలు"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"వార్తలు & మ్యాగజైన్లు"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"మీరు ప్రశాంతంగా ఉండే ప్రదేశం"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"వినోదం"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 5a88489..9e723dd 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Ana ekrana ekle"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı ana ekrana eklendi"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Öneriler"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Kaçırmamanız gerekenler"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Önemliler"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Haberler ve dergiler"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Huzur alanınız"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Eğlence"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 8f5cce4..9552a57 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -44,7 +44,7 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Додати на головний екран"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Віджет <xliff:g id="WIDGET_NAME">%1$s</xliff:g> додано на головний екран"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Пропозиції"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Основне для роботи"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Основне"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Новини й журнали"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ваша зона розваг"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Розваги"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index c9b0610..89ccde3 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -45,7 +45,7 @@
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjeti bosh ekranga qoʻshildi"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Takliflar"</string>
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Asosiy ilovalar"</string>
- <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Gazeta va jurnallar"</string>
+ <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Yangiliklar va jurnallar"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Sokin hududingiz"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Hordiq"</string>
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Ijtimoiy"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9ed1b72..5ff9902 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -147,13 +147,15 @@
<dimen name="work_fab_height">56dp</dimen>
<dimen name="work_fab_radius">16dp</dimen>
<dimen name="work_fab_icon_size">24dp</dimen>
- <dimen name="work_fab_text_start_margin">8dp</dimen>
+ <dimen name="work_fab_icon_end_margin">12dp</dimen>
+ <dimen name="work_fab_text_end_margin">16dp</dimen>
<dimen name="work_card_padding_horizontal">10dp</dimen>
<dimen name="work_fab_width">214dp</dimen>
<dimen name="work_card_button_height">52dp</dimen>
<dimen name="work_fab_margin">16dp</dimen>
<dimen name="work_fab_margin_bottom">20dp</dimen>
- <dimen name="work_mode_fab_padding">16dp</dimen>
+ <dimen name="work_mode_fab_background_start_padding">16dp</dimen>
+ <dimen name="work_mode_fab_background_end_padding">4dp</dimen>
<dimen name="work_profile_footer_padding">20dp</dimen>
<dimen name="work_edu_card_margin">16dp</dimen>
<dimen name="work_edu_card_radius">16dp</dimen>
@@ -206,6 +208,7 @@
<!-- Margin applied to the recycler view with search bar & the list of widget apps below it. -->
<dimen name="widget_list_left_pane_horizontal_margin">0dp</dimen>
<dimen name="widget_list_horizontal_margin_two_pane">24dp</dimen>
+ <dimen name="widget_picker_vertical_margin_right_pane">24dp</dimen>
<dimen name="widget_preview_shadow_blur">0.5dp</dimen>
<dimen name="widget_preview_key_shadow_distance">1dp</dimen>
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index 51c7a05..eff748a 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -155,7 +155,7 @@
* Maps the touch (from 0..1) to the adapter position that should be visible.
* <p>Override in each subclass of this base class.
*/
- public abstract String scrollToPositionAtProgress(float touchFraction);
+ public abstract CharSequence scrollToPositionAtProgress(float touchFraction);
/**
* Updates the bounds for the scrollbar.
@@ -193,14 +193,4 @@
}
scrollToPosition(0);
}
-
- /**
- * Scrolls this recycler view to the bottom with easing and duration.
- */
- public void scrollToBottomWithMotion(int duration) {
- if (mScrollbar != null) {
- mScrollbar.reattachThumbToScroll();
- }
- smoothScrollBy(0, getAvailableScrollHeight(), Interpolators.EMPHASIZED, duration);
- }
}
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 2fd5ebd..98cb84e 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -262,7 +262,7 @@
// Get the display info based on default display and interpolate it to existing display
Info defaultInfo = DisplayController.INSTANCE.get(context).getInfo();
- @DeviceType int defaultDeviceType = getDeviceType(defaultInfo);
+ @DeviceType int defaultDeviceType = defaultInfo.getDeviceType();
DisplayOption defaultDisplayOption = invDistWeightedInterpolate(
defaultInfo,
getPredefinedDeviceProfiles(context, gridName, defaultDeviceType,
@@ -271,7 +271,7 @@
Context displayContext = context.createDisplayContext(display);
Info myInfo = new Info(displayContext);
- @DeviceType int deviceType = getDeviceType(myInfo);
+ @DeviceType int deviceType = myInfo.getDeviceType();
DisplayOption myDisplayOption = invDistWeightedInterpolate(
myInfo,
getPredefinedDeviceProfiles(context, gridName, deviceType,
@@ -324,30 +324,13 @@
}
}
- private static @DeviceType int getDeviceType(Info displayInfo) {
- int flagPhone = 1 << 0;
- int flagTablet = 1 << 1;
-
- int type = displayInfo.supportedBounds.stream()
- .mapToInt(bounds -> displayInfo.isTablet(bounds) ? flagTablet : flagPhone)
- .reduce(0, (a, b) -> a | b);
- if (type == (flagPhone | flagTablet)) {
- // device has profiles supporting both phone and table modes
- return TYPE_MULTI_DISPLAY;
- } else if (type == flagTablet) {
- return TYPE_TABLET;
- } else {
- return TYPE_PHONE;
- }
- }
-
public static String getCurrentGridName(Context context) {
return LauncherPrefs.get(context).get(GRID_NAME);
}
private String initGrid(Context context, String gridName) {
Info displayInfo = DisplayController.INSTANCE.get(context).getInfo();
- @DeviceType int deviceType = getDeviceType(displayInfo);
+ @DeviceType int deviceType = displayInfo.getDeviceType();
ArrayList<DisplayOption> allOptions =
getPredefinedDeviceProfiles(context, gridName, deviceType,
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c91d4d0..dc7c349 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2508,7 +2508,13 @@
final int itemCount = container.getChildCount();
for (int itemIdx = 0; itemIdx < itemCount; itemIdx++) {
View item = container.getChildAt(itemIdx);
- if (op.test((ItemInfo) item.getTag())) {
+ if (item instanceof ViewGroup viewGroup) {
+ View view = mapOverViewGroup(viewGroup, op);
+ if (view != null) {
+ return view;
+ }
+ }
+ if (item.getTag() instanceof ItemInfo itemInfo && op.test(itemInfo)) {
return item;
}
}
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 84b8ba1..87ac193 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -183,6 +183,7 @@
public static final int CONTAINER_SHORTCUTS = -107;
public static final int CONTAINER_SETTINGS = -108;
public static final int CONTAINER_TASKSWITCHER = -109;
+ public static final int CONTAINER_PRIVATESPACE = -110;
// Represents any of the extended containers implemented in non-AOSP variants.
public static final int EXTENDED_CONTAINERS = -200;
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 9792300..814d142 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -414,7 +414,7 @@
LauncherSettings.Favorites.CONTAINER_DESKTOP,
screenId, coordinates[0], coordinates[1]);
- bindItem(item, accessibility, finishCallback);
+ bindItem(info, accessibility, finishCallback);
announceConfirmation(R.string.item_added_to_workspace);
} else if (item instanceof PendingAddItemInfo) {
PendingAddItemInfo info = (PendingAddItemInfo) item;
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 36a44cc..ba34f59 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -180,7 +180,7 @@
* Maps the touch (from 0..1) to the adapter position that should be visible.
*/
@Override
- public String scrollToPositionAtProgress(float touchFraction) {
+ public CharSequence scrollToPositionAtProgress(float touchFraction) {
int rowCount = mApps.getNumAppRows();
if (rowCount == 0) {
return "";
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 4d4b8d2..60df7c5 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -22,6 +22,10 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_USER_INSTALLED_APPS_COUNT;
import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.text.Spannable;
+import android.text.SpannableString;
+import android.text.style.ImageSpan;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
@@ -65,11 +69,11 @@
*/
public static class FastScrollSectionInfo {
// The section name
- public final String sectionName;
+ public final CharSequence sectionName;
// The item position
public final int position;
- public FastScrollSectionInfo(String sectionName, int position) {
+ public FastScrollSectionInfo(CharSequence sectionName, int position) {
this.sectionName = sectionName;
this.position = position;
}
@@ -93,6 +97,7 @@
// The of ordered component names as a result of a search query
private final ArrayList<AdapterItem> mSearchResults = new ArrayList<>();
+ private final SpannableString mPrivateProfileAppScrollerBadge;
private BaseAllAppsAdapter<T> mAdapter;
private AppInfoComparator mAppNameComparator;
private int mNumAppsPerRowAllApps;
@@ -110,6 +115,10 @@
if (mAllAppsStore != null) {
mAllAppsStore.addUpdateListener(this);
}
+ mPrivateProfileAppScrollerBadge = new SpannableString(" ");
+ mPrivateProfileAppScrollerBadge.setSpan(new ImageSpan(context,
+ R.drawable.ic_private_profile_app_scroller_badge, ImageSpan.ALIGN_CENTER),
+ 0, 1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
}
/** Set the number of apps per row when device profile changes. */
@@ -383,6 +392,7 @@
private int addAppsWithSections(List<AppInfo> appList, int startPosition) {
String lastSectionName = null;
boolean hasPrivateApps = false;
+ int position = startPosition;
if (mPrivateProviderManager != null) {
hasPrivateApps = appList.stream().
allMatch(mPrivateProviderManager.getItemInfoMatcher());
@@ -403,11 +413,12 @@
// Create a new section if the section names do not match
if (!sectionName.equals(lastSectionName)) {
lastSectionName = sectionName;
- mFastScrollerSections.add(new FastScrollSectionInfo(sectionName, startPosition));
+ mFastScrollerSections.add(new FastScrollSectionInfo(hasPrivateApps ?
+ mPrivateProfileAppScrollerBadge : sectionName, position));
}
- startPosition++;
+ position++;
}
- return startPosition;
+ return position;
}
/**
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 90ed3eb..38fe138 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -21,6 +21,7 @@
import static android.view.View.VISIBLE;
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PRIVATESPACE;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
@@ -159,7 +160,6 @@
itemInfo.contentDescription = context.getResources().getString(
com.android.launcher3.R.string.ps_add_button_content_description);
itemInfo.runtimeStatusFlags |= FLAG_NOT_PINNABLE;
- itemInfo.user = getProfileUser();
BaseAllAppsAdapter.AdapterItem item = new BaseAllAppsAdapter.AdapterItem(VIEW_TYPE_ICON);
item.itemInfo = itemInfo;
@@ -216,11 +216,27 @@
resetPrivateSpaceDecorator(updatedState);
}
- /** Opens the Private Space Settings Page. */
- public void openPrivateSpaceSettings() {
+ /**
+ * Opens the Private Space Settings Page.
+ *
+ * @param view the view that was clicked to open the settings page and which will be the same
+ * view to animate back. Otherwise if there is no view, simply start the activity.
+ */
+ public void openPrivateSpaceSettings(View view) {
if (mPrivateSpaceSettingsAvailable) {
- mAllApps.getContext().startActivity(
- ApiWrapper.INSTANCE.get(mAllApps.getContext()).getPrivateSpaceSettingsIntent());
+ Context context = mAllApps.getContext();
+ Intent intent = ApiWrapper.INSTANCE.get(context).getPrivateSpaceSettingsIntent();
+ if (view == null) {
+ context.startActivity(intent);
+ return;
+ }
+ ActivityContext activityContext = ActivityContext.lookupContext(context);
+ AppInfo itemInfo = new AppInfo();
+ itemInfo.id = CONTAINER_PRIVATESPACE;
+ itemInfo.componentName = intent.getComponent();
+ itemInfo.container = CONTAINER_PRIVATESPACE;
+ view.setTag(itemInfo);
+ activityContext.startActivitySafely(view, intent, itemInfo);
}
}
@@ -423,7 +439,7 @@
settingsButton.setOnClickListener(
view -> {
logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
- openPrivateSpaceSettings();
+ openPrivateSpaceSettings(view);
});
} else {
settingsButton.setVisibility(GONE);
@@ -747,6 +763,7 @@
}
boolean isPrivateSpaceItem(BaseAllAppsAdapter.AdapterItem item) {
- return getItemInfoMatcher().test(item.itemInfo) || item.decorationInfo != null;
+ return getItemInfoMatcher().test(item.itemInfo) || item.decorationInfo != null
+ || (item.itemInfo instanceof PrivateSpaceInstallAppButtonInfo);
}
}
diff --git a/src/com/android/launcher3/allapps/WorkModeSwitch.java b/src/com/android/launcher3/allapps/WorkModeSwitch.java
index eb7d429..6049574 100644
--- a/src/com/android/launcher3/allapps/WorkModeSwitch.java
+++ b/src/com/android/launcher3/allapps/WorkModeSwitch.java
@@ -15,14 +15,10 @@
*/
package com.android.launcher3.allapps;
-import static com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.getTabWidth;
-
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
-import android.view.View;
import android.view.WindowInsets;
-import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -35,7 +31,6 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.KeyboardInsetAnimationCallback;
-import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.views.ActivityContext;
/**
@@ -53,12 +48,11 @@
private final Rect mImeInsets = new Rect();
private int mFlags;
private final ActivityContext mActivityContext;
+ private final Context mContext;
// Threshold when user scrolls up/down to determine when should button extend/collapse
private final int mScrollThreshold;
- private ImageView mIcon;
private TextView mTextView;
- private final StatsLogManager mStatsLogManager;
public WorkModeSwitch(@NonNull Context context) {
@@ -71,16 +65,15 @@
public WorkModeSwitch(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
+ mContext = context;
mScrollThreshold = Utilities.dpToPx(SCROLL_THRESHOLD_DP);
mActivityContext = ActivityContext.lookupContext(getContext());
- mStatsLogManager = mActivityContext.getStatsLogManager();
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mIcon = findViewById(R.id.work_icon);
mTextView = findViewById(R.id.pause_text);
setSelected(true);
KeyboardInsetAnimationCallback keyboardInsetAnimationCallback =
@@ -114,13 +107,8 @@
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
- View parent = (View) getParent();
boolean isRtl = Utilities.isRtl(getResources());
- Rect allAppsPadding = mActivityContext.getDeviceProfile().allAppsPadding;
- int size = parent.getWidth() - parent.getPaddingLeft() - parent.getPaddingRight()
- - (allAppsPadding.left + allAppsPadding.right);
- int tabWidth = getTabWidth(getContext(), size);
- int shift = (size - tabWidth) / 2 + (isRtl ? allAppsPadding.left : allAppsPadding.right);
+ int shift = mActivityContext.getDeviceProfile().getAllAppsIconStartMargin(mContext);
setTranslationX(isRtl ? shift : -shift);
}
diff --git a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
index ec45415..19c3ebe 100644
--- a/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
+++ b/src/com/android/launcher3/allapps/search/AllAppsSearchBarController.java
@@ -31,7 +31,6 @@
import com.android.launcher3.ExtendedEditText;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.search.SearchAlgorithm;
import com.android.launcher3.search.SearchCallback;
import com.android.launcher3.views.ActivityContext;
@@ -144,7 +143,7 @@
@Override
public void onFocusChange(View view, boolean hasFocus) {
- if (!hasFocus && !FeatureFlags.ENABLE_DEVICE_SEARCH.get()) {
+ if (!hasFocus) {
mInput.hideKeyboard();
}
}
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
index 6b153dd..cea4380 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -184,6 +184,9 @@
}
}
}
+ if (intent.`package` == null) {
+ intent.`package` = targetPkg
+ }
// else if cn == null => can't infer much, leave it
// else if !validPkg => could be restored icon or missing sd-card
when {
@@ -329,8 +332,12 @@
}
val activityInfo = c.launcherActivityInfo
if (activityInfo != null) {
- AppInfo.updateRuntimeFlagsForActivityTarget(info, activityInfo,
- userCache.getUserInfo(c.user), ApiWrapper.INSTANCE[app.context])
+ AppInfo.updateRuntimeFlagsForActivityTarget(
+ info,
+ activityInfo,
+ userCache.getUserInfo(c.user),
+ ApiWrapper.INSTANCE[app.context]
+ )
}
if (
(c.restoreFlag != 0 ||
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index ff95212..8806e27 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -19,6 +19,9 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_MULTI_DISPLAY;
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_PHONE;
+import static com.android.launcher3.InvariantDeviceProfile.TYPE_TABLET;
import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_KEY;
import static com.android.launcher3.Utilities.dpiFromPx;
@@ -47,6 +50,7 @@
import androidx.annotation.UiThread;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.InvariantDeviceProfile.DeviceType;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.FileLog;
@@ -466,6 +470,23 @@
public int getDensityDpi() {
return densityDpi;
}
+
+ public @DeviceType int getDeviceType() {
+ int flagPhone = 1 << 0;
+ int flagTablet = 1 << 1;
+
+ int type = supportedBounds.stream()
+ .mapToInt(bounds -> isTablet(bounds) ? flagTablet : flagPhone)
+ .reduce(0, (a, b) -> a | b);
+ if (type == (flagPhone | flagTablet)) {
+ // device has profiles supporting both phone and tablet modes
+ return TYPE_MULTI_DISPLAY;
+ } else if (type == flagTablet) {
+ return TYPE_TABLET;
+ } else {
+ return TYPE_PHONE;
+ }
+ }
}
/**
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index 9f6e8f8..5ce455a 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -25,6 +25,8 @@
import static com.android.launcher3.allapps.AllAppsTransitionController.REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS;
import static com.android.launcher3.util.ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE;
+import android.animation.Animator;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
@@ -135,6 +137,7 @@
protected final AnimatedFloat mSwipeToDismissProgress =
new AnimatedFloat(this::onUserSwipeToDismissProgressChanged, 0f);
protected boolean mIsDismissInProgress;
+ private View mViewToAnimateInSwipeToDismiss = this;
private @Nullable Drawable mContentBackground;
private @Nullable View mContentBackgroundParentView;
@@ -286,18 +289,37 @@
@Override
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
+ public void onBackStarted(BackEvent backEvent) {
+ super.onBackStarted(backEvent);
+ mViewToAnimateInSwipeToDismiss = shouldAnimateContentViewInBackSwipe() ? mContent : this;
+ }
+
+ @Override
+ @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public void onBackProgressed(BackEvent backEvent) {
final float progress = backEvent.getProgress();
float deceleratedProgress = Interpolators.BACK_GESTURE.getInterpolation(progress);
mSwipeToDismissProgress.updateValue(deceleratedProgress);
}
+ /**
+ * During predictive back swipe, the default behavior is to scale {@link AbstractSlideInView}
+ * during back swipe. This method allow subclass to scale {@link #mContent}, typically to exit
+ * search mode.
+ *
+ * <p>Note that this method can be expensive, and should only be called from
+ * {@link #onBackStarted(BackEvent)}, not from {@link #onBackProgressed(BackEvent)}.
+ */
+ protected boolean shouldAnimateContentViewInBackSwipe() {
+ return false;
+ }
+
protected void onUserSwipeToDismissProgressChanged() {
float progress = mSwipeToDismissProgress.value;
mIsDismissInProgress = progress > 0f;
float scale = PREDICTIVE_BACK_MIN_SCALE + (1 - PREDICTIVE_BACK_MIN_SCALE) * (1f - progress);
- SCALE_PROPERTY.set(this, scale);
+ SCALE_PROPERTY.set(mViewToAnimateInSwipeToDismiss, scale);
setClipChildren(!mIsDismissInProgress);
setClipToPadding(!mIsDismissInProgress);
mContent.setClipChildren(!mIsDismissInProgress);
@@ -312,9 +334,32 @@
}
protected void animateSwipeToDismissProgressToStart() {
- mSwipeToDismissProgress.animateToValue(0f)
- .setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS)
- .start();
+ ObjectAnimator objectAnimator = mSwipeToDismissProgress.animateToValue(0f)
+ .setDuration(REVERT_SWIPE_ALL_APPS_TO_HOME_ANIMATION_DURATION_MS);
+
+ // If we are animating a different view, we should reset the animating view back to
+ // AbstractSlideInView as it is the default view to animate.
+ if (this != mViewToAnimateInSwipeToDismiss) {
+ objectAnimator.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationCancel(Animator animator) {
+ mViewToAnimateInSwipeToDismiss = AbstractSlideInView.this;
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ mViewToAnimateInSwipeToDismiss = AbstractSlideInView.this;
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animator) {}
+
+ @Override
+ public void onAnimationStart(Animator animator) {}
+ });
+ }
+
+ objectAnimator.start();
}
@Override
diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java
index f76b53b..f560311 100644
--- a/src/com/android/launcher3/views/FloatingIconView.java
+++ b/src/com/android/launcher3/views/FloatingIconView.java
@@ -55,6 +55,7 @@
import com.android.launcher3.graphics.PreloadIconDrawable;
import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.icons.LauncherIcons;
+import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.popup.SystemShortcut;
@@ -282,6 +283,8 @@
} else if (btvIcon instanceof PreloadIconDrawable) {
// Force the progress bar to display.
drawable = btvIcon;
+ } else if (originalView instanceof ImageView) {
+ drawable = ((ImageView) originalView).getDrawable();
} else {
int width = (int) pos.width();
int height = (int) pos.height();
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 8408cc7..df8f635 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -30,6 +30,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.RectF;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.Log;
import android.util.Property;
@@ -121,7 +122,7 @@
// Fast scroller popup
private TextView mPopupView;
private boolean mPopupVisible;
- private String mPopupSectionName;
+ private CharSequence mPopupSectionName;
private Insets mSystemGestureInsets;
protected FastScrollRecyclerView mRv;
@@ -307,13 +308,13 @@
// Update the fastscroller section name at this touch position
int bottom = mRv.getScrollbarTrackHeight() - mThumbHeight;
float boundedY = (float) Math.max(0, Math.min(bottom, y - mTouchOffsetY));
- String sectionName = mRv.scrollToPositionAtProgress(boundedY / bottom);
+ CharSequence sectionName = mRv.scrollToPositionAtProgress(boundedY / bottom);
if (!sectionName.equals(mPopupSectionName)) {
mPopupSectionName = sectionName;
mPopupView.setText(sectionName);
performHapticFeedback(CLOCK_TICK);
}
- animatePopupVisibility(!sectionName.isEmpty());
+ animatePopupVisibility(!TextUtils.isEmpty(sectionName));
mLastTouchY = boundedY;
setThumbOffsetY((int) mLastTouchY);
}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index aa797ab..e5b5daa 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -16,8 +16,6 @@
package com.android.launcher3.widget;
import static com.android.app.animation.Interpolators.EMPHASIZED;
-import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
-import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
import static com.android.launcher3.Flags.enableWidgetTapToAdd;
import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_TIP_SEEN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_ADD_BUTTON_TAP;
@@ -320,19 +318,8 @@
MeasureSpec.getSize(heightMeasureSpec));
}
- private int getTabletHorizontalMargin(DeviceProfile deviceProfile) {
- // All bottom-sheets showing widgets will be full-width across all devices.
- if (enableCategorizedWidgetSuggestions()) {
- return 0;
- }
- if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
- return getResources().getDimensionPixelSize(
- R.dimen.widget_picker_landscape_tablet_left_right_margin);
- }
- if (deviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
- return getResources().getDimensionPixelSize(
- R.dimen.widget_picker_two_panels_left_right_margin);
- }
+ /** Returns the horizontal margins to be applied to the widget sheet. **/
+ protected int getTabletHorizontalMargin(DeviceProfile deviceProfile) {
return deviceProfile.allAppsLeftRightMargin;
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index c6cbb60..28eeb10 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -902,11 +902,23 @@
return isFoldUnFold || useDifferentLayoutOnOrientationChange;
}
+ /**
+ * In widget search mode, we should scale down content inside widget bottom sheet, rather
+ * than the whole bottom sheet, to indicate we will navigate back within the widget
+ * bottom sheet.
+ */
+ @Override
+ public boolean shouldAnimateContentViewInBackSwipe() {
+ return mIsInSearchMode;
+ }
+
@Override
public void onBackInvoked() {
if (mIsInSearchMode) {
mSearchBar.reset();
- animateSwipeToDismissProgressToStart();
+ // Posting animation to next frame will let widget sheet finish updating UI first, and
+ // make animation smoother.
+ post(this::animateSwipeToDismissProgressToStart);
} else {
super.onBackInvoked();
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
index 698e764..a47818f 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecyclerView.java
@@ -73,7 +73,7 @@
* Maps the touch (from 0..1) to the adapter position that should be visible.
*/
@Override
- public String scrollToPositionAtProgress(float touchFraction) {
+ public CharSequence scrollToPositionAtProgress(float touchFraction) {
// Skip early if widgets are not bound.
if (isModelNotReady()) {
return "";
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index cb8b14e..2a2feed 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -23,14 +23,12 @@
import static com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree;
import android.content.Context;
-import android.graphics.Outline;
import android.graphics.Rect;
import android.os.Process;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewOutlineProvider;
import android.view.ViewParent;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
@@ -39,6 +37,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Px;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.model.data.PackageItemInfo;
@@ -79,21 +78,6 @@
private int mActivePage = -1;
private PackageUserKey mSelectedHeader;
- private final ViewOutlineProvider mViewOutlineProviderRightPane = new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(
- 0,
- 0,
- view.getMeasuredWidth(),
- view.getMeasuredHeight() - getResources().getDimensionPixelSize(
- R.dimen.widget_list_horizontal_margin_two_pane),
- view.getResources().getDimensionPixelSize(
- R.dimen.widget_list_top_bottom_corner_radius)
- );
- }
- };
-
public WidgetsTwoPaneSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@@ -137,11 +121,8 @@
mHeaderTitle = mContent.findViewById(R.id.title);
mRightPane = mContent.findViewById(R.id.right_pane);
- mRightPane.setOutlineProvider(mViewOutlineProviderRightPane);
mRightPaneScrollView = mContent.findViewById(R.id.right_pane_scroll_view);
mRightPaneScrollView.setOverScrollMode(View.OVER_SCROLL_NEVER);
- mRightPaneScrollView.setOutlineProvider(mViewOutlineProvider);
- mRightPaneScrollView.setClipToOutline(true);
mPrimaryWidgetListView = findViewById(R.id.primary_widgets_list_view);
mPrimaryWidgetListView.setOutlineProvider(mViewOutlineProvider);
@@ -155,6 +136,26 @@
}
@Override
+ protected int getTabletHorizontalMargin(DeviceProfile deviceProfile) {
+ if (enableCategorizedWidgetSuggestions()) {
+ // two pane picker is full width for fold as well as tablet.
+ return getResources().getDimensionPixelSize(
+ R.dimen.widget_picker_two_panels_left_right_margin);
+ }
+ if (deviceProfile.isTwoPanels && enableUnfoldedTwoPanePicker()) {
+ // enableUnfoldedTwoPanePicker made two pane picker full-width for fold only.
+ return getResources().getDimensionPixelSize(
+ R.dimen.widget_picker_two_panels_left_right_margin);
+ }
+ if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
+ // non-fold tablet landscape margins (ag/22163531)
+ return getResources().getDimensionPixelSize(
+ R.dimen.widget_picker_landscape_tablet_left_right_margin);
+ }
+ return deviceProfile.allAppsLeftRightMargin;
+ }
+
+ @Override
protected void onUserSwipeToDismissProgressChanged() {
super.onUserSwipeToDismissProgressChanged();
boolean isSwipeToDismissInProgress = mSwipeToDismissProgress.value > 0;
diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
index 4021b17..2a4d21d 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -209,7 +209,7 @@
ArgumentCaptor<Intent> acIntent = ArgumentCaptor.forClass(Intent.class);
mPrivateProfileManager.setPrivateSpaceSettingsAvailable(true);
- mPrivateProfileManager.openPrivateSpaceSettings();
+ mPrivateProfileManager.openPrivateSpaceSettings(null);
Mockito.verify(mContext).startActivity(acIntent.capture());
assertEquals("Intent Action is different",
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
index 0023ec8..c2e73fc 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
@@ -66,7 +66,6 @@
@Mock private lateinit var mockBgDataModel: BgDataModel
@Mock private lateinit var mockContext: Context
@Mock private lateinit var mockAppState: LauncherAppState
- @Mock private lateinit var mockIntent: Intent
@Mock private lateinit var mockPmHelper: PackageManagerHelper
@Mock private lateinit var mockLauncherApps: LauncherApps
@Mock private lateinit var mockCursor: LoaderCursor
@@ -74,6 +73,7 @@
@Mock private lateinit var mockUserManagerState: UserManagerState
@Mock private lateinit var mockWidgetInflater: WidgetInflater
+ private lateinit var intent: Intent
private lateinit var userHandle: UserHandle
private lateinit var iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>>
private lateinit var componentName: ComponentName
@@ -93,11 +93,11 @@
mockBgDataModel = mock<BgDataModel>()
componentName = ComponentName("package", "class")
unlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
- mockIntent =
- mock<Intent>().apply {
- whenever(component).thenReturn(componentName)
- whenever(`package`).thenReturn("pkg")
- whenever(getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID)).thenReturn("")
+ intent =
+ Intent().apply {
+ component = componentName
+ `package` = "pkg"
+ putExtra(ShortcutKey.EXTRA_SHORTCUT_ID, "")
}
mockContext =
mock<Context>().apply {
@@ -113,7 +113,7 @@
mockPmHelper =
mock<PackageManagerHelper>().apply {
whenever(getAppLaunchIntent(componentName.packageName, userHandle))
- .thenReturn(mockIntent)
+ .thenReturn(intent)
}
mockLauncherApps =
mock<LauncherApps>().apply {
@@ -127,19 +127,17 @@
id = 1
restoreFlag = 1
serialNumber = 101
- whenever(parseIntent()).thenReturn(mockIntent)
+ whenever(parseIntent()).thenReturn(intent)
whenever(markRestored()).doAnswer { restoreFlag = 0 }
- whenever(updater().put(Favorites.INTENT, mockIntent.toUri(0)).commit())
- .thenReturn(1)
+ whenever(updater().put(Favorites.INTENT, intent.toUri(0)).commit()).thenReturn(1)
whenever(getAppShortcutInfo(any(), any(), any(), any()))
.thenReturn(mockWorkspaceInfo)
whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo)
}
mockUserCache =
mock<UserCache>().apply {
- val userIconInfo = mock<UserIconInfo>().apply() {
- whenever(isPrivate).thenReturn(false)
- }
+ val userIconInfo =
+ mock<UserIconInfo>().apply() { whenever(isPrivate).thenReturn(false) }
whenever(getUserInfo(any())).thenReturn(userIconInfo)
}
@@ -198,9 +196,11 @@
fun `When user is null then mark item deleted`() {
// Given
mockCursor = mock<LoaderCursor>().apply { id = 1 }
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
+
// Then
verify(mockCursor).markDeleted("User has been deleted for item id=1", PROFILE_DELETED)
verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
@@ -210,8 +210,9 @@
fun `When app has null intent then mark deleted`() {
// Given
mockCursor.apply { whenever(parseIntent()).thenReturn(null) }
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
verify(mockCursor).markDeleted("Null intent from db for item id=1", MISSING_INFO)
@@ -222,13 +223,13 @@
fun `When app has null target package then mark deleted`() {
// Given
- mockIntent.apply {
- whenever(component).thenReturn(null)
- whenever(`package`).thenReturn(null)
+ intent.apply {
+ component = null
+ `package` = null
}
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
@@ -241,11 +242,11 @@
// Given
componentName = ComponentName("", "")
- whenever(mockIntent.component).thenReturn(componentName)
- whenever(mockCursor.parseIntent()).thenReturn(mockIntent)
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+ intent.component = componentName
+ intent.`package` = ""
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
@@ -256,10 +257,8 @@
@Test
fun `When valid app then mark restored`() {
- // Given
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
-
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
@@ -284,18 +283,18 @@
mockPmHelper =
mock<PackageManagerHelper>().apply {
whenever(getAppLaunchIntent(componentName.packageName, userHandle))
- .thenReturn(mockIntent)
+ .thenReturn(intent)
}
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
assertWithMessage("item restoreFlag should be set to 0")
.that(mockCursor.restoreFlag)
.isEqualTo(0)
- verify(mockCursor.updater().put(Favorites.INTENT, mockIntent.toUri(0))).commit()
+ verify(mockCursor.updater().put(Favorites.INTENT, intent.toUri(0))).commit()
assertThat(iconRequestInfos).containsExactly(mockIconRequestInfo)
verify(mockCursor).checkAndAddItem(mockWorkspaceInfo, mockBgDataModel, null)
}
@@ -313,9 +312,9 @@
mock<PackageManagerHelper>().apply {
whenever(getAppLaunchIntent(componentName.packageName, userHandle)).thenReturn(null)
}
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
@@ -349,13 +348,13 @@
whenever(disabledReason).thenReturn(0)
whenever(persons).thenReturn(EMPTY_PERSON_ARRAY)
}
- val shortcutKey = ShortcutKey.fromIntent(mockIntent, mockCursor.user)
+ val shortcutKey = ShortcutKey.fromIntent(intent, mockCursor.user)
keyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
iconRequestInfos = mutableListOf()
- itemProcessorUnderTest =
- createWorkspaceItemProcessorUnderTest(allDeepShortcuts = allDeepShortcuts)
// When
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(allDeepShortcuts = allDeepShortcuts)
itemProcessorUnderTest.processItem()
// Then
@@ -375,9 +374,9 @@
mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
iconRequestInfos = mutableListOf()
keyToPinnedShortcutsMap = hashMapOf()
- itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
// When
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
itemProcessorUnderTest.processItem()
// Then
@@ -394,6 +393,45 @@
}
@Test
+ fun `When valid Pinned Deep Shortcut with null intent package then use targetPkg`() {
+
+ // Given
+ mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
+ val expectedShortcutInfo =
+ mock<ShortcutInfo>().apply {
+ whenever(id).thenReturn("")
+ whenever(`package`).thenReturn("")
+ whenever(activity).thenReturn(mock())
+ whenever(longLabel).thenReturn("")
+ whenever(isEnabled).thenReturn(true)
+ whenever(disabledMessage).thenReturn("")
+ whenever(disabledReason).thenReturn(0)
+ whenever(persons).thenReturn(EMPTY_PERSON_ARRAY)
+ }
+ iconRequestInfos = mutableListOf()
+ // Make sure shortcuts map has expected key from expected package
+ intent.`package` = componentName.packageName
+ val shortcutKey = ShortcutKey.fromIntent(intent, mockCursor.user)
+ keyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
+ // set intent package back to null to test scenario
+ intent.`package` = null
+
+ // When
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(allDeepShortcuts = allDeepShortcuts)
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ assertWithMessage("item restoreFlag should be set to 0")
+ .that(mockCursor.restoreFlag)
+ .isEqualTo(0)
+ assertThat(iconRequestInfos).isEmpty()
+ assertThat(allDeepShortcuts).containsExactly(expectedShortcutInfo)
+ verify(mockCursor).markRestored()
+ verify(mockCursor).checkAndAddItem(any(), any(), anyOrNull())
+ }
+
+ @Test
fun `When processing Folder then create FolderInfo and mark restored`() {
val actualFolderInfo = FolderInfo()
mockBgDataModel =