diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index ed90c85bc5..5cbe55638e 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -22,6 +22,8 @@
"Speld vas"
"Vormvry"
"Rekenaar"
+
+
"Werkskerm"
"Geen onlangse items nie"
"Programgebruikinstellings"
@@ -154,4 +156,6 @@
"Maak almal toe"
"vou %1$s uit"
"vou %1$s in"
+
+
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 0848ddd48e..ce12f9da4a 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -22,6 +22,8 @@
"ሰካ"
"ነፃ ቅጽ"
"ዴስክቶፕ"
+
+
"ዴስክቶፕ"
"ምንም የቅርብ ጊዜ ንጥሎች የሉም"
"የመተግበሪያ አጠቃቀም ቅንብሮች"
@@ -154,4 +156,6 @@
"ሁሉንም አሰናብት"
"%1$sን ዘርጋ"
"%1$sን ሰብስብ"
+
+
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 501654f0eb..0f3a854c14 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -22,6 +22,8 @@
"تثبيت"
"شكل مجاني"
"الكمبيوتر المكتبي"
+
+
"كمبيوتر مكتبي"
"ما مِن عناصر تم استخدامها مؤخرًا"
"إعدادات استخدام التطبيق"
@@ -154,4 +156,6 @@
"إغلاق الكل"
"توسيع %1$s"
"تصغير %1$s"
+
+
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 1dbab02d17..1d536e840d 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -22,6 +22,8 @@
"পিন"
"Freeform"
"ডেস্কটপ"
+
+
"ডেস্কটপ"
"কোনো শেহতীয়া বস্তু নাই"
"এপে ব্যৱহাৰ কৰা ডেটাৰ ছেটিং"
@@ -154,4 +156,6 @@
"সকলো অগ্ৰাহ্য কৰক"
"%1$s বিস্তাৰ কৰক"
"%1$s সংকোচন কৰক"
+
+
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index e211463c0c..2e6337a71f 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -22,6 +22,8 @@
"Sancın"
"Sərbəst rejim"
"Masaüstü"
+
+
"Masaüstü"
"Son elementlər yoxdur"
"Tətbiq istifadə ayarları"
@@ -154,4 +156,6 @@
"Hamısını kənarlaşdırın"
"genişləndirin: %1$s"
"yığcamlaşdırın: %1$s"
+
+
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index aa16f3c353..93a8d48283 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -22,6 +22,8 @@
"Zakači"
"Slobodni oblik"
"Računar"
+
+
"Računari"
"Nema nedavnih stavki"
"Podešavanja korišćenja aplikacije"
@@ -154,4 +156,6 @@
"Odbaci sve"
"proširite oblačić %1$s"
"skupite oblačić %1$s"
+
+
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 4dcfe62c1c..3f5a6178a3 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -22,6 +22,8 @@
"Замацаваць"
"Адвольная форма"
"Працоўны стол"
+
+
"Працоўны стол"
"Няма новых элементаў"
"Налады выкарыстання праграмы"
@@ -154,4 +156,6 @@
"Закрыць усе"
"%1$s: разгарнуць"
"%1$s: згарнуць"
+
+
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 8ceef779a8..adabb31cbb 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -22,6 +22,8 @@
"Фиксиране"
"Свободна форма"
"За компютър"
+
+
"Настолен компютър"
"Няма скорошни елементи"
"Настройки за използването на приложенията"
@@ -154,4 +156,6 @@
"Отхвърляне на всички"
"разгъване на %1$s"
"свиване на %1$s"
+
+
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 14b86de345..7d93d9b323 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -22,6 +22,8 @@
"পিন করুন"
"ফ্রি-ফর্ম"
"ডেস্কটপ"
+
+
"ডেস্কটপ"
"কোনও সাম্প্রতিক আইটেম নেই"
"অ্যাপ ব্যবহারের সেটিংস"
@@ -154,4 +156,6 @@
"সব বাতিল করুন"
"%1$s বড় করুন"
"%1$s আড়াল করুন"
+
+
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index b60436cb10..2ac0ab1336 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -22,6 +22,8 @@
"Zakači"
"Slobodan oblik"
"Radna površina"
+
+
"Radna površina"
"Nema nedavnih stavki"
"Postavke korištenja aplikacije"
@@ -154,4 +156,6 @@
"Odbacivanje svega"
"proširivanje oblačića %1$s"
"sužavanje oblačića %1$s"
+
+
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 4447c019a1..1c27b08ddc 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -22,6 +22,8 @@
"Fixa"
"Format lliure"
"Escriptori"
+
+
"Escriptori"
"No hi ha cap element recent"
"Configuració d\'ús d\'aplicacions"
@@ -154,4 +156,6 @@
"Ignora-ho tot"
"desplega %1$s"
"replega %1$s"
+
+
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 711cbfa788..2f8d4b0b7b 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -22,6 +22,8 @@
"Připnout"
"Neomezený režim"
"Počítač"
+
+
"Počítač"
"Žádné položky z nedávné doby"
"Nastavení využití aplikací"
@@ -154,4 +156,6 @@
"Zavřít vše"
"rozbalit %1$s"
"sbalit %1$s"
+
+
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 2a5b34d838..4684af2df4 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -22,6 +22,8 @@
"Fastgør"
"Frit format"
"Computertilstand"
+
+
"Computer"
"Ingen nye elementer"
"Indstillinger for appforbrug"
@@ -154,4 +156,6 @@
"Afvis alle"
"udvid %1$s"
"skjul %1$s"
+
+
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 478a7a39ee..155abb4727 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -22,6 +22,8 @@
"Fixieren"
"Freeform-Modus"
"Desktopmodus"
+
+
"Desktopmodus"
"Keine kürzlich verwendeten Elemente"
"Einstellungen zur App-Nutzung"
@@ -154,4 +156,6 @@
"Alle schließen"
"„%1$s“ maximieren"
"„%1$s“ minimieren"
+
+
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index e47b423bfb..39e891637d 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -22,6 +22,8 @@
"Καρφίτσωμα"
"Ελεύθερη μορφή"
"Υπολογιστής"
+
+
"Υπολογιστής"
"Δεν υπάρχουν πρόσφατα στοιχεία"
"Ρυθμίσεις χρήσης εφαρμογής"
@@ -154,4 +156,6 @@
"Παράβλεψη όλων"
"ανάπτυξη %1$s"
"σύμπτυξη %1$s"
+
+
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index 04b04dde75..bc73bfe488 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -22,6 +22,8 @@
"Pin"
"Freeform"
"Desktop"
+
+
"Desktop"
"No recent items"
"App usage settings"
@@ -154,4 +156,6 @@
"Dismiss all"
"expand %1$s"
"collapse %1$s"
+
+
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index e0787ca316..da4effbb2c 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -22,6 +22,7 @@
"Pin"
"Freeform"
"Desktop"
+ "Move to external display"
"Desktop"
"No recent items"
"App usage settings"
@@ -154,4 +155,5 @@
"Dismiss all"
"expand %1$s"
"collapse %1$s"
+ "Circle to Search"
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index 04b04dde75..bc73bfe488 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -22,6 +22,8 @@
"Pin"
"Freeform"
"Desktop"
+
+
"Desktop"
"No recent items"
"App usage settings"
@@ -154,4 +156,6 @@
"Dismiss all"
"expand %1$s"
"collapse %1$s"
+
+
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index 04b04dde75..bc73bfe488 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -22,6 +22,8 @@
"Pin"
"Freeform"
"Desktop"
+
+
"Desktop"
"No recent items"
"App usage settings"
@@ -154,4 +156,6 @@
"Dismiss all"
"expand %1$s"
"collapse %1$s"
+
+
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index dd8de5fad4..25bbba27fa 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -22,6 +22,8 @@
"Fijar"
"Formato libre"
"Escritorio"
+
+
"Computadoras"
"No hay elementos recientes"
"Configuración de uso de la app"
@@ -154,4 +156,6 @@
"Descartar todo"
"expandir %1$s"
"contraer %1$s"
+
+
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index d8bbc55815..a4d7a8b1dc 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -22,6 +22,8 @@
"Fijar"
"Formato libre"
"Escritorio"
+
+
"Ordenador"
"No hay nada reciente"
"Ajustes de uso de la aplicación"
@@ -154,4 +156,6 @@
"Cerrar todo"
"desplegar %1$s"
"contraer %1$s"
+
+
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 114f3a187e..63d4d2fcfc 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -22,6 +22,8 @@
"Kinnita"
"Vabavorm"
"Lauaarvuti režiim"
+
+
"Töölaud"
"Hiljutisi üksusi pole"
"Rakenduse kasutuse seaded"
@@ -154,4 +156,6 @@
"Loobu kõigist"
"Toiminguriba %1$s laiendamine"
"Toiminguriba %1$s ahendamine"
+
+
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 45fa5790d0..3c0698c158 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -22,6 +22,8 @@
"Ainguratu"
"Modu librea"
"Ordenagailua"
+
+
"Mahaigaina"
"Ez dago azkenaldi honetako ezer"
"Aplikazioen erabileraren ezarpenak"
@@ -154,4 +156,6 @@
"Baztertu guztiak"
"zabaldu %1$s"
"tolestu %1$s"
+
+
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index d3e38000d6..8d5d15e7e6 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -22,6 +22,8 @@
"پین"
"Freeform"
"حالت رایانه"
+
+
"رایانه"
"چیز جدیدی اینجا نیست"
"تنظیمات استفاده از برنامه"
@@ -154,4 +156,6 @@
"رد کردن همه"
"ازهم باز کردن %1$s"
"جمع کردن %1$s"
+
+
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 54a0c23e34..10ea9ee215 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -22,6 +22,8 @@
"Kiinnitä"
"Vapaamuotoinen"
"Tietokone"
+
+
"Tietokone"
"Ei viimeaikaisia kohteita"
"Sovelluksen käyttöasetukset"
@@ -154,4 +156,6 @@
"Hylkää kaikki"
"laajenna %1$s"
"tiivistä %1$s"
+
+
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 591c7b7f65..b624b4f73b 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -22,6 +22,8 @@
"Épingler"
"Forme libre"
"Ordinateur de bureau"
+
+
"Ordinateur de bureau"
"Aucun élément récent"
"Paramètres d\'utilisation de l\'appli"
@@ -154,4 +156,6 @@
"Tout ignorer"
"Développer %1$s"
"Réduire %1$s"
+
+
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 6371f30a38..3f61d65f35 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -22,6 +22,8 @@
"Épingler"
"Format libre"
"Ordinateur"
+
+
"Ordinateur"
"Aucun élément récent"
"Paramètres de consommation de l\'application"
@@ -154,4 +156,6 @@
"Tout fermer"
"Développer %1$s"
"Réduire %1$s"
+
+
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 060328405b..d9d06a1a8a 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -22,6 +22,8 @@
"Fixar"
"Forma libre"
"Escritorio"
+
+
"Ordenador"
"Non hai elementos recentes"
"Configuración do uso de aplicacións"
@@ -154,4 +156,6 @@
"Pechar todo"
"despregar %1$s"
"contraer %1$s"
+
+
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 4a8e9f9642..7716d4d3ef 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -22,6 +22,8 @@
"પિન કરો"
"ફ્રિફોર્મ"
"ડેસ્કટૉપ"
+
+
"ડેસ્કટૉપ"
"તાજેતરની કોઈ આઇટમ નથી"
"ઍપ વપરાશનું સેટિંગ"
@@ -154,4 +156,6 @@
"તમામ છોડી દો"
"%1$s મોટો કરો"
"%1$s નાનો કરો"
+
+
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 2cec388ac7..02e23ec579 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -22,6 +22,8 @@
"पिन करें"
"फ़्रीफ़ॉर्म"
"डेस्कटॉप"
+
+
"डेस्कटॉप"
"हाल ही का कोई आइटम नहीं है"
"ऐप्लिकेशन इस्तेमाल की सेटिंग"
@@ -154,4 +156,6 @@
"सभी खारिज करें"
"%1$s को बड़ा करें"
"%1$s को छोटा करें"
+
+
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index ed52e90b48..a742c01bdc 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -22,6 +22,8 @@
"Prikvači"
"Slobodni oblik"
"Računalo"
+
+
"Radna površina"
"Nema nedavnih stavki"
"Postavke upotrebe aplikacija"
@@ -154,4 +156,6 @@
"Odbaci sve"
"proširite oblačić %1$s"
"sažmite oblačić %1$s"
+
+
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 27db3e0b3b..439d6ed55a 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -22,6 +22,8 @@
"Kitűzés"
"Szabad forma"
"Asztali"
+
+
"Asztali"
"Nincsenek mostanában használt elemek"
"Alkalmazáshasználati beállítások"
@@ -154,4 +156,6 @@
"Az összes elvetése"
"%1$s kibontása"
"%1$s összecsukása"
+
+
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 9a2cb2ee3e..87681c0ea1 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -22,6 +22,8 @@
"Ամրացնել"
"Կամայական ձև"
"Համակարգիչ"
+
+
"Համակարգիչ"
"Այստեղ դեռ ոչինչ չկա"
"Հավելվածի օգտագործման կարգավորումներ"
@@ -154,4 +156,6 @@
"Փակել բոլորը"
"%1$s. ծավալել"
"%1$s. ծալել"
+
+
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 5ddfb7e716..119ed6b8cf 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -22,6 +22,8 @@
"Sematkan"
"Format bebas"
"Desktop"
+
+
"Desktop"
"Tidak ada item yang baru dibuka"
"Setelan penggunaan aplikasi"
@@ -154,4 +156,6 @@
"Tutup semua"
"luaskan %1$s"
"ciutkan %1$s"
+
+
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index 3aec0ceb32..68f46565e6 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -22,6 +22,8 @@
"Festa"
"Frjálst snið"
"Tölva"
+
+
"Tölva"
"Engin nýleg atriði"
"Notkunarstillingar forrits"
@@ -154,4 +156,6 @@
"Hunsa allt"
"stækka %1$s"
"minnka %1$s"
+
+
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index b9e6f623c6..0498c4ea41 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -22,6 +22,8 @@
"Blocca su schermo"
"Forma libera"
"Desktop"
+
+
"Desktop"
"Nessun elemento recente"
"Impostazioni di utilizzo delle app"
@@ -154,4 +156,6 @@
"Ignora tutte"
"espandi %1$s"
"comprimi %1$s"
+
+
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 2a016fa962..ad525609aa 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -22,6 +22,8 @@
"הצמדה"
"מצב חופשי"
"במחשב"
+
+
"מחשב"
"אין פריטים אחרונים"
"הגדרות שימוש באפליקציה"
@@ -154,4 +156,6 @@
"ביטול של הכול"
"הרחבה של %1$s"
"כיווץ של %1$s"
+
+
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 28b7746b43..4cfe9ed4f5 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -22,6 +22,8 @@
"固定"
"フリーフォーム"
"デスクトップ"
+
+
"パソコン"
"最近のアイテムはありません"
"アプリの使用状況の設定"
@@ -154,4 +156,6 @@
"すべて解除"
"%1$sを開きます"
"%1$sを閉じます"
+
+
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index d84d53e576..c02e9ad755 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -22,6 +22,8 @@
"ჩამაგრება"
"თავისუფალი ფორმა"
"დესკტოპი"
+
+
"დესკტოპი"
"ბოლოს გამოყენებული ერთეულები არ არის"
"აპების გამოყენების პარამეტრები"
@@ -154,4 +156,6 @@
"ყველას დახურვა"
"%1$s-ის გაფართოება"
"%1$s-ის ჩაკეცვა"
+
+
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 4cdbfc4d94..64b3e53ddc 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -22,6 +22,8 @@
"Бекіту"
"Еркін форма"
"Компьютер"
+
+
"Жұмыс үстелі"
"Соңғы элементтер жоқ"
"Қолданбаны пайдалану параметрлері"
@@ -154,4 +156,6 @@
"Барлығын жабу"
"%1$s: жаю"
"%1$s: жию"
+
+
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 5cf1b92737..d962ba5572 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -22,6 +22,8 @@
"ខ្ទាស់"
"មុខងារទម្រង់សេរី"
"ដែសថប"
+
+
"អេក្រង់ដើម"
"មិនមានធាតុថ្មីៗទេ"
"ការកំណត់ការប្រើប្រាស់កម្មវិធី"
@@ -154,4 +156,6 @@
"ច្រានចោលទាំងអស់"
"ពង្រីក %1$s"
"បង្រួម %1$s"
+
+
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 63b0006ee9..3a05e21dec 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -22,6 +22,8 @@
"ಪಿನ್ ಮಾಡಿ"
"ಮುಕ್ತಸ್ವರೂಪ"
"ಡೆಸ್ಕ್ಟಾಪ್"
+
+
"ಡೆಸ್ಕ್ಟಾಪ್"
"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"
"ಆ್ಯಪ್ ಬಳಕೆಯ ಸೆಟ್ಟಿಂಗ್ಗಳು"
@@ -154,4 +156,6 @@
"ಎಲ್ಲವನ್ನು ವಜಾಗೊಳಿಸಿ"
"%1$s ಅನ್ನು ವಿಸ್ತೃತಗೊಳಿಸಿ"
"%1$s ಅನ್ನು ಕುಗ್ಗಿಸಿ"
+
+
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 589cc225f6..6a7ba74377 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -22,6 +22,8 @@
"고정"
"자유 형식"
"데스크톱"
+
+
"데스크톱"
"최근 항목이 없습니다."
"앱 사용 설정"
@@ -154,4 +156,6 @@
"모두 닫기"
"%1$s 펼치기"
"%1$s 접기"
+
+
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index faf5675762..e92b920bb3 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -22,6 +22,8 @@
"Кадап коюу"
"Эркин форма режими"
"Компьютер"
+
+
"Компьютер"
"Акыркы колдонмолор жок"
"Колдонмону пайдалануу параметрлери"
@@ -154,4 +156,6 @@
"Баарын четке кагуу"
"%1$s жайып көрсөтүү"
"%1$s жыйыштыруу"
+
+
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 622db2d1b0..f45c8ce0a6 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -22,6 +22,8 @@
"ປັກໝຸດ"
"ຮູບແບບອິດສະຫລະ"
"ເດັສທັອບ"
+
+
"ເດັສທັອບ"
"ບໍ່ມີລາຍການຫຼ້າສຸດ"
"ການຕັ້ງຄ່າການນຳໃຊ້ແອັບ"
@@ -154,4 +156,6 @@
"ປິດທັງໝົດ"
"ຂະຫຍາຍ %1$s"
"ຫຍໍ້ %1$s ລົງ"
+
+
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index a95249b508..c488859752 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -22,6 +22,8 @@
"Prisegti"
"Laisva forma"
"Stalinis kompiuteris"
+
+
"Stalinis kompiuteris"
"Nėra jokių naujausių elementų"
"Programos naudojimo nustatymai"
@@ -154,4 +156,5 @@
"Atsisakyti visų"
"išskleisti „%1$s“"
"sutraukti „%1$s“"
+ "Paieška apibrėžiant"
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 1892f6462e..23e64a7fff 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -22,6 +22,8 @@
"Piespraust"
"Brīva forma"
"Dators"
+
+
"Darbvirsma"
"Nav nesenu vienumu."
"Lietotņu izmantošanas iestatījumi"
@@ -154,4 +156,6 @@
"Nerādīt nevienu"
"izvērst “%1$s”"
"sakļaut “%1$s”"
+
+
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index ce4e1b098e..f0588e88da 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -22,6 +22,8 @@
"Закачи"
"Freeform"
"Работна површина"
+
+
"За компјутер"
"Нема неодамнешни ставки"
"Поставки за користење на апликациите"
@@ -154,4 +156,6 @@
"Отфрли ги сите"
"прошири %1$s"
"собери %1$s"
+
+
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index c15a241bdb..833090cc62 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -22,6 +22,8 @@
"പിൻ ചെയ്യുക"
"ഫ്രീഫോം"
"ഡെസ്ക്ടോപ്പ്"
+
+
"ഡെസ്ക്ടോപ്പ്"
"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"
"ആപ്പ് ഉപയോഗ ക്രമീകരണം"
@@ -154,4 +156,6 @@
"എല്ലാം ഡിസ്മിസ് ചെയ്യുക"
"%1$s വികസിപ്പിക്കുക"
"%1$s ചുരുക്കുക"
+
+
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 1ff7502644..100b8edfb4 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -22,6 +22,8 @@
"Бэхлэх"
"Чөлөөтэй хувьсах"
"Компьютер"
+
+
"Дэлгэц"
"Сүүлийн үеийн зүйл алга"
"Апп ашиглалтын тохиргоо"
@@ -154,4 +156,6 @@
"Бүгдийг үл хэрэгсэх"
"%1$s-г дэлгэх"
"%1$s-г хураах"
+
+
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 215ae3f77c..870cf4ea6d 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -22,6 +22,8 @@
"पिन करा"
"फ्रीफॉर्म"
"डेस्कटॉप"
+
+
"डेस्कटॉप"
"कोणतेही अलीकडील आयटम नाहीत"
"अॅप वापर सेटिंग्ज"
@@ -154,4 +156,6 @@
"सर्व डिसमिस करा"
"%1$s चा विस्तार करा"
"%1$s कोलॅप्स करा"
+
+
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index a1f19a95a4..bed2fce8d5 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -22,6 +22,8 @@
"Semat"
"Bentuk bebas"
"Desktop"
+
+
"Desktop"
"Tiada item terbaharu"
"Tetapan penggunaan apl"
@@ -154,4 +156,6 @@
"Ketepikan semua"
"kembangkan %1$s"
"kuncupkan %1$s"
+
+
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index eeb774b367..ae0f66d1cb 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -22,6 +22,8 @@
"ပင်ထိုးရန်"
"အလွတ်ပုံစံ"
"ဒက်စ်တော့"
+
+
"ဒက်စ်တော့"
"မကြာမီကဖွင့်ထားသည်များ မရှိပါ"
"အက်ပ်အသုံးပြုမှု ဆက်တင်များ"
@@ -154,4 +156,6 @@
"အားလုံးကို ပယ်ရန်"
"%1$s ကို ပိုပြပါ"
"%1$s ကို လျှော့ပြပါ"
+
+
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index b62b7fde0c..1ce18c1b3b 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -22,6 +22,8 @@
"Fest"
"Fritt format"
"Skrivebord"
+
+
"Skrivebord"
"Ingen nylige elementer"
"Innstillinger for appbruk"
@@ -154,4 +156,6 @@
"Lukk alle"
"vis %1$s"
"skjul %1$s"
+
+
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index a2d4d325b3..1921fed160 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -22,6 +22,8 @@
"पिन गर्नुहोस्"
"फ्रिफर्म"
"डेस्कटप"
+
+
"डेस्कटप"
"हालसालैको कुनै पनि वस्तु छैन"
"एपको उपयोगका सेटिङहरू"
@@ -154,4 +156,6 @@
"सबै हटाउनुहोस्"
"%1$s एक्स्पान्ड गर्नुहोस्"
"%1$s कोल्याप्स गर्नुहोस्"
+
+
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index ee876cfcfc..995d8d4849 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -22,6 +22,8 @@
"Vastzetten"
"Vrije vorm"
"Desktop"
+
+
"Desktop"
"Geen recente items"
"Instellingen voor app-gebruik"
@@ -154,4 +156,6 @@
"Alles sluiten"
"%1$s uitvouwen"
"%1$s samenvouwen"
+
+
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 3ee59b5194..430058b24d 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -22,6 +22,8 @@
"ପିନ୍"
"ଫ୍ରିଫର୍ମ"
"ଡେସ୍କଟପ"
+
+
"ଡେସ୍କଟପ"
"ବର୍ତ୍ତମାନର କୌଣସି ଆଇଟମ ନାହିଁ"
"ଆପ ବ୍ୟବହାର ସେଟିଂସ"
@@ -154,4 +156,6 @@
"ସବୁ ଖାରଜ କରନ୍ତୁ"
"%1$s ବିସ୍ତାର କରନ୍ତୁ"
"%1$s ସଙ୍କୁଚିତ କରନ୍ତୁ"
+
+
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 1e8d52e741..d8d0907390 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -22,6 +22,8 @@
"ਪਿੰਨ ਕਰੋ"
"ਫ੍ਰੀਫਾਰਮ"
"ਡੈਸਕਟਾਪ"
+
+
"ਡੈਸਕਟਾਪ"
"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮ ਨਹੀਂ"
"ਐਪ ਵਰਤੋਂ ਦੀਆਂ ਸੈਟਿੰਗਾਂ"
@@ -154,4 +156,6 @@
"ਸਭ ਖਾਰਜ ਕਰੋ"
"%1$s ਦਾ ਵਿਸਤਾਰ ਕਰੋ"
"%1$s ਨੂੰ ਸਮੇਟੋ"
+
+
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 64adddf55e..957e5c47e2 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -22,6 +22,8 @@
"Przypnij"
"Tryb dowolny"
"Pulpit"
+
+
"Pulpit"
"Brak ostatnich elementów"
"Ustawienia użycia aplikacji"
@@ -154,4 +156,6 @@
"Zamknij wszystkie"
"rozwiń dymek: %1$s"
"zwiń dymek: %1$s"
+
+
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 2167875719..ca7cd58bb5 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -22,6 +22,8 @@
"Fixar"
"Forma livre"
"Computador"
+
+
"Computador"
"Nenhum item recente"
"Definições de utilização de aplicações"
@@ -154,4 +156,6 @@
"Ignorar tudo"
"expandir %1$s"
"reduzir %1$s"
+
+
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 9309810cdf..aee1c8d758 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -22,6 +22,8 @@
"Fixar"
"Forma livre"
"Modo área de trabalho"
+
+
"Computador"
"Nenhum item recente"
"Configurações de uso do app"
@@ -154,4 +156,6 @@
"Dispensar todos"
"abrir %1$s"
"fechar %1$s"
+
+
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 19075cd554..c05b85b5ab 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -22,6 +22,8 @@
"Fixează"
"Formă liberă"
"Desktop"
+
+
"Computer"
"Niciun element recent"
"Setări de utilizare a aplicației"
@@ -154,4 +156,6 @@
"Închide-le pe toate"
"extinde %1$s"
"restrânge %1$s"
+
+
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 76c4e1f646..fca0a056d3 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -22,6 +22,8 @@
"Закрепить"
"Произвольная форма"
"Мультиоконный режим"
+
+
"Мультиоконный режим"
"Здесь пока ничего нет."
"Настройки использования приложения"
@@ -154,4 +156,6 @@
"Закрыть все"
"Развернуто: %1$s"
"Свернуто: %1$s"
+
+
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 0953b38bd1..cfbf1ddd2e 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -22,6 +22,8 @@
"අමුණන්න"
"Freeform"
"ඩෙස්ක්ටොපය"
+
+
"ඩෙස්ක්ටොපය"
"මෑත අයිතම නැත"
"යෙදුම් භාවිත සැකසීම්"
@@ -154,4 +156,6 @@
"සියල්ල ඉවතලන්න"
"%1$s දිග හරින්න"
"%1$s හකුළන්න"
+
+
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 9b682e6034..b3145de532 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -22,6 +22,8 @@
"Pripnúť"
"Voľný režim"
"Počítač"
+
+
"Počítač"
"Žiadne nedávne položky"
"Nastavenia využívania aplikácie"
@@ -154,4 +156,6 @@
"Zavrieť všetko"
"rozbaliť %1$s"
"zbaliť %1$s"
+
+
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 94de1e0567..d72436a046 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -22,6 +22,8 @@
"Pripni"
"Prosta oblika"
"Namizni računalnik"
+
+
"Namizni način"
"Ni nedavnih elementov"
"Nastavitve uporabe aplikacij"
@@ -154,4 +156,6 @@
"Opusti vse"
"razširitev oblačka %1$s"
"strnitev oblačka %1$s"
+
+
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 29214c9701..30ba61df9f 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -22,6 +22,8 @@
"Gozhdo"
"Formë e lirë"
"Desktopi"
+
+
"Desktopi"
"Nuk ka asnjë artikull të fundit"
"Cilësimet e përdorimit të aplikacionit"
@@ -154,4 +156,6 @@
"Hiqi të gjitha"
"zgjero %1$s"
"palos %1$s"
+
+
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index d6e5d03cee..b83a4f251e 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -22,6 +22,8 @@
"Закачи"
"Слободни облик"
"Рачунар"
+
+
"Рачунари"
"Нема недавних ставки"
"Подешавања коришћења апликације"
@@ -154,4 +156,6 @@
"Одбаци све"
"проширите облачић %1$s"
"скупите облачић %1$s"
+
+
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index bba98c6fb6..5ab3866475 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -22,6 +22,8 @@
"Fäst"
"Fritt format"
"Dator"
+
+
"Dator"
"Listan är tom"
"Inställningar för appanvändning"
@@ -154,4 +156,6 @@
"Stäng alla"
"utöka %1$s"
"komprimera %1$s"
+
+
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index f8d6a4f229..9d13df8a77 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -22,6 +22,8 @@
"Bandika"
"Muundo huru"
"Kompyuta ya mezani"
+
+
"Kompyuta ya Mezani"
"Hakuna vipengee vya hivi karibuni"
"Mipangilio ya matumizi ya programu"
@@ -154,4 +156,6 @@
"Ondoa vyote"
"panua %1$s"
"kunja %1$s"
+
+
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 73c6c3746f..8ac0ff8aab 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -22,6 +22,8 @@
"பின் செய்தல்"
"குறிப்பிட்ட வடிவமில்லாத பயன்முறை"
"டெஸ்க்டாப்"
+
+
"டெஸ்க்டாப்"
"சமீபத்தியவை எதுவுமில்லை"
"ஆப்ஸ் உபயோக அமைப்புகள்"
@@ -154,4 +156,6 @@
"அனைத்தையும் மூடும்"
"%1$s ஐ விரிவாக்கும்"
"%1$s ஐச் சுருக்கும்"
+
+
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 91ef8463a9..4ae7a58ed5 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -22,6 +22,8 @@
"పిన్ చేయండి"
"సంప్రదాయేతర"
"డెస్క్టాప్"
+
+
"డెస్క్టాప్"
"ఇటీవలి ఐటెమ్లు ఏవీ లేవు"
"యాప్ వినియోగ సెట్టింగ్లు"
@@ -154,4 +156,6 @@
"అన్నింటినీ విస్మరించండి"
"%1$sను విస్తరించండి"
"%1$sను కుదించండి"
+
+
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 2218e6d0e1..210e996664 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -22,6 +22,8 @@
"ปักหมุด"
"รูปแบบอิสระ"
"เดสก์ท็อป"
+
+
"เดสก์ท็อป"
"ไม่มีรายการล่าสุด"
"การตั้งค่าการใช้แอป"
@@ -154,4 +156,6 @@
"ปิดทั้งหมด"
"ขยาย %1$s"
"ยุบ %1$s"
+
+
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index fac6a52650..13d89a269d 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -22,6 +22,8 @@
"I-pin"
"Freeform"
"Desktop"
+
+
"Desktop"
"Walang kamakailang item"
"Mga setting ng paggamit ng app"
@@ -154,4 +156,6 @@
"I-dismiss lahat"
"i-expand ang %1$s"
"i-collapse ang %1$s"
+
+
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index d44d710365..1cb1fa7e4f 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -22,6 +22,8 @@
"Sabitle"
"Serbest çalışma"
"Masaüstü"
+
+
"Masaüstü"
"Yeni öğe yok"
"Uygulama kullanım ayarları"
@@ -154,4 +156,6 @@
"Tümünü kapat"
"genişlet: %1$s"
"daralt: %1$s"
+
+
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 320c2ea10e..84ddd81fbc 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -22,6 +22,8 @@
"Закріпити"
"Довільна форма"
"Робочий стіл"
+
+
"Комп’ютер"
"Немає нещодавніх додатків"
"Налаштування використання додатка"
@@ -154,4 +156,6 @@
"Закрити все"
"розгорнути \"%1$s\""
"згорнути \"%1$s\""
+
+
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index c71625a117..43e97c24b7 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -22,6 +22,8 @@
"پن کریں"
"فری فارم"
"ڈیسک ٹاپ"
+
+
"ڈیسک ٹاپ"
"کوئی حالیہ آئٹم نہیں"
"ایپ کے استعمال کی ترتیبات"
@@ -154,4 +156,6 @@
"سبھی کو برخاست کریں"
"%1$s کو پھیلائیں"
"%1$s کو سکیڑیں"
+
+
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index e37945355a..090753ff45 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -22,6 +22,8 @@
"Qadash"
"Erkin shakl"
"Desktop"
+
+
"Desktop"
"Yaqinda ishlatilgan ilovalar yo‘q"
"Ilovadan foydalanish sozlamalari"
@@ -154,4 +156,6 @@
"Hammasini yopish"
"%1$sni yoyish"
"%1$sni yigʻish"
+
+
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index ddefb9e9c4..b0d31cbfb6 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -22,6 +22,8 @@
"Ghim"
"Dạng tự do"
"Máy tính"
+
+
"Máy tính"
"Không có mục gần đây nào"
"Cài đặt mức sử dụng ứng dụng"
@@ -154,4 +156,6 @@
"Đóng tất cả"
"mở rộng %1$s"
"thu gọn %1$s"
+
+
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 8540cd9c4c..73121b4976 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -22,6 +22,8 @@
"固定"
"自由窗口"
"桌面"
+
+
"桌面设备"
"近期没有任何内容"
"应用使用设置"
@@ -154,4 +156,6 @@
"全部关闭"
"展开“%1$s”"
"收起“%1$s”"
+
+
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 3d16e8db3c..b934dfcf44 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -22,6 +22,8 @@
"固定"
"自由形式"
"桌面"
+
+
"桌面"
"最近沒有任何項目"
"應用程式使用情況設定"
@@ -154,4 +156,6 @@
"全部關閉"
"打開%1$s"
"收埋%1$s"
+
+
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index bf0381205e..1cba81966b 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -22,6 +22,8 @@
"固定"
"自由形式"
"桌面"
+
+
"電腦"
"最近沒有任何項目"
"應用程式使用情況設定"
@@ -154,4 +156,6 @@
"全部關閉"
"展開「%1$s」"
"收合「%1$s」"
+
+
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index d0d0bb646a..ee6b3b7208 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -22,6 +22,8 @@
"Phina"
"I-Freeform"
"Ideskithophu"
+
+
"Ideskithophu"
"Azikho izinto zakamuva"
"Izilungiselelo zokusetshenziswa kohlelo lokusebenza"
@@ -154,4 +156,6 @@
"Chitha konke"
"nweba %1$s"
"goqa %1$s"
+
+
diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml
index 41b2384a35..db5ff199ab 100644
--- a/quickstep/res/values/config.xml
+++ b/quickstep/res/values/config.xml
@@ -33,7 +33,6 @@
com.android.launcher3.taskbar.TaskbarModelCallbacksFactory
com.android.launcher3.taskbar.TaskbarViewCallbacksFactory
com.android.quickstep.LauncherRestoreEventLoggerImpl
- com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl
com.android.launcher3.taskbar.TaskbarEduTooltipController
com.android.quickstep.contextualeducation.SystemContextualEduStatsManager
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchTransition.kt b/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchTransition.kt
new file mode 100644
index 0000000000..dd2ff2d580
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopAppLaunchTransition.kt
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.desktop
+
+import android.animation.Animator
+import android.animation.AnimatorSet
+import android.animation.ValueAnimator
+import android.content.Context
+import android.os.IBinder
+import android.view.SurfaceControl.Transaction
+import android.view.WindowManager.TRANSIT_OPEN
+import android.view.WindowManager.TRANSIT_TO_BACK
+import android.view.WindowManager.TRANSIT_TO_FRONT
+import android.window.IRemoteTransitionFinishedCallback
+import android.window.RemoteTransitionStub
+import android.window.TransitionInfo
+import android.window.TransitionInfo.Change
+import androidx.core.animation.addListener
+import com.android.app.animation.Interpolators
+import com.android.quickstep.RemoteRunnable
+import java.util.concurrent.Executor
+
+/**
+ * [android.window.RemoteTransition] for Desktop app launches.
+ *
+ * This transition supports minimize-changes, i.e. in a launch-transition, if a window is moved back
+ * ([android.view.WindowManager.TRANSIT_TO_BACK]) this transition will apply a minimize animation to
+ * that window.
+ */
+class DesktopAppLaunchTransition(private val context: Context, private val mainExecutor: Executor) :
+ RemoteTransitionStub() {
+
+ override fun startAnimation(
+ token: IBinder,
+ info: TransitionInfo,
+ t: Transaction,
+ transitionFinishedCallback: IRemoteTransitionFinishedCallback,
+ ) {
+ val safeTransitionFinishedCallback = RemoteRunnable {
+ transitionFinishedCallback.onTransitionFinished(/* wct= */ null, /* sct= */ null)
+ }
+ mainExecutor.execute {
+ runAnimators(info, safeTransitionFinishedCallback)
+ t.apply()
+ }
+ }
+
+ private fun runAnimators(info: TransitionInfo, finishedCallback: RemoteRunnable) {
+ val animators = mutableListOf()
+ val animatorFinishedCallback: (Animator) -> Unit = { animator ->
+ animators -= animator
+ if (animators.isEmpty()) finishedCallback.run()
+ }
+ animators += createAnimators(info, animatorFinishedCallback)
+ animators.forEach { it.start() }
+ }
+
+ private fun createAnimators(
+ info: TransitionInfo,
+ finishCallback: (Animator) -> Unit,
+ ): List {
+ val transaction = Transaction()
+ val launchAnimator =
+ createLaunchAnimator(getLaunchChange(info), transaction, finishCallback)
+ val minimizeChange = getMinimizeChange(info) ?: return listOf(launchAnimator)
+ val minimizeAnimator = createMinimizeAnimator(minimizeChange, transaction, finishCallback)
+ return listOf(launchAnimator, minimizeAnimator)
+ }
+
+ private fun getLaunchChange(info: TransitionInfo): Change =
+ requireNotNull(info.changes.firstOrNull { change -> change.mode in LAUNCH_CHANGE_MODES }) {
+ "expected an app launch Change"
+ }
+
+ private fun getMinimizeChange(info: TransitionInfo): Change? =
+ info.changes.firstOrNull { change -> change.mode == TRANSIT_TO_BACK }
+
+ private fun createLaunchAnimator(
+ change: Change,
+ transaction: Transaction,
+ onAnimFinish: (Animator) -> Unit,
+ ): Animator {
+ val boundsAnimator =
+ WindowAnimator.createBoundsAnimator(
+ context,
+ launchBoundsAnimationDef,
+ change,
+ transaction,
+ )
+ val alphaAnimator =
+ ValueAnimator.ofFloat(0f, 1f).apply {
+ duration = LAUNCH_ANIM_ALPHA_DURATION_MS
+ interpolator = Interpolators.LINEAR
+ addUpdateListener { animation ->
+ transaction.setAlpha(change.leash, animation.animatedValue as Float).apply()
+ }
+ }
+ return AnimatorSet().apply {
+ playTogether(boundsAnimator, alphaAnimator)
+ addListener(onEnd = { animation -> onAnimFinish(animation) })
+ }
+ }
+
+ private fun createMinimizeAnimator(
+ change: Change,
+ transaction: Transaction,
+ onAnimFinish: (Animator) -> Unit,
+ ): Animator {
+ val boundsAnimator =
+ WindowAnimator.createBoundsAnimator(
+ context,
+ minimizeBoundsAnimationDef,
+ change,
+ transaction,
+ )
+ val alphaAnimator =
+ ValueAnimator.ofFloat(1f, 0f).apply {
+ duration = MINIMIZE_ANIM_ALPHA_DURATION_MS
+ interpolator = Interpolators.LINEAR
+ addUpdateListener { animation ->
+ transaction.setAlpha(change.leash, animation.animatedValue as Float).apply()
+ }
+ }
+ return AnimatorSet().apply {
+ playTogether(boundsAnimator, alphaAnimator)
+ addListener(onEnd = { animation -> onAnimFinish(animation) })
+ }
+ }
+
+ companion object {
+ private val LAUNCH_CHANGE_MODES = intArrayOf(TRANSIT_OPEN, TRANSIT_TO_FRONT)
+
+ private const val LAUNCH_ANIM_ALPHA_DURATION_MS = 100L
+ private const val MINIMIZE_ANIM_ALPHA_DURATION_MS = 100L
+
+ private val launchBoundsAnimationDef =
+ WindowAnimator.BoundsAnimationParams(
+ durationMs = 300,
+ startOffsetYDp = 12f,
+ startScale = 0.97f,
+ interpolator = Interpolators.STANDARD_DECELERATE,
+ )
+
+ private val minimizeBoundsAnimationDef =
+ WindowAnimator.BoundsAnimationParams(
+ durationMs = 200,
+ endOffsetYDp = 12f,
+ endScale = 0.97f,
+ interpolator = Interpolators.STANDARD_ACCELERATE,
+ )
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/desktop/WindowAnimator.kt b/quickstep/src/com/android/launcher3/desktop/WindowAnimator.kt
new file mode 100644
index 0000000000..1a99a36b4c
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/desktop/WindowAnimator.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.desktop
+
+import android.animation.RectEvaluator
+import android.animation.ValueAnimator
+import android.content.Context
+import android.graphics.Rect
+import android.util.TypedValue
+import android.view.SurfaceControl
+import android.view.animation.Interpolator
+import android.window.TransitionInfo
+
+/** Creates animations that can be applied to windows/surfaces. */
+object WindowAnimator {
+
+ /** Parameters defining a window bounds animation. */
+ data class BoundsAnimationParams(
+ val durationMs: Long,
+ val startOffsetYDp: Float = 0f,
+ val endOffsetYDp: Float = 0f,
+ val startScale: Float = 1f,
+ val endScale: Float = 1f,
+ val interpolator: Interpolator,
+ )
+
+ /**
+ * Creates an animator to reposition and scale the bounds of the leash of the given change.
+ *
+ * @param boundsAnimDef the parameters for the animation itself (duration, scale, position)
+ * @param change the change to which the animation should be applied
+ * @param transaction the transaction to apply the animation to
+ */
+ fun createBoundsAnimator(
+ context: Context,
+ boundsAnimDef: BoundsAnimationParams,
+ change: TransitionInfo.Change,
+ transaction: SurfaceControl.Transaction,
+ ): ValueAnimator {
+ val startBounds =
+ createBounds(
+ context,
+ change.startAbsBounds,
+ boundsAnimDef.startScale,
+ boundsAnimDef.startOffsetYDp,
+ )
+ val leash = change.leash
+ val endBounds =
+ createBounds(
+ context,
+ change.startAbsBounds,
+ boundsAnimDef.endScale,
+ boundsAnimDef.endOffsetYDp,
+ )
+ return ValueAnimator.ofObject(RectEvaluator(), startBounds, endBounds).apply {
+ duration = boundsAnimDef.durationMs
+ interpolator = boundsAnimDef.interpolator
+ addUpdateListener { animation ->
+ val animBounds = animation.animatedValue as Rect
+ val animScale = 1 - (1 - boundsAnimDef.endScale) * animation.animatedFraction
+ transaction
+ .setPosition(leash, animBounds.left.toFloat(), animBounds.top.toFloat())
+ .setScale(leash, animScale, animScale)
+ .apply()
+ }
+ }
+ }
+
+ private fun createBounds(context: Context, origBounds: Rect, scale: Float, offsetYDp: Float) =
+ Rect(origBounds).apply {
+ check(scale in 0.0..1.0)
+ // Scale the bounds down with an anchor in the center
+ inset(
+ (origBounds.width().toFloat() * (1 - scale) / 2).toInt(),
+ (origBounds.height().toFloat() * (1 - scale) / 2).toInt(),
+ )
+ val offsetYPx =
+ TypedValue.applyDimension(
+ TypedValue.COMPLEX_UNIT_DIP,
+ offsetYDp,
+ context.resources.displayMetrics,
+ )
+ .toInt()
+ offset(/* dx= */ 0, offsetYPx)
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index 1c8a094c06..a80c11cc17 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import android.animation.Animator;
@@ -31,6 +32,7 @@ import androidx.annotation.Nullable;
import com.android.internal.jank.Cuj;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
+import com.android.launcher3.desktop.DesktopAppLaunchTransition;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer;
import com.android.launcher3.views.BaseDragLayer;
@@ -41,6 +43,7 @@ import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import com.android.systemui.shared.system.QuickStepContract;
+import com.android.window.flags.Flags;
import java.io.PrintWriter;
import java.util.List;
@@ -181,7 +184,7 @@ public class KeyboardQuickSwitchViewController {
Runnable onFinishCallback = () -> InteractionJankMonitorWrapper.end(
Cuj.CUJ_LAUNCHER_KEYBOARD_QUICK_SWITCH_APP_LAUNCH);
TaskbarActivityContext context = mControllers.taskbarActivityContext;
- RemoteTransition remoteTransition = new RemoteTransition(new SlideInRemoteTransition(
+ final RemoteTransition slideInTransition = new RemoteTransition(new SlideInRemoteTransition(
Utilities.isRtl(mControllers.taskbarActivityContext.getResources()),
context.getDeviceProfile().overviewPageSpacing,
QuickStepContract.getWindowCornerRadius(context),
@@ -195,7 +198,7 @@ public class KeyboardQuickSwitchViewController {
SystemUiProxy.INSTANCE.get(mKeyboardQuickSwitchView.getContext())
.showDesktopApps(
mKeyboardQuickSwitchView.getDisplay().getDisplayId(),
- remoteTransition));
+ slideInTransition));
return -1;
}
// Even with a valid index, this can be null if the user tries to quick switch before the
@@ -208,6 +211,13 @@ public class KeyboardQuickSwitchViewController {
// Ignore attempts to run the selected task if it is already running.
return -1;
}
+ RemoteTransition remoteTransition = slideInTransition;
+ if (mOnDesktop && task.task1.isMinimized
+ && Flags.enableDesktopAppLaunchAlttabTransitions()) {
+ // This app is being unminimized - use our own transition runner.
+ remoteTransition = new RemoteTransition(
+ new DesktopAppLaunchTransition(context, MAIN_EXECUTOR));
+ }
mControllers.taskbarActivityContext.handleGroupTaskLaunch(
task,
remoteTransition,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 1b9614a33a..12be99dc3d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -952,6 +952,12 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
* Hides the taskbar icons and background when the notification shade is expanded.
*/
private void onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim) {
+ // Close all floating views within the Taskbar window to make sure nothing is shown over
+ // the notification shade.
+ if (isExpanded) {
+ AbstractFloatingView.closeAllOpenViewsExcept(this, TYPE_TASKBAR_OVERLAY_PROXY);
+ }
+
float alpha = isExpanded ? 0 : 1;
AnimatorSet anim = new AnimatorSet();
anim.play(mControllers.taskbarViewController.getTaskbarIconAlpha().get(
@@ -1234,7 +1240,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
} else if (tag instanceof TaskItemInfo info) {
UI_HELPER_EXECUTOR.execute(() ->
- SystemUiProxy.INSTANCE.get(this).showDesktopApp(info.getTaskId()));
+ SystemUiProxy.INSTANCE.get(this).showDesktopApp(
+ info.getTaskId(), /* remoteTransition= */ null));
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(
/* stash= */ true);
} else if (tag instanceof WorkspaceItemInfo) {
@@ -1325,7 +1332,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
GroupTask task,
@Nullable RemoteTransition remoteTransition,
boolean onDesktop) {
- handleGroupTaskLaunch(task, remoteTransition, onDesktop, null, null);
+ handleGroupTaskLaunch(task, remoteTransition, onDesktop,
+ /* onStartCallback= */ null, /* onFinishCallback= */ null);
}
/**
@@ -1349,17 +1357,24 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
UI_HELPER_EXECUTOR.execute(() ->
SystemUiProxy.INSTANCE.get(this).showDesktopApps(getDisplay().getDisplayId(),
remoteTransition));
- } else if (onDesktop) {
+ return;
+ }
+ if (onDesktop) {
+ boolean useRemoteTransition = task.task1.isMinimized
+ && com.android.window.flags.Flags.enableDesktopAppLaunchAlttabTransitions();
UI_HELPER_EXECUTOR.execute(() -> {
if (onStartCallback != null) {
onStartCallback.run();
}
- SystemUiProxy.INSTANCE.get(this).showDesktopApp(task.task1.key.id);
+ SystemUiProxy.INSTANCE.get(this).showDesktopApp(
+ task.task1.key.id, useRemoteTransition ? remoteTransition : null);
if (onFinishCallback != null) {
onFinishCallback.run();
}
});
- } else if (task.task2 == null) {
+ return;
+ }
+ if (task.task2 == null) {
UI_HELPER_EXECUTOR.execute(() -> {
ActivityOptions activityOptions =
makeDefaultActivityOptions(SPLASH_SCREEN_STYLE_UNDEFINED).options;
@@ -1368,9 +1383,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
ActivityManagerWrapper.getInstance().startActivityFromRecents(
task.task1.key, activityOptions);
});
- } else {
- mControllers.uiController.launchSplitTasks(task, remoteTransition);
+ return;
}
+ mControllers.uiController.launchSplitTasks(task, remoteTransition);
}
/**
@@ -1547,6 +1562,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
/**
* Called when we want to unstash taskbar when user performs swipes up gesture.
+ *
* @param delayTaskbarBackground whether we will delay the taskbar background animation
*/
public void onSwipeToUnstashTaskbar(boolean delayTaskbarBackground) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 1141a01726..55722a9b62 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -151,30 +151,26 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
DisplayController.showLockedTaskbarOnHome(context)
) {
// adding the taskbar touch region
- val touchableHeight: Int
var left = 0
var right = context.deviceProfile.widthPx
- var bubbleBarAdjustment = 0
+ val touchableHeight: Int
if (uiController.isAnimatingToLauncher) {
val dp = controllers.taskbarActivityContext.deviceProfile
touchableHeight = windowLayoutParams.height
if (dp.isQsbInline) {
// if Qsb is inline need to exclude search icon from touch region
val isRtl = Utilities.isRtl(context.resources)
- bubbleControllers?.bubbleBarViewController?.let {
- if (dp.shouldAdjustHotseatOnBubblesLocationUpdate(context)) {
+ val navBarOffset =
+ bubbleControllers?.bubbleBarViewController?.let {
val isBubblesOnLeft = it.bubbleBarLocation.isOnLeft(isRtl)
- bubbleBarAdjustment =
- dp.getHotseatTranslationXForBubbleBar(isBubblesOnLeft, isRtl)
- }
- }
+ dp.getHotseatTranslationXForNavBar(context, isBubblesOnLeft)
+ } ?: 0
val hotseatPadding: Rect = dp.getHotseatLayoutPadding(context)
val borderSpacing: Int = dp.hotseatBorderSpace
if (isRtl) {
- right =
- dp.widthPx - hotseatPadding.right + borderSpacing + bubbleBarAdjustment
+ right = dp.widthPx - hotseatPadding.right + borderSpacing + navBarOffset
} else {
- left = hotseatPadding.left - borderSpacing + bubbleBarAdjustment
+ left = hotseatPadding.left - borderSpacing + navBarOffset
}
}
} else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 39aef28d45..4bc7d3c329 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -16,6 +16,7 @@
package com.android.launcher3.taskbar;
import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.app.animation.Interpolators.FINAL_FRAME;
import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_TASKBAR_ALIGNMENT;
import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_TASKBAR_STASH;
@@ -31,11 +32,8 @@ import static com.android.launcher3.taskbar.bubbles.BubbleBarView.FADE_IN_ANIM_A
import static com.android.launcher3.taskbar.bubbles.BubbleBarView.FADE_OUT_ANIM_POSITION_DURATION_MS;
import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
+import static com.android.quickstep.util.SystemUiFlagUtils.isTaskbarHidden;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_AWAKE;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK;
-import static com.android.systemui.shared.system.QuickStepContract.WAKEFULNESS_AWAKE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -380,16 +378,7 @@ public class TaskbarLauncherStateController {
updateStateForFlag(FLAG_DEVICE_LOCKED, SystemUiFlagUtils.isLocked(systemUiStateFlags));
- // Taskbar is hidden whenever the device is dreaming. The dreaming state includes the
- // interactive dreams, AoD, screen off. Since the SYSUI_STATE_DEVICE_DREAMING only kicks in
- // when the device is asleep, the second condition extends ensures that the transition from
- // and to the WAKEFULNESS_ASLEEP state also hide the taskbar, and improves the taskbar
- // hide/reveal animation timings. The Taskbar can show when dreaming if the glanceable hub
- // is showing on top.
- boolean isTaskbarHidden = (hasAnyFlag(systemUiStateFlags, SYSUI_STATE_DEVICE_DREAMING)
- && !hasAnyFlag(systemUiStateFlags, SYSUI_STATE_COMMUNAL_HUB_SHOWING))
- || (systemUiStateFlags & SYSUI_STATE_WAKEFULNESS_MASK) != WAKEFULNESS_AWAKE;
- updateStateForFlag(FLAG_TASKBAR_HIDDEN, isTaskbarHidden);
+ updateStateForFlag(FLAG_TASKBAR_HIDDEN, isTaskbarHidden(systemUiStateFlags));
if (applyState) {
applyState();
@@ -684,7 +673,11 @@ public class TaskbarLauncherStateController {
+ mIconAlignment.value
+ " -> " + toAlignment + ": " + duration);
}
- animatorSet.play(iconAlignAnim);
+ if (hasAnyFlag(FLAG_TASKBAR_HIDDEN)) {
+ iconAlignAnim.setInterpolator(FINAL_FRAME);
+ } else {
+ animatorSet.play(iconAlignAnim);
+ }
}
Interpolator interpolator = enableScalingRevealHomeAnimation()
@@ -893,19 +886,18 @@ public class TaskbarLauncherStateController {
mBubbleBarLocation = location;
if (location == null) {
// bubble bar is not present, hence no location, resetting the hotseat
- updateHotseatAndQsbTranslationX(0, animate);
+ updateHotseatAndQsbTranslationX(/* targetValue = */ 0, animate);
mBubbleBarLocation = null;
return;
}
DeviceProfile deviceProfile = mLauncher.getDeviceProfile();
- if (!deviceProfile.shouldAdjustHotseatOnBubblesLocationUpdate(
+ if (!deviceProfile.shouldAdjustHotseatOnNavBarLocationUpdate(
mControllers.taskbarActivityContext)) {
return;
}
- boolean isRtl = isRtl(mLauncher.getResources());
- boolean isBubblesOnLeft = location.isOnLeft(isRtl);
+ boolean isBubblesOnLeft = location.isOnLeft(isRtl(mLauncher.getResources()));
int targetX = deviceProfile
- .getHotseatTranslationXForBubbleBar(isBubblesOnLeft, isRtl);
+ .getHotseatTranslationXForNavBar(mLauncher, isBubblesOnLeft);
updateHotseatAndQsbTranslationX(targetX, animate);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
index 9c34ff0eb8..3e8b615b69 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -251,7 +251,7 @@ class TaskbarRecentAppsController(context: Context, private val recentsModel: Re
// Remove any newly-missing Tasks, and actual group-tasks
val newShownTasks =
shownTasks
- .filter { !it.hasMultipleTasks() }
+ .filter { !it.supportsMultipleTasks() }
.filter { it.task1.key.id in desktopTaskIds }
.toMutableList()
// Add any new Tasks, maintaining the order from previous shownTasks.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 8991965f61..b19da6b8e2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -30,6 +30,7 @@ import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
import static com.android.quickstep.util.SystemActionConstants.SYSTEM_ACTION_ID_TASKBAR;
+import static com.android.quickstep.util.SystemUiFlagUtils.isTaskbarHidden;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
@@ -104,6 +105,7 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
// An internal no-op flag to determine whether we should delay the taskbar background animation
private static final int FLAG_DELAY_TASKBAR_BG_TAG = 1 << 12;
public static final int FLAG_STASHED_FOR_BUBBLES = 1 << 13; // show handle for stashed hotseat
+ public static final int FLAG_TASKBAR_HIDDEN = 1 << 14; // taskbar hidden during dream, etc...
// If any of these flags are enabled, isInApp should return true.
private static final int FLAGS_IN_APP = FLAG_IN_APP | FLAG_IN_SETUP;
@@ -215,6 +217,13 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
*/
private static final int TRANSITION_UNSTASH_SUW_MANUAL = 3;
+ /**
+ * total duration of entering dream state animation, which we use as start delay to
+ * applyState() when SYSUI_STATE_DEVICE_DREAMING flag is present. Keep this in sync with
+ * DreamAnimationController.TOTAL_ANIM_DURATION.
+ */
+ private static final int SKIP_TOTAL_DREAM_ANIM_DURATION = 450;
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
TRANSITION_DEFAULT,
@@ -1123,7 +1132,13 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
startDelay = getTaskbarStashStartDelayForIme();
}
- applyState(skipAnim ? 0 : animDuration, skipAnim ? 0 : startDelay);
+ if (isTaskbarHidden(systemUiStateFlags) && !hasAnyFlag(FLAG_TASKBAR_HIDDEN)) {
+ updateStateForFlag(FLAG_TASKBAR_HIDDEN, isTaskbarHidden(systemUiStateFlags));
+ applyState(0, SKIP_TOTAL_DREAM_ANIM_DURATION);
+ } else {
+ updateStateForFlag(FLAG_TASKBAR_HIDDEN, isTaskbarHidden(systemUiStateFlags));
+ applyState(skipAnim ? 0 : animDuration, skipAnim ? 0 : startDelay);
+ }
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index f8adf8e247..d75718043b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -65,8 +65,8 @@ import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.IconButtonView;
-import com.android.quickstep.util.DesktopTask;
import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.views.TaskViewType;
import com.android.systemui.shared.recents.model.Task;
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
@@ -472,8 +472,8 @@ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconPar
// Replace any Recent views with the appropriate type if it's not already that type.
final int expectedLayoutResId;
boolean isCollection = false;
- if (task.hasMultipleTasks()) {
- if (task instanceof DesktopTask) {
+ if (task.supportsMultipleTasks()) {
+ if (task.taskViewType == TaskViewType.DESKTOP) {
// TODO(b/316004172): use Desktop tile layout.
expectedLayoutResId = -1;
} else {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index c275536b47..e9458ff5a5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -837,12 +837,11 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
int firstRecentTaskIndex = -1;
int hotseatNavBarTranslationX = 0;
- if (mCurrentBubbleBarLocation != null
- && taskbarDp.shouldAdjustHotseatOnBubblesLocationUpdate(mActivity)) {
- boolean isRtl = mTaskbarView.isLayoutRtl();
- boolean isBubblesOnLeft = mCurrentBubbleBarLocation.isOnLeft(isRtl);
+ if (mCurrentBubbleBarLocation != null) {
+ boolean isBubblesOnLeft = mCurrentBubbleBarLocation
+ .isOnLeft(mTaskbarView.isLayoutRtl());
hotseatNavBarTranslationX = taskbarDp
- .getHotseatTranslationXForBubbleBar(isBubblesOnLeft, isRtl);
+ .getHotseatTranslationXForNavBar(mActivity, isBubblesOnLeft);
}
for (int i = 0; i < mTaskbarView.getChildCount(); i++) {
View child = mTaskbarView.getChildAt(i);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index acdff71e61..4ad65e1be8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -1101,10 +1101,9 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer,
if (isBubbleBarEnabled()
&& enableBubbleBarInPersistentTaskBar()
&& mBubbleBarLocation != null) {
- boolean isRtl = isRtl(getResources());
- boolean isBubblesOnLeft = mBubbleBarLocation.isOnLeft(isRtl);
+ boolean isBubblesOnLeft = mBubbleBarLocation.isOnLeft(isRtl(getResources()));
translationX += mDeviceProfile
- .getHotseatTranslationXForBubbleBar(isBubblesOnLeft, isRtl);
+ .getHotseatTranslationXForNavBar(this, isBubblesOnLeft);
}
if (isBubbleBarEnabled()
&& mDeviceProfile.shouldAdjustHotseatForBubbleBar(getContext(), hasBubbles())) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapperImpl.java b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapperImpl.java
index 74572c4136..3aa196365b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapperImpl.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/plugins/PluginManagerWrapperImpl.java
@@ -27,6 +27,8 @@ import android.content.Intent;
import android.content.pm.ResolveInfo;
import com.android.launcher3.BuildConfig;
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.util.PluginManagerWrapper;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener;
@@ -34,7 +36,6 @@ import com.android.systemui.shared.plugins.PluginActionManager;
import com.android.systemui.shared.plugins.PluginInstance;
import com.android.systemui.shared.plugins.PluginManagerImpl;
import com.android.systemui.shared.plugins.PluginPrefs;
-import com.android.systemui.shared.system.UncaughtExceptionPreHandlerManager;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -42,16 +43,17 @@ import java.util.Collections;
import java.util.List;
import java.util.Set;
-public class PluginManagerWrapperImpl extends PluginManagerWrapper {
+import javax.inject.Inject;
- private static final UncaughtExceptionPreHandlerManager UNCAUGHT_EXCEPTION_PRE_HANDLER_MANAGER =
- new UncaughtExceptionPreHandlerManager();
+@LauncherAppSingleton
+public class PluginManagerWrapperImpl extends PluginManagerWrapper {
private final Context mContext;
private final PluginManagerImpl mPluginManager;
private final PluginEnablerImpl mPluginEnabler;
- public PluginManagerWrapperImpl(Context c) {
+ @Inject
+ public PluginManagerWrapperImpl(@ApplicationContext Context c) {
mContext = c;
mPluginEnabler = new PluginEnablerImpl(c);
List privilegedPlugins = Collections.emptyList();
@@ -64,9 +66,11 @@ public class PluginManagerWrapperImpl extends PluginManagerWrapper {
c.getSystemService(NotificationManager.class), mPluginEnabler,
privilegedPlugins, instanceFactory);
+ // Use null preHandlerManager, as the handler is never unregistered which can cause leaks
+ // when using multiple dagger graphs.
mPluginManager = new PluginManagerImpl(c, instanceManagerFactory,
BuildConfig.IS_DEBUG_DEVICE,
- UNCAUGHT_EXCEPTION_PRE_HANDLER_MANAGER, mPluginEnabler,
+ null /* preHandlerManager */, mPluginEnabler,
new PluginPrefs(c), privilegedPlugins);
}
diff --git a/quickstep/src/com/android/quickstep/GestureState.java b/quickstep/src/com/android/quickstep/GestureState.java
index 2892d2c913..015a449cc4 100644
--- a/quickstep/src/com/android/quickstep/GestureState.java
+++ b/quickstep/src/com/android/quickstep/GestureState.java
@@ -36,6 +36,7 @@ import android.view.RemoteAnimationTarget;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.launcher3.Flags;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulContainer;
import com.android.quickstep.TopTaskTracker.CachedTaskInfo;
@@ -301,6 +302,16 @@ public class GestureState implements RecentsAnimationCallbacks.RecentsAnimationL
return mTrackpadGestureType == TrackpadGestureType.FOUR_FINGER;
}
+ /**
+ * Requests that handling for this gesture should use a synthetic transition, as in that it
+ * will need to start a recents transition that is not backed by a system transition. This is
+ * generally only needed in scenarios where a system transition can not be created due to no
+ * changes in the WM hierarchy (ie. starting recents transition when you are already over home).
+ */
+ public boolean useSyntheticRecentsTransition() {
+ return mRunningTask.isHomeTask() && Flags.enableFallbackOverviewInWindow();
+ }
+
/**
* @return the running task for this gesture.
*/
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
index fc11812f0e..7d5bd377d0 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationCallbacks.java
@@ -15,7 +15,9 @@
*/
package com.android.quickstep;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -29,6 +31,7 @@ import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
import androidx.annotation.UiThread;
+import com.android.launcher3.Flags;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.Preconditions;
import com.android.quickstep.util.ActiveGestureProtoLogProxy;
@@ -102,7 +105,11 @@ public class RecentsAnimationCallbacks implements
long appCount = Arrays.stream(appTargets)
.filter(app -> app.mode == MODE_CLOSING)
.count();
- if (appCount == 0) {
+
+ boolean isOpeningHome = Arrays.stream(appTargets).filter(app -> app.mode == MODE_OPENING
+ && app.windowConfiguration.getActivityType() == ACTIVITY_TYPE_HOME)
+ .count() > 0;
+ if (appCount == 0 && (!Flags.enableFallbackOverviewInWindow() || isOpeningHome)) {
ActiveGestureProtoLogProxy.logOnRecentsAnimationStartCancelled();
// Edge case, if there are no closing app targets, then Launcher has nothing to handle
notifyAnimationCanceled();
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index c66813fe8b..c1d7ffa7e0 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -1426,10 +1426,10 @@ public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
/**
* If task with the given id is on the desktop, bring it to front
*/
- public void showDesktopApp(int taskId) {
+ public void showDesktopApp(int taskId, @Nullable RemoteTransition transition) {
if (mDesktopMode != null) {
try {
- mDesktopMode.showDesktopApp(taskId);
+ mDesktopMode.showDesktopApp(taskId, transition);
} catch (RemoteException e) {
Log.w(TAG, "Failed call showDesktopApp", e);
}
@@ -1535,7 +1535,7 @@ public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
* Starts the recents activity. The caller should manage the thread on which this is called.
*/
public boolean startRecentsActivity(Intent intent, ActivityOptions options,
- RecentsAnimationListener listener) {
+ RecentsAnimationListener listener, boolean useSyntheticRecentsTransition) {
if (mRecentTasks == null) {
ActiveGestureProtoLogProxy.logRecentTasksMissing();
return false;
@@ -1566,6 +1566,9 @@ public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
}
};
final Bundle optsBundle = options.toBundle();
+ if (useSyntheticRecentsTransition) {
+ optsBundle.putBoolean("is_synthetic_recents_transition", true);
+ }
try {
mRecentTasks.startRecentsTransition(mRecentsPendingIntent, intent, optsBundle,
mContext.getIApplicationThread(), runner);
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index bda292af01..56c978a318 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -296,8 +296,8 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
// TODO:(b/365777482) if flag is enabled, but on launcher it will crash.
if(containerInterface.getCreatedContainer() instanceof RecentsWindowManager
&& Flags.enableFallbackOverviewInWindow()){
- mRecentsAnimationStartPending =
- getSystemUiProxy().startRecentsActivity(intent, options, mCallbacks);
+ mRecentsAnimationStartPending = getSystemUiProxy().startRecentsActivity(intent, options,
+ mCallbacks, gestureState.useSyntheticRecentsTransition());
mRecentsWindowsManager.startRecentsWindow(mCallbacks);
} else {
options.setPendingIntentBackgroundActivityStartMode(
@@ -326,9 +326,10 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn
});
}
- mRecentsAnimationStartPending = getSystemUiProxy()
- .startRecentsActivity(intent, options, mCallbacks);
+ mRecentsAnimationStartPending = getSystemUiProxy().startRecentsActivity(intent,
+ options, mCallbacks, false /* useSyntheticRecentsTransition */);
}
+
if (enableHandleDelayedGestureCallbacks()) {
ActiveGestureProtoLogProxy.logSettingRecentsAnimationStartPending(
mRecentsAnimationStartPending);
diff --git a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
index 08345b85f6..ab77a7f62c 100644
--- a/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
+++ b/quickstep/src/com/android/quickstep/dagger/QuickStepModule.java
@@ -15,8 +15,14 @@
*/
package com.android.quickstep.dagger;
+import com.android.launcher3.uioverrides.plugins.PluginManagerWrapperImpl;
+import com.android.launcher3.util.PluginManagerWrapper;
+
+import dagger.Binds;
import dagger.Module;
@Module
-public class QuickStepModule {
+public abstract class QuickStepModule {
+
+ @Binds abstract PluginManagerWrapper bindPluginManagerWrapper(PluginManagerWrapperImpl impl);
}
diff --git a/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
index 335161b24c..e82d9fcd1b 100644
--- a/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
+++ b/quickstep/src/com/android/quickstep/dagger/QuickstepBaseAppComponent.java
@@ -19,7 +19,6 @@ package com.android.quickstep.dagger;
import com.android.launcher3.dagger.LauncherAppComponent;
import com.android.launcher3.dagger.LauncherBaseAppComponent;
import com.android.launcher3.model.WellbeingModel;
-import com.android.quickstep.logging.SettingsChangeLogger;
import com.android.quickstep.util.AsyncClockEventDelegate;
import com.android.quickstep.util.ContextualSearchHapticManager;
@@ -32,7 +31,6 @@ import com.android.quickstep.util.ContextualSearchHapticManager;
* See {@link LauncherAppComponent} for the one actually used.
*/
public interface QuickstepBaseAppComponent extends LauncherBaseAppComponent {
- SettingsChangeLogger getSettingsChangeLogger();
WellbeingModel getWellbeingModel();
diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
index 995635fa6c..dd721e16f6 100644
--- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
+++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
@@ -44,20 +44,16 @@ import androidx.annotation.VisibleForTesting;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.dagger.ApplicationContext;
-import com.android.launcher3.dagger.LauncherAppSingleton;
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
import com.android.launcher3.model.DeviceGridState;
-import com.android.launcher3.util.DaggerSingletonObject;
-import com.android.launcher3.util.DaggerSingletonTracker;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
-import com.android.launcher3.util.ExecutorUtil;
+import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.SettingsCache;
-import com.android.quickstep.dagger.QuickstepBaseAppComponent;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -65,12 +61,9 @@ import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.Optional;
-import javax.inject.Inject;
-
/**
* Utility class to log launcher settings changes
*/
-@LauncherAppSingleton
public class SettingsChangeLogger implements
DisplayController.DisplayInfoChangeListener, OnSharedPreferenceChangeListener,
SafeCloseable {
@@ -78,8 +71,8 @@ public class SettingsChangeLogger implements
/**
* Singleton instance
*/
- public static DaggerSingletonObject INSTANCE =
- new DaggerSingletonObject<>(QuickstepBaseAppComponent::getSettingsChangeLogger);
+ public static MainThreadInitializedObject INSTANCE =
+ new MainThreadInitializedObject<>(SettingsChangeLogger::new);
private static final String TAG = "SettingsChangeLogger";
private static final String BOOLEAN_PREF = "SwitchPreference";
@@ -92,31 +85,26 @@ public class SettingsChangeLogger implements
private StatsLogManager.LauncherEvent mNotificationDotsEvent;
private StatsLogManager.LauncherEvent mHomeScreenSuggestionEvent;
- @Inject
- SettingsChangeLogger(@ApplicationContext Context context, DaggerSingletonTracker tracker) {
- this(context, StatsLogManager.newInstance(context), tracker);
+ SettingsChangeLogger(@ApplicationContext Context context) {
+ this(context, StatsLogManager.newInstance(context));
}
@VisibleForTesting
- SettingsChangeLogger(Context context, StatsLogManager statsLogManager,
- DaggerSingletonTracker tracker) {
+ SettingsChangeLogger(Context context, StatsLogManager statsLogManager) {
mContext = context;
mStatsLogManager = statsLogManager;
mLoggablePrefs = loadPrefKeys(context);
- ExecutorUtil.executeSyncOnMainOrFail(() -> {
- DisplayController.INSTANCE.get(context).addChangeListener(this);
- mNavMode = DisplayController.getNavigationMode(context);
+ DisplayController.INSTANCE.get(context).addChangeListener(this);
+ mNavMode = DisplayController.getNavigationMode(context);
- getPrefs(context).registerOnSharedPreferenceChangeListener(this);
- getDevicePrefs(context).registerOnSharedPreferenceChangeListener(this);
+ getPrefs(context).registerOnSharedPreferenceChangeListener(this);
+ getDevicePrefs(context).registerOnSharedPreferenceChangeListener(this);
- SettingsCache settingsCache = SettingsCache.INSTANCE.get(context);
- settingsCache.register(NOTIFICATION_BADGING_URI,
- this::onNotificationDotsChanged);
- onNotificationDotsChanged(settingsCache.getValue(NOTIFICATION_BADGING_URI));
- tracker.addCloseable(this);
- });
+ SettingsCache settingsCache = SettingsCache.INSTANCE.get(context);
+ settingsCache.register(NOTIFICATION_BADGING_URI,
+ this::onNotificationDotsChanged);
+ onNotificationDotsChanged(settingsCache.getValue(NOTIFICATION_BADGING_URI));
}
private static ArrayMap loadPrefKeys(Context context) {
@@ -223,8 +211,6 @@ public class SettingsChangeLogger implements
public void close() {
getPrefs(mContext).unregisterOnSharedPreferenceChangeListener(this);
getDevicePrefs(mContext).unregisterOnSharedPreferenceChangeListener(this);
- SettingsCache settingsCache = SettingsCache.INSTANCE.get(mContext);
- settingsCache.unregister(NOTIFICATION_BADGING_URI, this::onNotificationDotsChanged);
}
@VisibleForTesting
diff --git a/quickstep/src/com/android/quickstep/util/DesktopTask.java b/quickstep/src/com/android/quickstep/util/DesktopTask.java
index a727aa2efb..fc4fc4df78 100644
--- a/quickstep/src/com/android/quickstep/util/DesktopTask.java
+++ b/quickstep/src/com/android/quickstep/util/DesktopTask.java
@@ -50,6 +50,11 @@ public class DesktopTask extends GroupTask {
@Override
public boolean hasMultipleTasks() {
+ return tasks.size() > 1;
+ }
+
+ @Override
+ public boolean supportsMultipleTasks() {
return true;
}
diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.java b/quickstep/src/com/android/quickstep/util/GroupTask.java
index fba08a96b2..7aeeb2fc32 100644
--- a/quickstep/src/com/android/quickstep/util/GroupTask.java
+++ b/quickstep/src/com/android/quickstep/util/GroupTask.java
@@ -65,6 +65,13 @@ public class GroupTask {
return task2 != null;
}
+ /**
+ * Returns whether this task supports multiple tasks or not.
+ */
+ public boolean supportsMultipleTasks() {
+ return taskViewType == TaskViewType.GROUPED;
+ }
+
/**
* Returns a List of all the Tasks in this GroupTask
*/
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 511c989928..ea582c493f 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -900,7 +900,7 @@ public class SplitSelectStateController {
SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext())
.startRecentsActivity(
mOverviewComponentObserver.getOverviewIntent(), options,
- callbacks);
+ callbacks, false /* useSyntheticRecentsTransition */);
});
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
index 4c6e4ff359..744c08cc3c 100644
--- a/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitWithKeyboardShortcutController.java
@@ -99,7 +99,8 @@ public class SplitWithKeyboardShortcutController {
options.setTransientLaunch();
SystemUiProxy.INSTANCE.get(mLauncher.getApplicationContext())
.startRecentsActivity(mOverviewComponentObserver.getOverviewIntent(),
- ActivityOptions.makeBasic(), callbacks);
+ ActivityOptions.makeBasic(), callbacks,
+ false /* useSyntheticRecentsTransition */);
});
});
}
diff --git a/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt b/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt
index 5f4388c918..1ff05dae56 100644
--- a/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt
+++ b/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt
@@ -47,6 +47,22 @@ object SystemUiFlagUtils {
!hasAnyFlag(flags, QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY)
}
+ /**
+ * Taskbar is hidden whenever the device is dreaming. The dreaming state includes the
+ * interactive dreams, AoD, screen off. Since the SYSUI_STATE_DEVICE_DREAMING only kicks in when
+ * the device is asleep, the second condition extends ensures that the transition from and to
+ * the WAKEFULNESS_ASLEEP state also hide the taskbar, and improves the taskbar hide/reveal
+ * animation timings. The Taskbar can show when dreaming if the glanceable hub is showing on
+ * top.
+ */
+ @JvmStatic
+ fun isTaskbarHidden(@SystemUiStateFlags flags: Long): Boolean {
+ return ((hasAnyFlag(flags, QuickStepContract.SYSUI_STATE_DEVICE_DREAMING) &&
+ !hasAnyFlag(flags, QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING)) ||
+ (flags and QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK) !=
+ QuickStepContract.WAKEFULNESS_AWAKE)
+ }
+
private fun hasAnyFlag(@SystemUiStateFlags flags: Long, flagMask: Long): Boolean {
return (flags and flagMask) != 0L
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index bccfa0c756..b18af65ece 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1885,19 +1885,22 @@ public abstract class RecentsView<
// taskGroups backwards populates the thumbnail grid from least recent to most recent.
for (int i = taskGroups.size() - 1; i >= 0; i--) {
GroupTask groupTask = taskGroups.get(i);
- boolean isRemovalNeeded = stagedTaskIdToBeRemoved != INVALID_TASK_ID
+ boolean containsStagedTask = stagedTaskIdToBeRemoved != INVALID_TASK_ID
&& groupTask.containsTask(stagedTaskIdToBeRemoved);
+ boolean shouldSkipGroupTask = containsStagedTask && !groupTask.hasMultipleTasks();
- if (isRemovalNeeded && !groupTask.hasMultipleTasks()) {
- // If the task we need to remove is not part of a pair, avoiding creating the
- // TaskView.
+ if ((isSplitSelectionActive() && groupTask.taskViewType == TaskViewType.DESKTOP)
+ || shouldSkipGroupTask) {
+ // To avoid these tasks from being chosen as the app pair, the creation of a
+ // TaskView is bypassed. The staged task is already selected for the app pair,
+ // and the Desktop task should be hidden when selecting a pair.
continue;
}
// If we need to remove half of a pair of tasks, force a TaskView with Type.SINGLE
// to be a temporary container for the remaining task.
TaskView taskView = getTaskViewFromPool(
- isRemovalNeeded ? TaskViewType.SINGLE : groupTask.taskViewType);
+ containsStagedTask ? TaskViewType.SINGLE : groupTask.taskViewType);
if (taskView instanceof GroupedTaskView) {
boolean firstTaskIsLeftTopTask =
groupTask.mSplitBounds.leftTopTaskId == groupTask.task1.key.id;
@@ -5572,15 +5575,13 @@ public abstract class RecentsView<
remoteTargetHandle -> remoteTargetHandle.getTaskViewSimulator()
.addOverviewToAppAnim(mPendingAnimation, interpolator));
mPendingAnimation.addOnFrameCallback(this::redrawLiveTile);
- if (taskView instanceof DesktopTaskView && mRemoteTargetHandles != null) {
- mPendingAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- runActionOnRemoteHandles(remoteTargetHandle ->
- remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false));
- }
- });
- }
+ mPendingAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false));
+ }
+ });
mPendingAnimation.addEndListener(isSuccess -> {
if (isSuccess) {
if (taskView instanceof GroupedTaskView && hasAllValidTaskIds(taskView.getTaskIds())
@@ -5612,6 +5613,13 @@ public abstract class RecentsView<
protected Unit onTaskLaunchAnimationEnd(boolean success) {
if (success) {
resetTaskVisuals();
+ } else {
+ // If launch animation didn't complete i.e. user dragged live tile down and then
+ // back up and returned to Overview, then we need to ensure we reset the
+ // view to draw below recents so that it can't be interacted with.
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(true));
+ redrawLiveTile();
}
return Unit.INSTANCE;
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
index 0a607744d0..7c48ea489c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
@@ -34,7 +34,6 @@ import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVI
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_ENABLED
import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_DISABLED
import com.android.launcher3.states.RotationHelper.ALLOW_ROTATION_PREFERENCE_KEY
-import com.android.launcher3.util.DaggerSingletonTracker
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -63,7 +62,6 @@ class SettingsChangeLoggerTest {
@Mock private lateinit var mMockLogger: StatsLogManager.StatsLogger
@Captor private lateinit var mEventCaptor: ArgumentCaptor
- @Mock private lateinit var mTracker: DaggerSingletonTracker
private var mDefaultThemedIcons = false
private var mDefaultAllowRotation = false
@@ -81,7 +79,7 @@ class SettingsChangeLoggerTest {
// To match the default value of ALLOW_ROTATION
LauncherPrefs.get(mContext).put(item = ALLOW_ROTATION, value = false)
- mSystemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager, mTracker)
+ mSystemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager)
}
@After
@@ -92,7 +90,7 @@ class SettingsChangeLoggerTest {
@Test
fun loggingPrefs_correctDefaultValue() {
- val systemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager, mTracker)
+ val systemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager)
assertThat(systemUnderTest.loggingPrefs[ALLOW_ROTATION_PREFERENCE_KEY]!!.defaultValue)
.isFalse()
@@ -119,7 +117,7 @@ class SettingsChangeLoggerTest {
LauncherPrefs.get(mContext).put(item = ALLOW_ROTATION, value = true)
// This a new object so the values of mLoggablePrefs will be different
- SettingsChangeLogger(mContext, mStatsLogManager, mTracker).logSnapshot(mInstanceId)
+ SettingsChangeLogger(mContext, mStatsLogManager).logSnapshot(mInstanceId)
verify(mMockLogger, atLeastOnce()).log(mEventCaptor.capture())
val capturedEvents = mEventCaptor.allValues
diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
index 800fd4aa93..b15b78e305 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -56,8 +56,6 @@ public class TaplPrivateSpaceTest extends AbstractQuickStepTest {
@Override
public void setUp() throws Exception {
super.setUp();
- initialize(this);
-
createAndStartPrivateProfileUser();
mDevice.pressHome();
diff --git a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
index ec07b9310e..633a5756c2 100644
--- a/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaskAnimationManagerTest.java
@@ -17,8 +17,8 @@
package com.android.quickstep;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -73,7 +73,8 @@ public class TaskAnimationManagerTest {
final ArgumentCaptor optionsCaptor =
ArgumentCaptor.forClass(ActivityOptions.class);
- verify(mSystemUiProxy).startRecentsActivity(any(), optionsCaptor.capture(), any());
+ verify(mSystemUiProxy)
+ .startRecentsActivity(any(), optionsCaptor.capture(), any(), anyBoolean());
assertEquals(ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOW_ALWAYS,
optionsCaptor.getValue().getPendingIntentBackgroundActivityStartMode());
}
diff --git a/quickstep/tests/src/com/android/quickstep/desktop/WindowAnimatorTest.kt b/quickstep/tests/src/com/android/quickstep/desktop/WindowAnimatorTest.kt
new file mode 100644
index 0000000000..e5e6df3b1e
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/desktop/WindowAnimatorTest.kt
@@ -0,0 +1,139 @@
+/*
+ * 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.desktop
+
+import android.animation.ValueAnimator
+import android.content.Context
+import android.content.res.Resources
+import android.graphics.Rect
+import android.util.DisplayMetrics
+import android.view.SurfaceControl
+import android.window.TransitionInfo
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.internal.runner.junit4.statement.UiThreadStatement.runOnUiThread
+import com.android.app.animation.Interpolators
+import com.android.launcher3.desktop.WindowAnimator
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.ArgumentMatchers.anyFloat
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class WindowAnimatorTest {
+
+ private val context = mock()
+ private val resources = mock()
+ private val transaction = mock()
+ private val change = mock()
+ private val leash = mock()
+
+ private val displayMetrics = DisplayMetrics().apply { density = 1f }
+
+ @Before
+ fun setup() {
+ whenever(context.resources).thenReturn(resources)
+ whenever(resources.displayMetrics).thenReturn(displayMetrics)
+ whenever(change.leash).thenReturn(leash)
+ whenever(change.startAbsBounds).thenReturn(START_BOUNDS)
+ whenever(transaction.setPosition(any(), anyFloat(), anyFloat())).thenReturn(transaction)
+ whenever(transaction.setScale(any(), anyFloat(), anyFloat())).thenReturn(transaction)
+ }
+
+ @Test
+ fun createBoundsAnimator_returnsCorrectDefaultAnimatorParams() = runOnUiThread {
+ val boundsAnimParams =
+ WindowAnimator.BoundsAnimationParams(
+ durationMs = 100L,
+ interpolator = Interpolators.STANDARD_ACCELERATE,
+ )
+
+ val valueAnimator =
+ WindowAnimator.createBoundsAnimator(context, boundsAnimParams, change, transaction)
+
+ assertThat(valueAnimator.duration).isEqualTo(100L)
+ assertThat(valueAnimator.interpolator).isEqualTo(Interpolators.STANDARD_ACCELERATE)
+ assertStartAndEndBounds(valueAnimator, startBounds = START_BOUNDS, endBounds = START_BOUNDS)
+ }
+
+ @Test
+ fun createBoundsAnimator_startScaleAndOffset_returnsCorrectBounds() = runOnUiThread {
+ val bounds = Rect(/* left= */ 100, /* top= */ 200, /* right= */ 300, /* bottom= */ 400)
+ whenever(change.startAbsBounds).thenReturn(bounds)
+ val boundsAnimParams =
+ WindowAnimator.BoundsAnimationParams(
+ durationMs = 100L,
+ startOffsetYDp = 10f,
+ startScale = 0.5f,
+ interpolator = Interpolators.STANDARD_ACCELERATE,
+ )
+
+ val valueAnimator =
+ WindowAnimator.createBoundsAnimator(context, boundsAnimParams, change, transaction)
+
+ assertStartAndEndBounds(
+ valueAnimator,
+ startBounds =
+ Rect(/* left= */ 150, /* top= */ 260, /* right= */ 250, /* bottom= */ 360),
+ endBounds = bounds,
+ )
+ }
+
+ @Test
+ fun createBoundsAnimator_endScaleAndOffset_returnsCorrectBounds() = runOnUiThread {
+ val bounds = Rect(/* left= */ 100, /* top= */ 200, /* right= */ 300, /* bottom= */ 400)
+ whenever(change.startAbsBounds).thenReturn(bounds)
+ val boundsAnimParams =
+ WindowAnimator.BoundsAnimationParams(
+ durationMs = 100L,
+ endOffsetYDp = 10f,
+ endScale = 0.5f,
+ interpolator = Interpolators.STANDARD_ACCELERATE,
+ )
+
+ val valueAnimator =
+ WindowAnimator.createBoundsAnimator(context, boundsAnimParams, change, transaction)
+
+ assertStartAndEndBounds(
+ valueAnimator,
+ startBounds = bounds,
+ endBounds = Rect(/* left= */ 150, /* top= */ 260, /* right= */ 250, /* bottom= */ 360),
+ )
+ }
+
+ private fun assertStartAndEndBounds(
+ valueAnimator: ValueAnimator,
+ startBounds: Rect,
+ endBounds: Rect,
+ ) {
+ valueAnimator.start()
+ valueAnimator.animatedValue
+ assertThat(valueAnimator.animatedValue).isEqualTo(startBounds)
+ valueAnimator.end()
+ assertThat(valueAnimator.animatedValue).isEqualTo(endBounds)
+ }
+
+ companion object {
+ private val START_BOUNDS =
+ Rect(/* left= */ 10, /* top= */ 20, /* right= */ 30, /* bottom= */ 40)
+ }
+}
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 9211e7640d..0d78d9032d 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -174,7 +174,7 @@
"Genveje"
"Afvis"
"Luk"
- "Personlige"
+ "Personlig"
"Arbejde"
"Arbejdsprofil"
"Arbejdsapps har badges og kan ses af din it-administrator"
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 0c46eb43e5..786cea1e58 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
"Launcher3"
"ಕೆಲಸ"
- "ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"
+ "ಆ್ಯಪ್ ಅನ್ನು ಸ್ಥಾಪಿಸಲಾಗಿಲ್ಲ"
"ಅಪ್ಲಿಕೇಶನ್ ಲಭ್ಯವಿಲ್ಲ"
"ಡೌನ್ಲೋಡ್ ಮಾಡಲಾದ ಅಪ್ಲಿಕೇಶನ್ ಅನ್ನು ಸುರಕ್ಷಿತ ಮೋಡ್ನಲ್ಲಿ ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"
"ಸುರಕ್ಷಿತ ಮೋಡ್ನಲ್ಲಿ ವಿಜೆಟ್ಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"
@@ -103,7 +103,7 @@
"ವಿಜೆಟ್ ಅನ್ನು ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"
"ವಿಜೆಟ್ ಸೆಟ್ಟಿಂಗ್ಗಳು"
"ಸೆಟಪ್ ಪೂರ್ಣಗೊಳಿಸಲು ಟ್ಯಾಪ್ ಮಾಡಿ"
- "ಇದೊಂದು ಅಪ್ಲಿಕೇಶನ್ ಆಗಿದೆ ಮತ್ತು ಅಸ್ಥಾಪಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."
+ "ಇದೊಂದು ಆ್ಯಪ್ ಆಗಿದೆ ಮತ್ತು ಅಸ್ಥಾಪಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ."
"ಹೆಸರನ್ನು ಎಡಿಟ್ ಮಾಡಿ"
"%1$s ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"
"{count,plural, =1{{app_name} ಆ್ಯಪ್ # ಅಧಿಸೂಚನೆಯನ್ನು ಹೊಂದಿದೆ}one{{app_name} ಆ್ಯಪ್ # ಅಧಿಸೂಚನೆಗಳನ್ನು ಹೊಂದಿದೆ}other{{app_name} ಆ್ಯಪ್ # ಅಧಿಸೂಚನೆಗಳನ್ನು ಹೊಂದಿದೆ}}"
diff --git a/res/values/config.xml b/res/values/config.xml
index 701e64a4b4..504218b78e 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -85,7 +85,6 @@
-
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index afe0ee1967..886255094f 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -2355,18 +2355,23 @@ public class DeviceProfile {
/**
* Returns whether Taskbar and Hotseat should adjust horizontally on bubble bar location update.
*/
- public boolean shouldAdjustHotseatOnBubblesLocationUpdate(Context context) {
+ public boolean shouldAdjustHotseatOnNavBarLocationUpdate(Context context) {
return enableBubbleBar()
&& enableBubbleBarInPersistentTaskBar()
&& !DisplayController.getNavigationMode(context).hasGestures;
}
/** Returns hotseat translation X for the bubble bar position. */
- public int getHotseatTranslationXForBubbleBar(boolean isNavbarOnRight, boolean isRtl) {
- if (isNavbarOnRight) {
- return isRtl ? -navButtonsLayoutWidthPx : 0;
+ public int getHotseatTranslationXForNavBar(Context context, boolean isBubblesOnLeft) {
+ if (shouldAdjustHotseatOnNavBarLocationUpdate(context)) {
+ boolean isRtl = Utilities.isRtl(context.getResources());
+ if (isBubblesOnLeft) {
+ return isRtl ? -navButtonsLayoutWidthPx : 0;
+ } else {
+ return isRtl ? 0 : navButtonsLayoutWidthPx;
+ }
} else {
- return isRtl ? 0 : navButtonsLayoutWidthPx;
+ return 0;
}
}
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 6a401215f1..9c36dc2751 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -474,7 +474,8 @@ public class PrivateProfileManager extends UserProfileManager {
break;
}
// Make the private space apps gone to "collapse".
- if (mFloatingMaskView == null && isPrivateSpaceItem(currentItem)) {
+ if ((mFloatingMaskView == null && isPrivateSpaceItem(currentItem)) ||
+ currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER) {
RecyclerView.ViewHolder viewHolder =
allAppsRecyclerView.findViewHolderForAdapterPosition(i);
if (viewHolder != null) {
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index c3508b77db..4da7c2716a 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -20,6 +20,7 @@ import android.content.Context;
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.util.DaggerSingletonTracker;
+import com.android.launcher3.util.PluginManagerWrapper;
import com.android.launcher3.util.ScreenOnTracker;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.widget.custom.CustomWidgetManager;
@@ -40,6 +41,7 @@ public interface LauncherBaseAppComponent {
ScreenOnTracker getScreenOnTracker();
SettingsCache getSettingsCache();
CustomWidgetManager getCustomWidgetManager();
+ PluginManagerWrapper getPluginManagerWrapper();
/** Builder for LauncherBaseAppComponent. */
interface Builder {
diff --git a/src/com/android/launcher3/util/PluginManagerWrapper.java b/src/com/android/launcher3/util/PluginManagerWrapper.java
index b27aa120b9..5b28570acb 100644
--- a/src/com/android/launcher3/util/PluginManagerWrapper.java
+++ b/src/com/android/launcher3/util/PluginManagerWrapper.java
@@ -15,32 +15,39 @@
*/
package com.android.launcher3.util;
-import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
+import androidx.annotation.AnyThread;
-import com.android.launcher3.R;
+import com.android.launcher3.dagger.LauncherAppSingleton;
+import com.android.launcher3.dagger.LauncherBaseAppComponent;
import com.android.systemui.plugins.Plugin;
import com.android.systemui.plugins.PluginListener;
import java.io.PrintWriter;
-public class PluginManagerWrapper implements ResourceBasedOverride, SafeCloseable {
+import javax.inject.Inject;
- public static final MainThreadInitializedObject INSTANCE =
- forOverride(PluginManagerWrapper.class, R.string.plugin_manager_wrapper_class);
+@LauncherAppSingleton
+public class PluginManagerWrapper{
+ public static final DaggerSingletonObject INSTANCE =
+ new DaggerSingletonObject<>(LauncherBaseAppComponent::getPluginManagerWrapper);
+
+ @Inject
+ public PluginManagerWrapper() { }
+
+ @AnyThread
public void addPluginListener(
PluginListener listener, Class pluginClass) {
addPluginListener(listener, pluginClass, false);
}
+ @AnyThread
public void addPluginListener(
PluginListener listener, Class pluginClass, boolean allowMultiple) {
}
+ @AnyThread
public void removePluginListener(PluginListener extends Plugin> listener) { }
- @Override
- public void close() { }
-
public void dump(PrintWriter pw) { }
}
diff --git a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
index 0778172127..4aeac7639a 100644
--- a/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
+++ b/src/com/android/launcher3/widget/custom/CustomWidgetManager.java
@@ -41,7 +41,6 @@ import com.android.launcher3.util.DaggerSingletonTracker;
import com.android.launcher3.util.ExecutorUtil;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.PluginManagerWrapper;
-import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.systemui.plugins.CustomWidgetPlugin;
@@ -61,7 +60,7 @@ import javax.inject.Inject;
* CustomWidgetManager handles custom widgets implemented as a plugin.
*/
@LauncherAppSingleton
-public class CustomWidgetManager implements PluginListener, SafeCloseable {
+public class CustomWidgetManager implements PluginListener {
public static final DaggerSingletonObject INSTANCE =
new DaggerSingletonObject<>(LauncherBaseAppComponent::getCustomWidgetManager);
@@ -75,12 +74,14 @@ public class CustomWidgetManager implements PluginListener,
private final @NonNull AppWidgetManager mAppWidgetManager;
@Inject
- CustomWidgetManager(@ApplicationContext Context context, DaggerSingletonTracker tracker) {
- this(context, AppWidgetManager.getInstance(context), tracker);
+ CustomWidgetManager(@ApplicationContext Context context, PluginManagerWrapper pluginManager,
+ DaggerSingletonTracker tracker) {
+ this(context, pluginManager, AppWidgetManager.getInstance(context), tracker);
}
@VisibleForTesting
CustomWidgetManager(@ApplicationContext Context context,
+ PluginManagerWrapper pluginManager,
@NonNull AppWidgetManager widgetManager,
DaggerSingletonTracker tracker) {
mContext = context;
@@ -88,11 +89,9 @@ public class CustomWidgetManager implements PluginListener,
mPlugins = new HashMap<>();
mCustomWidgets = new ArrayList<>();
+ pluginManager.addPluginListener(this, CustomWidgetPlugin.class, true);
ExecutorUtil.executeSyncOnMainOrFail(() -> {
- PluginManagerWrapper.INSTANCE.get(context)
- .addPluginListener(this, CustomWidgetPlugin.class, true);
-
if (enableSmartspaceAsAWidget()) {
for (String s: context.getResources()
.getStringArray(R.array.custom_widget_providers)) {
@@ -110,15 +109,10 @@ public class CustomWidgetManager implements PluginListener,
}
}
- tracker.addCloseable(this);
+ tracker.addCloseable(() -> pluginManager.removePluginListener(this));
});
}
- @Override
- public void close() {
- PluginManagerWrapper.INSTANCE.get(mContext).removePluginListener(this);
- }
-
@Override
public void onPluginConnected(CustomWidgetPlugin plugin, Context context) {
List providers = mAppWidgetManager
diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index 4e9143e050..825b52b5fb 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -167,7 +167,6 @@ public final class TestProtocol {
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
public static final String ICON_MISSING = "b/282963545";
- public static final String WIDGET_CONFIG_NULL_EXTRA_INTENT = "b/324419890";
public static final String REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW = "enable-grid-only-overview";
public static final String REQUEST_FLAG_ENABLE_APP_PAIRS = "enable-app-pairs";
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/custom/CustomWidgetManagerTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/custom/CustomWidgetManagerTest.kt
index 82f56b8c2e..1c25db92be 100644
--- a/tests/multivalentTests/src/com/android/launcher3/widget/custom/CustomWidgetManagerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/custom/CustomWidgetManagerTest.kt
@@ -26,17 +26,19 @@ import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.util.DaggerSingletonTracker
import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
import com.android.launcher3.util.PluginManagerWrapper
+import com.android.launcher3.util.SafeCloseable
import com.android.launcher3.util.WidgetUtils
import com.android.launcher3.widget.LauncherAppWidgetHostView
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
import com.android.systemui.plugins.CustomWidgetPlugin
-import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.Captor
import org.mockito.Mock
import org.mockito.Mockito.mock
import org.mockito.MockitoAnnotations
@@ -60,16 +62,12 @@ class CustomWidgetManagerTest {
@Mock private lateinit var mockAppWidgetManager: AppWidgetManager
@Mock private lateinit var tracker: DaggerSingletonTracker
+ @Captor private lateinit var closableCaptor: ArgumentCaptor
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
- context.putObject(PluginManagerWrapper.INSTANCE, pluginManager)
- underTest = CustomWidgetManager(context, mockAppWidgetManager, tracker)
- }
-
- @After
- fun tearDown() {
- underTest.close()
+ underTest = CustomWidgetManager(context, pluginManager, mockAppWidgetManager, tracker)
}
@Test
@@ -80,7 +78,8 @@ class CustomWidgetManagerTest {
@Test
fun close_widget_manager_should_remove_plugin_listener() {
- underTest.close()
+ verify(tracker).addCloseable(closableCaptor.capture())
+ closableCaptor.allValues.forEach(SafeCloseable::close)
verify(pluginManager).removePluginListener(same(underTest))
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index cee88ac047..4ca6da8a47 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -20,7 +20,6 @@ import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType
import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
-import static com.android.launcher3.testing.shared.TestProtocol.WIDGET_CONFIG_NULL_EXTRA_INTENT;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static org.junit.Assert.assertEquals;
@@ -415,6 +414,7 @@ public abstract class AbstractLauncherUiTest {
public void verifyLauncherState() {
try {
// Limits UI tests affecting tests running after them.
+ mDevice.pressHome();
mLauncher.waitForLauncherInitialized();
if (mLauncherPid != 0) {
assertEquals("Launcher crashed, pid mismatch:",
@@ -563,23 +563,13 @@ public abstract class AbstractLauncherUiTest {
@Override
public void onReceive(Context context, Intent intent) {
- Log.d(WIDGET_CONFIG_NULL_EXTRA_INTENT, intent == null
- ? "AbstractLauncherUiTest.onReceive(): inputted intent NULL"
- : "AbstractLauncherUiTest.onReceive(): inputted intent NOT NULL");
mIntent = intent;
latch.countDown();
- Log.d(WIDGET_CONFIG_NULL_EXTRA_INTENT,
- "AbstractLauncherUiTest.onReceive() Countdown Latch started");
}
public Intent blockingGetIntent() throws InterruptedException {
- Log.d(WIDGET_CONFIG_NULL_EXTRA_INTENT,
- "AbstractLauncherUiTest.blockingGetIntent()");
assertTrue("Timed Out", latch.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS));
mTargetContext.unregisterReceiver(this);
- Log.d(WIDGET_CONFIG_NULL_EXTRA_INTENT, mIntent == null
- ? "AbstractLauncherUiTest.onReceive(): mIntent NULL"
- : "AbstractLauncherUiTest.onReceive(): mIntent NOT NULL");
return mIntent;
}
diff --git a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
index b38dd4ba11..a45e3bbb84 100644
--- a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
@@ -70,7 +70,6 @@ public class TaplWorkProfileTest extends AbstractLauncherUiTest {
@Override
public void setUp() throws Exception {
super.setUp();
- initialize(this);
String output =
mDevice.executeShellCommand(
"pm create-user --profileOf 0 --managed TestProfile");
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
index 490cff20b4..237f2a97a7 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplWorkspaceTest.java
@@ -32,7 +32,6 @@ import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import org.junit.After;
-import org.junit.Before;
import org.junit.Test;
/**
@@ -50,12 +49,6 @@ public class TaplWorkspaceTest extends AbstractLauncherUiTest {
return launcher.getWorkspace().getCurrentPage();
}
- @Before
- public void setUp() throws Exception {
- super.setUp();
- initialize(this);
- }
-
@After
public void tearDown() throws Exception {
if (mLauncherLayout != null) {