diff --git a/Android.mk b/Android.mk
index 5d3eb8ab55..239eaf6634 100644
--- a/Android.mk
+++ b/Android.mk
@@ -125,6 +125,8 @@ LOCAL_FULL_LIBS_MANIFEST_FILES := \
$(LOCAL_PATH)/AndroidManifest.xml \
$(LOCAL_PATH)/AndroidManifest-common.xml
+LOCAL_MANIFEST_FILE := go/AndroidManifest.xml
+
LOCAL_JACK_COVERAGE_INCLUDE_FILTER := com.android.launcher3.*
include $(BUILD_PACKAGE)
diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index c3ddfd62b8..fde22ebc54 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -34,7 +34,7 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/go/res/drawable/ic_widget.xml b/go/res/drawable/ic_widget.xml
new file mode 100644
index 0000000000..53368760ee
--- /dev/null
+++ b/go/res/drawable/ic_widget.xml
@@ -0,0 +1,25 @@
+
+
+
+
diff --git a/go/res/layout/widget_cell_content.xml b/go/res/layout/widget_cell_content.xml
new file mode 100644
index 0000000000..49506d9bec
--- /dev/null
+++ b/go/res/layout/widget_cell_content.xml
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/go/res/values-af/strings.xml b/go/res/values-af/strings.xml
new file mode 100644
index 0000000000..10ac473c1f
--- /dev/null
+++ b/go/res/values-af/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Raak en hou om \'n kortpad op te tel."
+ "Dubbeltik en hou om \'n kortpad op te tel of gebruik gepasmaakte handelinge."
+ "Kortpaaie"
+ "%1$s-kortpaaie"
+
diff --git a/go/res/values-am/strings.xml b/go/res/values-am/strings.xml
new file mode 100644
index 0000000000..b3b253f423
--- /dev/null
+++ b/go/res/values-am/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "አንድ አቋራጭ ለመውሰድ ነክተው ይያዙ"
+ "አንድ አቋራጭ ለመውሰድ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ አድርገው ይያዙ።"
+ "አቋራጮች"
+ "%1$s አቋራጮች"
+
diff --git a/go/res/values-ar/strings.xml b/go/res/values-ar/strings.xml
new file mode 100644
index 0000000000..2b3b80746f
--- /dev/null
+++ b/go/res/values-ar/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "المس مع الاستمرار لاختيار اختصار."
+ "يمكنك النقر نقرًا مزدوجًا مع الاستمرار لاختيار اختصار أو استخدام الإجراءات المخصصة."
+ "الاختصارات"
+ "اختصارات %1$s"
+
diff --git a/go/res/values-az/strings.xml b/go/res/values-az/strings.xml
new file mode 100644
index 0000000000..c4b8cb7801
--- /dev/null
+++ b/go/res/values-az/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Qısayolu seçmək üçün toxunub saxlayın."
+ "Qısayolu seçmək üçün iki dəfə basıb saxlayın və ya fərdi əməliyyatlardan istifadə edin."
+ "Qısayollar"
+ "%1$s qısayolları"
+
diff --git a/go/res/values-b+sr+Latn/strings.xml b/go/res/values-b+sr+Latn/strings.xml
new file mode 100644
index 0000000000..0da5699410
--- /dev/null
+++ b/go/res/values-b+sr+Latn/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Dodirnite i zadržite da biste izabrali prečicu."
+ "Dvaput dodirnite i zadržite da biste izabrali prečicu ili koristite prilagođene radnje."
+ "Prečice"
+ "Prečice za %1$s"
+
diff --git a/go/res/values-be/strings.xml b/go/res/values-be/strings.xml
new file mode 100644
index 0000000000..4189e35fa0
--- /dev/null
+++ b/go/res/values-be/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Дакраніцеся і ўтрымлiвайце ярлык, каб дадаць яго."
+ "Дакраніцеся двойчы і ўтрымлівайце, каб выбраць ярлык або выкарыстоўваць спецыяльныя дзеянні."
+ "Ярлыкі"
+ "Ярлыкі %1$s"
+
diff --git a/go/res/values-bg/strings.xml b/go/res/values-bg/strings.xml
new file mode 100644
index 0000000000..1b85992d99
--- /dev/null
+++ b/go/res/values-bg/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Докоснете и задръжте за избор на пряк път."
+ "Докоснете двукратно и задръжте за избор на пряк път или използвайте персонализирани действия."
+ "Преки пътища"
+ "Преки пътища за %1$s"
+
diff --git a/go/res/values-bn/strings.xml b/go/res/values-bn/strings.xml
new file mode 100644
index 0000000000..c56c925a29
--- /dev/null
+++ b/go/res/values-bn/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "কোনও শর্টকাট বেছে নিতে টাচ করে ধরে রাখুন।"
+ "কোনও শর্টকাট বেছে নিতে ডাবল ট্যাপ করে ধরে রাখুন অথবা কাস্টম ক্রিয়াগুলি ব্যবহার করুন।"
+ "শর্টকাট"
+ "%1$s এর শর্টকাট"
+
diff --git a/go/res/values-bs/strings.xml b/go/res/values-bs/strings.xml
new file mode 100644
index 0000000000..7042468b47
--- /dev/null
+++ b/go/res/values-bs/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Dodirnite i držite da uzmete prečicu."
+ "Dvaput dodirnite i držite da uzmete prečicu ili koristite prilagođene akcije."
+ "Prečice"
+ "Prečice aplikacije %1$s"
+
diff --git a/go/res/values-ca/strings.xml b/go/res/values-ca/strings.xml
new file mode 100644
index 0000000000..3b5c3f7b56
--- /dev/null
+++ b/go/res/values-ca/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Mantén premuda una drecera per seleccionar-la."
+ "Fes doble toc i mantén premut per seleccionar una drecera o per utilitzar accions personalitzades."
+ "Dreceres"
+ "Dreceres de l\'aplicació %1$s"
+
diff --git a/go/res/values-cs/strings.xml b/go/res/values-cs/strings.xml
new file mode 100644
index 0000000000..e4018f2c0f
--- /dev/null
+++ b/go/res/values-cs/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Zkratku vyberete podržením."
+ "Dvojitým klepnutím a podržením vyberte zkratku, případně použijte vlastní akce."
+ "Zkratky"
+ "Zkratky aplikace %1$s"
+
diff --git a/go/res/values-da/strings.xml b/go/res/values-da/strings.xml
new file mode 100644
index 0000000000..821d36a7da
--- /dev/null
+++ b/go/res/values-da/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Hold en genvej nede for at samle den op."
+ "Tryk to gange, og hold en genvej nede for at samle den op og bruge tilpassede handlinger."
+ "Genveje"
+ "%1$s-genveje"
+
diff --git a/go/res/values-de/strings.xml b/go/res/values-de/strings.xml
new file mode 100644
index 0000000000..43a1b3a9e1
--- /dev/null
+++ b/go/res/values-de/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Doppeltippen und halten, um eine Verknüpfung auszuwählen."
+ "Doppeltippen und halten, um eine Verknüpfung auszuwählen oder benutzerdefinierte Aktionen zu nutzen."
+ "Verknüpfungen"
+ "%1$s-Verknüpfungen"
+
diff --git a/go/res/values-el/strings.xml b/go/res/values-el/strings.xml
new file mode 100644
index 0000000000..ae59907d16
--- /dev/null
+++ b/go/res/values-el/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Αγγίξτε παρατεταμένα για να σηκώσετε μια συντόμευση."
+ "Πατήσετε δύο φορές παρατεταμένα για να σηκώσετε μια συντόμευση ή για να χρησιμοποιήσετε προσαρμοσμένες ενέργειες."
+ "Συντομεύσεις"
+ "Συντομεύσεις %1$s"
+
diff --git a/go/res/values-en-rAU/strings.xml b/go/res/values-en-rAU/strings.xml
new file mode 100644
index 0000000000..2ee2c26457
--- /dev/null
+++ b/go/res/values-en-rAU/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Touch & hold to pick up a shortcut."
+ "Double-tap & hold to pick up a shortcut or use custom actions."
+ "Shortcuts"
+ "%1$s shortcuts"
+
diff --git a/go/res/values-en-rGB/strings.xml b/go/res/values-en-rGB/strings.xml
new file mode 100644
index 0000000000..2ee2c26457
--- /dev/null
+++ b/go/res/values-en-rGB/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Touch & hold to pick up a shortcut."
+ "Double-tap & hold to pick up a shortcut or use custom actions."
+ "Shortcuts"
+ "%1$s shortcuts"
+
diff --git a/go/res/values-en-rIN/strings.xml b/go/res/values-en-rIN/strings.xml
new file mode 100644
index 0000000000..2ee2c26457
--- /dev/null
+++ b/go/res/values-en-rIN/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Touch & hold to pick up a shortcut."
+ "Double-tap & hold to pick up a shortcut or use custom actions."
+ "Shortcuts"
+ "%1$s shortcuts"
+
diff --git a/go/res/values-es-rUS/strings.xml b/go/res/values-es-rUS/strings.xml
new file mode 100644
index 0000000000..5212c035d3
--- /dev/null
+++ b/go/res/values-es-rUS/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Mantén presionado para elegir un acceso directo."
+ "Presiona dos veces y mantén presionado para elegir un acceso directo o usar acciones personalizadas."
+ "Accesos directos"
+ "Accesos directos de %1$s"
+
diff --git a/go/res/values-es/strings.xml b/go/res/values-es/strings.xml
new file mode 100644
index 0000000000..3ae45889cf
--- /dev/null
+++ b/go/res/values-es/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Mantén pulsado el acceso directo que quieras."
+ "Toca dos veces y mantén pulsado el acceso directo o utiliza acciones personalizadas."
+ "Accesos directos"
+ "Accesos directos de %1$s"
+
diff --git a/go/res/values-et/strings.xml b/go/res/values-et/strings.xml
new file mode 100644
index 0000000000..2513e65a33
--- /dev/null
+++ b/go/res/values-et/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Otsetee valimiseks puudutage seda pikalt."
+ "Topeltpuudutage ja hoidke otsetee valimiseks või kohandatud toimingute kasutamiseks."
+ "Otseteed"
+ "Rakenduse %1$s otseteed"
+
diff --git a/go/res/values-eu/strings.xml b/go/res/values-eu/strings.xml
new file mode 100644
index 0000000000..9949ef091d
--- /dev/null
+++ b/go/res/values-eu/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Eduki sakatuta lasterbide bat aukeratzeko."
+ "Sakatu birritan eta eduki sakatuta lasterbide bat aukeratzeko edo ekintza pertsonalizatuak erabiltzeko."
+ "Lasterbideak"
+ "%1$s aplikazioaren lasterbidea"
+
diff --git a/go/res/values-fa/strings.xml b/go/res/values-fa/strings.xml
new file mode 100644
index 0000000000..f1584d9ff7
--- /dev/null
+++ b/go/res/values-fa/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "برای انتخاب یک میانبر، لمس کنید و نگهدارید."
+ "برای انتخاب میانبر، دو ضربه سریع بزنید و نگه دارید یا از کنشهای سفارشی استفاده کنید."
+ "میانبرها"
+ "میانبرهای %1$s"
+
diff --git a/go/res/values-fi/strings.xml b/go/res/values-fi/strings.xml
new file mode 100644
index 0000000000..da9b0e1c42
--- /dev/null
+++ b/go/res/values-fi/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Valitse pikakuvake painamalla sitä pitkään."
+ "Valitse pikakuvake tai käytä muokattuja toimintoja kaksoisnapauttamalla ja painamalla pitkään."
+ "Pikakuvakkeet"
+ "Kohteen %1$s pikakuvakkeet"
+
diff --git a/go/res/values-fr-rCA/strings.xml b/go/res/values-fr-rCA/strings.xml
new file mode 100644
index 0000000000..c7fd6d6423
--- /dev/null
+++ b/go/res/values-fr-rCA/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Maintenez un doigt sur le raccourci pour l\'ajouter"
+ "Touchez 2x un raccourci et maintenez doigt dessus pour l’aj. ou utiliser des actions personnalisées."
+ "Raccourcis"
+ "Raccourcis : %1$s"
+
diff --git a/go/res/values-fr/strings.xml b/go/res/values-fr/strings.xml
new file mode 100644
index 0000000000..238fe73d75
--- /dev/null
+++ b/go/res/values-fr/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Appui prolongé pour sélectionner raccourci."
+ "Appuyez 2 fois et maintenez pression pour sélectionner raccourci ou utilisez actions personnalisées."
+ "Raccourcis"
+ "Raccourcis %1$s"
+
diff --git a/go/res/values-gl/strings.xml b/go/res/values-gl/strings.xml
new file mode 100644
index 0000000000..31621d5c2c
--- /dev/null
+++ b/go/res/values-gl/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Mantén premido un atallo para seleccionalo."
+ "Toca dúas veces e mantén premido para seleccionar un atallo ou utiliza accións personalizadas."
+ "Atallos"
+ "Atallos da aplicación %1$s"
+
diff --git a/go/res/values-gu/strings.xml b/go/res/values-gu/strings.xml
new file mode 100644
index 0000000000..bdb549ff7f
--- /dev/null
+++ b/go/res/values-gu/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "એક શૉર્ટકટ ચૂંટવા ટૅપ કરી રાખો."
+ "એક શૉર્ટકટ ચૂંટવા અથવા કોઈ કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટૅપ કરી રાખો."
+ "શૉર્ટકટ"
+ "%1$s શૉર્ટકટ"
+
diff --git a/go/res/values-hi/strings.xml b/go/res/values-hi/strings.xml
new file mode 100644
index 0000000000..2c1650a0dd
--- /dev/null
+++ b/go/res/values-hi/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "शॉर्टकट चुनने के लिए छूकर रखें."
+ "शॉर्टकट चुनने के लिए दो बार छूएं और कुछ देर दबाएं रखें या अपने मुताबिक कार्रवाइयों का इस्तेमाल करें."
+ "शॉर्टकट"
+ "%1$s शॉर्टकट"
+
diff --git a/go/res/values-hr/strings.xml b/go/res/values-hr/strings.xml
new file mode 100644
index 0000000000..fccdeb59d7
--- /dev/null
+++ b/go/res/values-hr/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Dodirnite i zadržite kako biste podigli prečac."
+ "Dvaput dodirnite i zadržite pritisak kako biste podigli prečac ili pokušajte prilagođenim radnjama."
+ "Prečaci"
+ "Prečaci za aplikaciju %1$s"
+
diff --git a/go/res/values-hu/strings.xml b/go/res/values-hu/strings.xml
new file mode 100644
index 0000000000..369c22745a
--- /dev/null
+++ b/go/res/values-hu/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Felvételhez tartsa nyomva a parancsikont."
+ "Parancsikon felvételéhez koppintson rá duplán és tartsa nyomva, vagy használjon egyéni műveleteket."
+ "Parancsikonok"
+ "%1$s-parancsikonok"
+
diff --git a/go/res/values-hy/strings.xml b/go/res/values-hy/strings.xml
new file mode 100644
index 0000000000..4747f6df35
--- /dev/null
+++ b/go/res/values-hy/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար։"
+ "Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար կամ օգտվեք հարմարեցրած գործողություններից:"
+ "Դյուրանցումներ"
+ "%1$s դյուրանցումներ"
+
diff --git a/go/res/values-in/strings.xml b/go/res/values-in/strings.xml
new file mode 100644
index 0000000000..c8b9da306d
--- /dev/null
+++ b/go/res/values-in/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Tap lama untuk memilih pintasan."
+ "Tap dua kali & tahan untuk memilih pintasan atau menggunakan tindakan khusus."
+ "Pintasan"
+ "Pintasan %1$s"
+
diff --git a/go/res/values-is/strings.xml b/go/res/values-is/strings.xml
new file mode 100644
index 0000000000..b8bb923746
--- /dev/null
+++ b/go/res/values-is/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Haltu fingri á flýtileið til að grípa hana."
+ "Ýttu tvisvar og haltu fingri á flýtileið til að grípa hana eða notaðu sérsniðnar aðgerðir."
+ "Flýtileiðir"
+ "%1$s flýtileiðir"
+
diff --git a/go/res/values-it/strings.xml b/go/res/values-it/strings.xml
new file mode 100644
index 0000000000..bc5d99863d
--- /dev/null
+++ b/go/res/values-it/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Tocca e tieni premuto per scegliere la scorciatoia"
+ "Tocca due volte e tieni premuto per scegliere una scorciatoia o per usare azioni personalizzate."
+ "Scorciatoie"
+ "Scorciatoie di %1$s"
+
diff --git a/go/res/values-iw/strings.xml b/go/res/values-iw/strings.xml
new file mode 100644
index 0000000000..f541d4d316
--- /dev/null
+++ b/go/res/values-iw/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "כדי להוסיף קיצור דרך, מקישים עליו פעמיים ומחזיקים."
+ "כדי להוסיף קיצור דרך או להשתמש בפעולות מותאמות אישית, מקישים על קיצור הדרך פעמיים ומחזיקים."
+ "קיצורי דרך"
+ "קיצורי דרך לאפליקציה %1$s"
+
diff --git a/go/res/values-ja/strings.xml b/go/res/values-ja/strings.xml
new file mode 100644
index 0000000000..8f02d7f4eb
--- /dev/null
+++ b/go/res/values-ja/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "ショートカットを追加するには押し続けます。"
+ "ダブルタップ後に押し続けてショートカットを選択するか、カスタム操作を使用してください。"
+ "ショートカット"
+ "「%1$s」のショートカット"
+
diff --git a/go/res/values-ka/strings.xml b/go/res/values-ka/strings.xml
new file mode 100644
index 0000000000..1b46534788
--- /dev/null
+++ b/go/res/values-ka/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "შეეხეთ და დააყოვნეთ მალსახმობის ასარჩევად."
+ "ორმაგად შეეხეთ და გეჭიროთ მალსახმობის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად."
+ "მალსახმობები"
+ "%1$s-ის მალსახმობები"
+
diff --git a/go/res/values-kk/strings.xml b/go/res/values-kk/strings.xml
new file mode 100644
index 0000000000..e909818afc
--- /dev/null
+++ b/go/res/values-kk/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Таңбашаны таңдау үшін оны түртіп, ұстап тұрыңыз."
+ "Таңбашаны таңдау немесе арнаулы әрекеттерді пайдалану үшін екі рет түртіп, ұстап тұрыңыз."
+ "Таңбашалар"
+ "%1$s таңбаша"
+
diff --git a/go/res/values-km/strings.xml b/go/res/values-km/strings.xml
new file mode 100644
index 0000000000..40082a4b9d
--- /dev/null
+++ b/go/res/values-km/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "ប៉ះ ហើយចុចឲ្យជាប់ដើម្បីរើសផ្លូវកាត់មួយ។"
+ "ប៉ះពីរដង ហើយចុចឱ្យជាប់ដើម្បីរើសផ្លូវកាត់មួយ ឬប្រើសកម្មភាពផ្ទាល់ខ្លួន។"
+ "ផ្លូវកាត់"
+ "ផ្លូវកាត់សម្រាប់ %1$s"
+
diff --git a/go/res/values-kn/strings.xml b/go/res/values-kn/strings.xml
new file mode 100644
index 0000000000..9c121fd294
--- /dev/null
+++ b/go/res/values-kn/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ."
+ "ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಿಕೊಳ್ಳಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಿ."
+ "ಶಾರ್ಟ್ಕಟ್ಗಳು"
+ "%1$s ಶಾರ್ಟ್ಕಟ್ಗಳು"
+
diff --git a/go/res/values-ko/strings.xml b/go/res/values-ko/strings.xml
new file mode 100644
index 0000000000..60f925e36b
--- /dev/null
+++ b/go/res/values-ko/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "바로가기를 선택하려면 길게 터치하세요."
+ "바로가기를 선택하려면 두 번 탭한 다음 길게 터치하거나 맞춤 액션을 사용합니다."
+ "바로가기"
+ "%1$s 바로가기"
+
diff --git a/go/res/values-ky/strings.xml b/go/res/values-ky/strings.xml
new file mode 100644
index 0000000000..4c7e973cef
--- /dev/null
+++ b/go/res/values-ky/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Кыска жолду тандоо үчүн басып туруңуз."
+ "Кыска жолду тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."
+ "Кыска жолдор"
+ "%1$s кыска жол"
+
diff --git a/go/res/values-lo/strings.xml b/go/res/values-lo/strings.xml
new file mode 100644
index 0000000000..7864884acc
--- /dev/null
+++ b/go/res/values-lo/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "ແຕະຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ."
+ "ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ ຫຼື ໃຊ້ຄຳສັ່ງແບບກຳນົດເອງ."
+ "ປຸ່ມລັດ"
+ "ປຸ່ມລັດ %1$s"
+
diff --git a/go/res/values-lt/strings.xml b/go/res/values-lt/strings.xml
new file mode 100644
index 0000000000..8f49032cfb
--- /dev/null
+++ b/go/res/values-lt/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Dukart pal. ir palaik., kad pasir. spart. klav."
+ "Dukart palieskite ir palaikykite, kad pasirinkt. spartųjį klavišą ar naudotumėte tinkintus veiksmus."
+ "Spartieji klavišai"
+ "„%1$s“ spartieji klavišai"
+
diff --git a/go/res/values-lv/strings.xml b/go/res/values-lv/strings.xml
new file mode 100644
index 0000000000..04315ebaa0
--- /dev/null
+++ b/go/res/values-lv/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Lai izvēlētos saīsni, pieskarieties un turiet to."
+ "Lai atlasītu saīsni, veiciet dubultskārienu uz tās un turiet to vai arī veiciet pielāgotas darbības."
+ "Saīsnes"
+ "Lietotnes %1$s saīsnes"
+
diff --git a/go/res/values-mk/strings.xml b/go/res/values-mk/strings.xml
new file mode 100644
index 0000000000..52d66b5e28
--- /dev/null
+++ b/go/res/values-mk/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Допрете двапати и задржете за да изберете кратенка."
+ "Допрете двапати и задржете за да изберете кратенка или да користите приспособени дејства."
+ "Кратенки"
+ "Кратенки за %1$s"
+
diff --git a/go/res/values-ml/strings.xml b/go/res/values-ml/strings.xml
new file mode 100644
index 0000000000..b3c12e16e1
--- /dev/null
+++ b/go/res/values-ml/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "ഒരു കുറുക്കുവഴി ചേർക്കുന്നതിന് അത് സ്പർശിച്ച് പിടിക്കുക."
+ "ഒരു കുറുക്കുവഴി തിരഞ്ഞെടുക്കാനോ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ രണ്ടുതവണ ടാപ്പുചെയ്ത് പിടിക്കുക."
+ "കുറുക്കുവഴികൾ"
+ "%1$s കുറുക്കുവഴികൾ"
+
diff --git a/go/res/values-mn/strings.xml b/go/res/values-mn/strings.xml
new file mode 100644
index 0000000000..c89dfd1bdc
--- /dev/null
+++ b/go/res/values-mn/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Товчлол авах бол удаан дарна уу."
+ "Товчлол авах болон тохируулсан үйлдлийг ашиглахын тулд хоёр товшоод хүлээнэ үү."
+ "Товчлол"
+ "%1$s-н товчлол"
+
diff --git a/go/res/values-mr/strings.xml b/go/res/values-mr/strings.xml
new file mode 100644
index 0000000000..2c767b4f19
--- /dev/null
+++ b/go/res/values-mr/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "शॉर्टकट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."
+ "शॉर्टकट निवडण्यासाठी किंवा कस्टम क्रिया वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."
+ "शॉर्टकट"
+ "%1$s शॉर्टकट"
+
diff --git a/go/res/values-ms/strings.xml b/go/res/values-ms/strings.xml
new file mode 100644
index 0000000000..42add9a197
--- /dev/null
+++ b/go/res/values-ms/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Sentuh & tahan untuk mengambil pintasan."
+ "Ketik dua kali & tahan untuk mengambil pintasan atau menggunakan tindakan tersuai."
+ "Pintasan"
+ "Pintasan %1$s"
+
diff --git a/go/res/values-my/strings.xml b/go/res/values-my/strings.xml
new file mode 100644
index 0000000000..5784df63bf
--- /dev/null
+++ b/go/res/values-my/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "လက်ကွက်ဖြတ်လမ်းတစ်ခုကို ရွေးရန် ထိပြီး ဖိထားပါ"
+ "လက်ကွက်ဖြတ်လမ်းကို ရွေးရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန်နှစ်ချက်တို့ပြီး ဖိထားပါ။"
+ "ဖြတ်လမ်းလင့်ခ်များ"
+ "%1$s ဖြတ်လမ်းလင့်ခ်များ"
+
diff --git a/go/res/values-nb/strings.xml b/go/res/values-nb/strings.xml
new file mode 100644
index 0000000000..2a5ffb6e7c
--- /dev/null
+++ b/go/res/values-nb/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Trykk og hold for å velge en snarvei."
+ "Dobbelttrykk og hold for å velge en snarvei eller bruke tilpassede handlinger."
+ "Snarveier"
+ "%1$s-snarveier"
+
diff --git a/go/res/values-ne/strings.xml b/go/res/values-ne/strings.xml
new file mode 100644
index 0000000000..0be0375f3a
--- /dev/null
+++ b/go/res/values-ne/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "कुनै सटकर्ट छनौट गर्न छोइराख्नुहोस्।"
+ "कुनै सर्टकट छनौट गर्न दुईपटक ट्याप गरेर होल्ड गर्नुहोस् वा रोजेका कारबाहीहरू प्रयोग गर्नुहोस्।"
+ "सर्टकटहरू"
+ "%1$s सर्टकटहरू"
+
diff --git a/go/res/values-nl/strings.xml b/go/res/values-nl/strings.xml
new file mode 100644
index 0000000000..5bcd016b4a
--- /dev/null
+++ b/go/res/values-nl/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Tik en houd vast om snelkoppeling toe te voegen."
+ "Dubbeltik en houd vast om een snelkoppeling toe te voegen of aangepaste acties te gebruiken."
+ "Snelkoppelingen"
+ "%1$s-snelkoppelingen"
+
diff --git a/go/res/values-pa/strings.xml b/go/res/values-pa/strings.xml
new file mode 100644
index 0000000000..c7e4abf3a8
--- /dev/null
+++ b/go/res/values-pa/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"
+ "ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ ਜਾਂ ਵਿਉਂਂਤੀ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।"
+ "ਸ਼ਾਰਟਕੱਟ"
+ "%1$s ਸ਼ਾਰਟਕੱਟ"
+
diff --git a/go/res/values-pl/strings.xml b/go/res/values-pl/strings.xml
new file mode 100644
index 0000000000..45a1dc2cac
--- /dev/null
+++ b/go/res/values-pl/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Kliknij i przytrzymaj, by wybrać skrót."
+ "Kliknij dwukrotnie i przytrzymaj, by wybrać skrót lub użyć działań niestandardowych."
+ "Skróty"
+ "%1$s – skróty"
+
diff --git a/go/res/values-pt-rPT/strings.xml b/go/res/values-pt-rPT/strings.xml
new file mode 100644
index 0000000000..7a75a05456
--- /dev/null
+++ b/go/res/values-pt-rPT/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Toque sem soltar para escolher um atalho."
+ "Toque duas vezes sem soltar para escolher um atalho ou utilize ações personalizadas."
+ "Atalhos"
+ "Atalhos da aplicação %1$s"
+
diff --git a/go/res/values-pt/strings.xml b/go/res/values-pt/strings.xml
new file mode 100644
index 0000000000..53bbfc41a6
--- /dev/null
+++ b/go/res/values-pt/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Toque e segure para selecionar um atalho."
+ "Toque duas vezes na tela e segure para selecionar um atalho ou usar ações personalizadas."
+ "Atalhos"
+ "Atalhos do app %1$s"
+
diff --git a/go/res/values-ro/strings.xml b/go/res/values-ro/strings.xml
new file mode 100644
index 0000000000..75d1796b57
--- /dev/null
+++ b/go/res/values-ro/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Atingeți și țineți apăsat pentru a selecta o comandă rapidă."
+ "Atingeți de două ori și țineți apăsat pentru comandă rapidă sau folosiți acțiuni personalizate."
+ "Comenzi rapide"
+ "Comenzi rapide pentru %1$s"
+
diff --git a/go/res/values-ru/strings.xml b/go/res/values-ru/strings.xml
new file mode 100644
index 0000000000..9c5c8cd340
--- /dev/null
+++ b/go/res/values-ru/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Чтобы выбрать ярлык, нажмите на него и удерживайте."
+ "Чтобы выбрать ярлык или использовать специальные действия, нажмите на него дважды и не отпускайте."
+ "Ярлыки"
+ "%1$s: ярлыки"
+
diff --git a/go/res/values-si/strings.xml b/go/res/values-si/strings.xml
new file mode 100644
index 0000000000..4b25c90b0b
--- /dev/null
+++ b/go/res/values-si/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "කෙටි මගක් තෝරා ගැනීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න."
+ "විජට් එකක් තෝරා ගැනීමට හෝ අභිරුචි භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."
+ "කෙටි මං"
+ "කෙටි මං %1$s"
+
diff --git a/go/res/values-sk/strings.xml b/go/res/values-sk/strings.xml
new file mode 100644
index 0000000000..fc02933734
--- /dev/null
+++ b/go/res/values-sk/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Skratku pridáte pridržaním."
+ "Skratku pridáte dvojitým klepnutím a pridržaním alebo pomocou vlastných akcií."
+ "Skratky"
+ "Skratky aplikácie %1$s"
+
diff --git a/go/res/values-sl/strings.xml b/go/res/values-sl/strings.xml
new file mode 100644
index 0000000000..6ecedfb166
--- /dev/null
+++ b/go/res/values-sl/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Pridržite bližnjico, da jo izberete."
+ "Dvakrat se dotaknite bližnjice in jo pridržite, da jo izberete, ali pa uporabite dejanja po meri."
+ "Bližnjice"
+ "Bližnjice za %1$s"
+
diff --git a/go/res/values-sq/strings.xml b/go/res/values-sq/strings.xml
new file mode 100644
index 0000000000..bb74db6b55
--- /dev/null
+++ b/go/res/values-sq/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Prek dhe mbaj prekur për të zgjedhur një shkurtore."
+ "Prek dy herë dhe mbaj prekur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara."
+ "Shkurtoret"
+ "%1$s shkurtore"
+
diff --git a/go/res/values-sr/strings.xml b/go/res/values-sr/strings.xml
new file mode 100644
index 0000000000..0b9aea2f9a
--- /dev/null
+++ b/go/res/values-sr/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Додирните и задржите да бисте изабрали пречицу."
+ "Двапут додирните и задржите да бисте изабрали пречицу или користите прилагођене радње."
+ "Пречице"
+ "Пречице за %1$s"
+
diff --git a/go/res/values-sv/strings.xml b/go/res/values-sv/strings.xml
new file mode 100644
index 0000000000..c3f434c276
--- /dev/null
+++ b/go/res/values-sv/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Tryck länge om du vill ta upp en genväg."
+ "Tryck snabbt två gånger och håll kvar om du vill ta upp en genväg eller använda anpassade åtgärder."
+ "Genvägar"
+ "Genvägar för %1$s"
+
diff --git a/go/res/values-sw/strings.xml b/go/res/values-sw/strings.xml
new file mode 100644
index 0000000000..13c12e4a6c
--- /dev/null
+++ b/go/res/values-sw/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Gusa na ushikilie ili uchague njia ya mkato."
+ "Gusa mara mbili na ushikilie ile uchague njia ya mkato au utumie vitendo maalum."
+ "Njia za mkato"
+ "Njia za mkato za %1$s"
+
diff --git a/go/res/values-ta/strings.xml b/go/res/values-ta/strings.xml
new file mode 100644
index 0000000000..50059b65f9
--- /dev/null
+++ b/go/res/values-ta/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "குறுக்குவழியைச் சேர்க்க, தொட்டு பிடித்திருக்கவும்."
+ "குறுக்குவழியை சேர்க்க, இருமுறை தட்டிப் பிடித்திருக்கவும் அல்லது தனிப்பயன் செயல்களைப் பயன்படுத்தவும்."
+ "குறுக்குவழிகள்"
+ "%1$s குறுக்குவழிகள்"
+
diff --git a/go/res/values-te/strings.xml b/go/res/values-te/strings.xml
new file mode 100644
index 0000000000..0bdf743342
--- /dev/null
+++ b/go/res/values-te/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "సత్వరమార్గాన్ని ఎంచుకోవడానికి తాకి & నొక్కి ఉంచండి."
+ "సత్వరమార్గాన్ని ఎంచుకోవడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కి &ఉంచండి."
+ "సత్వరమార్గాలు"
+ "%1$s సత్వరమార్గాలు"
+
diff --git a/go/res/values-th/strings.xml b/go/res/values-th/strings.xml
new file mode 100644
index 0000000000..e73d89fb0e
--- /dev/null
+++ b/go/res/values-th/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "แตะค้างไว้เพื่อเลือกทางลัด"
+ "แตะสองครั้งค้างไว้เพื่อเลือกทางลัดหรือใช้การกระทำที่กำหนดเอง"
+ "ทางลัด"
+ "ทางลัด %1$s"
+
diff --git a/go/res/values-tl/strings.xml b/go/res/values-tl/strings.xml
new file mode 100644
index 0000000000..8f44ec5742
--- /dev/null
+++ b/go/res/values-tl/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Pindutin nang matagal upang kumuha ng shortcut."
+ "I-double tap nang matagal upang kumuha ng shortcut o gumamit ng mga custom na pagkilos."
+ "Mga Shortcut"
+ "Mga shortcut sa %1$s"
+
diff --git a/go/res/values-tr/strings.xml b/go/res/values-tr/strings.xml
new file mode 100644
index 0000000000..f0f3cce6d1
--- /dev/null
+++ b/go/res/values-tr/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Kısayol seçmek için dokunun ve basılı tutun."
+ "Bir kısayolu seçmek veya özel işlemleri kullanmak için iki kez dokunun ve basılı tutun."
+ "Kısayollar"
+ "%1$s kısayolları"
+
diff --git a/go/res/values-uk/strings.xml b/go/res/values-uk/strings.xml
new file mode 100644
index 0000000000..8d1f58395b
--- /dev/null
+++ b/go/res/values-uk/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Натисніть і утримуйте, щоб вибрати ярлик."
+ "Двічі натисніть і утримуйте, щоб вибрати ярлик, або виконайте іншу дію."
+ "Ярлики"
+ "Ярлики додатка %1$s"
+
diff --git a/go/res/values-ur/strings.xml b/go/res/values-ur/strings.xml
new file mode 100644
index 0000000000..46bd823d8e
--- /dev/null
+++ b/go/res/values-ur/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "کوئی شارٹ کٹ منتخب کرنے کیلئے ٹچ کریں اور دبائے رکھیں۔"
+ "کوئی شارٹ کٹ منتخب کرنے یا حسب ضرورت کاروائیاں استعمال کرنے کیلئے دو بار تھپتھپائیں اور دبائے رکھیں۔"
+ "شارٹ کٹس"
+ "%1$s شارٹ کٹس"
+
diff --git a/go/res/values-uz/strings.xml b/go/res/values-uz/strings.xml
new file mode 100644
index 0000000000..318bc15722
--- /dev/null
+++ b/go/res/values-uz/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Yorliqni tanlab olish uchun bosib turing."
+ "Ikki marta bosib va bosib turgan holatda yorliqni tanlang yoki maxsus amaldan foydalaning."
+ "Yorliqlar"
+ "%1$s ilovasi yorliqlari"
+
diff --git a/go/res/values-vi/strings.xml b/go/res/values-vi/strings.xml
new file mode 100644
index 0000000000..1197619c57
--- /dev/null
+++ b/go/res/values-vi/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Chạm và giữ để chọn lối tắt."
+ "Nhấn đúp và giữ để chọn lối tắt hoặc sử dụng hành động tùy chỉnh."
+ "Lối tắt"
+ "Lối tắt %1$s"
+
diff --git a/go/res/values-zh-rCN/strings.xml b/go/res/values-zh-rCN/strings.xml
new file mode 100644
index 0000000000..57351d37f5
--- /dev/null
+++ b/go/res/values-zh-rCN/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "触摸并按住快捷方式即可选择快捷方式。"
+ "点按两次并按住快捷方式即可选择快捷方式,您也可以使用自定义操作。"
+ "快捷方式"
+ "%1$s快捷方式"
+
diff --git a/go/res/values-zh-rHK/strings.xml b/go/res/values-zh-rHK/strings.xml
new file mode 100644
index 0000000000..dea7749f68
--- /dev/null
+++ b/go/res/values-zh-rHK/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "按住捷徑即可選取捷徑。"
+ "扲兩下然後扲住就可以揀選捷徑,或者用自訂嘅操作。"
+ "捷徑"
+ "%1$s 捷徑"
+
diff --git a/go/res/values-zh-rTW/strings.xml b/go/res/values-zh-rTW/strings.xml
new file mode 100644
index 0000000000..07ae2ed5b4
--- /dev/null
+++ b/go/res/values-zh-rTW/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "按住捷徑即可選取。"
+ "輕觸兩下並按住捷徑即可選取,你也可以使用自訂動作。"
+ "捷徑"
+ "「%1$s」捷徑"
+
diff --git a/go/res/values-zu/strings.xml b/go/res/values-zu/strings.xml
new file mode 100644
index 0000000000..e5051df1f1
--- /dev/null
+++ b/go/res/values-zu/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "Thinta futhi ubambe ukuze ukhethe isinqamuleli."
+ "Thepha kabulu futhi ubambe ukuze ukhethe isinqamuleli noma usebenzise izenzo zangokwezifiso."
+ "Izinqamuleli"
+ "%1$s izinqamuleli"
+
diff --git a/go/res/values/strings.xml b/go/res/values/strings.xml
new file mode 100644
index 0000000000..8ef2e62430
--- /dev/null
+++ b/go/res/values/strings.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+ Touch & hold to pick up a shortcut.
+
+ Double-tap & hold to pick up a shortcut or use custom actions.
+
+ Shortcuts
+
+
+
+ %1$s shortcuts
+
+
diff --git a/go/src_flags/com/android/launcher3/config/FeatureFlags.java b/go/src_flags/com/android/launcher3/config/FeatureFlags.java
index f324fcd6c5..b11bb7c6aa 100644
--- a/go/src_flags/com/android/launcher3/config/FeatureFlags.java
+++ b/go/src_flags/com/android/launcher3/config/FeatureFlags.java
@@ -24,5 +24,6 @@ public final class FeatureFlags extends BaseFlags {
private FeatureFlags() {}
// Features to control Launcher3Go behavior
+ public static final boolean GO_DISABLE_WIDGETS = true;
public static final boolean LAUNCHER3_SPRING_ICONS = false;
}
diff --git a/proguard.flags b/proguard.flags
index 086337dfa2..e9f6db462e 100644
--- a/proguard.flags
+++ b/proguard.flags
@@ -107,6 +107,11 @@
public (...);
}
+# MainProcessInitializer
+-keep class com.android.quickstep.QuickstepProcessInitializer {
+ public (...);
+}
+
-keep interface com.android.launcher3.userevent.nano.LauncherLogProto.** {
*;
}
diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto
index 3b983d254f..4013429b17 100644
--- a/protos/launcher_log.proto
+++ b/protos/launcher_log.proto
@@ -69,6 +69,7 @@ enum ItemType {
EDITTEXT = 7;
NOTIFICATION = 8;
TASK = 9; // Each page of Recents UI (QuickStep)
+ WEB_APP = 10;
}
// Used to define what type of container a Target would represent.
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 8b28597dd1..f62d1d6ed5 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -48,7 +48,16 @@
It is set to true so that the activity can be started from command line -->
+ android:excludeFromRecents="true"
+ android:launchMode="singleTask"
+ android:clearTaskOnLaunch="true"
+ android:stateNotNeeded="true"
+ android:theme="@style/LauncherTheme"
+ android:screenOrientation="unspecified"
+ android:configChanges="keyboard|keyboardHidden|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
+ android:resizeableActivity="true"
+ android:resumeWhilePausing="true"
+ android:taskAffinity="" />
+
+
+
diff --git a/res/layout/launcher_preference.xml b/quickstep/res/layout/drag_handle_indicator.xml
similarity index 63%
rename from res/layout/launcher_preference.xml
rename to quickstep/res/layout/drag_handle_indicator.xml
index ed0ea7c0e2..9ee05d5ad5 100644
--- a/res/layout/launcher_preference.xml
+++ b/quickstep/res/layout/drag_handle_indicator.xml
@@ -13,15 +13,11 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
-
\ No newline at end of file
+ android:id="@+id/drag_indicator"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:contentDescription="@string/accessibility_desc_recent_apps"
+ android:scaleType="centerInside"
+ android:tint="?attr/workspaceTextColor" />
diff --git a/quickstep/res/layout/fallback_recents_activity.xml b/quickstep/res/layout/fallback_recents_activity.xml
index b3fc4ed58c..22f8b55a2a 100644
--- a/quickstep/res/layout/fallback_recents_activity.xml
+++ b/quickstep/res/layout/fallback_recents_activity.xml
@@ -13,13 +13,14 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-
+ android:layout_height="match_parent"
+ android:fitsSystemWindows="true">
-
-
\ No newline at end of file
+
\ No newline at end of file
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index 0ac2b11030..b8b360a48e 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -28,5 +28,6 @@
android:id="@+id/icon"
android:layout_width="@dimen/task_thumbnail_icon_size"
android:layout_height="@dimen/task_thumbnail_icon_size"
+ android:importantForAccessibility="no"
android:layout_gravity="top|center_horizontal" />
\ No newline at end of file
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index b4c735b867..fa8f9dc589 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -22,4 +22,8 @@
"Verdeelde skerm"
"Speld vas"
"Swiep van onder af op om programme te wissel"
+ "Oorsig"
+ "Geen onlangse items nie"
+
+
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 62d54dbe3e..d14e06c9e0 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -22,4 +22,8 @@
"የተከፈለ ማያ ገጽ"
"ሰካ"
"መተግበሪያዎችን ለመቀያየር ከግርጌ ወደ ላይ በጣት ጠረግ ያድርጉ"
+ "ማጠቃለያ"
+ "ምንም የቅርብ ጊዜ ንጥሎች የሉም"
+
+
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index de210b796f..8efffd26db 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -22,4 +22,8 @@
"تقسيم الشاشة"
"تثبيت"
"التمرير سريعًا لأعلى من أسفل للتبديل بين التطبيقات"
+ "نظرة عامة"
+ "ليست هناك عناصر تم استخدامها مؤخرًا"
+
+
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 91c5179749..a832f9aa0e 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -22,4 +22,8 @@
"Bölünmüş ekran"
"Sancın"
"Tətbiqləri dəyişmək üçün aşağıdan yuxarı doğru sürüşdürün"
+ "İcmal"
+ "Son elementlər yoxdur"
+
+
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index a4eb3e89d1..ba44830be4 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -22,4 +22,8 @@
"Podeljeni ekran"
"Zakači"
"Prevucite nagore da biste prešli na drugu aplikaciju"
+ "Pregled"
+ "Nema nedavnih stavki"
+
+
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index f798802dc5..df55803afe 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -22,4 +22,8 @@
"Падзяліць экран"
"Замацаваць"
"Для пераключэння праграм правядзіце па экране пальцам знізу ўверх"
+ "Агляд"
+ "Няма новых элементаў"
+
+
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index de88634d6e..c46245c83b 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -22,4 +22,8 @@
"Разделен екран"
"Фиксиране"
"Прекарайте пръст нагоре от долната част, за да превключите между приложенията"
+ "Общ преглед"
+ "Няма скорошни елементи"
+
+
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 028a475d98..9080072316 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -22,4 +22,10 @@
"স্ক্রিন স্প্লিট করুন"
"পিন করুন"
"অ্যাপগুলির মধ্যে সুইচ করতে উপর থেকে নিচের দিকে সোয়াইপ করুন"
+
+
+
+
+
+
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 16b72ea365..7e61277d59 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -22,4 +22,8 @@
"Način rada podijeljenog ekrana"
"Zakači"
"Prevucite od dolje prema gore za promjenu aplikacije"
+ "Pregled"
+ "Nema nedavnih stavki"
+
+
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 6d65fd7d5e..ac77992132 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -22,4 +22,10 @@
"Divideix la pantalla"
"Fixa"
"Llisca cap amunt des de la part inferior per canviar d\'aplicació"
+
+
+
+
+
+
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index b6894c0e1c..e8c0cb055e 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -22,4 +22,8 @@
"Rozdělená obrazovka"
"PIN"
"Aplikace můžete přepínat přejetím zdola nahoru"
+ "Přehled"
+ "Žádné nedávné položky"
+
+
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index ff2d25d73e..6ddb31b364 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -22,4 +22,8 @@
"Delt skærm"
"Fastgør"
"Stryg opad fra bunden for at skifte apps"
+ "Oversigt"
+ "Ingen nye elementer"
+
+
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index e5242c7a80..01c785e60a 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -22,4 +22,8 @@
"Bildschirm teilen"
"Fixieren"
"Zum Wechseln zwischen Apps vom unteren Bildschirmrand nach oben wischen"
+ "Übersicht"
+ "Keine kürzlich verwendeten Elemente"
+
+
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 9d7023de65..6b2a25f909 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -22,4 +22,8 @@
"Διαχωρισμός οθόνης"
"Καρφίτσωμα"
"Σύρετε από κάτω προς τα επάνω για εναλλαγή εφαρμογών"
+ "Επισκόπηση"
+ "Δεν υπάρχουν πρόσφατα στοιχεία"
+
+
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index 694e73a956..402499e65d 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -22,4 +22,8 @@
"Split screen"
"Pin"
"Swipe up from the bottom to switch apps"
+ "Overview"
+ "No recent items"
+
+
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index 694e73a956..402499e65d 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -22,4 +22,8 @@
"Split screen"
"Pin"
"Swipe up from the bottom to switch apps"
+ "Overview"
+ "No recent items"
+
+
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index 694e73a956..402499e65d 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -22,4 +22,8 @@
"Split screen"
"Pin"
"Swipe up from the bottom to switch apps"
+ "Overview"
+ "No recent items"
+
+
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 37a3168126..1b9f926dbb 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -22,4 +22,8 @@
"Pantalla dividida"
"Fijar"
"Desliza el dedo hacia arriba para cambiar de app"
+ "Recientes"
+ "No hay elementos recientes"
+
+
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 60c87d30ca..c63f1d3ea5 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -22,4 +22,8 @@
"Dividir pantalla"
"Fijar"
"Desliza el dedo hacia arriba desde la parte inferior para cambiar de aplicación"
+ "Aplicaciones recientes"
+ "No hay elementos recientes"
+
+
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 33d1cba7e8..30199b91ca 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -22,4 +22,8 @@
"Jagatud ekraan"
"Kinnita"
"Rakenduste vahetamiseks pühkige alaosast üles"
+ "Ülevaade"
+ "Hiljutisi üksusi pole"
+
+
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index d0e86c23e4..b6386cd48d 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -22,4 +22,8 @@
"Zatitu pantaila"
"Ainguratu"
"Aplikazioak aldatzeko, pasatu hatza pantailako behealdetik gora"
+ "Ikuspegi orokorra"
+ "Ez dago azkenaldi honetako ezer"
+
+
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 198f33db80..52beadd791 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -22,4 +22,8 @@
"تقسیم صفحه"
"پین"
"برای تغییر برنامهها، از پایین تند به بالا بکشید"
+ "نمای کلی"
+ "بدون موارد اخیر"
+
+
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index f244586fa6..a27a9cb497 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -22,4 +22,8 @@
"Jaettu näyttö"
"Kiinnitä"
"Vaihda sovellusta pyyhkäisemällä alareunasta ylös."
+ "Viimeisimmät"
+ "Ei viimeaikaisia kohteita"
+
+
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index d9b2a51fe7..8a603e98ea 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -22,4 +22,8 @@
"Écran divisé"
"Épingler"
"Balayez l\'écran du bas vers le haut pour changer d\'application"
+ "Aperçu"
+ "Aucun élément récent"
+
+
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 8c1a5d2a75..91922872c6 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -22,4 +22,8 @@
"Écran partagé"
"Épingler"
"Balayer l\'écran de bas en haut pour changer d\'application"
+ "Aperçu"
+ "Aucun élément récent"
+
+
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index d6f26accf2..25d3796b49 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -22,4 +22,8 @@
"Pantalla dividida"
"Fixar"
"Pasa o dedo cara arriba desde a parte inferior para cambiar de aplicacións"
+ "Visión xeral"
+ "Non hai elementos recentes"
+
+
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 8c779d60ec..f463e130c9 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -22,4 +22,10 @@
"સ્ક્રીનને વિભાજિત કરો"
"પિન કરો"
"ઍપને સ્વિચ કરવા માટે નીચેથી ઉપર સ્વાઇપ કરો"
+
+
+
+
+
+
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 65507a9de2..ee933d1bd0 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -22,4 +22,10 @@
"स्क्रीन को दो हिस्सों में बाँटना (स्प्लिट स्क्रीन)"
"पिन करना"
"ऐप्लिकेशन स्विच करने के लिए सबसे नीचे से ऊपर की ओर स्वाइप करें"
+
+
+
+
+
+
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index eaa44167e0..a0b734f5ef 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -22,4 +22,8 @@
"Podijeljeni zaslon"
"Prikvači"
"Prijeđite prstom od dna prema gore da biste promijenili aplikaciju"
+ "Pregled"
+ "Nema nedavnih stavki"
+
+
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index b72c760b99..8a465e2a3c 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -22,4 +22,8 @@
"Osztott képernyő"
"Rögzítés"
"Ha váltani szeretne az alkalmazások között, csúsztassa gyorsan az ujját a képernyő aljától felfelé"
+ "Áttekintés"
+ "Nincsenek mostanában használt elemek"
+
+
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 632ea3e7b8..fdfe81895e 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -22,4 +22,8 @@
"Տրոհել էկրանը"
"Ամրացնել"
"Սահեցրեք ներքևից վերև՝ մյուս հավելվածին անցնելու համար"
+ "Ընդհանուր տեղեկություններ"
+ "Վերջին տարրեր չկան"
+
+
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index d731bcec98..786a10ccda 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -22,4 +22,8 @@
"Layar terpisah"
"Pasang pin"
"Geser dari bawah ke atas untuk beralih aplikasi"
+ "Ringkasan"
+ "Tidak ada item baru-baru ini"
+
+
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index d4d54d3087..b01a749245 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -22,4 +22,8 @@
"Skipta skjá"
"Festa"
"Strjúktu upp til að skipta um forrit"
+
+
+
+
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 6223ddb87d..0da2251be2 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -22,4 +22,8 @@
"Schermo diviso"
"Blocca"
"Scorri verso l\'alto dalla parte inferiore per cambiare app"
+ "Panoramica"
+ "Nessun elemento recente"
+
+
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 1da258aeaf..f7e8338781 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -22,4 +22,8 @@
"מסך מפוצל"
"הצמדה"
"יש להחליק כלפי מעלה מהחלק התחתון כדי לעבור בין אפליקציות"
+ "מסכים אחרונים"
+ "אין פריטים אחרונים"
+
+
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index bee863fa5a..7e14d2c689 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -22,4 +22,8 @@
"分割画面"
"固定"
"アプリを切り替えるには、下から上にスワイプします"
+ "概要"
+ "最近のアイテムはありません"
+
+
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 4488cf8b67..cf4c661d3d 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -22,4 +22,8 @@
"ეკრანის გაყოფა"
"ჩამაგრება"
"აპების გადასართავად გადაფურცლეთ ქვედა კიდედან ზემოთ"
+ "მიმოხილვა"
+ "ბოლოს გამოყენებული ერთეულები არ არის"
+
+
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 8c82ef1839..f865a0405e 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -22,4 +22,8 @@
"Экранды бөлу"
"Бекіту"
"Қолданбалар арасында ауысу үшін төменнен жоғары қарай саусақпен сырғытыңыз"
+ "Шолу"
+ "Соңғы элементтер жоқ"
+
+
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 64136c9bee..a35ab26aad 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -22,4 +22,8 @@
"មុខងារបំបែកអេក្រង់"
"ដៅ"
"អូសពីក្រោមឡើងលើ ដើម្បីប្ដូរកម្មវិធី"
+ "ទិដ្ឋភាពរួម"
+ "មិនមានធាតុថ្មីៗទេ"
+
+
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 7f12deef3b..dc57df1d35 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -22,4 +22,8 @@
"ಪರದೆಯನ್ನು ಬೇರ್ಪಡಿಸಿ"
"ಪಿನ್ ಮಾಡಿ"
"ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಬದಲಿಸಲು ಕೆಳಗಿನಿಂದ ಮೇಲಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡಿ"
+ "ಅವಲೋಕನ"
+ "ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"
+
+
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 39fdf33113..36fd122d73 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -22,4 +22,8 @@
"화면 분할"
"고정"
"아래에서 위로 스와이프하여 앱을 전환합니다."
+ "최근 사용"
+ "최근 항목이 없습니다."
+
+
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 2602b51adf..060a8dd21c 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -22,4 +22,8 @@
"Экранды бөлүү"
"Кадап коюу"
"Колдонмолорду которуштуруу үчүн экранды төмөндөн жогору карай сүрүңүз"
+ "Сереп салуу"
+ "Акыркы колдонмолор жок"
+
+
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index 7ba29d2331..1abb856d97 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -22,4 +22,8 @@
"ແບ່ງໜ້າຈໍ"
"ປັກໝຸດ"
"ປັດຂຶ້ນຈາກລຸ່ມສຸດເພື່ອສະຫຼັບແອັບ"
+ "ພາບຮວມ"
+ "ບໍ່ມີລາຍການຫຼ້າສຸດ"
+
+
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index 2252381fb5..0c09a94500 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -22,4 +22,8 @@
"Skaidyti ekraną"
"Prisegti"
"Perbraukite aukštyn iš apačios, kad perjungtumėte programas"
+ "Apžvalga"
+ "Nėra jokių naujausių elementų"
+
+
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index d5f5e9c98d..72d1cb575d 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -22,4 +22,8 @@
"Sadalīt ekrānu"
"Piespraust"
"Lai pārslēgtu lietotnes, velciet augšup no apakšdaļas."
+ "Pārskats"
+ "Nav nesenu vienumu."
+
+
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 6458aa085a..06bf5d0c11 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -22,4 +22,8 @@
"Поделен екран"
"Прикачување"
"Повлечете нагоре од дното за да ги смените апликациите"
+ "Преглед"
+ "Нема неодамнешни ставки"
+
+
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 4d2745af4f..b936906560 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -22,4 +22,8 @@
"സ്ക്രീൻ വിഭജിക്കുക"
"പിൻ ചെയ്യുക"
"ആപ്പുകൾ മാറാൻ താഴെ നിന്ന് മുകളിലേക്ക് സ്വൈപ്പ് ചെയ്യുക"
+ "അവലോകനം"
+ "സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"
+
+
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 4aec25724a..8b92214916 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -22,4 +22,8 @@
"Дэлгэцийг хуваах"
"Тогтоох"
"Аппыг сэлгэхийн тулд доороос дээш шударна уу"
+ "Тойм"
+ "Сүүлийн үеийн зүйл алга"
+
+
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 3f85d777ef..596792d103 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -22,4 +22,8 @@
"विभाजित स्क्रीन"
"पिन करा"
"अॅप्स स्विच करण्यासाठी तळापासून वर स्वाइप करा"
+ "अवलोकन"
+ "कोणतेही अलीकडील आयटम नाहीत"
+
+
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 80e942cb4a..336aaf6594 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -22,4 +22,8 @@
"Skrin pisah"
"Semat"
"Leret ke atas dari bawah untuk menukar apl"
+ "Ikhtisar"
+ "Tiada item terbaharu"
+
+
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index b6b0300a45..d71e5fc93f 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -22,4 +22,8 @@
"မျက်နှာပြင် ခွဲ၍ပြသခြင်း"
"ပင်ထိုးခြင်း"
"အက်ပ်များပြောင်းရန် အောက်ခြေမှ အပေါ်သို့ပွတ်ဆွဲပါ"
+ "အနှစ်ချုပ်"
+ "မကြာမီကဖွင့်ထားသည်များ မရှိပါ"
+
+
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 4dc144cc40..504f43ae80 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -22,4 +22,8 @@
"Delt skjerm"
"Fest"
"Sveip opp fra bunnen for å bytte app"
+ "Oversikt"
+ "Ingen nylige elementer"
+
+
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index a171b73df0..7500213890 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -22,4 +22,8 @@
"स्क्रिन विभाजन गर्नुहोस्"
"पिन गर्नुहोस्"
"अनुप्रयोगहरू बदल्न तलबाट माथितिर स्वाइप गर्नुहोस्"
+ "परिदृश्य"
+ "हालसालैको कुनै पनि वस्तु छैन"
+
+
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 4acddc54b3..2ba24a6e28 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -22,4 +22,8 @@
"Gesplitst scherm"
"Vastzetten"
"Veeg omhoog vanaf de onderkant om tussen apps te wisselen"
+ "Overzicht"
+ "Geen recente items"
+
+
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 6bc1876b57..fbcb60cd6f 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -22,4 +22,8 @@
"ਸਪਲਿਟ ਸਕ੍ਰੀਨ"
"ਪਿੰਨ ਕਰੋ"
"ਐਪਾਂ ਵਿੱਚ ਅਦਲਾ-ਬਦਲੀ ਕਰਨ ਲਈ ਹੇਠਾਂ ਤੋਂ ਉੱਪਰ ਵੱਲ ਸਵਾਈਪ ਕਰੋ"
+ "ਰੂਪ-ਰੇਖਾ"
+ "ਕੋਈ ਹਾਲੀਆ ਆਈਟਮਾਂ ਨਹੀਂ"
+
+
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 174a96a767..1ad7070bd5 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -22,4 +22,8 @@
"Podziel ekran"
"Przypnij"
"Przesuń palcem z dołu ekranu, by przełączać aplikacje"
+ "Przegląd"
+ "Brak ostatnich elementów"
+
+
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index c3df4f2438..a63d32998d 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -22,4 +22,8 @@
"Ecrã dividido"
"Fixar"
"Deslize rapidamente para cima a partir da parte inferior para alternar entre aplicações."
+ "Vista geral"
+ "Nenhum item recente"
+
+
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 9730b98c30..05d20e08e0 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -22,4 +22,8 @@
"Tela dividida"
"Fixar"
"Deslize de baixo para cima para alternar entre apps"
+ "Visão geral"
+ "Nenhum item recente"
+
+
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 46671e8350..4264370f40 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -22,4 +22,8 @@
"Ecran divizat"
"Fixați"
"Glisați de jos în sus pentru a schimba aplicațiile"
+ "Recente"
+ "Niciun element recent"
+
+
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index c2edf750b7..47ddff53ca 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -22,4 +22,8 @@
"Разделить экран"
"Блокировать"
"Чтобы переключить приложение, проведите по экрану снизу вверх"
+ "Обзор"
+ "Недавних приложений нет."
+
+
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 7702543ecc..a9b1493bb5 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -22,4 +22,8 @@
"බෙදුම් තිරය"
"අමුණන්න"
"යෙදුම් මාරු කිරීම සඳහා පහළ සිට ස්වයිප් කරන්න"
+ "දළ විශ්ලේෂණය"
+ "මෑත අයිතම නැත"
+
+
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 84e779324d..fe028554f6 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -22,4 +22,8 @@
"Rozdeliť obrazovku"
"Pripnúť"
"Aplikácie môžete prepínať potiahnutím prstom zdola nahor"
+ "Prehľad"
+ "Žiadne nedávne položky"
+
+
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index c01fcd42a8..72d52a51c6 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -22,4 +22,8 @@
"Razdeljen zaslon"
"Pripni"
"Če želite preklopiti med aplikacijami, z dna zaslona s prstom povlecite navzgor"
+ "Pregled"
+ "Ni nedavnih elementov"
+
+
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index ae6e6bc961..954342cd93 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -22,4 +22,8 @@
"Ekrani i ndarë"
"Gozhdo"
"Rrëshqit larg nga poshtë për të ndryshuar aplikacionet"
+ "Përmbledhja"
+ "Nuk ka asnjë artikull të fundit"
+
+
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 84debfd670..51a9586e64 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -22,4 +22,8 @@
"Подељени екран"
"Закачи"
"Превуците нагоре да бисте прешли на другу апликацију"
+ "Преглед"
+ "Нема недавних ставки"
+
+
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 495bca7960..266cf60ef7 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -22,4 +22,8 @@
"Delad skärm"
"Fäst"
"Växla mellan appar genom att svepa uppåt från nederkanten"
+ "Översikt"
+ "Listan med de senaste åtgärderna är tom"
+
+
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 63594f2bf7..e85fa45bbd 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -22,4 +22,8 @@
"Gawa skrini"
"Bandika"
"Telezesha kidole juu kuanzia chini ili ubadilishe programu"
+ "Muhtasari"
+ "Hakuna vipengee vya hivi karibuni"
+
+
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 2d740cab9b..de03ae62e8 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -22,4 +22,8 @@
"திரைப் பிரிப்பு"
"பின் செய்தல்"
"ஆப்ஸிற்கு இடையே மாற்றுவதற்கு, கீழிருந்து மேல்நோக்கி ஸ்வைப் செய்க"
+
+
+
+
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 36e5e3ef70..108f35042c 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -22,4 +22,8 @@
"స్క్రీన్ని విభజించు"
"పిన్ చేయి"
"యాప్లను మార్చడానికి దిగువ నుండి పైకి స్వైప్ చేయండి"
+ "అవలోకనం"
+ "ఇటీవలి అంశాలు ఏవీ లేవు"
+
+
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 882b096122..80f91b087b 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -22,4 +22,8 @@
"แยกหน้าจอ"
"ตรึง"
"เลื่อนขึ้นจากด้านล่างเพื่อสลับแอป"
+ "ภาพรวม"
+ "ไม่มีรายการล่าสุด"
+
+
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index dbd03b162c..b28e04e72d 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -22,4 +22,8 @@
"Hatiin ang screen"
"I-pin"
"Mag-swipe pataas mula sa ibaba para lumipat ng app"
+ "Overview"
+ "Walang kamakailang item"
+
+
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 57cb3499e3..1399353561 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -22,4 +22,8 @@
"Bölünmüş ekran"
"Sabitle"
"Uygulamaları değiştirmek için alttan yukarı kaydırın"
+ "Genel bakış"
+ "Yeni öğe yok"
+
+
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 8c2c6f6f0b..929bbe795d 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -22,4 +22,8 @@
"Розділити екран"
"Закріпити"
"Щоб переходити між додатками, проводьте пальцем знизу вгору"
+ "Огляд"
+ "Немає нещодавніх додатків"
+
+
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index ab5b38f756..0271fe4d24 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -22,4 +22,10 @@
"اسپلٹ اسکرین وضع"
"پن کریں"
"ایپس کو سوئچ کرنے کیلئے نیچے سے اوپر سوائپ کریں"
+
+
+
+
+
+
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 280bd88df2..91e11d3dca 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -22,4 +22,8 @@
"Ekranni ikkiga ajratish"
"Mahkamlash"
"Ilovalarni almashtirish uchun pastdan yuqoriga suring"
+ "Nazar"
+ "Yaqinda ishlatilgan ilovalar yo‘q"
+
+
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 2aca3b8076..809517a58b 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -22,4 +22,8 @@
"Chia đôi màn hình"
"Ghim"
"Vuốt từ dưới lên để chuyển đổi ứng dụng"
+ "Tổng quan"
+ "Không có mục gần đây nào"
+
+
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 165f141331..a44dd2db06 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -22,4 +22,8 @@
"分屏"
"固定"
"从屏幕底部向上滑动即可切换应用"
+ "概览"
+ "近期没有任何内容"
+
+
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 6ba0244c6a..3879bc568e 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -22,4 +22,8 @@
"分割畫面"
"固定"
"從螢幕底部向上快速滑動,即可切換應用程式"
+ "概覽"
+ "最近沒有任何項目"
+
+
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 9834038218..f275168f67 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -22,4 +22,8 @@
"分割畫面"
"固定"
"從畫面底部向上滑動以切換應用程式"
+ "總覽"
+ "最近沒有任何項目"
+
+
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index a4ba48ca4d..206718eff8 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -22,4 +22,8 @@
"Hlukanisa isikrini"
"Phina"
"Swayiphela phezulu kusukela phansi ukuze ushintshe izinhlelo zokusebenza"
+ "Buka konke"
+ "Azikho izinto zakamuva"
+
+
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index b751e0d9c9..c741913953 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -20,7 +20,6 @@
48dp
12dp
2dp
- 20dp
10dp
25dp
80dp
- 140dp
- 80dp
- 150%
+
+ 16sp
+ 16dp
+
+
+ 40dp
+ 136dp
+ 200dp
+ 100dp
+
+ 10dp
diff --git a/quickstep/res/values/override.xml b/quickstep/res/values/override.xml
index 2bd9f8f6f3..d6836594f4 100644
--- a/quickstep/res/values/override.xml
+++ b/quickstep/res/values/override.xml
@@ -18,5 +18,7 @@
com.android.launcher3.LauncherAppTransitionManagerImpl
com.android.quickstep.InstantAppResolverImpl
+
+ com.android.quickstep.QuickstepProcessInitializer
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index ec8eb5274b..7ba91b3db5 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -29,4 +29,13 @@
Swipe up from the bottom to switch apps
+
+
+ Overview
+
+
+ No recent items
+
+
+ Close
\ No newline at end of file
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index 5a090d9e4c..ad0b7344b6 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -52,16 +52,15 @@ import com.android.launcher3.InsettableFrameLayout.LayoutParams;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.graphics.DrawableFactory;
-import com.android.launcher3.shortcuts.DeepShortcutTextView;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.quickstep.RecentsAnimationInterpolator;
import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds;
+import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.views.RecentsView;
-import com.android.systemui.shared.recents.model.Task;
import com.android.quickstep.views.TaskView;
+import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityCompat;
import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
@@ -93,8 +92,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
private static final int CLOSING_TRANSITION_DURATION_MS = 350;
// Progress = 0: All apps is fully pulled up, Progress = 1: All apps is fully pulled down.
- private static final float ALL_APPS_PROGRESS_OFF_SCREEN = 1.3059858f;
- private static final float ALL_APPS_PROGRESS_OVERSHOOT = 0.99581414f;
+ public static final float ALL_APPS_PROGRESS_OFF_SCREEN = 1.3059858f;
+ public static final float ALL_APPS_PROGRESS_OVERSHOOT = 0.99581414f;
private final DragLayer mDragLayer;
private final Launcher mLauncher;
@@ -104,13 +103,12 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
private final float mContentTransY;
private final float mWorkspaceTransY;
- private final float mRecentsTransX;
- private final float mRecentsTransY;
- private final float mRecentsScale;
private DeviceProfile mDeviceProfile;
private View mFloatingView;
+ private RemoteAnimationProvider mRemoteAnimationProvider;
+
private final AnimatorListenerAdapter mReapplyStateListener = new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
@@ -129,9 +127,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
Resources res = mLauncher.getResources();
mContentTransY = res.getDimensionPixelSize(R.dimen.content_trans_y);
mWorkspaceTransY = res.getDimensionPixelSize(R.dimen.workspace_trans_y);
- mRecentsTransX = res.getDimensionPixelSize(R.dimen.recents_adjacent_trans_x);
- mRecentsTransY = res.getDimensionPixelSize(R.dimen.recents_adjacent_trans_y);
- mRecentsScale = res.getFraction(R.fraction.recents_adjacent_scale, 1, 1);
mLauncher.addOnDeviceProfileChangeListener(this);
registerRemoteAnimations();
@@ -154,15 +149,20 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
@Override
public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
- Animator[] anims = composeRecentsLaunchAnimator(v, targetCompats);
AnimatorSet anim = new AnimatorSet();
- if (anims != null) {
- anim.playTogether(anims);
- } else {
- anim.play(getLauncherAnimators(v, targetCompats));
+
+
+ if (!composeRecentsLaunchAnimator(v, targetCompats, anim)) {
+ // Set the state animation first so that any state listeners are called
+ // before our internal listeners.
+ mLauncher.getStateManager().setCurrentAnimation(anim);
+
+ anim.play(getIconAnimator(v));
+ if (launcherIsATargetWithMode(targetCompats, MODE_CLOSING)) {
+ anim.play(getLauncherContentAnimator(false /* show */));
+ }
anim.play(getWindowAnimators(v, targetCompats));
}
- mLauncher.getStateManager().setCurrentAnimation(anim);
return anim;
}
};
@@ -180,6 +180,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
return getDefaultActivityLaunchOptions(launcher, v);
}
+ public void setRemoteAnimationProvider(RemoteAnimationProvider animationProvider) {
+ mRemoteAnimationProvider = animationProvider;
+ }
+
/**
* Try to find a TaskView that corresponds with the component of the launched view.
*
@@ -241,11 +245,11 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
/**
* Composes the animations for a launch from the recents list if possible.
*/
- private Animator[] composeRecentsLaunchAnimator(View v,
- RemoteAnimationTargetCompat[] targets) {
+ private boolean composeRecentsLaunchAnimator(View v,
+ RemoteAnimationTargetCompat[] targets, AnimatorSet target) {
// Ensure recents is actually visible
if (!mLauncher.getStateManager().getState().overviewUi) {
- return null;
+ return false;
}
RecentsView recentsView = mLauncher.getOverviewPanel();
@@ -254,14 +258,17 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
TaskView taskView = findTaskViewToLaunch(mLauncher, v, targets);
if (taskView == null) {
- return null;
+ return false;
}
// Found a visible recents task that matches the opening app, lets launch the app from there
Animator launcherAnim;
final AnimatorListenerAdapter windowAnimEndListener;
if (launcherClosing) {
- launcherAnim = getRecentsLauncherAnimator(recentsView, taskView);
+ launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView);
+ launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
+ launcherAnim.setDuration(RECENTS_LAUNCH_DURATION);
+
// Make sure recents gets fixed up by resetting task alphas and scales, etc.
windowAnimEndListener = mReapplyStateListener;
} else {
@@ -278,90 +285,15 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
};
}
- Animator windowAnim = getRecentsWindowAnimator(taskView, skipLauncherChanges, targets);
- windowAnim.addListener(windowAnimEndListener);
- return new Animator[] {launcherAnim, windowAnim};
- }
+ target.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, targets));
+ target.play(launcherAnim);
- /**
- * Animate adjacent tasks off screen while scaling up, and translate hotseat off screen as well.
- *
- * If launching one of the adjacent tasks, parallax the center task and other adjacent task
- * to the right.
- */
- private Animator getRecentsLauncherAnimator(RecentsView recentsView, TaskView v) {
- AnimatorSet launcherAnimator = new AnimatorSet();
-
- int launchedTaskIndex = recentsView.indexOfChild(v);
- int centerTaskIndex = recentsView.getCurrentPage();
- boolean launchingCenterTask = launchedTaskIndex == centerTaskIndex;
- boolean isRtl = recentsView.isRtl();
- if (launchingCenterTask) {
- if (launchedTaskIndex - 1 >= 0) {
- TaskView adjacentPage1 = (TaskView) recentsView.getPageAt(launchedTaskIndex - 1);
- ObjectAnimator adjacentTask1ScaleAndTranslate =
- LauncherAnimUtils.ofPropertyValuesHolder(adjacentPage1,
- new PropertyListBuilder()
- .scale(adjacentPage1.getScaleX() * mRecentsScale)
- .translationY(mRecentsTransY)
- .translationX(isRtl ? mRecentsTransX : -mRecentsTransX)
- .build());
- launcherAnimator.play(adjacentTask1ScaleAndTranslate);
- }
- if (launchedTaskIndex + 1 < recentsView.getPageCount()) {
- TaskView adjacentTask2 = (TaskView) recentsView.getPageAt(launchedTaskIndex + 1);
- ObjectAnimator adjacentTask2ScaleAndTranslate =
- LauncherAnimUtils.ofPropertyValuesHolder(adjacentTask2,
- new PropertyListBuilder()
- .scale(adjacentTask2.getScaleX() * mRecentsScale)
- .translationY(mRecentsTransY)
- .translationX(isRtl ? -mRecentsTransX : mRecentsTransX)
- .build());
- launcherAnimator.play(adjacentTask2ScaleAndTranslate);
- }
- } else {
- // We are launching an adjacent task, so parallax the center and other adjacent task.
- TaskView centerTask = (TaskView) recentsView.getPageAt(centerTaskIndex);
- float translationX = mRecentsTransX / 2;
- ObjectAnimator centerTaskParallaxOffscreen =
- LauncherAnimUtils.ofPropertyValuesHolder(centerTask,
- new PropertyListBuilder()
- .translationX(isRtl ? -translationX : translationX)
- .build());
- launcherAnimator.play(centerTaskParallaxOffscreen);
- int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex);
- if (otherAdjacentTaskIndex >= 0
- && otherAdjacentTaskIndex < recentsView.getPageCount()) {
- TaskView otherAdjacentTask = (TaskView) recentsView.getPageAt(
- otherAdjacentTaskIndex);
- ObjectAnimator otherAdjacentTaskParallaxOffscreen =
- LauncherAnimUtils.ofPropertyValuesHolder(otherAdjacentTask,
- new PropertyListBuilder()
- .translationX(isRtl ? -translationX : translationX)
- .build());
- launcherAnimator.play(otherAdjacentTaskParallaxOffscreen);
- }
- }
-
- Animator allAppsSlideOut = ObjectAnimator.ofFloat(mLauncher.getAllAppsController(),
- ALL_APPS_PROGRESS, ALL_APPS_PROGRESS_OFF_SCREEN);
- launcherAnimator.play(allAppsSlideOut);
-
- Workspace workspace = mLauncher.getWorkspace();
- float[] workspaceScaleAndTranslation = NORMAL
- .getWorkspaceScaleAndTranslation(mLauncher);
- Animator recenterWorkspace = LauncherAnimUtils.ofPropertyValuesHolder(
- workspace, new PropertyListBuilder()
- .translationX(workspaceScaleAndTranslation[1])
- .translationY(workspaceScaleAndTranslation[2])
- .build());
- launcherAnimator.play(recenterWorkspace);
- CellLayout currentWorkspacePage = (CellLayout) workspace.getPageAt(
- workspace.getCurrentPage());
-
- launcherAnimator.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR);
- launcherAnimator.setDuration(RECENTS_LAUNCH_DURATION);
- return launcherAnimator;
+ // Set the current animation first, before adding windowAnimEndListener. Setting current
+ // animation adds some listeners which need to be called before windowAnimEndListener
+ // (the ordering of listeners matter in this case).
+ mLauncher.getStateManager().setCurrentAnimation(target);
+ target.addListener(windowAnimEndListener);
+ return true;
}
/**
@@ -370,18 +302,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
*/
private ValueAnimator getRecentsWindowAnimator(TaskView v, boolean skipLauncherChanges,
RemoteAnimationTargetCompat[] targets) {
- Rect taskViewBounds = new Rect();
- mDragLayer.getDescendantRectRelativeToSelf(v, taskViewBounds);
-
- // TODO: Use the actual target insets instead of the current thumbnail insets in case the
- // device state has changed
- RecentsAnimationInterpolator recentsInterpolator = new RecentsAnimationInterpolator(
- new Rect(0, 0, mDeviceProfile.widthPx, mDeviceProfile.heightPx),
- v.getThumbnail().getInsets(),
- taskViewBounds,
- new Rect(0, v.getThumbnail().getTop(), 0, 0),
- v.getScaleX(),
- v.getTranslationX());
+ final RecentsAnimationInterpolator recentsInterpolator = v.getRecentsInterpolator();
Rect crop = new Rect();
Matrix matrix = new Matrix();
@@ -404,13 +325,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
final float percent = animation.getAnimatedFraction();
TaskWindowBounds tw = recentsInterpolator.interpolate(percent);
+ float alphaDuration = 75;
if (!skipLauncherChanges) {
v.setScaleX(tw.taskScale);
v.setScaleY(tw.taskScale);
v.setTranslationX(tw.taskX);
v.setTranslationY(tw.taskY);
// Defer fading out the view until after the app window gets faded in
- v.setAlpha(getValue(1f, 0f, 75, 75,
+ v.setAlpha(getValue(1f, 0f, alphaDuration, alphaDuration,
appAnimator.getDuration() * percent, Interpolators.LINEAR));
}
@@ -419,7 +341,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
crop.set(tw.winCrop);
// Fade in the app window.
- float alphaDuration = 75;
float alpha = getValue(0f, 1f, 0, alphaDuration,
appAnimator.getDuration() * percent, Interpolators.LINEAR);
@@ -442,6 +363,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
t.show(target.leash);
}
}
+ t.setEarlyWakeup();
t.apply();
matrix.reset();
@@ -451,18 +373,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
return appAnimator;
}
- /**
- * @return Animators that control the movements of the Launcher and icon of the opening target.
- */
- private AnimatorSet getLauncherAnimators(View v, RemoteAnimationTargetCompat[] targets) {
- AnimatorSet launcherAnimators = new AnimatorSet();
- launcherAnimators.play(getIconAnimator(v));
- if (launcherIsATargetWithMode(targets, MODE_CLOSING)) {
- launcherAnimators.play(getLauncherContentAnimator(false /* show */));
- }
- return launcherAnimators;
- }
-
/**
* Content is everything on screen except the background and the floating view (if any).
*
@@ -727,6 +637,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
t.show(target.leash);
}
}
+ t.setEarlyWakeup();
t.apply();
matrix.reset();
@@ -740,6 +651,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
* Registers remote animations used when closing apps to home screen.
*/
private void registerRemoteAnimations() {
+ // Unregister this
if (hasControlRemoteAppTransitionPermission()) {
try {
RemoteAnimationDefinitionCompat definition = new RemoteAnimationDefinitionCompat();
@@ -775,21 +687,33 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
return new LauncherAnimationRunner(mHandler) {
@Override
public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
- if (mLauncher.getStateManager().getState().overviewUi) {
- // We use a separate transition for Overview mode.
- return null;
+ AnimatorSet anim = null;
+ RemoteAnimationProvider provider = mRemoteAnimationProvider;
+ if (provider != null) {
+ anim = provider.createWindowAnimation(targetCompats);
}
- AnimatorSet anim = new AnimatorSet();
- anim.play(getClosingWindowAnimators(targetCompats));
+ if (anim == null) {
+ anim = new AnimatorSet();
+ anim.play(getClosingWindowAnimators(targetCompats));
- if (launcherIsATargetWithMode(targetCompats, MODE_OPENING)) {
- AnimatorSet contentAnimation = getLauncherResumeAnimation();
- anim.play(contentAnimation);
-
- // Only register the content animation for cancellation when state changes
- mLauncher.getStateManager().setCurrentAnimation(contentAnimation);
+ // Normally, we run the launcher content animation when we are transitioning
+ // home, but if home is already visible, then we don't want to animate the
+ // contents of launcher unless we know that we are animating home as a result
+ // of the home button press with quickstep, which will result in launcher being
+ // started on touch down, prior to the animation home (and won't be in the
+ // targets list because it is already visible). In that case, we force
+ // invisibility on touch down, and only reset it after the animation to home
+ // is initialized.
+ if (launcherIsATargetWithMode(targetCompats, MODE_OPENING)
+ || mLauncher.isForceInvisible()) {
+ // Only register the content animation for cancellation when state changes
+ mLauncher.getStateManager().setCurrentAnimation(anim);
+ createLauncherResumeAnimation(anim);
+ }
}
+
+ mLauncher.setForceInvisible(false);
return anim;
}
};
@@ -841,6 +765,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
t.show(app.leash);
}
}
+ t.setEarlyWakeup();
t.apply();
matrix.reset();
@@ -851,14 +776,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
}
/**
- * @return Animator that modifies Launcher as a result from {@link #getWallpaperOpenRunner}.
+ * Creates an animator that modifies Launcher as a result from {@link #getWallpaperOpenRunner}.
*/
- private AnimatorSet getLauncherResumeAnimation() {
+ private void createLauncherResumeAnimation(AnimatorSet anim) {
if (mLauncher.isInState(LauncherState.ALL_APPS)
|| mLauncher.getDeviceProfile().isVerticalBarLayout()) {
AnimatorSet contentAnimator = getLauncherContentAnimator(true /* show */);
contentAnimator.setStartDelay(LAUNCHER_RESUME_START_DELAY);
- return contentAnimator;
+ anim.play(contentAnimator);
} else {
AnimatorSet workspaceAnimator = new AnimatorSet();
@@ -896,12 +821,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag
allAppsOvershoot.setDuration(153);
allAppsOvershoot.setInterpolator(Interpolators.OVERSHOOT_0);
- AnimatorSet resumeLauncherAnimation = new AnimatorSet();
- resumeLauncherAnimation.play(workspaceAnimator);
- resumeLauncherAnimation.playSequentially(allAppsSlideIn, allAppsOvershoot);
- resumeLauncherAnimation.addListener(mReapplyStateListener);
- return resumeLauncherAnimation;
+ anim.play(workspaceAnimator);
+ anim.playSequentially(allAppsSlideIn, allAppsOvershoot);
+ anim.addListener(mReapplyStateListener);
}
}
diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java
index 0d1038a2d9..27f169834d 100644
--- a/quickstep/src/com/android/launcher3/LauncherInitListener.java
+++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java
@@ -15,13 +15,16 @@
*/
package com.android.launcher3;
-import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
-
import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.Intent;
import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
import com.android.launcher3.states.InternalStateHandler;
import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+import com.android.quickstep.util.RemoteAnimationProvider;
import java.util.function.BiPredicate;
@@ -30,15 +33,33 @@ public class LauncherInitListener extends InternalStateHandler implements Activi
private final BiPredicate mOnInitListener;
+ private RemoteAnimationProvider mRemoteAnimationProvider;
+
public LauncherInitListener(BiPredicate onInitListener) {
mOnInitListener = onInitListener;
}
@Override
protected boolean init(Launcher launcher, boolean alreadyOnHome) {
- // For the duration of the gesture, lock the screen orientation to ensure that we do not
- // rotate mid-quickscrub
- launcher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK);
+ if (mRemoteAnimationProvider != null) {
+ LauncherAppTransitionManagerImpl appTransitionManager =
+ (LauncherAppTransitionManagerImpl) launcher.getAppTransitionManager();
+
+ // Set a one-time animation provider. After the first call, this will get cleared.
+ // TODO: Probably also check the intended target id.
+ appTransitionManager.setRemoteAnimationProvider((targets) -> {
+
+ // On the first call clear the reference.
+ appTransitionManager.setRemoteAnimationProvider(null);
+ RemoteAnimationProvider provider = mRemoteAnimationProvider;
+ mRemoteAnimationProvider = null;
+
+ if (provider != null && launcher.getStateManager().getState().overviewUi) {
+ return provider.createWindowAnimation(targets);
+ }
+ return null;
+ });
+ }
return mOnInitListener.test(launcher, alreadyOnHome);
}
@@ -49,6 +70,18 @@ public class LauncherInitListener extends InternalStateHandler implements Activi
@Override
public void unregister() {
+ mRemoteAnimationProvider = null;
clearReference();
}
+
+ @Override
+ public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
+ Context context, Handler handler, long duration) {
+ mRemoteAnimationProvider = animProvider;
+
+ register();
+
+ Bundle options = animProvider.toActivityOptions(handler, duration).toBundle();
+ context.startActivity(addToIntent(new Intent((intent))), options);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index 2626e7cccc..d2f54874f5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -88,10 +88,8 @@ public class AllAppsState extends LauncherState {
}
@Override
- public float[] getOverviewTranslationFactor(Launcher launcher) {
- // Keep the same translation as in overview, so that we don't slide around when
- // transitioning to All Apps.
- return LauncherState.OVERVIEW.getOverviewTranslationFactor(launcher);
+ public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
+ return new float[] {1f, -0.2f};
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
index 99bf2649b9..f98f7a5ffa 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
@@ -50,7 +50,7 @@ public class FastOverviewState extends OverviewState {
}
@Override
- public float[] getOverviewTranslationFactor(Launcher launcher) {
- return new float[] {0f, 0.5f};
+ public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
+ return new float[] {1f, 0.5f};
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
index 23add9595c..3622fc4250 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/LandscapeEdgeSwipeController.java
@@ -37,11 +37,15 @@ public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchContro
@Override
protected int getSwipeDirection(MotionEvent ev) {
- mFromState = NORMAL;
- mToState = OVERVIEW;
return SwipeDetector.DIRECTION_BOTH;
}
+ @Override
+ protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+ boolean draggingFromNav = mLauncher.getDeviceProfile().isSeascape() != isDragTowardPositive;
+ return draggingFromNav ? OVERVIEW : NORMAL;
+ }
+
@Override
protected float getShiftRange() {
return mLauncher.getDragLayer().getWidth();
diff --git a/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java
index 720b20ac1b..30ceb43f93 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/LandscapeStatesTouchController.java
@@ -58,13 +58,15 @@ public class LandscapeStatesTouchController extends PortraitStatesTouchControlle
}
}
- protected LauncherState getTargetState() {
- if (mLauncher.isInState(ALL_APPS)) {
+ @Override
+ protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+ if (fromState == ALL_APPS && !isDragTowardPositive) {
// Should swipe down go to OVERVIEW instead?
return TouchInteractionService.isConnected() ?
mLauncher.getStateManager().getLastState() : NORMAL;
- } else {
+ } else if (isDragTowardPositive) {
return ALL_APPS;
}
+ return fromState;
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index a72b1b15bf..9c7db3093a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -19,13 +19,11 @@ import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
-import android.graphics.Rect;
import android.view.View;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.Workspace;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.views.RecentsView;
@@ -47,19 +45,13 @@ public class OverviewState extends LauncherState {
@Override
public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
- Rect pageRect = new Rect();
- RecentsView.getPageRect(launcher.getDeviceProfile(), launcher, pageRect);
-
- if (launcher.getWorkspace().getNormalChildWidth() <= 0 || pageRect.isEmpty()) {
- return super.getWorkspaceScaleAndTranslation(launcher);
- }
-
- return getScaleAndTranslationForPageRect(launcher, pageRect);
+ // TODO: provide a valid value
+ return new float[]{1, 0, -launcher.getDeviceProfile().hotseatBarSizePx / 2};
}
@Override
- public float[] getOverviewTranslationFactor(Launcher launcher) {
- return new float[] {0f, 0f};
+ public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
+ return new float[] {1f, 0f};
}
@Override
@@ -93,27 +85,14 @@ public class OverviewState extends LauncherState {
};
}
- public static float[] getScaleAndTranslationForPageRect(Launcher launcher, Rect pageRect) {
- Workspace ws = launcher.getWorkspace();
- float childWidth = ws.getNormalChildWidth();
-
- float scale = pageRect.width() / childWidth;
- Rect insets = launcher.getDragLayer().getInsets();
-
- float halfHeight = ws.getExpectedHeight() / 2;
- float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top);
- float translationY = pageRect.top - childTop;
-
- return new float[] {scale, 0, translationY};
- }
-
@Override
public int getVisibleElements(Launcher launcher) {
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
- return NONE;
+ return DRAG_HANDLE_INDICATOR;
} else {
- return launcher.getAppsView().getFloatingHeaderView().hasVisibleContent()
- ? HOTSEAT_EXTRA | ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS | HOTSEAT_EXTRA;
+ return HOTSEAT_SEARCH_BOX | DRAG_HANDLE_INDICATOR |
+ (launcher.getAppsView().getFloatingHeaderView().hasVisibleContent()
+ ? ALL_APPS_HEADER_EXTRA : HOTSEAT_ICONS);
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
index 1e006e5752..012b545212 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/PortraitStatesTouchController.java
@@ -32,22 +32,27 @@ import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
+import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SwipeDetector;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.TouchInteractionService;
import com.android.quickstep.util.SysuiEventLogger;
+import com.android.quickstep.views.RecentsView;
+import com.android.quickstep.views.TaskView;
/**
* Touch controller for handling various state transitions in portrait UI.
*/
public class PortraitStatesTouchController extends AbstractStateChangeTouchController {
- private static final float TOTAL_DISTANCE_MULTIPLIER = 2f;
+ private static final float TOTAL_DISTANCE_MULTIPLIER = 3f;
private static final float LINEAR_SCALE_LIMIT = 1 / TOTAL_DISTANCE_MULTIPLIER;
- // Much be greater than LINEAR_SCALE_LIMIT;
+ // Must be greater than LINEAR_SCALE_LIMIT;
private static final float MAXIMUM_DISTANCE_FACTOR = 0.9f;
// Maximum amount to overshoot.
@@ -57,9 +62,6 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
private InterpolatorWrapper mAllAppsInterpolatorWrapper = new InterpolatorWrapper();
- // If > 0, the animation progress is clamped at that value as long as user is dragging.
- private float mClampProgressUpdate = -1;
-
// If true, we will finish the current animation instantly on second touch.
private boolean mFinishFastOnSecondTouch;
@@ -129,29 +131,26 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
mStartContainerType = ContainerType.HOTSEAT;
} else if (mLauncher.isInState(OVERVIEW)) {
- directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+ directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
mStartContainerType = ContainerType.TASKSWITCHER;
} else {
return 0;
}
- mFromState = mLauncher.getStateManager().getState();
- mToState = getTargetState();
- if (mFromState == mToState) {
- return 0;
- }
return directionsToDetectScroll;
}
- protected LauncherState getTargetState() {
- if (mLauncher.isInState(ALL_APPS)) {
+ @Override
+ protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+ if (fromState == ALL_APPS && !isDragTowardPositive) {
// Should swipe down go to OVERVIEW instead?
return TouchInteractionService.isConnected() ?
mLauncher.getStateManager().getLastState() : NORMAL;
- } else if (mLauncher.isInState(OVERVIEW)) {
- return ALL_APPS;
- } else {
+ } else if (fromState == OVERVIEW) {
+ return isDragTowardPositive ? ALL_APPS : NORMAL;
+ } else if (isDragTowardPositive) {
return TouchInteractionService.isConnected() ? OVERVIEW : ALL_APPS;
}
+ return fromState;
}
private AnimatorSetBuilder getNormalToOverviewAnimation() {
@@ -164,15 +163,6 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
return builder;
}
- @Override
- protected void updateProgress(float fraction) {
- if (mClampProgressUpdate > 0) {
- mCurrentAnimation.setPlayFraction(Math.min(fraction, mClampProgressUpdate));
- } else {
- super.updateProgress(fraction);
- }
- }
-
@Override
protected float initCurrentAnimation() {
float range = getShiftRange();
@@ -188,14 +178,27 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
if (mFromState == NORMAL && mToState == OVERVIEW && totalShift != 0) {
builder = getNormalToOverviewAnimation();
totalShift = totalShift * TOTAL_DISTANCE_MULTIPLIER;
- mClampProgressUpdate = MAXIMUM_DISTANCE_FACTOR;
} else {
builder = new AnimatorSetBuilder();
- mClampProgressUpdate = -1;
}
- mCurrentAnimation = mLauncher.getStateManager()
- .createAnimationToNewWorkspace(mToState, builder, maxAccuracy);
+ if (mPendingAnimation != null) {
+ mPendingAnimation.finish(false, Touch.SWIPE);
+ mPendingAnimation = null;
+ }
+
+ RecentsView recentsView = mLauncher.getOverviewPanel();
+ TaskView taskView = (TaskView) recentsView.getChildAt(recentsView.getNextPage());
+ if (recentsView.shouldSwipeDownLaunchApp() && mFromState == OVERVIEW && mToState == NORMAL
+ && taskView != null) {
+ mPendingAnimation = recentsView.createTaskLauncherAnimation(taskView, maxAccuracy);
+ mPendingAnimation.anim.setInterpolator(Interpolators.ZOOM_IN);
+
+ mCurrentAnimation = AnimatorPlaybackController.wrap(mPendingAnimation.anim, maxAccuracy);
+ } else {
+ mCurrentAnimation = mLauncher.getStateManager()
+ .createAnimationToNewWorkspace(mToState, builder, maxAccuracy);
+ }
if (totalShift == 0) {
totalShift = Math.signum(mFromState.ordinal - mToState.ordinal)
@@ -207,6 +210,14 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
@Override
protected void updateSwipeCompleteAnimation(ValueAnimator animator, long expectedDuration,
LauncherState targetState, float velocity, boolean isFling) {
+ handleFirstSwipeToOverview(animator, expectedDuration, targetState, velocity, isFling);
+ super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState,
+ velocity, isFling);
+ }
+
+ private void handleFirstSwipeToOverview(final ValueAnimator animator,
+ final long expectedDuration, final LauncherState targetState, final float velocity,
+ final boolean isFling) {
if (mFromState == NORMAL && mToState == OVERVIEW && targetState == OVERVIEW) {
mFinishFastOnSecondTouch = true;
@@ -220,7 +231,7 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
// TODO: Clean up these magic calculations
// Linearly interpolate the max value based on the velocity.
float maxValue = Math.max(absVelocity > 4 ? 1 + MAX_OVERSHOOT :
- 1 + (absVelocity - 1) * MAX_OVERSHOOT / 3,
+ 1 + (absVelocity - 1) * MAX_OVERSHOOT / 3,
currentValue);
double angleToPeak = PI_BY_2 - Math.asin(currentValue / maxValue);
@@ -248,8 +259,6 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
if (currentFraction < LINEAR_SCALE_LIMIT) {
mAllAppsInterpolatorWrapper.baseInterpolator = LINEAR;
- super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState,
- velocity, isFling);
return;
}
float extraValue = mAllAppsDampedInterpolator.getInterpolation(currentFraction) - 1;
@@ -267,8 +276,6 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr
return;
}
mFinishFastOnSecondTouch = false;
- super.updateSwipeCompleteAnimation(animator, expectedDuration, targetState,
- velocity, isFling);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index d8f206c5ed..124ec202d1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -15,13 +15,11 @@
*/
package com.android.launcher3.uioverrides;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.anim.AlphaUpdateListener.updateVisibility;
import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_TRANSLATION;
+import static com.android.launcher3.anim.Interpolators.AGGRESSIVE_EASE_IN_OUT;
import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
-import static com.android.quickstep.views.LauncherRecentsView.TRANSLATION_X_FACTOR;
import static com.android.quickstep.views.LauncherRecentsView.TRANSLATION_Y_FACTOR;
+import static com.android.quickstep.views.RecentsView.ADJACENT_SCALE;
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
import android.animation.ValueAnimator;
@@ -32,7 +30,6 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.PagedView;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
import com.android.quickstep.views.LauncherRecentsView;
@@ -51,11 +48,11 @@ public class RecentsViewStateController implements StateHandler {
@Override
public void setState(LauncherState state) {
mRecentsView.setContentAlpha(state.overviewUi ? 1 : 0);
- updateVisibility(mRecentsView, isAccessibilityEnabled(mLauncher));
- float[] translationFactor = state.getOverviewTranslationFactor(mLauncher);
- mRecentsView.setTranslationXFactor(translationFactor[0]);
- mRecentsView.setTranslationYFactor(translationFactor[1]);
+ float[] scaleTranslationYFactor = state.getOverviewScaleAndTranslationYFactor(mLauncher);
+ mRecentsView.setAdjacentScale(scaleTranslationYFactor[0]);
+ mRecentsView.setTranslationYFactor(scaleTranslationYFactor[1]);
if (state.overviewUi) {
+ mRecentsView.updateEmptyMessage();
mRecentsView.resetTaskVisuals();
}
}
@@ -63,28 +60,18 @@ public class RecentsViewStateController implements StateHandler {
@Override
public void setStateWithAnimation(final LauncherState toState,
AnimatorSetBuilder builder, AnimationConfig config) {
-
- // Scroll to the workspace card before changing to the NORMAL state.
- LauncherState fromState = mLauncher.getStateManager().getState();
- int currPage = mRecentsView.getCurrentPage();
- if (fromState.overviewUi && toState == NORMAL && currPage != 0 && !config.userControlled) {
- int maxSnapDuration = PagedView.SLOW_PAGE_SNAP_ANIMATION_DURATION;
- int durationPerPage = maxSnapDuration / 10;
- int snapDuration = Math.min(maxSnapDuration, durationPerPage * currPage);
- mRecentsView.snapToPage(0, snapDuration);
- // Let the snapping animation play for a bit before we translate off screen.
- builder.setStartDelay(snapDuration / 4);
- }
-
PropertySetter setter = config.getProperSetter(builder);
- float[] translationFactor = toState.getOverviewTranslationFactor(mLauncher);
- setter.setFloat(mRecentsView, TRANSLATION_X_FACTOR,
- translationFactor[0],
+ float[] scaleTranslationYFactor = toState.getOverviewScaleAndTranslationYFactor(mLauncher);
+ setter.setFloat(mRecentsView, ADJACENT_SCALE, scaleTranslationYFactor[0],
builder.getInterpolator(ANIM_OVERVIEW_TRANSLATION, LINEAR));
- setter.setFloat(mRecentsView, TRANSLATION_Y_FACTOR,
- translationFactor[1],
+ setter.setFloat(mRecentsView, TRANSLATION_Y_FACTOR, scaleTranslationYFactor[1],
builder.getInterpolator(ANIM_OVERVIEW_TRANSLATION, LINEAR));
- setter.setFloat(mRecentsView, CONTENT_ALPHA, toState.overviewUi ? 1 : 0, LINEAR);
+ setter.setFloat(mRecentsView, CONTENT_ALPHA, toState.overviewUi ? 1 : 0,
+ AGGRESSIVE_EASE_IN_OUT);
+
+ if (!toState.overviewUi) {
+ builder.addOnFinishRunnable(mRecentsView::resetTaskVisuals);
+ }
if (toState.overviewUi) {
ValueAnimator updateAnim = ValueAnimator.ofFloat(0, 1);
@@ -94,6 +81,7 @@ public class RecentsViewStateController implements StateHandler {
});
updateAnim.setDuration(config.duration);
builder.play(updateAnim);
+ mRecentsView.updateEmptyMessage();
}
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
index d11547de84..84a60bd9a0 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/TaskViewTouchController.java
@@ -15,35 +15,33 @@
*/
package com.android.launcher3.uioverrides;
-import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.touch.SwipeDetector;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.util.PendingAnimation;
import com.android.launcher3.util.TouchController;
-import com.android.quickstep.PendingAnimation;
+import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
/**
* Touch controller for handling task view card swipes
*/
-public class TaskViewTouchController extends AnimatorListenerAdapter
- implements TouchController, SwipeDetector.Listener {
+public abstract class TaskViewTouchController
+ extends AnimatorListenerAdapter implements TouchController, SwipeDetector.Listener {
private static final String TAG = "OverviewSwipeController";
@@ -53,7 +51,7 @@ public class TaskViewTouchController extends AnimatorListenerAdapter
// Progress after which the transition is assumed to be a success in case user does not fling
private static final float SUCCESS_TRANSITION_PROGRESS = 0.5f;
- private final Launcher mLauncher;
+ protected final T mActivity;
private final SwipeDetector mDetector;
private final RecentsView mRecentsView;
private final int[] mTempCords = new int[2];
@@ -70,10 +68,10 @@ public class TaskViewTouchController extends AnimatorListenerAdapter
private TaskView mTaskBeingDragged;
- public TaskViewTouchController(Launcher launcher) {
- mLauncher = launcher;
- mRecentsView = launcher.getOverviewPanel();
- mDetector = new SwipeDetector(launcher, this, SwipeDetector.VERTICAL);
+ public TaskViewTouchController(T activity) {
+ mActivity = activity;
+ mRecentsView = activity.getOverviewPanel();
+ mDetector = new SwipeDetector(activity, this, SwipeDetector.VERTICAL);
}
private boolean canInterceptTouch() {
@@ -81,12 +79,14 @@ public class TaskViewTouchController extends AnimatorListenerAdapter
// If we are already animating from a previous state, we can intercept.
return true;
}
- if (AbstractFloatingView.getTopOpenView(mLauncher) != null) {
+ if (AbstractFloatingView.getTopOpenView(mActivity) != null) {
return false;
}
- return mLauncher.isInState(OVERVIEW);
+ return isRecentsInteractive();
}
+ protected abstract boolean isRecentsInteractive();
+
@Override
public void onAnimationCancel(Animator animation) {
if (mCurrentAnimation != null && animation == mCurrentAnimation.getTarget()) {
@@ -115,7 +115,7 @@ public class TaskViewTouchController extends AnimatorListenerAdapter
mTaskBeingDragged = null;
View view = mRecentsView.getChildAt(mRecentsView.getCurrentPage());
- if (view instanceof TaskView && mLauncher.getDragLayer().isEventOverView(view, ev)) {
+ if (view instanceof TaskView && mActivity.getDragLayer().isEventOverView(view, ev)) {
// The tile can be dragged down to open the task.
mTaskBeingDragged = (TaskView) view;
directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
@@ -151,31 +151,31 @@ public class TaskViewTouchController extends AnimatorListenerAdapter
mCurrentAnimation.setPlayFraction(0);
}
if (mPendingAnimation != null) {
- mPendingAnimation.finish(false);
+ mPendingAnimation.finish(false, Touch.SWIPE);
mPendingAnimation = null;
}
mCurrentAnimationIsGoingUp = goingUp;
- float range = mLauncher.getAllAppsController().getShiftRange();
- long maxDuration = (long) (2 * range);
- DragLayer dl = mLauncher.getDragLayer();
+ BaseDragLayer dl = mActivity.getDragLayer();
+ long maxDuration = (long) (2 * dl.getHeight());
if (goingUp) {
mPendingAnimation = mRecentsView.createTaskDismissAnimation(mTaskBeingDragged,
true /* animateTaskView */, true /* removeTask */, maxDuration);
- mCurrentAnimation = AnimatorPlaybackController
- .wrap(mPendingAnimation.anim, maxDuration);
+
mEndDisplacement = -mTaskBeingDragged.getHeight();
} else {
- AnimatorSet anim = new AnimatorSet();
- // TODO: Setup a zoom animation
- mCurrentAnimation = AnimatorPlaybackController.wrap(anim, maxDuration);
+ mPendingAnimation = mRecentsView.createTaskLauncherAnimation(
+ mTaskBeingDragged, maxDuration);
+ mPendingAnimation.anim.setInterpolator(Interpolators.ZOOM_IN);
mTempCords[1] = mTaskBeingDragged.getHeight();
dl.getDescendantCoordRelativeToSelf(mTaskBeingDragged, mTempCords);
mEndDisplacement = dl.getHeight() - mTempCords[1];
}
+ mCurrentAnimation = AnimatorPlaybackController
+ .wrap(mPendingAnimation.anim, maxDuration);
mCurrentAnimation.getTarget().addListener(this);
mCurrentAnimation.dispatchOnStart();
mProgressMultiplier = 1 / mEndDisplacement;
@@ -248,16 +248,9 @@ public class TaskViewTouchController extends AnimatorListenerAdapter
private void onCurrentAnimationEnd(boolean wasSuccess, int logAction) {
if (mPendingAnimation != null) {
- mPendingAnimation.finish(wasSuccess);
+ mPendingAnimation.finish(wasSuccess, logAction);
mPendingAnimation = null;
}
- if (wasSuccess) {
- if (!mCurrentAnimationIsGoingUp) {
- mTaskBeingDragged.launchTask(false);
- mLauncher.getUserEventDispatcher().logTaskLaunch(logAction,
- Direction.DOWN, mTaskBeingDragged.getTask().getTopComponent());
- }
- }
mDetector.finishedScrolling();
mTaskBeingDragged = null;
mCurrentAnimation = null;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
index 846e80377e..c1590f63de 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java
@@ -16,23 +16,25 @@
package com.android.launcher3.uioverrides;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.Utilities.getPrefs;
import static com.android.quickstep.OverviewInteractionState.KEY_SWIPE_UP_ENABLED;
+import static com.android.launcher3.LauncherState.ALL_APPS;
import android.content.Context;
import android.content.SharedPreferences;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Hotseat;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.R;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.OverviewInteractionState;
import com.android.quickstep.RecentsModel;
import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.system.WindowManagerWrapper;
public class UiFactory {
@@ -43,26 +45,22 @@ public class UiFactory {
return new TouchController[] {
launcher.getDragController(),
new LandscapeStatesTouchController(launcher),
- new TaskViewTouchController(launcher)};
+ new LauncherTaskViewcontroller(launcher)};
}
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
return new TouchController[] {
launcher.getDragController(),
new LandscapeStatesTouchController(launcher),
new LandscapeEdgeSwipeController(launcher),
- new TaskViewTouchController(launcher)};
+ new LauncherTaskViewcontroller(launcher)};
} else {
return new TouchController[] {
launcher.getDragController(),
new PortraitStatesTouchController(launcher),
- new TaskViewTouchController(launcher)};
+ new LauncherTaskViewcontroller(launcher)};
}
}
- public static AccessibilityDelegate newPageIndicatorAccessibilityDelegate() {
- return null;
- }
-
public static StateHandler[] getStateHandler(Launcher launcher) {
return new StateHandler[] {
launcher.getAllAppsController(), launcher.getWorkspace(),
@@ -93,6 +91,18 @@ public class UiFactory {
}
}
+ public static void onLauncherStateOrResumeChanged(Launcher launcher) {
+ LauncherState state = launcher.getStateManager().getState();
+ DeviceProfile profile = launcher.getDeviceProfile();
+ WindowManagerWrapper.getInstance().setShelfHeight(
+ state != ALL_APPS && launcher.isUserActive() && !profile.isVerticalBarLayout(),
+ profile.hotseatBarSizePx);
+
+ if (state == NORMAL) {
+ launcher.getOverviewPanel().setSwipeDownShouldLaunchApp(false);
+ }
+ }
+
public static void onTrimMemory(Context context, int level) {
RecentsModel model = RecentsModel.getInstance(context);
if (model != null) {
@@ -100,10 +110,15 @@ public class UiFactory {
}
}
- public static View[] getHotseatExtraContent(Hotseat hotseat) {
- return new View[] {
- hotseat.findViewById(R.id.drag_indicator),
- hotseat.findViewById(R.id.search_container_hotseat),
- };
+ private static class LauncherTaskViewcontroller extends TaskViewTouchController {
+
+ public LauncherTaskViewcontroller(Launcher activity) {
+ super(activity);
+ }
+
+ @Override
+ protected boolean isRecentsInteractive() {
+ return mActivity.isInState(OVERVIEW);
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
index 9e2e5acf5f..584128585f 100644
--- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java
+++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java
@@ -22,7 +22,6 @@ import static com.android.launcher3.anim.Interpolators.LINEAR;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
-import android.app.ActivityOptions;
import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
@@ -41,14 +40,15 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.util.ViewOnDrawExecutor;
+import com.android.quickstep.fallback.FallbackRecentsView;
+import com.android.quickstep.util.RemoteAnimationProvider;
import com.android.quickstep.views.LauncherLayoutListener;
+import com.android.quickstep.views.LauncherRecentsView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.ActivityOptionsCompat;
import com.android.systemui.shared.system.AssistDataReceiver;
import com.android.systemui.shared.system.RecentsAnimationListener;
-import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
import java.util.function.BiPredicate;
@@ -61,7 +61,13 @@ public interface ActivityControlHelper {
void onQuickstepGestureStarted(T activity, boolean activityVisible);
- void onQuickInteractionStart(T activity, boolean activityVisible);
+ /**
+ * Updates the UI to indicate quick interaction.
+ * @return true if there any any UI change as a result of this
+ */
+ boolean onQuickInteractionStart(T activity, boolean activityVisible);
+
+ void executeOnWindowAvailable(T activity, Runnable action);
void executeOnNextDraw(T activity, TaskView targetView, Runnable action);
@@ -79,8 +85,11 @@ public interface ActivityControlHelper {
ActivityInitListener createActivityInitListener(BiPredicate onInitListener);
- void startRecents(Context context, Intent intent, AssistDataReceiver assistDataReceiver,
- RecentsAnimationListener remoteAnimationListener);
+ void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
+ final RecentsAnimationListener remoteAnimationListener);
+
+ @Nullable
+ T getCreatedActivity();
@UiThread
@Nullable
@@ -102,8 +111,18 @@ public interface ActivityControlHelper {
}
@Override
- public void onQuickInteractionStart(Launcher activity, boolean activityVisible) {
+ public boolean onQuickInteractionStart(Launcher activity, boolean activityVisible) {
+ LauncherState fromState = activity.getStateManager().getState();
activity.getStateManager().goToState(FAST_OVERVIEW, activityVisible);
+ return !fromState.overviewUi;
+ }
+
+ @Override
+ public void executeOnWindowAvailable(Launcher activity, Runnable action) {
+ if (activity.getWorkspace().runOnOverlayHidden(action)) {
+ // Notify the activity that qiuckscrub has started
+ onQuickstepGestureStarted(activity, true);
+ }
}
@Override
@@ -122,7 +141,7 @@ public interface ActivityControlHelper {
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
- RecentsView.getPageRect(dp, context, outRect);
+ LauncherRecentsView.getPageRect(dp, context, outRect);
if (dp.isVerticalBarLayout()) {
Rect targetInsets = dp.getInsets();
int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
@@ -202,21 +221,26 @@ public interface ActivityControlHelper {
}
@Override
- public void startRecents(Context context, Intent intent,
- AssistDataReceiver assistDataReceiver,
- RecentsAnimationListener remoteAnimationListener) {
+ public void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
+ final RecentsAnimationListener remoteAnimationListener) {
ActivityManagerWrapper.getInstance().startRecentsActivity(
intent, assistDataReceiver, remoteAnimationListener, null, null);
}
@Nullable
- @UiThread
- private Launcher getVisibleLaucher() {
+ @Override
+ public Launcher getCreatedActivity() {
LauncherAppState app = LauncherAppState.getInstanceNoCreate();
if (app == null) {
return null;
}
- Launcher launcher = (Launcher) app.getModel().getCallback();
+ return (Launcher) app.getModel().getCallback();
+ }
+
+ @Nullable
+ @UiThread
+ private Launcher getVisibleLaucher() {
+ Launcher launcher = getCreatedActivity();
return (launcher != null) && launcher.isStarted() && launcher.hasWindowFocus() ?
launcher : null;
}
@@ -248,8 +272,14 @@ public interface ActivityControlHelper {
}
@Override
- public void onQuickInteractionStart(RecentsActivity activity, boolean activityVisible) {
- // TODO:
+ public boolean onQuickInteractionStart(RecentsActivity activity, boolean activityVisible) {
+ // Activity does not need any UI change for quickscrub.
+ return false;
+ }
+
+ @Override
+ public void executeOnWindowAvailable(RecentsActivity activity, Runnable action) {
+ action.run();
}
@Override
@@ -266,7 +296,7 @@ public interface ActivityControlHelper {
@Override
public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) {
- FallbackRecentsView.getCenterPageRect(dp, context, outRect);
+ FallbackRecentsView.getPageRect(dp, context, outRect);
if (dp.isVerticalBarLayout()) {
Rect targetInsets = dp.getInsets();
int hotseatInset = dp.isSeascape() ? targetInsets.left : targetInsets.right;
@@ -324,19 +354,23 @@ public interface ActivityControlHelper {
}
@Override
- public void startRecents(Context context, Intent intent,
- AssistDataReceiver assistDataReceiver,
+ public void startRecentsFromSwipe(Intent intent, AssistDataReceiver assistDataReceiver,
final RecentsAnimationListener remoteAnimationListener) {
- ActivityOptions options =
- ActivityOptionsCompat.makeRemoteAnimation(new RemoteAnimationAdapterCompat(
- new FallbackActivityOptions(remoteAnimationListener), 10000, 10000));
- context.startActivity(intent, options.toBundle());
+ // We can use the normal recents animation for swipe up
+ ActivityManagerWrapper.getInstance().startRecentsActivity(
+ intent, assistDataReceiver, remoteAnimationListener, null, null);
+ }
+
+ @Nullable
+ @Override
+ public RecentsActivity getCreatedActivity() {
+ return RecentsActivityTracker.getCurrentActivity();
}
@Nullable
@Override
public RecentsView getVisibleRecentsView() {
- RecentsActivity activity = RecentsActivityTracker.getCurrentActivity();
+ RecentsActivity activity = getCreatedActivity();
if (activity != null && activity.hasWindowFocus()) {
return activity.getOverviewPanel();
}
@@ -363,5 +397,8 @@ public interface ActivityControlHelper {
void register();
void unregister();
+
+ void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
+ Context context, Handler handler, long duration);
}
}
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityOptions.java b/quickstep/src/com/android/quickstep/FallbackActivityOptions.java
deleted file mode 100644
index 3a7fb2db6d..0000000000
--- a/quickstep/src/com/android/quickstep/FallbackActivityOptions.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import android.graphics.Rect;
-import android.util.Log;
-
-import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
-import com.android.systemui.shared.system.RecentsAnimationListener;
-import com.android.systemui.shared.system.RemoteAnimationRunnerCompat;
-import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import com.android.systemui.shared.system.WindowManagerWrapper;
-
-/**
- * Temporary class to create activity options to emulate recents transition for fallback activtiy.
- */
-public class FallbackActivityOptions implements RemoteAnimationRunnerCompat {
-
- private final RecentsAnimationListener mListener;
-
- public FallbackActivityOptions(RecentsAnimationListener listener) {
- mListener = listener;
- }
-
- @Override
- public void onAnimationStart(RemoteAnimationTargetCompat[] targetCompats,
- Runnable runnable) {
- DummyRecentsAnimationControllerCompat dummyRecentsAnim =
- new DummyRecentsAnimationControllerCompat(runnable);
-
- Rect insets = new Rect();
- WindowManagerWrapper.getInstance().getStableInsets(insets);
- mListener.onAnimationStart(dummyRecentsAnim, targetCompats, insets, null);
- }
-
- @Override
- public void onAnimationCancelled() {
- mListener.onAnimationCanceled();
- }
-
- private static class DummyRecentsAnimationControllerCompat
- extends RecentsAnimationControllerCompat {
-
- final Runnable mFinishCallback;
-
- public DummyRecentsAnimationControllerCompat(Runnable finishCallback) {
- mFinishCallback = finishCallback;
- }
-
- @Override
- public ThumbnailData screenshotTask(int taskId) {
- return new ThumbnailData();
- }
-
- @Override
- public void setInputConsumerEnabled(boolean enabled) { }
-
- @Override
- public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) { }
-
- @Override
- public void finish(boolean toHome) {
- if (toHome) {
- mFinishCallback.run();
- }
- }
- }
-}
diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java
index 8e6e4c70b8..538e23c3af 100644
--- a/quickstep/src/com/android/quickstep/MotionEventQueue.java
+++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java
@@ -53,6 +53,8 @@ public class MotionEventQueue {
ACTION_VIRTUAL | (5 << ACTION_POINTER_INDEX_SHIFT);
private static final int ACTION_SHOW_OVERVIEW_FROM_ALT_TAB =
ACTION_VIRTUAL | (6 << ACTION_POINTER_INDEX_SHIFT);
+ private static final int ACTION_QUICK_STEP =
+ ACTION_VIRTUAL | (7 << ACTION_POINTER_INDEX_SHIFT);
private final EventArray mEmptyArray = new EventArray();
private final Object mExecutionLock = new Object();
@@ -160,6 +162,9 @@ public class MotionEventQueue {
mConsumer.onShowOverviewFromAltTab();
mConsumer.updateTouchTracking(INTERACTION_QUICK_SCRUB);
break;
+ case ACTION_QUICK_STEP:
+ mConsumer.onQuickStep(event.getX(), event.getY(), event.getEventTime());
+ break;
default:
Log.e(TAG, "Invalid virtual event: " + event.getAction());
}
@@ -204,6 +209,11 @@ public class MotionEventQueue {
queueVirtualAction(ACTION_QUICK_SCRUB_END, 0);
}
+ public void onQuickStep(MotionEvent event) {
+ event.setAction(ACTION_QUICK_STEP);
+ queueNoPreProcess(event);
+ }
+
public void reset() {
queueVirtualAction(ACTION_RESET, 0);
}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 4877abbe19..4d695de907 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -23,6 +23,7 @@ import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
+import static com.android.systemui.shared.system.NavigationBarCompat.QUICK_STEP_DRAG_SLOP_PX;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
@@ -79,8 +80,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private int mActivePointerId = INVALID_POINTER_ID;
- private boolean mTouchThresholdCrossed;
- private int mTouchSlop;
+ private boolean mPassedInitialSlop;
private float mStartDisplacement;
private WindowTransformSwipeHandler mInteractionHandler;
private int mDisplayRotation;
@@ -121,8 +121,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
mActivePointerId = ev.getPointerId(0);
mDownPos.set(ev.getX(), ev.getY());
mLastPos.set(mDownPos);
- mTouchSlop = ViewConfiguration.get(this).getScaledPagingTouchSlop();
- mTouchThresholdCrossed = false;
+ mPassedInitialSlop = false;
// Start the window animation on down to give more time for launcher to draw if the
// user didn't start the gesture over the back button
@@ -154,26 +153,19 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
break;
}
mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
+ float displacement = getDisplacement(ev);
+ if (!mPassedInitialSlop && Math.abs(displacement) > QUICK_STEP_DRAG_SLOP_PX) {
+ mPassedInitialSlop = true;
+ mStartDisplacement = displacement;
- float displacement = ev.getY(pointerIndex) - mDownPos.y;
- if (isNavBarOnRight()) {
- displacement = ev.getX(pointerIndex) - mDownPos.x;
- } else if (isNavBarOnLeft()) {
- displacement = mDownPos.x - ev.getX(pointerIndex);
- }
- if (!mTouchThresholdCrossed) {
- mTouchThresholdCrossed = Math.abs(displacement) >= mTouchSlop;
- if (mTouchThresholdCrossed) {
- mStartDisplacement = Math.signum(displacement) * mTouchSlop;
-
- if (mIsDeferredDownTarget) {
- // If we deferred starting the window animation on touch down, then
- // start tracking now
- startTouchTrackingForWindowAnimation(ev.getEventTime());
- }
- notifyGestureStarted();
+ // If we deferred starting the window animation on touch down, then
+ // start tracking now
+ if (mIsDeferredDownTarget) {
+ startTouchTrackingForWindowAnimation(ev.getEventTime());
}
- } else if (mInteractionHandler != null) {
+ }
+
+ if (mPassedInitialSlop && mInteractionHandler != null) {
// Move
mInteractionHandler.updateDisplacement(displacement - mStartDisplacement);
}
@@ -226,7 +218,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
handler.initWhenReady();
TraceHelper.beginSection("RecentsController");
- Runnable startActivity = () -> mActivityControlHelper.startRecents(this, mHomeIntent,
+ Runnable startActivity = () -> mActivityControlHelper.startRecentsFromSwipe(mHomeIntent,
new AssistDataReceiver() {
@Override
public void onHandleAssistData(Bundle bundle) {
@@ -259,10 +251,12 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
if (Looper.myLooper() != Looper.getMainLooper()) {
startActivity.run();
- try {
- drawWaitLock.await(LAUNCHER_DRAW_TIMEOUT_MS, TimeUnit.MILLISECONDS);
- } catch (Exception e) {
- // We have waited long enough for launcher to draw
+ if (!mIsDeferredDownTarget) {
+ try {
+ drawWaitLock.await(LAUNCHER_DRAW_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ } catch (Exception e) {
+ // We have waited long enough for launcher to draw
+ }
}
} else {
// We should almost always get touch-town on background thread. This is an edge case
@@ -276,7 +270,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
* the animation can still be running.
*/
private void finishTouchTracking() {
- if (mTouchThresholdCrossed && mInteractionHandler != null) {
+ if (mPassedInitialSlop && mInteractionHandler != null) {
mVelocityTracker.computeCurrentVelocity(1000,
ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
@@ -291,7 +285,8 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
// Also clean up in case the system has handled the UP and canceled the animation before
// we had a chance to start the recents animation. In such a case, we will not receive
- ActivityManagerWrapper.getInstance().cancelRecentsAnimation();
+ ActivityManagerWrapper.getInstance().cancelRecentsAnimation(
+ true /* restoreHomeStackPosition */);
}
mVelocityTracker.recycle();
mVelocityTracker = null;
@@ -336,6 +331,23 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC
}
}
+ @Override
+ public void onQuickStep(float eventX, float eventY, long eventTime) {
+ notifyGestureStarted();
+ }
+
+ private float getDisplacement(MotionEvent ev) {
+ float eventX = ev.getX();
+ float eventY = ev.getY();
+ float displacement = eventY - mDownPos.y;
+ if (isNavBarOnRight()) {
+ displacement = eventX - mDownPos.x;
+ } else if (isNavBarOnLeft()) {
+ displacement = mDownPos.x - eventX;
+ }
+ return displacement;
+ }
+
public void switchToMainChoreographer() {
mEventQueue.setInterimChoreographer(null);
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 311411f4cf..d76c49a09f 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -15,68 +15,44 @@
*/
package com.android.quickstep;
-import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN;
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
-import android.animation.Animator;
+import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
-import android.app.ActivityManager.RecentTaskInfo;
-import android.app.ActivityManager.RunningTaskInfo;
-import android.app.ActivityOptions;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ResolveInfo;
-import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.os.Build;
-import android.os.Bundle;
import android.os.SystemClock;
-import android.os.UserHandle;
-import android.support.annotation.UiThread;
-import android.support.annotation.WorkerThread;
-import android.util.SparseArray;
+import android.util.Log;
+import android.view.View;
import android.view.ViewConfiguration;
import com.android.launcher3.AbstractFloatingView;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.MainThreadExecutor;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.AnimationSuccessListener;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.states.InternalStateHandler;
-import com.android.launcher3.util.TraceHelper;
+import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
import com.android.quickstep.ActivityControlHelper.FallbackActivityControllerHelper;
import com.android.quickstep.ActivityControlHelper.LauncherActivityControllerHelper;
+import com.android.quickstep.util.ClipAnimationHelper;
+import com.android.quickstep.util.RemoteAnimationProvider;
+import com.android.quickstep.util.SysuiEventLogger;
import com.android.quickstep.views.RecentsView;
-import com.android.quickstep.views.TaskView;
-import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat;
-import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
-import com.android.systemui.shared.recents.view.RecentsTransition;
import com.android.systemui.shared.system.ActivityManagerWrapper;
-import com.android.systemui.shared.system.AssistDataReceiver;
-import com.android.systemui.shared.system.BackgroundExecutor;
-import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
-import com.android.systemui.shared.system.RecentsAnimationListener;
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
-import java.util.Collections;
-import java.util.List;
-import java.util.function.Consumer;
-
/**
* Helper class to handle various atomic commands for switching between Overview.
*/
@TargetApi(Build.VERSION_CODES.P)
-public class OverviewCommandHelper extends InternalStateHandler {
+public class OverviewCommandHelper {
- private static final int RID_RESET_SWIPE_HANDLER = 0;
- private static final int RID_CANCEL_CONTROLLER = 1;
- private static final int RID_CANCEL_ZOOM_OUT_ANIMATION = 2;
-
- private static final long RECENTS_LAUNCH_DURATION = 150;
+ private static final long RECENTS_LAUNCH_DURATION = 200;
private static final String TAG = "OverviewCommandHelper";
private static final boolean DEBUG_START_FALLBACK_ACTIVITY = false;
@@ -89,16 +65,7 @@ public class OverviewCommandHelper extends InternalStateHandler {
public final Intent homeIntent;
public final ComponentName launcher;
- private final SparseArray mCurrentCommandFinishRunnables = new SparseArray<>();
- // Monotonically increasing command ids.
- private int mCurrentCommandId = 0;
-
private long mLastToggleTime;
- private WindowTransformSwipeHandler mWindowTransformSwipeHandler;
-
- private final Point mWindowSize = new Point();
- private final Rect mTaskTargetRect = new Rect();
- private final RectF mTempTaskTargetRect = new RectF();
public OverviewCommandHelper(Context context) {
mContext = context;
@@ -124,239 +91,18 @@ public class OverviewCommandHelper extends InternalStateHandler {
homeIntent.setComponent(launcher).setPackage(null);
}
- private void openRecents() {
- Intent intent = addToIntent(new Intent(homeIntent));
- mContext.startActivity(intent);
- initWhenReady();
- }
-
- @UiThread
- private void addFinishCommand(int requestId, int id, Runnable action) {
- if (requestId < mCurrentCommandId) {
- action.run();
- } else {
- mCurrentCommandFinishRunnables.put(id, action);
- }
- }
-
- @UiThread
- private void clearFinishCommand(int requestId, int id) {
- if (requestId == mCurrentCommandId) {
- mCurrentCommandFinishRunnables.remove(id);
- }
- }
-
- @UiThread
- private void initSwipeHandler(ActivityControlHelper helper, long time,
- Consumer onAnimationInitCallback) {
- final int commandId = mCurrentCommandId;
- RunningTaskInfo taskInfo = ActivityManagerWrapper.getInstance().getRunningTask();
- final WindowTransformSwipeHandler handler =
- new WindowTransformSwipeHandler(taskInfo, mContext, time, helper);
-
- // Preload the plan
- mRecentsModel.loadTasks(taskInfo.id, null);
- mWindowTransformSwipeHandler = handler;
-
- mTempTaskTargetRect.setEmpty();
- handler.setGestureEndCallback(() -> {
- if (mWindowTransformSwipeHandler == handler) {
- mWindowTransformSwipeHandler = null;
- mTempTaskTargetRect.setEmpty();
- }
- clearFinishCommand(commandId, RID_RESET_SWIPE_HANDLER);
- clearFinishCommand(commandId, RID_CANCEL_CONTROLLER);
- });
- handler.initWhenReady();
- addFinishCommand(commandId, RID_RESET_SWIPE_HANDLER, handler::reset);
-
- TraceHelper.beginSection(TAG);
- Runnable startActivity = () -> helper.startRecents(mContext, homeIntent,
- new AssistDataReceiver() {
- @Override
- public void onHandleAssistData(Bundle bundle) {
- mRecentsModel.preloadAssistData(taskInfo.id, bundle);
- }
- },
- new RecentsAnimationListener() {
- public void onAnimationStart(
- RecentsAnimationControllerCompat controller,
- RemoteAnimationTargetCompat[] apps, Rect homeContentInsets,
- Rect minimizedHomeBounds) {
- if (mWindowTransformSwipeHandler == handler) {
- TraceHelper.partitionSection(TAG, "Received");
- handler.onRecentsAnimationStart(controller, apps, homeContentInsets,
- minimizedHomeBounds);
- mTempTaskTargetRect.set(handler.getTargetRect(mWindowSize));
-
- mMainThreadExecutor.execute(() -> {
- addFinishCommand(commandId,
- RID_CANCEL_CONTROLLER, () -> controller.finish(true));
- if (commandId == mCurrentCommandId) {
- onAnimationInitCallback.accept(handler);
- }
- });
- } else {
- TraceHelper.endSection(TAG, "Finishing no handler");
- controller.finish(false /* toHome */);
- }
- }
-
- public void onAnimationCanceled() {
- TraceHelper.endSection(TAG, "Cancelled: " + handler);
- if (mWindowTransformSwipeHandler == handler) {
- handler.onRecentsAnimationCanceled();
- }
- }
- });
-
- // We should almost always get touch-town on background thread. This is an edge case
- // when the background Choreographer has not yet initialized.
- BackgroundExecutor.get().submit(startActivity);
- }
-
- @UiThread
- private void startZoomOutAnim(final WindowTransformSwipeHandler handler) {
- final int commandId = mCurrentCommandId;
- ValueAnimator anim = ValueAnimator.ofInt(0, -handler.getTransitionLength());
- anim.addUpdateListener((a) -> handler.updateDisplacement((Integer) a.getAnimatedValue()));
- anim.addListener(new AnimationSuccessListener() {
- @Override
- public void onAnimationSuccess(Animator animator) {
- handler.onGestureEnded(0);
- clearFinishCommand(commandId, RID_CANCEL_ZOOM_OUT_ANIMATION);
- }
- });
- handler.onGestureStarted();
- anim.setDuration(RECENTS_LAUNCH_DURATION);
- anim.setInterpolator(Interpolators.AGGRESSIVE_EASE);
- anim.start();
- addFinishCommand(commandId, RID_CANCEL_ZOOM_OUT_ANIMATION, anim::cancel);
- }
-
public void onOverviewToggle() {
- long time = SystemClock.elapsedRealtime();
- mMainThreadExecutor.execute(() -> {
- long elapsedTime = time - mLastToggleTime;
- mLastToggleTime = time;
+ // If currently screen pinning, do not enter overview
+ if (mAM.isScreenPinningActive()) {
+ return;
+ }
- mCurrentCommandId++;
- mTempTaskTargetRect.round(mTaskTargetRect);
- boolean isQuickTap = elapsedTime < ViewConfiguration.getDoubleTapTimeout();
- int runnableCount = mCurrentCommandFinishRunnables.size();
- if (runnableCount > 0) {
- for (int i = 0; i < runnableCount; i++) {
- mCurrentCommandFinishRunnables.valueAt(i).run();
- }
- mCurrentCommandFinishRunnables.clear();
- isQuickTap = true;
- }
-
- ActivityControlHelper helper = getActivityControlHelper();
- RecentsView recents = helper.getVisibleRecentsView();
- if (recents != null) {
- int childCount = recents.getChildCount();
- if (childCount != 0) {
- ((TaskView) recents.getChildAt(childCount >= 2 ? 1 : 0)).launchTask(true);
- }
-
- // There are not enough tasks. Skip
- return;
- }
-
- if (isQuickTap) {
- // Focus last task. Start is on background thread so that all ActivityManager calls
- // are serialized
- BackgroundExecutor.get().submit(this::startLastTask);
- return;
- }
- if (helper.switchToRecentsIfVisible()) {
- return;
- }
-
- initSwipeHandler(helper, time, this::startZoomOutAnim);
- });
+ mAM.closeSystemWindows("recentapps");
+ mMainThreadExecutor.execute(new RecentsActivityCommand<>());
}
public void onOverviewShown() {
- getLauncher().runOnUiThread(() -> {
- if (isOverviewAlmostVisible()) {
- final RecentsView rv = getLauncher().getOverviewPanel();
- rv.snapToTaskAfterNext();
- } else {
- openRecents();
- }
- }
- );
- }
-
- public void onOverviewHidden() {
- getLauncher().runOnUiThread(() -> {
- if (isOverviewAlmostVisible()) {
- final RecentsView rv = getLauncher().getOverviewPanel();
- rv.launchNextTask();
- }
- }
- );
- }
-
- @WorkerThread
- private void startLastTask() {
- // TODO: This should go through recents model.
- List tasks = mAM.getRecentTasks(2, UserHandle.myUserId());
- if (tasks.size() > 1) {
- RecentTaskInfo rti = tasks.get(1);
-
- final ActivityOptions options;
- if (!mTaskTargetRect.isEmpty()) {
- final Rect targetRect = new Rect(mTaskTargetRect);
- targetRect.offset(Utilities.isRtl(mContext.getResources())
- ? - mTaskTargetRect.width() : mTaskTargetRect.width(), 0);
- final AppTransitionAnimationSpecCompat specCompat =
- new AppTransitionAnimationSpecCompat(rti.id, null, targetRect);
- AppTransitionAnimationSpecsFuture specFuture =
- new AppTransitionAnimationSpecsFuture(mMainThreadExecutor.getHandler()) {
-
- @Override
- public List composeSpecs() {
- return Collections.singletonList(specCompat);
- }
- };
- options = RecentsTransition.createAspectScaleAnimation(mContext,
- mMainThreadExecutor.getHandler(), true /* scaleUp */,
- specFuture, () -> {});
- } else {
- options = ActivityOptions.makeBasic();
- }
- mAM.startActivityFromRecents(rti.id, options);
- }
- }
-
- private boolean isOverviewAlmostVisible() {
- if (clearReference()) {
- return true;
- }
- if (!mAM.getRunningTask().topActivity.equals(launcher)) {
- return false;
- }
- Launcher launcher = getLauncher();
- return launcher != null && launcher.isStarted() && launcher.isInState(OVERVIEW);
- }
-
- private Launcher getLauncher() {
- return (Launcher) LauncherAppState.getInstance(mContext).getModel().getCallback();
- }
-
- @Override
- protected boolean init(Launcher launcher, boolean alreadyOnHome) {
- AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
- launcher.getStateManager().goToState(OVERVIEW, alreadyOnHome);
- clearReference();
- return false;
- }
-
- public boolean isUsingFallbackActivity() {
- return DEBUG_START_FALLBACK_ACTIVITY;
+ mMainThreadExecutor.execute(new ShowRecentsCommand());
}
public ActivityControlHelper getActivityControlHelper() {
@@ -366,4 +112,141 @@ public class OverviewCommandHelper extends InternalStateHandler {
return new LauncherActivityControllerHelper();
}
}
+
+ private class ShowRecentsCommand extends RecentsActivityCommand {
+
+ @Override
+ protected boolean handleCommand(long elapsedTime) {
+ RecentsView recents = mHelper.getVisibleRecentsView();
+ if (recents != null) {
+ recents.snapToTaskAfterNext();
+ return true;
+ } else {
+ return false;
+ }
+ }
+ }
+
+ private class RecentsActivityCommand implements Runnable {
+
+ protected final ActivityControlHelper mHelper;
+ private final long mCreateTime;
+ private final int mRunningTaskId;
+
+ private ActivityInitListener mListener;
+ private T mActivity;
+
+ public RecentsActivityCommand() {
+ mHelper = getActivityControlHelper();
+ mCreateTime = SystemClock.elapsedRealtime();
+ mRunningTaskId = mAM.getRunningTask().id;
+
+ // Preload the plan
+ mRecentsModel.loadTasks(mRunningTaskId, null);
+ }
+
+ @Override
+ public void run() {
+ long elapsedTime = mCreateTime - mLastToggleTime;
+ mLastToggleTime = mCreateTime;
+
+ if (!handleCommand(elapsedTime)) {
+ // Start overview
+ if (mHelper.switchToRecentsIfVisible()) {
+ SysuiEventLogger.writeDummyRecentsTransition(0);
+ // Do nothing
+ } else {
+ mListener = mHelper.createActivityInitListener(this::onActivityReady);
+ mListener.registerAndStartActivity(homeIntent, this::createWindowAnimation,
+ mContext, mMainThreadExecutor.getHandler(), RECENTS_LAUNCH_DURATION);
+ }
+ }
+ }
+
+ protected boolean handleCommand(long elapsedTime) {
+ // TODO: We need to fix this case with PIP, when an activity first enters PIP, it shows
+ // the menu activity which takes window focus, preventing the right condition from
+ // being run below
+ RecentsView recents = mHelper.getVisibleRecentsView();
+ if (recents != null) {
+ // Launch the next task
+ recents.showNextTask();
+ return true;
+ } else if (elapsedTime < ViewConfiguration.getDoubleTapTimeout()) {
+ // The user tried to launch back into overview too quickly, either after
+ // launching an app, or before overview has actually shown, just ignore for now
+ return true;
+ }
+ return false;
+ }
+
+ private boolean onActivityReady(T activity, Boolean wasVisible) {
+ activity.getOverviewPanel().setCurrentTask(mRunningTaskId);
+ AbstractFloatingView.closeAllOpenViews(activity, wasVisible);
+ mHelper.prepareRecentsUI(activity, wasVisible);
+ if (wasVisible) {
+ AnimatorPlaybackController controller =
+ mHelper.createControllerForVisibleActivity(activity);
+ controller.dispatchOnStart();
+ ValueAnimator anim =
+ controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION);
+ anim.setInterpolator(FAST_OUT_SLOW_IN);
+ anim.start();
+ }
+ mActivity = activity;
+ return false;
+ }
+
+ private AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targetCompats) {
+ if (mListener != null) {
+ mListener.unregister();
+ }
+ RemoteAnimationProvider.showOpeningTarget(targetCompats);
+ AnimatorSet anim = new AnimatorSet();
+ if (mActivity == null) {
+ Log.e(TAG, "Animation created, before activity");
+ anim.play(ValueAnimator.ofInt(0, 1).setDuration(100));
+ return anim;
+ }
+
+ RemoteAnimationTargetCompat closingTarget = null;
+ // Use the top closing app to determine the insets for the animation
+ for (RemoteAnimationTargetCompat target : targetCompats) {
+ if (target.mode == MODE_CLOSING) {
+ closingTarget = target;
+ break;
+ }
+ }
+ if (closingTarget == null) {
+ Log.e(TAG, "No closing app");
+ anim.play(ValueAnimator.ofInt(0, 1).setDuration(100));
+ return anim;
+ }
+
+ final ClipAnimationHelper clipHelper = new ClipAnimationHelper();
+
+ // At this point, the activity is already started and laid-out. Get the home-bounds
+ // relative to the screen using the rootView of the activity.
+ int loc[] = new int[2];
+ View rootView = mActivity.getRootView();
+ rootView.getLocationOnScreen(loc);
+ Rect homeBounds = new Rect(loc[0], loc[1],
+ loc[0] + rootView.getWidth(), loc[1] + rootView.getHeight());
+ clipHelper.updateSource(homeBounds, closingTarget);
+
+ Rect targetRect = new Rect();
+ mHelper.getSwipeUpDestinationAndLength(
+ mActivity.getDeviceProfile(), mActivity, targetRect);
+ clipHelper.updateTargetRect(targetRect);
+
+
+ ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
+ valueAnimator.setDuration(RECENTS_LAUNCH_DURATION).setInterpolator(FAST_OUT_SLOW_IN);
+ valueAnimator.addUpdateListener((v) -> {
+ clipHelper.applyTransform(targetCompats, (float) v.getAnimatedValue());
+ });
+ anim.play(valueAnimator);
+ return anim;
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
index d868d122b7..fd089b5927 100644
--- a/quickstep/src/com/android/quickstep/QuickScrubController.java
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -38,9 +38,14 @@ public class QuickScrubController implements OnAlarmListener {
public static final int QUICK_SCRUB_START_DURATION = 210;
+ /**
+ * Snap to a new page when crossing these thresholds. The first and last auto-advance.
+ */
+ private static final float[] QUICK_SCRUB_THRESHOLDS = new float[] {
+ 0.05f, 0.35f, 0.65f, 0.95f
+ };
+
private static final boolean ENABLE_AUTO_ADVANCE = true;
- private static final int NUM_QUICK_SCRUB_SECTIONS = 3;
- private static final long INITIAL_AUTO_ADVANCE_DELAY = 1000;
private static final long AUTO_ADVANCE_DELAY = 500;
private static final int QUICKSCRUB_SNAP_DURATION_PER_PAGE = 325;
private static final int QUICKSCRUB_END_SNAP_DURATION_PER_PAGE = 60;
@@ -52,7 +57,6 @@ public class QuickScrubController implements OnAlarmListener {
private boolean mInQuickScrub;
private int mQuickScrubSection;
private boolean mStartedFromHome;
- private boolean mHasAlarmRun;
private boolean mFinishedTransitionToQuickScrub;
public QuickScrubController(BaseActivity activity, RecentsView recentsView) {
@@ -68,7 +72,6 @@ public class QuickScrubController implements OnAlarmListener {
mInQuickScrub = true;
mStartedFromHome = startingFromHome;
mQuickScrubSection = 0;
- mHasAlarmRun = false;
mFinishedTransitionToQuickScrub = false;
snapToNextTaskIfAvailable();
@@ -105,16 +108,23 @@ public class QuickScrubController implements OnAlarmListener {
}
public void onQuickScrubProgress(float progress) {
- int quickScrubSection = Math.round(progress * NUM_QUICK_SCRUB_SECTIONS);
+ int quickScrubSection = 0;
+ for (float threshold : QUICK_SCRUB_THRESHOLDS) {
+ if (progress < threshold) {
+ break;
+ }
+ quickScrubSection++;
+ }
if (quickScrubSection != mQuickScrubSection) {
+ boolean cameFromAutoAdvance = mQuickScrubSection == QUICK_SCRUB_THRESHOLDS.length
+ || mQuickScrubSection == 0;
int pageToGoTo = mRecentsView.getNextPage() + quickScrubSection - mQuickScrubSection;
- if (mFinishedTransitionToQuickScrub) {
+ if (mFinishedTransitionToQuickScrub && !cameFromAutoAdvance) {
goToPageWithHaptic(pageToGoTo);
}
if (ENABLE_AUTO_ADVANCE) {
- if (quickScrubSection == NUM_QUICK_SCRUB_SECTIONS || quickScrubSection == 0) {
- mAutoAdvanceAlarm.setAlarm(mHasAlarmRun
- ? AUTO_ADVANCE_DELAY : INITIAL_AUTO_ADVANCE_DELAY);
+ if (quickScrubSection == QUICK_SCRUB_THRESHOLDS.length || quickScrubSection == 0) {
+ mAutoAdvanceAlarm.setAlarm(AUTO_ADVANCE_DELAY);
} else {
mAutoAdvanceAlarm.cancelAlarm();
}
@@ -128,9 +138,8 @@ public class QuickScrubController implements OnAlarmListener {
}
public void snapToNextTaskIfAvailable() {
- if (mInQuickScrub && mRecentsView.getChildCount() > 0) {
- int toPage = mStartedFromHome ? 0 : mRecentsView.getNextPage() + 1;
- mRecentsView.snapToPage(toPage, QUICK_SCRUB_START_DURATION);
+ if (!mStartedFromHome && mInQuickScrub && mRecentsView.getChildCount() > 0) {
+ mRecentsView.snapToPage(mRecentsView.getNextPage() + 1, QUICK_SCRUB_START_DURATION);
}
}
@@ -148,13 +157,12 @@ public class QuickScrubController implements OnAlarmListener {
@Override
public void onAlarm(Alarm alarm) {
int currPage = mRecentsView.getNextPage();
- if (mQuickScrubSection == NUM_QUICK_SCRUB_SECTIONS
+ if (mQuickScrubSection == QUICK_SCRUB_THRESHOLDS.length
&& currPage < mRecentsView.getPageCount() - 1) {
goToPageWithHaptic(currPage + 1);
} else if (mQuickScrubSection == 0 && currPage > 0) {
goToPageWithHaptic(currPage - 1);
}
- mHasAlarmRun = true;
if (ENABLE_AUTO_ADVANCE) {
mAutoAdvanceAlarm.setAlarm(AUTO_ADVANCE_DELAY);
}
diff --git a/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
new file mode 100644
index 0000000000..aed9959576
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/QuickstepProcessInitializer.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep;
+
+import android.content.Context;
+
+import com.android.launcher3.MainProcessInitializer;
+import com.android.systemui.shared.system.ThreadedRendererCompat;
+
+public class QuickstepProcessInitializer extends MainProcessInitializer {
+
+ public QuickstepProcessInitializer(Context context) { }
+
+ @Override
+ protected void init(Context context) {
+ super.init(context);
+
+ // Elevate GPU priority for Quickstep and Remote animations.
+ ThreadedRendererCompat.setContextPriority(ThreadedRendererCompat.EGL_CONTEXT_PRIORITY_HIGH_IMG);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index e5792056aa..cf60fdff65 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -26,7 +26,11 @@ import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.uioverrides.UiFactory;
+import com.android.launcher3.util.SystemUiController;
+import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.fallback.FallbackRecentsView;
+import com.android.quickstep.fallback.RecentsRootView;
/**
* A simple activity to show the recently launched tasks
@@ -51,6 +55,10 @@ public class RecentsActivity extends BaseDraggingActivity {
mRecentsRootView = findViewById(R.id.drag_layer);
mFallbackRecentsView = findViewById(R.id.overview_panel);
+ mRecentsRootView.setup();
+
+ getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
+ Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
RecentsActivityTracker.onRecentsActivityCreate(this);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsActivityTracker.java b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java
index 5bd606eb4a..77f0e7a53f 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivityTracker.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivityTracker.java
@@ -16,9 +16,14 @@
package com.android.quickstep;
import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.Intent;
import android.os.Build;
+import android.os.Bundle;
+import android.os.Handler;
import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
+import com.android.quickstep.util.RemoteAnimationProvider;
import java.lang.ref.WeakReference;
import java.util.function.BiPredicate;
@@ -78,4 +83,13 @@ public class RecentsActivityTracker implements ActivityInitListener {
return sCurrentActivity.get();
}
}
+
+ @Override
+ public void registerAndStartActivity(Intent intent, RemoteAnimationProvider animProvider,
+ Context context, Handler handler, long duration) {
+ register();
+
+ Bundle options = animProvider.toActivityOptions(handler, duration).toBundle();
+ context.startActivity(intent, options);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java b/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java
index 1f9c7281fe..fdeb0c1705 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationInterpolator.java
@@ -79,8 +79,8 @@ public class RecentsAnimationInterpolator {
Rect finalScaledTaskInsets = new Rect(taskInsets);
Utilities.scaleRect(finalScaledTaskInsets, mFinalTaskScale);
mTargetTask = new Rect(mInsetWindow);
- mTargetTask.offsetTo(window.top + insets.top - finalScaledTaskInsets.top,
- window.left + insets.left - finalScaledTaskInsets.left);
+ mTargetTask.offsetTo(window.left + insets.left - finalScaledTaskInsets.left,
+ window.top + insets.top - finalScaledTaskInsets.top);
float initialWinScale = 1f / mFinalTaskScale;
Rect scaledWindow = new Rect(mInsetWindow);
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
index 4e11220745..12f8d52b82 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java
@@ -28,7 +28,9 @@ public class RecentsAnimationWrapper {
public RecentsAnimationControllerCompat controller;
public RemoteAnimationTargetCompat[] targets;
- private boolean mInputConsumerEnabled;
+ private boolean mInputConsumerEnabled = false;
+ private boolean mBehindSystemBars = true;
+ private boolean mSplitScreenMinimized = false;
public synchronized void setController(
RecentsAnimationControllerCompat controller, RemoteAnimationTargetCompat[] targets) {
@@ -75,4 +77,42 @@ public class RecentsAnimationWrapper {
});
}
}
+
+ public void setAnimationTargetsBehindSystemBars(boolean behindSystemBars) {
+ if (mBehindSystemBars == behindSystemBars) {
+ return;
+ }
+ mBehindSystemBars = behindSystemBars;
+ BackgroundExecutor.get().submit(() -> {
+ synchronized (this) {
+ TraceHelper.partitionSection("RecentsController",
+ "Setting behind system bars on " + controller);
+ if (controller != null) {
+ controller.setAnimationTargetsBehindSystemBars(behindSystemBars);
+ }
+ }
+ });
+ }
+
+ /**
+ * NOTE: As a workaround for conflicting animations (Launcher animating the task leash, and
+ * SystemUI resizing the docked stack, which resizes the task), we currently only set the
+ * minimized mode, and not the inverse.
+ * TODO: Synchronize the minimize animation with the launcher animation
+ */
+ public void setSplitScreenMinimizedForTransaction(boolean minimized) {
+ if (mSplitScreenMinimized || !minimized) {
+ return;
+ }
+ mSplitScreenMinimized = minimized;
+ BackgroundExecutor.get().submit(() -> {
+ synchronized (this) {
+ TraceHelper.partitionSection("RecentsController",
+ "Setting minimize dock on " + controller);
+ if (controller != null) {
+ controller.setSplitScreenMinimized(minimized);
+ }
+ }
+ });
+ }
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 1e43202a1f..4652f2d656 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -158,6 +158,16 @@ public class RecentsModel extends TaskStackChangeListener {
return requestId;
}
+ @Override
+ public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+ mTaskChangeId++;
+ }
+
+ @Override
+ public void onActivityUnpinned() {
+ mTaskChangeId++;
+ }
+
@Override
public void onTaskStackChanged() {
mTaskChangeId++;
diff --git a/quickstep/src/com/android/quickstep/TaskUtils.java b/quickstep/src/com/android/quickstep/TaskUtils.java
index 2df951b86e..5bf1d07db4 100644
--- a/quickstep/src/com/android/quickstep/TaskUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskUtils.java
@@ -24,6 +24,7 @@ import android.util.Log;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.UserManagerCompat;
+import com.android.launcher3.util.ComponentKey;
import com.android.systemui.shared.recents.model.Task;
/**
@@ -48,4 +49,8 @@ public class TaskUtils {
return userManagerCompat.getBadgedLabelForUser(
applicationInfo.loadLabel(packageManager), user);
}
+
+ public static ComponentKey getComponentKeyForTask(Task.TaskKey taskKey) {
+ return new ComponentKey(taskKey.getComponent(), UserHandle.of(taskKey.userId));
+ }
}
diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java
index 4e351595ff..1290ec3375 100644
--- a/quickstep/src/com/android/quickstep/TouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/TouchConsumer.java
@@ -46,6 +46,8 @@ public interface TouchConsumer extends Consumer {
default void onQuickScrubProgress(float progress) { }
+ default void onQuickStep(float eventX, float eventY, long eventTime) { }
+
/**
* Called on the binder thread to allow the consumer to process the motion event before it is
* posted on a handler thread.
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index cc49dc743e..84d8983e03 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -21,8 +21,7 @@ import static android.view.MotionEvent.ACTION_MOVE;
import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
-import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
-import static com.android.launcher3.LauncherState.NORMAL;
+
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
import android.annotation.TargetApi;
@@ -43,9 +42,7 @@ import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherState;
+import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.util.TraceHelper;
@@ -61,8 +58,6 @@ import com.android.systemui.shared.system.NavigationBarCompat.HitTarget;
@TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service {
- public static final boolean DEBUG_OPEN_OVERVIEW_VIA_ALT_TAB = false;
-
private static final SparseArray sMotionEventNames;
static {
@@ -133,26 +128,26 @@ public class TouchInteractionService extends Service {
@Override
public void onOverviewShown(boolean triggeredFromAltTab) {
- if (DEBUG_OPEN_OVERVIEW_VIA_ALT_TAB) {
- if (triggeredFromAltTab) {
- setupTouchConsumer(HIT_TARGET_NONE);
- mEventQueue.onOverviewShownFromAltTab();
- }
+ if (triggeredFromAltTab) {
+ setupTouchConsumer(HIT_TARGET_NONE);
+ mEventQueue.onOverviewShownFromAltTab();
+ } else {
+ mOverviewCommandHelper.onOverviewShown();
}
}
@Override
public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
- if (DEBUG_OPEN_OVERVIEW_VIA_ALT_TAB) {
- if (triggeredFromAltTab && !triggeredFromHomeKey) {
- // onOverviewShownFromAltTab initiates quick scrub. Ending it here.
- mEventQueue.onQuickScrubEnd();
- }
+ if (triggeredFromAltTab && !triggeredFromHomeKey) {
+ // onOverviewShownFromAltTab initiates quick scrub. Ending it here.
+ mEventQueue.onQuickScrubEnd();
}
}
@Override
public void onQuickStep(MotionEvent motionEvent) {
+ mEventQueue.onQuickStep(motionEvent);
+ TraceHelper.endSection("SysUiBinder", "onQuickStep");
}
};
@@ -222,13 +217,13 @@ public class TouchInteractionService extends Service {
private TouchConsumer getCurrentTouchConsumer(
@HitTarget int downHitTarget, boolean forceToLauncher, VelocityTracker tracker) {
- RunningTaskInfo runningTaskInfo = mAM.getRunningTask();
+ RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0);
if (runningTaskInfo == null && !forceToLauncher) {
return mNoOpTouchConsumer;
} else if (forceToLauncher ||
runningTaskInfo.topActivity.equals(mOverviewCommandHelper.launcher)) {
- return getLauncherConsumer();
+ return getOverviewConsumer();
} else {
if (tracker == null) {
tracker = VelocityTracker.obtain();
@@ -240,18 +235,20 @@ public class TouchInteractionService extends Service {
}
}
- private TouchConsumer getLauncherConsumer() {
- Launcher launcher = (Launcher) LauncherAppState.getInstance(this).getModel().getCallback();
- if (launcher == null) {
+ private TouchConsumer getOverviewConsumer() {
+ ActivityControlHelper activityHelper = mOverviewCommandHelper.getActivityControlHelper();
+ BaseDraggingActivity activity = activityHelper.getCreatedActivity();
+ if (activity == null) {
return mNoOpTouchConsumer;
}
- View target = launcher.getDragLayer();
- return new LauncherTouchConsumer(launcher, target);
+ return new OverviewTouchConsumer(activityHelper, activity);
}
- private static class LauncherTouchConsumer implements TouchConsumer {
+ private static class OverviewTouchConsumer
+ implements TouchConsumer {
- private final Launcher mLauncher;
+ private final ActivityControlHelper mActivityHelper;
+ private final T mActivity;
private final View mTarget;
private final int[] mLocationOnScreen = new int[2];
private final PointF mDownPos = new PointF();
@@ -262,12 +259,17 @@ public class TouchInteractionService extends Service {
private boolean mInvalidated = false;
private boolean mHadWindowFocusOnDown;
- LauncherTouchConsumer(Launcher launcher, View target) {
- mLauncher = launcher;
- mTarget = target;
+ private float mLastProgress = 0;
+ private boolean mStartPending = false;
+ private boolean mEndPending = false;
+
+ OverviewTouchConsumer(ActivityControlHelper activityHelper, T activity) {
+ mActivityHelper = activityHelper;
+ mActivity = activity;
+ mTarget = activity.getDragLayer();
mTouchSlop = ViewConfiguration.get(mTarget.getContext()).getScaledTouchSlop();
- mQuickScrubController = mLauncher.getOverviewPanel()
+ mQuickScrubController = mActivity.getOverviewPanel()
.getQuickScrubController();
}
@@ -329,16 +331,22 @@ public class TouchInteractionService extends Service {
return;
}
if (interactionType == INTERACTION_QUICK_SCRUB) {
+ mStartPending = true;
+
Runnable action = () -> {
- LauncherState fromState = mLauncher.getStateManager().getState();
- mLauncher.getStateManager().goToState(FAST_OVERVIEW, true);
- mQuickScrubController.onQuickScrubStart(fromState == NORMAL);
+ mQuickScrubController.onQuickScrubStart(
+ mActivityHelper.onQuickInteractionStart(mActivity, true));
+ mQuickScrubController.onQuickScrubProgress(mLastProgress);
+ mStartPending = false;
+
+ if (mEndPending) {
+ mQuickScrubController.onQuickScrubEnd();
+ mEndPending = false;
+ }
+
};
- if (mLauncher.getWorkspace().runOnOverlayHidden(action)) {
- // Hide the minus one overlay so launcher can get window focus.
- mLauncher.onQuickstepGestureStarted(true);
- }
+ mActivityHelper.executeOnWindowAvailable(mActivity, action);
}
}
@@ -347,12 +355,17 @@ public class TouchInteractionService extends Service {
if (mInvalidated) {
return;
}
- mQuickScrubController.onQuickScrubEnd();
+ if (mStartPending) {
+ mEndPending = true;
+ } else {
+ mQuickScrubController.onQuickScrubEnd();
+ }
}
@Override
public void onQuickScrubProgress(float progress) {
- if (mInvalidated) {
+ mLastProgress = progress;
+ if (mInvalidated || mEndPending) {
return;
}
mQuickScrubController.onQuickScrubProgress(progress);
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 25f2f87601..d4c35e0b1e 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -30,11 +30,8 @@ import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
import android.content.res.Resources;
-import android.graphics.Matrix;
-import android.graphics.Matrix.ScaleToFit;
import android.graphics.Point;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
@@ -64,11 +61,11 @@ import com.android.launcher3.util.TraceHelper;
import com.android.quickstep.ActivityControlHelper.ActivityInitListener;
import com.android.quickstep.ActivityControlHelper.LayoutListener;
import com.android.quickstep.TouchConsumer.InteractionType;
+import com.android.quickstep.util.ClipAnimationHelper;
import com.android.quickstep.util.SysuiEventLogger;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.ThumbnailData;
-import com.android.systemui.shared.recents.utilities.RectFEvaluator;
import com.android.systemui.shared.system.InputConsumerController;
import com.android.systemui.shared.system.LatencyTrackerCompat;
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
@@ -132,26 +129,8 @@ public class WindowTransformSwipeHandler {
private static final float MIN_PROGRESS_FOR_OVERVIEW = 0.5f;
- // The bounds of the source app in device coordinates
- private final Rect mSourceStackBounds = new Rect();
- // The insets of the source app
- private final Rect mSourceInsets = new Rect();
- // The source app bounds with the source insets applied, in the source app window coordinates
- private final RectF mSourceRect = new RectF();
- // The bounds of the task view in launcher window coordinates
- private final RectF mTargetRect = new RectF();
- // Doesn't change after initialized, used as an anchor when changing mTargetRect
- private final RectF mInitialTargetRect = new RectF();
- // The insets to be used for clipping the app window, which can be larger than mSourceInsets
- // if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In
- // app window coordinates.
- private final RectF mSourceWindowClipInsets = new RectF();
+ private final ClipAnimationHelper mClipAnimationHelper = new ClipAnimationHelper();
- // The bounds of launcher (not including insets) in device coordinates
- private final Rect mHomeStackBounds = new Rect();
- // The clip rect in source app window coordinates
- private final Rect mClipRect = new Rect();
- private final RectFEvaluator mRectFEvaluator = new RectFEvaluator();
protected Runnable mGestureEndCallback;
protected boolean mIsGoingToHome;
private DeviceProfile mDp;
@@ -192,7 +171,6 @@ public class WindowTransformSwipeHandler {
InputConsumerController.getRecentsAnimationInputConsumer();
private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper();
- private Matrix mTmpMatrix = new Matrix();
private final long mTouchTimeMs;
private long mLauncherFrameDrawnTime;
@@ -269,42 +247,11 @@ public class WindowTransformSwipeHandler {
private void initTransitionEndpoints(DeviceProfile dp) {
mDp = dp;
- mSourceRect.set(mSourceInsets.left, mSourceInsets.top,
- mSourceStackBounds.width() - mSourceInsets.right,
- mSourceStackBounds.height() - mSourceInsets.bottom);
Rect tempRect = new Rect();
mTransitionDragLength = mActivityControlHelper
.getSwipeUpDestinationAndLength(dp, mContext, tempRect);
-
- mTargetRect.set(tempRect);
- mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left,
- mHomeStackBounds.top - mSourceStackBounds.top);
- mInitialTargetRect.set(mTargetRect);
-
- // Calculate the clip based on the target rect (since the content insets and the
- // launcher insets may differ, so the aspect ratio of the target rect can differ
- // from the source rect. The difference between the target rect (scaled to the
- // source rect) is the amount to clip on each edge.
- RectF scaledTargetRect = new RectF(mTargetRect);
- Utilities.scaleRectFAboutCenter(scaledTargetRect,
- mSourceRect.width() / mTargetRect.width());
- scaledTargetRect.offsetTo(mSourceRect.left, mSourceRect.top);
- mSourceWindowClipInsets.set(
- Math.max(scaledTargetRect.left, 0),
- Math.max(scaledTargetRect.top, 0),
- Math.max(mSourceStackBounds.width() - scaledTargetRect.right, 0),
- Math.max(mSourceStackBounds.height() - scaledTargetRect.bottom, 0));
- mSourceRect.set(scaledTargetRect);
- }
-
- public int getTransitionLength() {
- return mTransitionDragLength;
- }
-
- public RectF getTargetRect(Point outWindowSize) {
- outWindowSize.set(mDp.widthPx, mDp.heightPx);
- return mInitialTargetRect;
+ mClipAnimationHelper.updateTargetRect(tempRect);
}
private long getFadeInDuration() {
@@ -336,6 +283,9 @@ public class WindowTransformSwipeHandler {
}
mWasLauncherAlreadyVisible = alreadyOnHome;
mActivity = activity;
+ // Override the visibility of the activity until the gesture actually starts and we swipe
+ // up, or until we transition home and the home animation is composed
+ mActivity.setForceInvisible(true);
mRecentsView = activity.getOverviewPanel();
mQuickScrubController = mRecentsView.getQuickScrubController();
@@ -475,39 +425,10 @@ public class WindowTransformSwipeHandler {
synchronized (mRecentsAnimationWrapper) {
if (mRecentsAnimationWrapper.controller != null) {
- RectF currentRect;
- synchronized (mTargetRect) {
- Interpolator interpolator = mInteractionType == INTERACTION_QUICK_SCRUB
- ? ACCEL_2 : LINEAR;
- float interpolated = interpolator.getInterpolation(shift);
- currentRect = mRectFEvaluator.evaluate(interpolated, mSourceRect, mTargetRect);
- // Stay lined up with the center of the target, since it moves for quick scrub.
- currentRect.offset(mTargetRect.centerX() - currentRect.centerX(), 0);
- }
-
- mClipRect.left = (int) (mSourceWindowClipInsets.left * shift);
- mClipRect.top = (int) (mSourceWindowClipInsets.top * shift);
- mClipRect.right = (int)
- (mSourceStackBounds.width() - (mSourceWindowClipInsets.right * shift));
- mClipRect.bottom = (int)
- (mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * shift));
-
- mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
-
- TransactionCompat transaction = new TransactionCompat();
- for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
- if (app.mode == MODE_CLOSING) {
- transaction.setMatrix(app.leash, mTmpMatrix)
- .setWindowCrop(app.leash, mClipRect);
-
- if (app.isNotInRecents) {
- transaction.setAlpha(app.leash, 1 - shift);
- }
-
- transaction.show(app.leash);
- }
- }
- transaction.apply();
+ Interpolator interpolator = mInteractionType == INTERACTION_QUICK_SCRUB
+ ? ACCEL_2 : LINEAR;
+ float interpolated = interpolator.getInterpolation(shift);
+ mClipAnimationHelper.applyTransform(mRecentsAnimationWrapper.targets, interpolated);
}
}
@@ -520,20 +441,20 @@ public class WindowTransformSwipeHandler {
// Make sure the window follows the first task if it moves, e.g. during quick scrub.
View firstTask = mRecentsView.getPageAt(0);
- int scrollForFirstTask = mRecentsView.getScrollForPage(0);
- int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX());
- synchronized (mTargetRect) {
- mTargetRect.set(mInitialTargetRect);
- Utilities.scaleRectFAboutCenter(mTargetRect, firstTask.getScaleX());
- float offsetX = offsetFromFirstTask + firstTask.getTranslationX();
- float offsetY = mRecentsView.getTranslationY();
- mTargetRect.offset(offsetX, offsetY);
+ // The first task may be null if we are swiping up from a task that does not
+ // appear in the list (ie. the assistant)
+ if (firstTask != null) {
+ int scrollForFirstTask = mRecentsView.getScrollForPage(0);
+ int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX());
+ mClipAnimationHelper.offsetTarget(firstTask.getScaleX(),
+ offsetFromFirstTask + firstTask.getTranslationX(),
+ mRecentsView.getTranslationY());
}
if (mRecentsAnimationWrapper.controller != null) {
-
// TODO: This logic is spartanic!
- mRecentsAnimationWrapper.controller.setAnimationTargetsBehindSystemBars(
- shift < 0.12f);
+ boolean passedThreshold = shift > 0.12f;
+ mRecentsAnimationWrapper.setAnimationTargetsBehindSystemBars(!passedThreshold);
+ mRecentsAnimationWrapper.setSplitScreenMinimizedForTransaction(passedThreshold);
}
};
if (Looper.getMainLooper() == Looper.myLooper()) {
@@ -552,13 +473,15 @@ public class WindowTransformSwipeHandler {
for (RemoteAnimationTargetCompat target : apps) {
if (target.mode == MODE_CLOSING) {
DeviceProfile dp = LauncherAppState.getIDP(mContext).getDeviceProfile(mContext);
+ final Rect homeStackBounds;
+
if (minimizedHomeBounds != null) {
- mHomeStackBounds.set(minimizedHomeBounds);
+ homeStackBounds = minimizedHomeBounds;
dp = dp.getMultiWindowProfile(mContext,
new Point(minimizedHomeBounds.width(), minimizedHomeBounds.height()));
dp.updateInsets(homeContentInsets);
} else {
- mHomeStackBounds.set(new Rect(0, 0, dp.widthPx, dp.heightPx));
+ homeStackBounds = new Rect(0, 0, dp.widthPx, dp.heightPx);
// TODO: Workaround for an existing issue where the home content insets are
// not valid immediately after rotation, just use the stable insets for now
Rect insets = new Rect();
@@ -566,18 +489,8 @@ public class WindowTransformSwipeHandler {
dp.updateInsets(insets);
}
- // Initialize the start and end animation bounds
- // TODO: Remove once platform is updated
- try {
- mSourceInsets.set(target.getContentInsets());
- } catch (Error e) {
- // TODO: Remove once platform is updated, use stable insets as fallback
- WindowManagerWrapper.getInstance().getStableInsets(mSourceInsets);
- }
- mSourceStackBounds.set(target.sourceContainerBounds);
-
+ mClipAnimationHelper.updateSource(homeStackBounds, target);
initTransitionEndpoints(dp);
- break;
}
}
}
@@ -605,6 +518,9 @@ public class WindowTransformSwipeHandler {
private void notifyGestureStarted() {
final T curActivity = mActivity;
if (curActivity != null) {
+ // Once the gesture starts, we can no longer transition home through the button, so
+ // reset the force override of the activity visibility
+ mActivity.setForceInvisible(false);
mActivityControlHelper.onQuickstepGestureStarted(
curActivity, mWasLauncherAlreadyVisible);
}
@@ -720,6 +636,7 @@ public class WindowTransformSwipeHandler {
() -> setStateOnUiThread(STATE_SWITCH_TO_SCREENSHOT_COMPLETE));
}
};
+
synchronized (mRecentsAnimationWrapper) {
if (mRecentsAnimationWrapper.controller != null) {
TransactionCompat transaction = new TransactionCompat();
@@ -730,6 +647,7 @@ public class WindowTransformSwipeHandler {
mRecentsAnimationWrapper.controller.screenshotTask(app.taskId);
TaskView taskView = mRecentsView.updateThumbnail(app.taskId, thumbnail);
if (taskView != null) {
+ taskView.setAlpha(1);
// Defer finishing the animation until the next launcher frame with the
// new thumbnail
mActivityControlHelper.executeOnNextDraw(mActivity, taskView,
@@ -749,11 +667,17 @@ public class WindowTransformSwipeHandler {
}
private void setupLauncherUiAfterSwipeUpAnimation() {
+ if (mLauncherTransitionController != null) {
+ mLauncherTransitionController.getAnimationPlayer().end();
+ mLauncherTransitionController = null;
+ }
mActivityControlHelper.onSwipeUpComplete(mActivity);
// Animate the first icon.
mRecentsView.setFirstTaskIconScaledDown(false /* isScaledDown */, true /* animate */);
+ mRecentsView.setSwipeDownShouldLaunchApp(true);
+
reset();
}
diff --git a/quickstep/src/com/android/quickstep/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
similarity index 52%
rename from quickstep/src/com/android/quickstep/FallbackRecentsView.java
rename to quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 032d753a68..4ed165699e 100644
--- a/quickstep/src/com/android/quickstep/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -13,17 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.quickstep;
+package com.android.quickstep.fallback;
import android.content.Context;
+import android.graphics.Canvas;
import android.graphics.Rect;
+import android.support.annotation.AnyThread;
import android.util.AttributeSet;
+import android.view.View;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
+import com.android.quickstep.RecentsActivity;
+import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
-public class FallbackRecentsView extends RecentsView implements Insettable {
+public class FallbackRecentsView extends RecentsView {
public FallbackRecentsView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -32,6 +36,7 @@ public class FallbackRecentsView extends RecentsView implements
public FallbackRecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setOverviewStateEnabled(true);
+ updateEmptyMessage();
}
@Override
@@ -40,29 +45,30 @@ public class FallbackRecentsView extends RecentsView implements
}
@Override
- public void setInsets(Rect insets) {
- mInsets.set(insets);
- DeviceProfile dp = mActivity.getDeviceProfile();
- Rect padding = getPadding(dp, getContext());
- verticalCenter(padding, dp);
- setPadding(padding.left, padding.top, padding.right, padding.bottom);
+ public void onViewAdded(View child) {
+ super.onViewAdded(child);
+ updateEmptyMessage();
}
- private static void verticalCenter(Rect padding, DeviceProfile dp) {
- Rect insets = dp.getInsets();
- int totalSpace = (padding.top + padding.bottom - insets.top - insets.bottom) / 2;
- padding.top = insets.top + totalSpace;
- padding.bottom = insets.bottom + totalSpace;
+ @Override
+ public void onViewRemoved(View child) {
+ super.onViewRemoved(child);
+ updateEmptyMessage();
}
- public static void getCenterPageRect(DeviceProfile grid, Context context, Rect outRect) {
- Rect targetPadding = getPadding(grid, context);
- verticalCenter(targetPadding, grid);
- Rect insets = grid.getInsets();
- outRect.set(
- targetPadding.left + insets.left,
- targetPadding.top + insets.top,
- grid.widthPx - targetPadding.right - insets.right,
- grid.heightPx - targetPadding.bottom - insets.bottom);
+ @Override
+ public void draw(Canvas canvas) {
+ maybeDrawEmptyMessage(canvas);
+ super.draw(canvas);
+ }
+
+ @Override
+ protected void getTaskSize(DeviceProfile dp, Rect outRect) {
+ LayoutUtils.calculateTaskSize(getContext(), dp, 0, outRect);
+ }
+
+ @AnyThread
+ public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) {
+ LayoutUtils.calculateTaskSize(context, grid, 0, outRect);
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsRootView.java b/quickstep/src/com/android/quickstep/fallback/RecentsRootView.java
similarity index 79%
rename from quickstep/src/com/android/quickstep/RecentsRootView.java
rename to quickstep/src/com/android/quickstep/fallback/RecentsRootView.java
index 24785f9316..7aaa88c38d 100644
--- a/quickstep/src/com/android/quickstep/RecentsRootView.java
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsRootView.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.quickstep;
+package com.android.quickstep.fallback;
import android.annotation.TargetApi;
import android.content.Context;
@@ -25,15 +25,22 @@ import com.android.launcher3.R;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.views.BaseDragLayer;
+import com.android.quickstep.RecentsActivity;
public class RecentsRootView extends BaseDragLayer {
- private final BaseActivity mActivity;
+ private final RecentsActivity mActivity;
public RecentsRootView(Context context, AttributeSet attrs) {
super(context, attrs);
- mActivity = BaseActivity.fromContext(context);
- mControllers = new TouchController[0];
+ mActivity = (RecentsActivity) BaseActivity.fromContext(context);
+ setSystemUiVisibility(SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+ | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+ | SYSTEM_UI_FLAG_LAYOUT_STABLE);
+ }
+
+ public void setup() {
+ mControllers = new TouchController[] { new RecentsTaskController(mActivity) };
}
@TargetApi(23)
diff --git a/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
new file mode 100644
index 0000000000..9463cc90f1
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/fallback/RecentsTaskController.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.fallback;
+
+import com.android.launcher3.uioverrides.TaskViewTouchController;
+import com.android.quickstep.RecentsActivity;
+
+public class RecentsTaskController extends TaskViewTouchController {
+
+ public RecentsTaskController(RecentsActivity activity) {
+ super(activity);
+ }
+
+ @Override
+ protected boolean isRecentsInteractive() {
+ return mActivity.hasWindowFocus();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
new file mode 100644
index 0000000000..493e9e2386
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/ClipAnimationHelper.java
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING;
+
+import android.graphics.Matrix;
+import android.graphics.Matrix.ScaleToFit;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+import com.android.launcher3.Utilities;
+import com.android.systemui.shared.recents.utilities.RectFEvaluator;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.TransactionCompat;
+
+/**
+ * Utility class to handle window clip animation
+ */
+public class ClipAnimationHelper {
+
+ // The bounds of the source app in device coordinates
+ private final Rect mSourceStackBounds = new Rect();
+ // The insets of the source app
+ private final Rect mSourceInsets = new Rect();
+ // The source app bounds with the source insets applied, in the source app window coordinates
+ private final RectF mSourceRect = new RectF();
+ // The bounds of the task view in launcher window coordinates
+ private final RectF mTargetRect = new RectF();
+ // Doesn't change after initialized, used as an anchor when changing mTargetRect
+ private final RectF mInitialTargetRect = new RectF();
+ // The insets to be used for clipping the app window, which can be larger than mSourceInsets
+ // if the aspect ratio of the target is smaller than the aspect ratio of the source rect. In
+ // app window coordinates.
+ private final RectF mSourceWindowClipInsets = new RectF();
+
+ // The bounds of launcher (not including insets) in device coordinates
+ public final Rect mHomeStackBounds = new Rect();
+
+ // The clip rect in source app window coordinates
+ private final Rect mClipRect = new Rect();
+ private final RectFEvaluator mRectFEvaluator = new RectFEvaluator();
+ private final Matrix mTmpMatrix = new Matrix();
+
+
+ public void updateSource(Rect homeStackBounds, RemoteAnimationTargetCompat target) {
+ mHomeStackBounds.set(homeStackBounds);
+ mSourceInsets.set(target.getContentInsets());
+ mSourceStackBounds.set(target.sourceContainerBounds);
+
+ // TODO: Should sourceContainerBounds already have this offset?
+ mSourceStackBounds.offsetTo(target.position.x, target.position.y);
+ }
+
+ public void updateTargetRect(Rect targetRect) {
+ mSourceRect.set(mSourceInsets.left, mSourceInsets.top,
+ mSourceStackBounds.width() - mSourceInsets.right,
+ mSourceStackBounds.height() - mSourceInsets.bottom);
+ mTargetRect.set(targetRect);
+ mTargetRect.offset(mHomeStackBounds.left - mSourceStackBounds.left,
+ mHomeStackBounds.top - mSourceStackBounds.top);
+
+ mInitialTargetRect.set(mTargetRect);
+
+ // Calculate the clip based on the target rect (since the content insets and the
+ // launcher insets may differ, so the aspect ratio of the target rect can differ
+ // from the source rect. The difference between the target rect (scaled to the
+ // source rect) is the amount to clip on each edge.
+ RectF scaledTargetRect = new RectF(mTargetRect);
+ Utilities.scaleRectFAboutCenter(scaledTargetRect,
+ mSourceRect.width() / mTargetRect.width());
+ scaledTargetRect.offsetTo(mSourceRect.left, mSourceRect.top);
+ mSourceWindowClipInsets.set(
+ Math.max(scaledTargetRect.left, 0),
+ Math.max(scaledTargetRect.top, 0),
+ Math.max(mSourceStackBounds.width() - scaledTargetRect.right, 0),
+ Math.max(mSourceStackBounds.height() - scaledTargetRect.bottom, 0));
+ mSourceRect.set(scaledTargetRect);
+ }
+
+ public void applyTransform(RemoteAnimationTargetCompat[] targets, float progress) {
+ RectF currentRect;
+ synchronized (mTargetRect) {
+ currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTargetRect);
+ // Stay lined up with the center of the target, since it moves for quick scrub.
+ currentRect.offset(mTargetRect.centerX() - currentRect.centerX(), 0);
+ }
+
+ mClipRect.left = (int) (mSourceWindowClipInsets.left * progress);
+ mClipRect.top = (int) (mSourceWindowClipInsets.top * progress);
+ mClipRect.right = (int)
+ (mSourceStackBounds.width() - (mSourceWindowClipInsets.right * progress));
+ mClipRect.bottom = (int)
+ (mSourceStackBounds.height() - (mSourceWindowClipInsets.bottom * progress));
+
+ mTmpMatrix.setRectToRect(mSourceRect, currentRect, ScaleToFit.FILL);
+
+ TransactionCompat transaction = new TransactionCompat();
+ for (RemoteAnimationTargetCompat app : targets) {
+ if (app.mode == MODE_CLOSING) {
+ mTmpMatrix.postTranslate(app.position.x, app.position.y);
+ transaction.setMatrix(app.leash, mTmpMatrix)
+ .setWindowCrop(app.leash, mClipRect);
+ if (app.isNotInRecents) {
+ transaction.setAlpha(app.leash, 1 - progress);
+ }
+
+ transaction.show(app.leash);
+ }
+ }
+ transaction.setEarlyWakeup();
+ transaction.apply();
+ }
+
+ public void offsetTarget(float scale, float offsetX, float offsetY) {
+ synchronized (mTargetRect) {
+ mTargetRect.set(mInitialTargetRect);
+ Utilities.scaleRectFAboutCenter(mTargetRect, scale);
+ mTargetRect.offset(offsetX, offsetY);
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/LayoutUtils.java b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
new file mode 100644
index 0000000000..f29f9e4e92
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/LayoutUtils.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Rect;
+import android.graphics.RectF;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
+
+public class LayoutUtils {
+
+ public static void calculateLauncherTaskSize(Context context, DeviceProfile dp, Rect outRect) {
+ float extraSpace = dp.isVerticalBarLayout() ? 0 : dp.hotseatBarSizePx;
+ calculateTaskSize(context, dp, extraSpace, outRect);
+ }
+
+ public static void calculateTaskSize(Context context, DeviceProfile dp,
+ float extraVerticalSpace, Rect outRect) {
+ float taskWidth, taskHeight, paddingHorz;
+ Resources res = context.getResources();
+ Rect insets = dp.getInsets();
+
+ if (dp.isMultiWindowMode) {
+ DeviceProfile fullDp = dp.getFullScreenProfile();
+ // Use availableWidthPx and availableHeightPx instead of widthPx and heightPx to
+ // account for system insets
+ taskWidth = fullDp.availableWidthPx;
+ taskHeight = fullDp.availableHeightPx;
+ float halfDividerSize = res.getDimension(R.dimen.multi_window_task_divider_size) / 2;
+
+ if (fullDp.isLandscape) {
+ taskWidth = taskWidth / 2 - halfDividerSize;
+ } else {
+ taskHeight = taskHeight / 2 - halfDividerSize;
+ }
+ paddingHorz = res.getDimension(R.dimen.multi_window_task_card_horz_space);
+ } else {
+ taskWidth = dp.availableWidthPx;
+ taskHeight = dp.availableHeightPx;
+ paddingHorz = res.getDimension(dp.isVerticalBarLayout()
+ ? R.dimen.landscape_task_card_horz_space
+ : R.dimen.portrait_task_card_horz_space);
+ }
+
+ float topIconMargin = res.getDimension(R.dimen.task_thumbnail_top_margin);
+ float paddingVert = res.getDimension(R.dimen.task_card_vert_space);
+
+ // Note this should be same as dp.availableWidthPx and dp.availableHeightPx unless
+ // we override the insets ourselves.
+ int launcherVisibleWidth = dp.widthPx - insets.left - insets.right;
+ int launcherVisibleHeight = dp.heightPx - insets.top - insets.bottom;
+
+ float availableHeight = launcherVisibleHeight
+ - topIconMargin - extraVerticalSpace - paddingVert;
+ float availableWidth = launcherVisibleWidth - paddingHorz;
+
+ float scale = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
+ float outWidth = scale * taskWidth;
+ float outHeight = scale * taskHeight;
+
+ // Center in the visible space
+ float x = insets.left + (taskWidth - outWidth) / 2;
+ float y = insets.top + Math.max(topIconMargin,
+ (launcherVisibleHeight - extraVerticalSpace - outHeight) / 2);
+ outRect.set(Math.round(x), Math.round(y),
+ Math.round(x + outWidth), Math.round(y + outHeight));
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
new file mode 100644
index 0000000000..2ffcae38ef
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/RemoteAnimationProvider.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util;
+
+import android.animation.AnimatorSet;
+import android.app.ActivityOptions;
+import android.os.Handler;
+
+import com.android.launcher3.LauncherAnimationRunner;
+import com.android.systemui.shared.system.ActivityOptionsCompat;
+import com.android.systemui.shared.system.RemoteAnimationAdapterCompat;
+import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
+import com.android.systemui.shared.system.TransactionCompat;
+
+@FunctionalInterface
+public interface RemoteAnimationProvider {
+
+ AnimatorSet createWindowAnimation(RemoteAnimationTargetCompat[] targets);
+
+ default ActivityOptions toActivityOptions(Handler handler, long duration) {
+ LauncherAnimationRunner runner = new LauncherAnimationRunner(handler) {
+ @Override
+ public AnimatorSet getAnimator(RemoteAnimationTargetCompat[] targetCompats) {
+ return createWindowAnimation(targetCompats);
+ }
+ };
+ return ActivityOptionsCompat.makeRemoteAnimation(
+ new RemoteAnimationAdapterCompat(runner, duration, 0));
+ }
+
+ static void showOpeningTarget(RemoteAnimationTargetCompat[] targetCompats) {
+ TransactionCompat t = new TransactionCompat();
+ for (RemoteAnimationTargetCompat target : targetCompats) {
+ int layer = target.mode == RemoteAnimationTargetCompat.MODE_CLOSING
+ ? Integer.MAX_VALUE
+ : target.prefixOrderIndex;
+ t.setLayer(target.leash, layer);
+ t.show(target.leash);
+ }
+ t.apply();
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
index 6b7143d048..ac34d90b1d 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherLayoutListener.java
@@ -15,6 +15,7 @@
*/
package com.android.quickstep.views;
+import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
import android.graphics.Rect;
@@ -39,6 +40,10 @@ public class LauncherLayoutListener extends AbstractFloatingView
super(launcher, null);
mLauncher = launcher;
setVisibility(INVISIBLE);
+
+ // For the duration of the gesture, lock the screen orientation to ensure that we do not
+ // rotate mid-quickscrub
+ launcher.getRotationHelper().setStateHandlerRequest(REQUEST_LOCK);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 861b5fa038..4b4af3fa7e 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -15,40 +15,34 @@
*/
package com.android.quickstep.views;
+import static com.android.launcher3.LauncherAppTransitionManagerImpl.ALL_APPS_PROGRESS_OFF_SCREEN;
+import static com.android.launcher3.LauncherState.ALL_APPS_HEADER_EXTRA;
import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.allapps.AllAppsTransitionController.ALL_APPS_PROGRESS;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.annotation.TargetApi;
import android.content.Context;
+import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Build;
+import android.support.annotation.AnyThread;
import android.util.AttributeSet;
import android.util.FloatProperty;
-import android.widget.FrameLayout;
+import android.view.View;
+import android.view.ViewDebug;
import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
+import com.android.launcher3.LauncherState;
+import com.android.quickstep.util.LayoutUtils;
/**
* {@link RecentsView} used in Launcher activity
*/
@TargetApi(Build.VERSION_CODES.O)
-public class LauncherRecentsView extends RecentsView implements Insettable {
-
- public static final FloatProperty TRANSLATION_X_FACTOR =
- new FloatProperty("translationXFactor") {
-
- @Override
- public void setValue(LauncherRecentsView view, float v) {
- view.setTranslationXFactor(v);
- }
-
- @Override
- public Float get(LauncherRecentsView view) {
- return view.mTranslationXFactor;
- }
- };
+public class LauncherRecentsView extends RecentsView {
public static final FloatProperty TRANSLATION_Y_FACTOR =
new FloatProperty("translationYFactor") {
@@ -64,9 +58,8 @@ public class LauncherRecentsView extends RecentsView implements Insett
}
};
- private float mTranslationXFactor;
+ @ViewDebug.ExportedProperty(category = "launcher")
private float mTranslationYFactor;
- private Rect mPagePadding = new Rect();
public LauncherRecentsView(Context context) {
this(context, null);
@@ -81,20 +74,6 @@ public class LauncherRecentsView extends RecentsView implements Insett
setContentAlpha(0);
}
- @Override
- public void setInsets(Rect insets) {
- mInsets.set(insets);
- DeviceProfile dp = mActivity.getDeviceProfile();
- Rect padding = getPadding(dp, getContext());
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
- lp.bottomMargin = padding.bottom;
- setLayoutParams(lp);
-
- setPadding(padding.left, padding.top, padding.right, 0);
- mPagePadding.set(padding);
- mPagePadding.top += getResources().getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
- }
-
@Override
protected void onAllTasksRemoved() {
mActivity.getStateManager().goToState(NORMAL);
@@ -103,27 +82,58 @@ public class LauncherRecentsView extends RecentsView implements Insett
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
-
- int width = right - left;
- setTranslationX(mTranslationXFactor * (mIsRtl ? -width : width));
setTranslationYFactor(mTranslationYFactor);
}
- public void setTranslationXFactor(float translationFactor) {
- mTranslationXFactor = translationFactor;
- setTranslationX(translationFactor * (mIsRtl ? -getWidth() : getWidth()));
- }
-
- public float getTranslationXFactor() {
- return mTranslationXFactor;
- }
-
public void setTranslationYFactor(float translationFactor) {
mTranslationYFactor = translationFactor;
- setTranslationY(mTranslationYFactor * (mPagePadding.bottom - mPagePadding.top));
+ setTranslationY(mTranslationYFactor * (getPaddingBottom() - getPaddingTop()));
}
- public float getTranslationYFactor() {
- return mTranslationYFactor;
+ @Override
+ public void draw(Canvas canvas) {
+ maybeDrawEmptyMessage(canvas);
+ super.draw(canvas);
+ }
+
+ @Override
+ public void onViewAdded(View child) {
+ super.onViewAdded(child);
+ updateEmptyMessage();
+ }
+
+ @Override
+ protected void onTaskStackUpdated() {
+ // Lazily update the empty message only when the task stack is reapplied
+ updateEmptyMessage();
+ }
+
+ /**
+ * Animates adjacent tasks and translate hotseat off screen as well.
+ */
+ @Override
+ public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv) {
+ AnimatorSet anim = super.createAdjacentPageAnimForTaskLaunch(tv);
+
+ float allAppsProgressOffscreen = ALL_APPS_PROGRESS_OFF_SCREEN;
+ LauncherState state = mActivity.getStateManager().getState();
+ if ((state.getVisibleElements(mActivity) & ALL_APPS_HEADER_EXTRA) != 0) {
+ float maxShiftRange = mActivity.getDeviceProfile().heightPx;
+ float currShiftRange = mActivity.getAllAppsController().getShiftRange();
+ allAppsProgressOffscreen = 1f + (maxShiftRange - currShiftRange) / maxShiftRange;
+ }
+ anim.play(ObjectAnimator.ofFloat(
+ mActivity.getAllAppsController(), ALL_APPS_PROGRESS, allAppsProgressOffscreen));
+ return anim;
+ }
+
+ @Override
+ protected void getTaskSize(DeviceProfile dp, Rect outRect) {
+ LayoutUtils.calculateLauncherTaskSize(getContext(), dp, outRect);
+ }
+
+ @AnyThread
+ public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) {
+ LayoutUtils.calculateLauncherTaskSize(context, grid, outRect);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/QuickstepDragIndicator.java b/quickstep/src/com/android/quickstep/views/QuickstepDragIndicator.java
new file mode 100644
index 0000000000..5e9cd6e4fe
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/views/QuickstepDragIndicator.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.views;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.accessibility.AccessibilityNodeInfo;
+
+import com.android.launcher3.R;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+import com.android.launcher3.views.LauncherDragIndicator;
+
+public class QuickstepDragIndicator extends LauncherDragIndicator {
+
+ public QuickstepDragIndicator(Context context) {
+ super(context);
+ }
+
+ public QuickstepDragIndicator(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public QuickstepDragIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ }
+
+ private boolean isInOverview() {
+ return mLauncher.isInState(OVERVIEW);
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ info.setContentDescription(getContext().getString(R.string.all_apps_button_label));
+ }
+
+ @Override
+ protected void initCustomActions(AccessibilityNodeInfo info) {
+ if (!isInOverview()) {
+ super.initCustomActions(info);
+ }
+ }
+
+ @Override
+ public void onClick(View view) {
+ mLauncher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP,
+ ControlType.ALL_APPS_BUTTON,
+ isInOverview() ? ContainerType.TASKSWITCHER : ContainerType.WORKSPACE);
+ mLauncher.getStateManager().goToState(ALL_APPS);
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 8901e6d8c6..7e81ba9020 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -26,29 +26,49 @@ import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.annotation.TargetApi;
+import android.app.ActivityManager;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
+import android.graphics.Canvas;
+import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.os.Build;
+import android.text.Layout;
+import android.text.StaticLayout;
+import android.text.TextPaint;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.util.SparseBooleanArray;
import android.view.KeyEvent;
import android.view.LayoutInflater;
+import android.view.MotionEvent;
import android.view.View;
+import android.view.ViewDebug;
+import android.view.accessibility.AccessibilityEvent;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Insettable;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.anim.PropertyListBuilder;
import com.android.launcher3.config.FeatureFlags;
-import com.android.quickstep.PendingAnimation;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.util.PendingAnimation;
+import com.android.launcher3.util.Themes;
import com.android.quickstep.QuickScrubController;
+import com.android.quickstep.RecentsAnimationInterpolator;
+import com.android.quickstep.RecentsAnimationInterpolator.TaskWindowBounds;
import com.android.quickstep.RecentsModel;
+import com.android.quickstep.TaskUtils;
import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.shared.recents.model.RecentsTaskLoader;
import com.android.systemui.shared.recents.model.Task;
@@ -56,7 +76,6 @@ import com.android.systemui.shared.recents.model.TaskStack;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
-import com.android.systemui.shared.system.WindowManagerWrapper;
import java.util.ArrayList;
@@ -65,12 +84,12 @@ import java.util.ArrayList;
*/
@TargetApi(Build.VERSION_CODES.P)
public abstract class RecentsView
- extends PagedView implements OnSharedPreferenceChangeListener {
+ extends PagedView implements OnSharedPreferenceChangeListener, Insettable {
+
+ private final Rect mTempRect = new Rect();
public static final FloatProperty CONTENT_ALPHA =
new FloatProperty("contentAlpha") {
-
-
@Override
public void setValue(RecentsView recentsView, float v) {
recentsView.setContentAlpha(v);
@@ -82,11 +101,21 @@ public abstract class RecentsView
}
};
+ public static final FloatProperty ADJACENT_SCALE =
+ new FloatProperty("adjacentScale") {
+ @Override
+ public void setValue(RecentsView recentsView, float v) {
+ recentsView.setAdjacentScale(v);
+ }
+
+ @Override
+ public Float get(RecentsView recentsView) {
+ return recentsView.mAdjacentScale;
+ }
+ };
private static final String PREF_FLIP_RECENTS = "pref_flip_recents";
private static final int DISMISS_TASK_DURATION = 300;
- private static final Rect sTempStableInsets = new Rect();
-
protected final T mActivity;
private final QuickScrubController mQuickScrubController;
private final float mFastFlingVelocity;
@@ -102,13 +131,27 @@ public abstract class RecentsView
private final TaskStackChangeListener mTaskStackListener = new TaskStackChangeListener() {
@Override
public void onTaskSnapshotChanged(int taskId, ThumbnailData snapshot) {
- for (int i = 0; i < getChildCount(); i++) {
- final TaskView taskView = (TaskView) getChildAt(i);
- if (taskView.getTask().key.id == taskId) {
- taskView.getThumbnail().setThumbnail(taskView.getTask(), snapshot);
- return;
- }
+ updateThumbnail(taskId, snapshot);
+ }
+
+ @Override
+ public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+ // Check this is for the right user
+ if (!checkCurrentUserId(userId, false /* debug */)) {
+ return;
}
+
+ // Remove the task immediately from the task list
+ TaskView taskView = getTaskView(taskId);
+ if (taskView != null) {
+ removeView(taskView);
+ }
+ }
+
+ @Override
+ public void onActivityUnpinned() {
+ // TODO: Re-enable layout transitions for addition of the unpinned task
+ reloadIfNeeded();
}
};
@@ -116,20 +159,34 @@ public abstract class RecentsView
// Only valid until the launcher state changes to NORMAL
private int mRunningTaskId = -1;
+ private Task mTmpRunningTask;
private boolean mFirstTaskIconScaledDown = false;
private boolean mOverviewStateEnabled;
private boolean mTaskStackListenerRegistered;
private Runnable mNextPageSwitchRunnable;
+ private boolean mSwipeDownShouldLaunchApp;
private PendingAnimation mPendingAnimation;
+ @ViewDebug.ExportedProperty(category = "launcher")
private float mContentAlpha = 1;
+ @ViewDebug.ExportedProperty(category = "launcher")
+ private float mAdjacentScale = 1;
// Keeps track of task views whose visual state should not be reset
private ArraySet mIgnoreResetTaskViews = new ArraySet<>();
+ // Variables for empty state
+ private final Drawable mEmptyIcon;
+ private final CharSequence mEmptyMessage;
+ private final TextPaint mEmptyMessagePaint;
+ private final Point mLastMeasureSize = new Point();
+ private final int mEmptyMessagePadding;
+ private boolean mShowEmptyMessage;
+ private Layout mEmptyTextLayout;
+
public RecentsView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
setPageSpacing(getResources().getDimensionPixelSize(R.dimen.recents_page_spacing));
@@ -143,6 +200,17 @@ public abstract class RecentsView
mModel = RecentsModel.getInstance(context);
onSharedPreferenceChanged(Utilities.getPrefs(context), PREF_FLIP_RECENTS);
+
+ mEmptyIcon = context.getDrawable(R.drawable.ic_empty_recents);
+ mEmptyIcon.setCallback(this);
+ mEmptyMessage = context.getText(R.string.recents_empty_message);
+ mEmptyMessagePaint = new TextPaint();
+ mEmptyMessagePaint.setColor(Themes.getAttrColor(context, android.R.attr.textColorPrimary));
+ mEmptyMessagePaint.setTextSize(getResources()
+ .getDimension(R.dimen.recents_empty_message_text_size));
+ mEmptyMessagePadding = getResources()
+ .getDimensionPixelSize(R.dimen.recents_empty_message_text_padding);
+ setWillNotDraw(false);
}
@Override
@@ -165,7 +233,6 @@ public abstract class RecentsView
final TaskView taskView = (TaskView) getChildAt(i);
if (taskView.getTask().key.id == taskId) {
taskView.onTaskDataLoaded(taskView.getTask(), thumbnailData);
- taskView.setAlpha(1);
return taskView;
}
}
@@ -237,16 +304,27 @@ public abstract class RecentsView
mNextPageSwitchRunnable.run();
mNextPageSwitchRunnable = null;
}
+ if (getNextPage() > 0) {
+ setSwipeDownShouldLaunchApp(true);
+ }
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent ev) {
+ super.onTouchEvent(ev);
+ // Do not let touch escape to siblings below this view.
+ return true;
}
private void applyLoadPlan(RecentsTaskLoadPlan loadPlan) {
if (mPendingAnimation != null) {
- mPendingAnimation.addEndListener((b) -> applyLoadPlan(loadPlan));
+ mPendingAnimation.addEndListener((onEndListener) -> applyLoadPlan(loadPlan));
return;
}
TaskStack stack = loadPlan != null ? loadPlan.getTaskStack() : null;
if (stack == null) {
removeAllViews();
+ onTaskStackUpdated();
return;
}
@@ -283,8 +361,11 @@ public abstract class RecentsView
if (oldChildCount != getChildCount()) {
mQuickScrubController.snapToNextTaskIfAvailable();
}
+ onTaskStackUpdated();
}
+ protected void onTaskStackUpdated() { }
+
public void resetTaskVisuals() {
for (int i = getChildCount() - 1; i >= 0; i--) {
TaskView taskView = (TaskView) getChildAt(i);
@@ -314,49 +395,20 @@ public abstract class RecentsView
}
}
- protected static Rect getPadding(DeviceProfile profile, Context context) {
- WindowManagerWrapper.getInstance().getStableInsets(sTempStableInsets);
- Rect padding = new Rect(profile.workspacePadding);
-
- float taskWidth = profile.widthPx - sTempStableInsets.left - sTempStableInsets.right;
- float taskHeight = profile.heightPx - sTempStableInsets.top - sTempStableInsets.bottom;
-
- float overviewHeight, overviewWidth;
- if (profile.isVerticalBarLayout()) {
- float maxPadding = Math.max(padding.left, padding.right);
-
- // Use the same padding on both sides for symmetry.
- float availableWidth = taskWidth - 2 * maxPadding;
- float availableHeight = profile.availableHeightPx - padding.top - padding.bottom
- - sTempStableInsets.top;
- float scaledRatio = Math.min(availableWidth / taskWidth, availableHeight / taskHeight);
- overviewHeight = taskHeight * scaledRatio;
- overviewWidth = taskWidth * scaledRatio;
-
- } else {
- overviewHeight = profile.availableHeightPx - padding.top - padding.bottom
- - sTempStableInsets.top;
- overviewWidth = taskWidth * overviewHeight / taskHeight;
- }
-
- padding.bottom = profile.availableHeightPx - padding.top - sTempStableInsets.top
- - Math.round(overviewHeight);
- padding.left = padding.right = (int) ((profile.availableWidthPx - overviewWidth) / 2);
- return padding;
- }
-
- public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) {
- Rect targetPadding = getPadding(grid, context);
- Rect insets = grid.getInsets();
- outRect.set(
- targetPadding.left + insets.left,
- targetPadding.top + insets.top,
- grid.widthPx - targetPadding.right - insets.right,
- grid.heightPx - targetPadding.bottom - insets.bottom);
- outRect.top += context.getResources()
+ @Override
+ public void setInsets(Rect insets) {
+ mInsets.set(insets);
+ DeviceProfile dp = mActivity.getDeviceProfile();
+ getTaskSize(dp, mTempRect);
+ mTempRect.top -= getResources()
.getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
+ setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top,
+ dp.widthPx - mTempRect.right - mInsets.right,
+ dp.heightPx - mTempRect.bottom - mInsets.bottom);
}
+ protected abstract void getTaskSize(DeviceProfile dp, Rect outRect);
+
@Override
protected boolean computeScrollHelper() {
boolean scrolling = super.computeScrollHelper();
@@ -419,6 +471,10 @@ public abstract class RecentsView
Task task = taskView.getTask();
boolean visible = lower <= i && i <= upper;
if (visible) {
+ if (task == mTmpRunningTask) {
+ // Skip loading if this is the task that we are animating into
+ continue;
+ }
if (!mHasVisibleTaskData.get(task.key.id)) {
loader.loadTaskData(task);
loader.getHighResThumbnailLoader().onTaskVisible(task);
@@ -477,25 +533,54 @@ public abstract class RecentsView
* Also scrolls the view to this task
*/
public void showTask(int runningTaskId) {
- boolean needsReload = false;
if (getChildCount() == 0) {
- needsReload = true;
- // Add an empty view for now
+ // Add an empty view for now until the task plan is loaded and applied
final TaskView taskView = (TaskView) LayoutInflater.from(getContext())
.inflate(R.layout.task, this, false);
- addView(taskView, 0);
+ addView(taskView);
+
+ // The temporary running task is only used for the duration between the start of the
+ // gesture and the task list is loaded and applied
+ mTmpRunningTask = new Task(new Task.TaskKey(runningTaskId, 0, new Intent(), 0, 0), null,
+ null, "", "", 0, 0, false, true, false, false,
+ new ActivityManager.TaskDescription(), 0, new ComponentName("", ""), false);
+ taskView.bind(mTmpRunningTask);
}
+ setCurrentTask(mRunningTaskId);
+
+ // Hide the task that we are animating into, ignore if there is no associated task (ie. the
+ // assistant)
+ if (getPageAt(mCurrentPage) != null) {
+ getPageAt(mCurrentPage).setAlpha(0);
+ }
+ }
+
+ /**
+ * Similar to {@link #showTask(int)} but does not put any restrictions on the first tile.
+ */
+ public void setCurrentTask(int runningTaskId) {
mRunningTaskId = runningTaskId;
setCurrentPage(0);
- if (!needsReload) {
- needsReload = !mModel.isLoadPlanValid(mLoadPlanId);
- }
- if (needsReload) {
- mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan);
+
+ // Load the tasks (if the loading is already
+ mLoadPlanId = mModel.loadTasks(runningTaskId, this::applyLoadPlan);
+ }
+
+ public void showNextTask() {
+ TaskView runningTaskView = getTaskView(mRunningTaskId);
+ if (runningTaskView == null) {
+ // Launch the first task
+ if (getChildCount() > 0) {
+ ((TaskView) getChildAt(0)).launchTask(true /* animate */);
+ }
} else {
- loadVisibleTaskData();
+ // Get the next launch task
+ int runningTaskIndex = indexOfChild(runningTaskView);
+ int nextTaskIndex = Math.max(0, Math.min(getChildCount() - 1, runningTaskIndex + 1));
+ if (nextTaskIndex < getChildCount()) {
+ ((TaskView) getChildAt(nextTaskIndex)).launchTask(true /* animate */);
+ }
}
- getPageAt(mCurrentPage).setAlpha(0);
}
public QuickScrubController getQuickScrubController() {
@@ -522,6 +607,14 @@ public abstract class RecentsView
}
}
+ public void setSwipeDownShouldLaunchApp(boolean swipeDownShouldLaunchApp) {
+ mSwipeDownShouldLaunchApp = swipeDownShouldLaunchApp;
+ }
+
+ public boolean shouldSwipeDownLaunchApp() {
+ return mSwipeDownShouldLaunchApp;
+ }
+
public interface PageCallbacks {
/**
@@ -606,10 +699,16 @@ public abstract class RecentsView
}
mPendingAnimation = pendingAnimation;
- mPendingAnimation.addEndListener((isSuccess) -> {
- if (isSuccess) {
+ mPendingAnimation.addEndListener((onEndListener) -> {
+ if (onEndListener.isSuccess) {
if (removeTask) {
- ActivityManagerWrapper.getInstance().removeTask(taskView.getTask().key.id);
+ Task task = taskView.getTask();
+ if (task != null) {
+ ActivityManagerWrapper.getInstance().removeTask(task.key.id);
+ mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
+ onEndListener.logAction, Direction.UP,
+ TaskUtils.getComponentKeyForTask(task.key));
+ }
}
removeView(taskView);
if (getChildCount() == 0) {
@@ -629,6 +728,9 @@ public abstract class RecentsView
}
private void snapToPageRelative(int delta) {
+ if (getPageCount() == 0) {
+ return;
+ }
snapToPage((getNextPage() + getPageCount() + delta) % getPageCount());
}
@@ -648,7 +750,7 @@ public abstract class RecentsView
AnimatorPlaybackController controller = AnimatorPlaybackController.wrap(
pendingAnim.anim, DISMISS_TASK_DURATION);
controller.dispatchOnStart();
- controller.setEndAction(() -> pendingAnim.finish(true));
+ controller.setEndAction(() -> pendingAnim.finish(true, Touch.SWIPE));
controller.getAnimationPlayer().setInterpolator(FAST_OUT_SLOW_IN);
controller.start();
}
@@ -687,25 +789,247 @@ public abstract class RecentsView
snapToPageRelative(1);
}
- public void launchNextTask() {
- final TaskView nextTask = (TaskView) getChildAt(getNextPage());
- nextTask.launchTask(true);
- }
-
public void setContentAlpha(float alpha) {
if (mContentAlpha == alpha) {
return;
}
+
mContentAlpha = alpha;
for (int i = getChildCount() - 1; i >= 0; i--) {
getChildAt(i).setAlpha(alpha);
}
+
+ int alphaInt = Math.round(alpha * 255);
+ mEmptyMessagePaint.setAlpha(alphaInt);
+ mEmptyIcon.setAlpha(alphaInt);
+
setVisibility(alpha > 0 ? VISIBLE : GONE);
}
+ public void setAdjacentScale(float adjacentScale) {
+ if (mAdjacentScale == adjacentScale) {
+ return;
+ }
+ mAdjacentScale = adjacentScale;
+ TaskView currTask = getPageAt(mCurrentPage);
+ if (currTask == null) {
+ return;
+ }
+ currTask.setScaleX(mAdjacentScale);
+ currTask.setScaleY(mAdjacentScale);
+
+ if (mCurrentPage - 1 >= 0) {
+ TaskView adjacentTask = getPageAt(mCurrentPage - 1);
+ float[] scaleAndTranslation = getAdjacentScaleAndTranslation(currTask, adjacentTask,
+ mAdjacentScale, 0);
+ adjacentTask.setScaleX(scaleAndTranslation[0]);
+ adjacentTask.setScaleY(scaleAndTranslation[0]);
+ adjacentTask.setTranslationX(-scaleAndTranslation[1]);
+ adjacentTask.setTranslationY(scaleAndTranslation[2]);
+ }
+ if (mCurrentPage + 1 < getChildCount()) {
+ TaskView adjacentTask = getPageAt(mCurrentPage + 1);
+ float[] scaleAndTranslation = getAdjacentScaleAndTranslation(currTask, adjacentTask,
+ mAdjacentScale, 0);
+ adjacentTask.setScaleX(scaleAndTranslation[0]);
+ adjacentTask.setScaleY(scaleAndTranslation[0]);
+ adjacentTask.setTranslationX(scaleAndTranslation[1]);
+ adjacentTask.setTranslationY(scaleAndTranslation[2]);
+ }
+ }
+
+ private float[] getAdjacentScaleAndTranslation(TaskView currTask, TaskView adjacentTask,
+ float currTaskToScale, float currTaskToTranslationY) {
+ float displacement = currTask.getWidth() * (currTaskToScale - currTask.getCurveScale());
+ return new float[] {
+ currTaskToScale * adjacentTask.getCurveScale(),
+ mIsRtl ? -displacement : displacement,
+ currTaskToTranslationY
+ };
+ }
+
@Override
public void onViewAdded(View child) {
super.onViewAdded(child);
child.setAlpha(mContentAlpha);
+ setAdjacentScale(mAdjacentScale);
+ }
+
+ @Override
+ public TaskView getPageAt(int index) {
+ return (TaskView) getChildAt(index);
+ }
+
+ public void updateEmptyMessage() {
+ boolean isEmpty = getChildCount() == 0;
+ boolean hasSizeChanged = mLastMeasureSize.x != getWidth()
+ || mLastMeasureSize.y != getHeight();
+ if (isEmpty == mShowEmptyMessage && !hasSizeChanged) {
+ return;
+ }
+ setContentDescription(isEmpty ? mEmptyMessage : "");
+ mShowEmptyMessage = isEmpty;
+ updateEmptyStateUi(hasSizeChanged);
+ invalidate();
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ updateEmptyStateUi(changed);
+ }
+
+ private void updateEmptyStateUi(boolean sizeChanged) {
+ boolean hasValidSize = getWidth() > 0 && getHeight() > 0;
+ if (sizeChanged && hasValidSize) {
+ mEmptyTextLayout = null;
+ }
+
+ if (mShowEmptyMessage && hasValidSize && mEmptyTextLayout == null) {
+ mLastMeasureSize.set(getWidth(), getHeight());
+ int availableWidth = mLastMeasureSize.x - mEmptyMessagePadding - mEmptyMessagePadding;
+ mEmptyTextLayout = StaticLayout.Builder.obtain(mEmptyMessage, 0, mEmptyMessage.length(),
+ mEmptyMessagePaint, availableWidth)
+ .setAlignment(Layout.Alignment.ALIGN_CENTER)
+ .build();
+ int totalHeight = mEmptyTextLayout.getHeight()
+ + mEmptyMessagePadding + mEmptyIcon.getIntrinsicHeight();
+
+ int top = (mLastMeasureSize.y - totalHeight) / 2;
+ int left = (mLastMeasureSize.x - mEmptyIcon.getIntrinsicWidth()) / 2;
+ mEmptyIcon.setBounds(left, top, left + mEmptyIcon.getIntrinsicWidth(),
+ top + mEmptyIcon.getIntrinsicHeight());
+ }
+ }
+
+ @Override
+ protected boolean verifyDrawable(Drawable who) {
+ return super.verifyDrawable(who) || (mShowEmptyMessage && who == mEmptyIcon);
+ }
+
+ protected void maybeDrawEmptyMessage(Canvas canvas) {
+ if (mShowEmptyMessage && mEmptyTextLayout != null) {
+ mEmptyIcon.draw(canvas);
+ canvas.save();
+ canvas.translate(mEmptyMessagePadding,
+ mEmptyIcon.getBounds().bottom + mEmptyMessagePadding);
+ mEmptyTextLayout.draw(canvas);
+ canvas.restore();
+ }
+ }
+
+ /**
+ * Animate adjacent tasks off screen while scaling up.
+ *
+ * If launching one of the adjacent tasks, parallax the center task and other adjacent task
+ * to the right.
+ */
+ public AnimatorSet createAdjacentPageAnimForTaskLaunch(TaskView tv) {
+ AnimatorSet anim = new AnimatorSet();
+
+ int taskIndex = indexOfChild(tv);
+ int centerTaskIndex = getCurrentPage();
+ boolean launchingCenterTask = taskIndex == centerTaskIndex;
+
+ TaskWindowBounds endInterpolation = tv.getRecentsInterpolator().interpolate(1);
+ float toScale = endInterpolation.taskScale;
+ float toTranslationY = endInterpolation.taskY;
+
+ if (launchingCenterTask) {
+ TaskView centerTask = getPageAt(centerTaskIndex);
+ if (taskIndex - 1 >= 0) {
+ TaskView adjacentTask = getPageAt(taskIndex - 1);
+ float[] scaleAndTranslation = getAdjacentScaleAndTranslation(centerTask,
+ adjacentTask, toScale, toTranslationY);
+ scaleAndTranslation[1] = -scaleAndTranslation[1];
+ anim.play(createAnimForChild(adjacentTask, scaleAndTranslation));
+ }
+ if (taskIndex + 1 < getPageCount()) {
+ TaskView adjacentTask = getPageAt(taskIndex + 1);
+ float[] scaleAndTranslation = getAdjacentScaleAndTranslation(centerTask,
+ adjacentTask, toScale, toTranslationY);
+ anim.play(createAnimForChild(adjacentTask, scaleAndTranslation));
+ }
+ } else {
+ // We are launching an adjacent task, so parallax the center and other adjacent task.
+ float displacementX = tv.getWidth() * (toScale - tv.getCurveScale());
+ anim.play(ObjectAnimator.ofFloat(getPageAt(centerTaskIndex), TRANSLATION_X,
+ mIsRtl ? -displacementX : displacementX));
+
+ int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - taskIndex);
+ if (otherAdjacentTaskIndex >= 0 && otherAdjacentTaskIndex < getPageCount()) {
+ anim.play(ObjectAnimator.ofPropertyValuesHolder(getPageAt(otherAdjacentTaskIndex),
+ new PropertyListBuilder()
+ .translationX(mIsRtl ? -displacementX : displacementX)
+ .scale(1)
+ .build()));
+ }
+ }
+ return anim;
+ }
+
+ private ObjectAnimator createAnimForChild(View child, float[] toScaleAndTranslation) {
+ return ObjectAnimator.ofPropertyValuesHolder(child,
+ new PropertyListBuilder()
+ .scale(child.getScaleX() * toScaleAndTranslation[0])
+ .translationX(toScaleAndTranslation[1])
+ .translationY(toScaleAndTranslation[2])
+ .build());
+ }
+
+ public PendingAnimation createTaskLauncherAnimation(TaskView tv, long duration) {
+ if (FeatureFlags.IS_DOGFOOD_BUILD && mPendingAnimation != null) {
+ throw new IllegalStateException("Another pending animation is still running");
+ }
+ AnimatorSet anim = createAdjacentPageAnimForTaskLaunch(tv);
+
+ int count = getChildCount();
+ if (count == 0) {
+ return new PendingAnimation(anim);
+ }
+
+ final RecentsAnimationInterpolator recentsInterpolator = tv.getRecentsInterpolator();
+ ValueAnimator targetViewAnim = ValueAnimator.ofFloat(0, 1);
+ targetViewAnim.addUpdateListener((animation) -> {
+ float percent = animation.getAnimatedFraction();
+ TaskWindowBounds tw = recentsInterpolator.interpolate(percent);
+ tv.setScaleX(tw.taskScale);
+ tv.setScaleY(tw.taskScale);
+ tv.setTranslationX(tw.taskX);
+ tv.setTranslationY(tw.taskY);
+ });
+ anim.play(targetViewAnim);
+ anim.setDuration(duration);
+
+ mPendingAnimation = new PendingAnimation(anim);
+ mPendingAnimation.addEndListener((onEndListener) -> {
+ if (onEndListener.isSuccess) {
+ tv.launchTask(false);
+ Task task = tv.getTask();
+ if (task != null) {
+ mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss(
+ onEndListener.logAction, Direction.DOWN,
+ TaskUtils.getComponentKeyForTask(task.key));
+ }
+ } else {
+ resetTaskVisuals();
+ }
+ mPendingAnimation = null;
+ });
+ return mPendingAnimation;
+ }
+
+ @Override
+ protected void notifyPageSwitchListener(int prevPage) {
+ super.notifyPageSwitchListener(prevPage);
+ View currChild = getChildAt(mCurrentPage);
+ if (currChild != null) {
+ currChild.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
+ }
+ }
+
+ @Override
+ protected String getCurrentPageDescription() {
+ return "";
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 30cbcdf674..dd90c8867d 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -51,7 +51,7 @@ public class TaskMenuView extends AbstractFloatingView {
private static final Rect sTempRect = new Rect();
/** Note that these will be shown in order from top to bottom, if available for the task. */
- private static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[] {
+ public static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[] {
new TaskSystemShortcut.AppInfo(),
new TaskSystemShortcut.SplitScreen(),
new TaskSystemShortcut.Pin(),
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
index 87bb53bb61..58b7db7b22 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java
@@ -22,12 +22,9 @@ import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Color;
-import android.graphics.ComposeShader;
import android.graphics.LightingColorFilter;
-import android.graphics.LinearGradient;
import android.graphics.Matrix;
import android.graphics.Paint;
-import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.graphics.Shader;
import android.util.AttributeSet;
@@ -36,6 +33,7 @@ import android.view.View;
import com.android.launcher3.BaseActivity;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
+import com.android.launcher3.config.FeatureFlags;
import com.android.quickstep.TaskOverlayFactory;
import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
import com.android.systemui.shared.recents.model.Task;
@@ -49,13 +47,16 @@ public class TaskThumbnailView extends View {
private static final LightingColorFilter[] sDimFilterCache = new LightingColorFilter[256];
private final float mCornerRadius;
- private final float mFadeLength;
+ private final BaseActivity mActivity;
private final TaskOverlay mOverlay;
private final Paint mPaint = new Paint();
+ private final Paint mBackgroundPaint = new Paint();
private final Matrix mMatrix = new Matrix();
+ private float mClipBottom = -1;
+
private Task mTask;
private ThumbnailData mThumbnailData;
protected BitmapShader mBitmapShader;
@@ -73,9 +74,10 @@ public class TaskThumbnailView extends View {
public TaskThumbnailView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius);
- mFadeLength = getResources().getDimension(R.dimen.task_fade_length);
mOverlay = TaskOverlayFactory.get(context).createOverlay(this);
mPaint.setFilterBitmap(true);
+ mBackgroundPaint.setColor(Color.WHITE);
+ mActivity = BaseActivity.fromContext(context);
}
public void bind() {
@@ -87,7 +89,9 @@ public class TaskThumbnailView extends View {
*/
public void setThumbnail(Task task, ThumbnailData thumbnailData) {
mTask = task;
- mPaint.setColor(task == null ? Color.BLACK : task.colorBackground | 0xFF000000);
+ int color = task == null ? Color.BLACK : task.colorBackground | 0xFF000000;
+ mPaint.setColor(color);
+ mBackgroundPaint.setColor(color);
if (thumbnailData != null && thumbnailData.thumbnail != null) {
Bitmap bm = thumbnailData.thumbnail;
@@ -122,14 +126,34 @@ public class TaskThumbnailView extends View {
@Override
protected void onDraw(Canvas canvas) {
- canvas.drawRoundRect(0, 0, getMeasuredWidth(), getMeasuredHeight(),
- mCornerRadius, mCornerRadius, mPaint);
+ if (mTask == null) {
+ return;
+ }
+ int width = getMeasuredWidth();
+ int height = getMeasuredHeight();
+ if (mClipBottom > 0 && !mTask.isLocked) {
+ canvas.save();
+ canvas.clipRect(0, 0, width, mClipBottom);
+
+ canvas.drawRoundRect(0, 0, width, height, mCornerRadius, mCornerRadius, mPaint);
+ canvas.restore();
+ canvas.save();
+ canvas.clipRect(0, mClipBottom, width, height);
+ canvas.drawRoundRect(0, 0, width, height, mCornerRadius, mCornerRadius,
+ mBackgroundPaint);
+ canvas.restore();
+ } else {
+ canvas.drawRoundRect(0, 0, width, height, mCornerRadius,
+ mCornerRadius, mTask.isLocked ? mBackgroundPaint : mPaint);
+ }
}
private void updateThumbnailPaintFilter() {
int mul = (int) (mDimAlpha * 255);
if (mBitmapShader != null) {
- mPaint.setColorFilter(getLightingColorFilter(mul));
+ LightingColorFilter filter = getLightingColorFilter(mul);
+ mPaint.setColorFilter(filter);
+ mBackgroundPaint.setColorFilter(filter);
} else {
mPaint.setColorFilter(null);
mPaint.setColor(Color.argb(255, mul, mul, mul));
@@ -138,13 +162,18 @@ public class TaskThumbnailView extends View {
}
private void updateThumbnailMatrix() {
+ boolean rotate = false;
+ mClipBottom = -1;
if (mBitmapShader != null && mThumbnailData != null) {
float scale = mThumbnailData.scale;
+ Rect thumbnailInsets = mThumbnailData.insets;
float thumbnailWidth = mThumbnailData.thumbnail.getWidth() -
- (mThumbnailData.insets.left + mThumbnailData.insets.right) * scale;
+ (thumbnailInsets.left + thumbnailInsets.right) * scale;
float thumbnailHeight = mThumbnailData.thumbnail.getHeight() -
- (mThumbnailData.insets.top + mThumbnailData.insets.bottom) * scale;
+ (thumbnailInsets.top + thumbnailInsets.bottom) * scale;
+
final float thumbnailScale;
+ final DeviceProfile profile = mActivity.getDeviceProfile();
if (getMeasuredWidth() == 0) {
// If we haven't measured , skip the thumbnail drawing and only draw the background
@@ -152,49 +181,54 @@ public class TaskThumbnailView extends View {
thumbnailScale = 0f;
} else {
final Configuration configuration =
- getContext().getApplicationContext().getResources().getConfiguration();
- final DeviceProfile profile = BaseActivity.fromContext(getContext())
- .getDeviceProfile();
- if (configuration.orientation == mThumbnailData.orientation) {
- // If we are in the same orientation as the screenshot, just scale it to the
- // width of the task view
- thumbnailScale = getMeasuredWidth() / thumbnailWidth;
- } else if (configuration.orientation == Configuration.ORIENTATION_PORTRAIT) {
- // Scale the landscape thumbnail up to app size, then scale that to the task
- // view size to match other portrait screenshots
- thumbnailScale = ((float) getMeasuredWidth() / profile.widthPx);
- } else {
- // Otherwise, scale the screenshot to fit 1:1 in the current orientation
- thumbnailScale = 1;
- }
+ getContext().getResources().getConfiguration();
+ // Rotate the screenshot if not in multi-window mode
+ rotate = FeatureFlags.OVERVIEW_USE_SCREENSHOT_ORIENTATION &&
+ configuration.orientation != mThumbnailData.orientation &&
+ !mActivity.isInMultiWindowModeCompat();
+ // Scale the screenshot to always fit the width of the card.
+ thumbnailScale = rotate
+ ? getMeasuredWidth() / thumbnailHeight
+ : getMeasuredWidth() / thumbnailWidth;
+ }
+
+ if (rotate) {
+ int rotationDir = profile.isVerticalBarLayout() && !profile.isSeascape() ? -1 : 1;
+ mMatrix.setRotate(90 * rotationDir);
+ int newLeftInset = rotationDir == 1 ? thumbnailInsets.bottom : thumbnailInsets.top;
+ int newTopInset = rotationDir == 1 ? thumbnailInsets.left : thumbnailInsets.right;
+ mMatrix.postTranslate(-newLeftInset * scale, -newTopInset * scale);
+ if (rotationDir == -1) {
+ // Crop the right/bottom side of the screenshot rather than left/top
+ float excessHeight = thumbnailWidth * thumbnailScale - getMeasuredHeight();
+ mMatrix.postTranslate(0, -excessHeight);
+ }
+ // Move the screenshot to the thumbnail window (rotation moved it out).
+ if (rotationDir == 1) {
+ mMatrix.postTranslate(mThumbnailData.thumbnail.getHeight(), 0);
+ } else {
+ mMatrix.postTranslate(0, mThumbnailData.thumbnail.getWidth());
+ }
+ } else {
+ mMatrix.setTranslate(-mThumbnailData.insets.left * scale,
+ -mThumbnailData.insets.top * scale);
}
- mMatrix.setTranslate(-mThumbnailData.insets.left * scale,
- -mThumbnailData.insets.top * scale);
mMatrix.postScale(thumbnailScale, thumbnailScale);
mBitmapShader.setLocalMatrix(mMatrix);
float bitmapHeight = Math.max(thumbnailHeight * thumbnailScale, 0);
- Shader shader = mBitmapShader;
- if (bitmapHeight < getMeasuredHeight()) {
- int color = mPaint.getColor();
- LinearGradient fade = new LinearGradient(
- 0, bitmapHeight - mFadeLength, 0, bitmapHeight,
- color & 0x00FFFFFF, color, Shader.TileMode.CLAMP);
- shader = new ComposeShader(fade, shader, Mode.DST_OVER);
+ if (Math.round(bitmapHeight) < getMeasuredHeight()) {
+ mClipBottom = bitmapHeight;
}
-
- float bitmapWidth = Math.max(thumbnailWidth * thumbnailScale, 0);
- if (bitmapWidth < getMeasuredWidth()) {
- int color = mPaint.getColor();
- LinearGradient fade = new LinearGradient(
- bitmapWidth - mFadeLength, 0, bitmapWidth, 0,
- color & 0x00FFFFFF, color, Shader.TileMode.CLAMP);
- shader = new ComposeShader(fade, shader, Mode.DST_OVER);
- }
- mPaint.setShader(shader);
+ mPaint.setShader(mBitmapShader);
}
- mOverlay.setTaskInfo(mTask, mThumbnailData, mMatrix);
+ if (rotate) {
+ // The overlay doesn't really work when the screenshot is rotated, so don't add it.
+ mOverlay.reset();
+ } else {
+ mOverlay.setTaskInfo(mTask, mThumbnailData, mMatrix);
+ }
invalidate();
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 9884a4858f..f04acaf12e 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -21,15 +21,25 @@ import android.app.ActivityOptions;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Outline;
+import android.graphics.Rect;
+import android.os.Bundle;
import android.os.Handler;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewOutlineProvider;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.ImageView;
+import com.android.launcher3.BaseActivity;
import com.android.launcher3.BaseDraggingActivity;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.quickstep.RecentsAnimationInterpolator;
+import com.android.quickstep.TaskSystemShortcut;
+import com.android.quickstep.TaskUtils;
import com.android.quickstep.views.RecentsView.PageCallbacks;
import com.android.quickstep.views.RecentsView.ScrollState;
import com.android.systemui.shared.recents.model.Task;
@@ -64,6 +74,7 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
private Task mTask;
private TaskThumbnailView mSnapshotView;
private ImageView mIconView;
+ private float mCurveScale;
public TaskView(Context context) {
this(context, null);
@@ -75,7 +86,13 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
public TaskView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- setOnClickListener((view) -> launchTask(true /* animate */));
+ setOnClickListener((view) -> {
+ if (mTask != null) {
+ launchTask(true /* animate */);
+ BaseActivity.fromContext(context).getUserEventDispatcher().logTaskLaunchOrDismiss(
+ Touch.TAP, Direction.NONE, TaskUtils.getComponentKeyForTask(mTask.key));
+ }
+ });
setOutlineProvider(new TaskOutlineProvider(getResources()));
}
@@ -131,7 +148,10 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
mSnapshotView.setThumbnail(task, thumbnailData);
mIconView.setImageDrawable(task.icon);
mIconView.setOnClickListener(icon -> TaskMenuView.showForTask(this));
- mIconView.setOnLongClickListener(icon -> TaskMenuView.showForTask(this));
+ mIconView.setOnLongClickListener(icon -> {
+ requestDisallowInterceptTouchEvent(true);
+ return TaskMenuView.showForTask(this);
+ });
}
@Override
@@ -172,9 +192,13 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
mSnapshotView.setDimAlpha(1 - curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
- float scale = 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR;
- setScaleX(scale);
- setScaleY(scale);
+ mCurveScale = 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR;
+ setScaleX(mCurveScale);
+ setScaleY(mCurveScale);
+ }
+
+ public float getCurveScale() {
+ return mCurveScale;
}
@Override
@@ -183,6 +207,23 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
return false;
}
+ public RecentsAnimationInterpolator getRecentsInterpolator() {
+ Rect taskViewBounds = new Rect();
+ BaseDraggingActivity activity = BaseDraggingActivity.fromContext(getContext());
+ DeviceProfile dp = activity.getDeviceProfile();
+ activity.getDragLayer().getDescendantRectRelativeToSelf(this, taskViewBounds);
+
+ // TODO: Use the actual target insets instead of the current thumbnail insets in case the
+ // device state has changed
+ return new RecentsAnimationInterpolator(
+ new Rect(0, 0, dp.widthPx, dp.heightPx),
+ getThumbnail().getInsets(),
+ taskViewBounds,
+ new Rect(0, getThumbnail().getTop(), 0, 0),
+ getScaleX(),
+ getTranslationX());
+ }
+
private static final class TaskOutlineProvider extends ViewOutlineProvider {
private final int mMarginTop;
@@ -199,4 +240,45 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback
view.getHeight(), mRadius);
}
}
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+
+ info.addAction(
+ new AccessibilityNodeInfo.AccessibilityAction(R.string.accessibility_close_task,
+ getContext().getText(R.string.accessibility_close_task)));
+
+ final Context context = getContext();
+ final BaseDraggingActivity activity = BaseDraggingActivity.fromContext(context);
+ for (TaskSystemShortcut menuOption : TaskMenuView.MENU_OPTIONS) {
+ OnClickListener onClickListener = menuOption.getOnClickListener(activity, this);
+ if (onClickListener != null) {
+ info.addAction(new AccessibilityNodeInfo.AccessibilityAction(menuOption.labelResId,
+ context.getText(menuOption.labelResId)));
+ }
+ }
+ }
+
+ @Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ if (action == R.string.accessibility_close_task) {
+ ((RecentsView) getParent()).dismissTask(this, true /*animateTaskView*/,
+ true /*removeTask*/);
+ return true;
+ }
+
+ for (TaskSystemShortcut menuOption : TaskMenuView.MENU_OPTIONS) {
+ if (action == menuOption.labelResId) {
+ OnClickListener onClickListener = menuOption.getOnClickListener(
+ BaseDraggingActivity.fromContext(getContext()), this);
+ if (onClickListener != null) {
+ onClickListener.onClick(this);
+ }
+ return true;
+ }
+ }
+
+ return super.performAccessibilityAction(action, arguments);
+ }
}
diff --git a/res/drawable/ic_close.xml b/res/drawable/ic_close.xml
index fc9ed49e94..8b2f55fb32 100644
--- a/res/drawable/ic_close.xml
+++ b/res/drawable/ic_close.xml
@@ -19,5 +19,5 @@
android:viewportWidth="24.0">
+ android:pathData="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41z" />
\ No newline at end of file
diff --git a/res/drawable/ic_setting.xml b/res/drawable/ic_setting.xml
index 33cd6ce34a..a83aab3204 100644
--- a/res/drawable/ic_setting.xml
+++ b/res/drawable/ic_setting.xml
@@ -16,16 +16,28 @@ Copyright (C) 2016 The Android Open Source Project
+ android:pathData="M13.85,22.25h-3.7c-0.74,0-1.36-0.54-1.45-1.27l-0.27-1.89c-0.27-0.14-0.53-0.29-0.79-0.46l-1.8,0.72
+ c-0.7,0.26-1.47-0.03-1.81-0.65L2.2,15.53c-0.35-0.66-0.2-1.44,0.36-1.88l1.53-1.19c-0.01-0.15-0.02-0.3-0.02-0.46
+ c0-0.15,0.01-0.31,0.02-0.46l-1.52-1.19C1.98,9.9,1.83,9.09,2.2,8.47l1.85-3.19c0.34-0.62,1.11-0.9,1.79-0.63l1.81,0.73
+ c0.26-0.17,0.52-0.32,0.78-0.46l0.27-1.91c0.09-0.7,0.71-1.25,1.44-1.25h3.7c0.74,0,1.36,0.54,1.45,1.27l0.27,1.89
+ c0.27,0.14,0.53,0.29,0.79,0.46l1.8-0.72c0.71-0.26,1.48,0.03,1.82,0.65l1.84,3.18c0.36,0.66,0.2,1.44-0.36,1.88l-1.52,1.19
+ c0.01,0.15,0.02,0.3,0.02,0.46s-0.01,0.31-0.02,0.46l1.52,1.19c0.56,0.45,0.72,1.23,0.37,1.86l-1.86,3.22
+ c-0.34,0.62-1.11,0.9-1.8,0.63l-1.8-0.72c-0.26,0.17-0.52,0.32-0.78,0.46l-0.27,1.91C15.21,21.71,14.59,22.25,13.85,22.25z
+ M13.32,20.72c0,0.01,0,0.01,0,0.02L13.32,20.72z M10.68,20.7l0,0.02C10.69,20.72,10.69,20.71,10.68,20.7z M10.62,20.25h2.76
+ l0.37-2.55l0.53-0.22c0.44-0.18,0.88-0.44,1.34-0.78l0.45-0.34l2.38,0.96l1.38-2.4l-2.03-1.58l0.07-0.56
+ c0.03-0.26,0.06-0.51,0.06-0.78c0-0.27-0.03-0.53-0.06-0.78l-0.07-0.56l2.03-1.58l-1.39-2.4l-2.39,0.96l-0.45-0.35
+ c-0.42-0.32-0.87-0.58-1.33-0.77L13.75,6.3l-0.37-2.55h-2.76L10.25,6.3L9.72,6.51C9.28,6.7,8.84,6.95,8.38,7.3L7.93,7.63
+ L5.55,6.68L4.16,9.07l2.03,1.58l-0.07,0.56C6.09,11.47,6.06,11.74,6.06,12c0,0.26,0.02,0.53,0.06,0.78l0.07,0.56l-2.03,1.58
+ l1.38,2.4l2.39-0.96l0.45,0.35c0.43,0.33,0.86,0.58,1.33,0.77l0.53,0.22L10.62,20.25z M18.22,17.72c0,0.01-0.01,0.02-0.01,0.03
+ L18.22,17.72z M5.77,17.71l0.01,0.02C5.78,17.72,5.77,17.71,5.77,17.71z M3.93,9.47L3.93,9.47C3.93,9.47,3.93,9.47,3.93,9.47z
+ M18.22,6.27c0,0.01,0.01,0.02,0.01,0.02L18.22,6.27z M5.79,6.25L5.78,6.27C5.78,6.27,5.79,6.26,5.79,6.25z M13.31,3.28
+ c0,0.01,0,0.01,0,0.02L13.31,3.28z M10.69,3.26l0,0.02C10.69,3.27,10.69,3.27,10.69,3.26z"/>
+
diff --git a/res/drawable/ic_uninstall_no_shadow.xml b/res/drawable/ic_uninstall_no_shadow.xml
index 2a86e1042d..37632d1a4b 100644
--- a/res/drawable/ic_uninstall_no_shadow.xml
+++ b/res/drawable/ic_uninstall_no_shadow.xml
@@ -21,6 +21,11 @@
android:tint="?android:attr/textColorPrimary" >
+ android:pathData="M15,4V3H9v1H4v2h1v13c0,1.1,0.9,2,2,2h10c1.1,0,2-0.9,2-2V6h1V4H15z M17,19H7V6h10V19z" />
+
+
diff --git a/res/drawable/ic_wallpaper.xml b/res/drawable/ic_wallpaper.xml
index 0c5a125b60..7fd93403c5 100644
--- a/res/drawable/ic_wallpaper.xml
+++ b/res/drawable/ic_wallpaper.xml
@@ -16,14 +16,11 @@ Copyright (C) 2016 The Android Open Source Project
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ android:pathData="M9,12.71l2.14,2.58l3-3.87L18,16.57H6L9,12.71z M5,5h6V3H5C3.9,3,3,3.9,3,5v6h2V5z M19,19h-6v2h6c1.1,0,2-0.9,2-2v-6h-2V19z
+ M5,19v-6H3v6c0,1.1,0.9,2,2,2h6v-2H5z M19,5v6h2V5c0-1.1-0.9-2-2-2h-6v2H19z M16,9c0.55,0,1-0.45,1-1s-0.45-1-1-1
+ c-0.55,0-1,0.45-1,1S15.45,9,16,9z"/>
diff --git a/res/drawable/ic_widget.xml b/res/drawable/ic_widget.xml
index 4bb23b3f4b..3ebbb68bb9 100644
--- a/res/drawable/ic_widget.xml
+++ b/res/drawable/ic_widget.xml
@@ -16,11 +16,10 @@ Copyright (C) 2016 The Android Open Source Project
+ android:viewportWidth="24.0"
+ android:viewportHeight="24.0">
+ android:pathData="M16.66,4.52l2.83,2.83l-2.83,2.83l-2.83-2.83L16.66,4.52 M9,5v4H5V5H9 M19,15v4h-4v-4H19 M9,15v4H5v-4H9 M16.66,1.69
+ L11,7.34L16.66,13l5.66-5.66L16.66,1.69L16.66,1.69z M11,3H3v8h8V7.34V3L11,3z M21,13h-4.34H13v8h8V13L21,13z M11,13H3v8h8V13L11,13z"/>
diff --git a/res/layout/all_apps_fast_scroller.xml b/res/layout/all_apps_fast_scroller.xml
index d858d3e21a..5537bc60a5 100644
--- a/res/layout/all_apps_fast_scroller.xml
+++ b/res/layout/all_apps_fast_scroller.xml
@@ -21,8 +21,8 @@
android:id="@+id/fast_scroller_popup"
style="@style/FastScrollerPopup"
android:layout_alignParentEnd="true"
- android:layout_marginEnd="@dimen/fastscroll_popup_margin"
- android:layout_marginTop="@dimen/all_apps_search_bar_field_height_and_margin" />
+ android:layout_below="@+id/search_container_all_apps"
+ android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
\ No newline at end of file
diff --git a/res/layout/all_apps_floating_header.xml b/res/layout/all_apps_floating_header.xml
index f88c600423..c4240f80db 100644
--- a/res/layout/all_apps_floating_header.xml
+++ b/res/layout/all_apps_floating_header.xml
@@ -18,10 +18,10 @@
android:id="@+id/all_apps_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginTop="@dimen/all_apps_search_bar_field_height_and_margin"
+ android:layout_below="@id/search_container_all_apps"
android:clipToPadding="false"
- android:orientation="vertical"
- android:paddingTop="@dimen/all_apps_header_top_padding" >
+ android:paddingTop="@dimen/all_apps_header_top_padding"
+ android:orientation="vertical" >
diff --git a/res/layout/all_apps_tabs.xml b/res/layout/all_apps_tabs.xml
index fea2eeae30..2accd2d21f 100644
--- a/res/layout/all_apps_tabs.xml
+++ b/res/layout/all_apps_tabs.xml
@@ -20,8 +20,9 @@
android:id="@+id/all_apps_tabs_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
+ android:layout_below="@id/search_container_all_apps"
android:layout_gravity="center_horizontal|top"
- android:layout_marginTop="@dimen/all_apps_tabs_top_margin"
+ android:layout_marginTop="@dimen/all_apps_header_tab_height"
android:clipChildren="true"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
diff --git a/res/layout/drag_handle_indicator.xml b/res/layout/drag_handle_indicator.xml
new file mode 100644
index 0000000000..d5a7b8a038
--- /dev/null
+++ b/res/layout/drag_handle_indicator.xml
@@ -0,0 +1,23 @@
+
+
+
diff --git a/res/layout/hotseat.xml b/res/layout/hotseat.xml
index 01cd92a63d..00f0b5ff8a 100644
--- a/res/layout/hotseat.xml
+++ b/res/layout/hotseat.xml
@@ -18,15 +18,6 @@
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto">
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
+ android:orientation="vertical" />
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index d24b63cea4..02dd1c98a4 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -40,10 +40,8 @@
"Kon geen programme kry wat by \"%1$s\" pas nie"
"Soek meer programme"
"Kennisgewings"
-
-
-
-
+ "Raak en hou om \'n kortpad op te tel."
+ "Dubbeltik en hou om \'n kortpad op te tel of gebruik gepasmaakte handelinge."
"Niks meer spasie op die tuisskerm nie."
"Geen plek meer in die Gunstelinge-laai nie"
"Programmelys"
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 07fe5ef7b1..21b01ddb09 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -40,9 +40,13 @@
"ከ«%1$s» ጋር የሚዛመዱ ምንም መተግበሪያዎች አልተገኙም"
"ተጨማሪ መተግበሪያዎች ይፈልጉ"
"ማሳወቂያዎች"
+ "አንድ አቋራጭ ለመውሰድ ነክተው ይያዙ።"
+ "አንድ አቋራጭ ለመውሰድ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ አድርገው ይያዙ።"
"በዚህ መነሻ ማያ ገጽ ላይ ምንም ቦታ የለም።"
"በተወዳጆች መሣቢያ ውስጥ ተጨማሪ ቦታ የለም"
"የመተግበሪያዎች ዝርዝር"
+ "የግል መተግበሪያዎች ዝርዝር"
+ "የሥራ መተግበሪያዎች ዝርዝር"
"መነሻ"
"አስወግድ"
"አራግፍ"
@@ -77,19 +81,17 @@
"የግድግዳ ወረቀቶች"
"የመነሻ ቅንብሮች"
"በእርስዎ አስተዳዳሪ የተሰናከለ"
- "አጠቃላይ ዕይታ"
- "የመነሻ ማያ ገጽ ማሽከርከርን ይፍቀዱ"
- "ስልኩ ሲዞር"
- "የአሁኑ የማሳያ ቅንብር ማሽከርከርን አይፈቅድም"
"የማሳወቂያ ነጥቦች"
"በርቷል"
"ጠፍቷል"
"የማሳወቂያ መዳረሻ ያስፈልጋል"
"የማሳወቂያ ነጥቦችን ለማሳየት የመተግብሪያ ማሳወቂያዎችን ለ%1$s ያብሩ"
"ቅንብሮችን ቀይር"
+ "የማሳወቂያ ነጥቦችን አሳይ"
"አዶ ወደ የመነሻ ማያ ገጽ አክል"
"ለአዲስ መተግበሪያዎች"
"የአዶ ቅርፅ ለውጥ"
+ "በመነሻ ማያ ገጽ ላይ"
"የሥርዓቱን ነባሪ ተጠቀም"
"ካሬ"
"Squircle"
@@ -119,9 +121,6 @@
"አቃፊ ፍጠር ከዚህ ጋር፦ %1$s"
"አቃፊ ተፈጥሮዋል"
"ወደ መነሻ ማያ ገጽ አንቀሳቅስ"
- "ማያ ገጽን ወደ ግራ አንቀሳቅስ"
- "ማያ ገጽን ወደ ቀኝ አንቀሳቅስ"
- "ማያ ገጽ ተንቀሳቅሷል"
"መጠን ቀይር"
"ስፋት ጨምር"
"ቁመት ጨምር"
@@ -137,8 +136,9 @@
"ሥራ"
"የሥራ መገለጫ"
"የስራ መተግበሪያዎችን እዚህ ያግኙ"
-
-
+ "እያንዳንዱ የሥራ መተግበሪያ ባጅ አለው፣ እና በድርጅትዎ ደህንነቱ ተጠብቋል። ለቀለለ መዳረሻ መተግበሪያዎችን ወደ የእርስዎ መነሻ ማያ ገጽ ይውሰዷቸው።"
"በእርስዎ ድርጅት የሚተዳደር"
"ማሳወቂያዎች እና መተግበሪያዎች ጠፍተዋል"
+ "ዝጋ"
+ "ዝግ"
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 95508e1212..8598a8bb85 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -40,9 +40,13 @@
"لم يتم العثور على أي تطبيقات تتطابق مع \"%1$s\""
"البحث عن مزيد من التطبيقات"
"الإشعارات"
+ "انقر مع الاستمرار لاختيار اختصار."
+ "يمكنك النقر نقرًا مزدوجًا مع الاستمرار لاختيار اختصار أو استخدام الإجراءات المخصصة."
"ليس هناك مساحة أخرى في هذه الشاشة الرئيسية."
"لا يوجد المزيد من الحقول في علبة المفضلة"
"قائمة التطبيقات"
+ "قائمة التطبيقات الشخصية"
+ "قائمة تطبيقات العمل"
"الرئيسية"
"إزالة"
"إلغاء التثبيت"
@@ -81,19 +85,17 @@
"الخلفيات"
"إعدادات الصفحة الرئيسية"
"عطَّل المشرف هذه الميزة"
- "نظرة عامة"
- "السماح بتدوير الشاشة الرئيسية"
- "عند تدوير الهاتف"
- "لا يسمح إعداد العرض الحالي بالتدوير"
"نقاط الإشعارات"
"قيد التشغيل"
"قيد الإيقاف"
"يلزم تمكين الوصول إلى الإشعارات"
"لعرض نقاط الإشعارات، يجب تشغيل إشعارات التطبيق في %1$s"
"تغيير الإعدادات"
+ "عرض نقاط الإشعارات"
"إضافة رمز إلى الشاشة الرئيسية"
"للتطبيقات الجديدة"
"تغيير شكل الرمز"
+ "على الشاشة الرئيسية"
"استخدام الإعداد الافتراضي للنظام"
"مربّع"
"رمز دائري مربّع"
@@ -123,9 +125,6 @@
"إنشاء مجلد يتضمن: %1$s"
"تم إنشاء المجلد"
"نقل إلى الشاشة الرئيسية"
- "نقل الشاشة إلى اليسار"
- "نقل الشاشة إلى اليمين"
- "تم نقل الشاشة"
"تغيير حجم"
"زيادة العرض"
"زيادة الارتفاع"
@@ -141,8 +140,9 @@
"للعمل"
"الملف الشخصي للعمل"
"البحث عن تطبيقات العمل هنا"
-
-
+ "يحتوي كل تطبيق للعمل على شارة ويظل تحت حماية مؤسستك. يمكنك نقل التطبيقات إلى شاشتك الرئيسية لتسهيل الوصول إليها."
"ملف شخصي للعمل تديره مؤسستك"
"الإشعارات والتطبيقات متوقفة."
+ "إغلاق"
+ "تمّ الإغلاق"
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index b4b3c79174..a0a1f57731 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -40,10 +40,8 @@
"%1$s sorğusuna uyğun tətbiq tapılmadı"
"Daha çox tətbiq üçün axtarış edin"
"Bildirişlər"
-
-
-
-
+ "Qısayolu seçmək üçün basıb saxlayın."
+ "Qısayolu seçmək üçün iki dəfə basıb saxlayın və ya fərdi əməliyyatlardan istifadə edin."
"Bu Əsas ekranda boş yer yoxdur."
"Favoritlər-də yer yoxdur"
"Tətbiq siyahısı"
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 4b577bad19..275cf0f250 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -40,9 +40,13 @@
"Nije pronađena nijedna aplikacija za „%1$s“"
"Pretraži još aplikacija"
"Obaveštenja"
+ "Dodirnite i zadržite da biste izabrali prečicu."
+ "Dvaput dodirnite i zadržite da biste izabrali prečicu ili koristite prilagođene radnje."
"Nema više prostora na ovom početnom ekranu."
"Nema više prostora na traci Omiljeno"
"Lista aplikacija"
+ "Lista ličnih aplikacija"
+ "Lista poslovnih aplikacija"
"Početna"
"Ukloni"
"Deinstaliraj"
@@ -78,19 +82,17 @@
"Pozadine"
"Podešavanja početnog ekrana"
"Administrator je onemogućio"
- "Pregled"
- "Dozvoli rotaciju početnog ekrana"
- "Kada se telefon rotira"
- "Aktuelno podešavanje prikaza ne dozvoljava rotaciju"
"Tačke za obaveštenja"
"Uključeno"
"Isključeno"
"Potreban je pristup za obaveštenja"
"Da biste prikazali tačke za obaveštenja, uključite obaveštenja za aplikaciju %1$s"
"Promenite podešavanja"
+ "Prikazuj tačke za obaveštenja"
"Dodaj ikonu na početni ekran"
"Za nove aplikacije"
"Promenite oblik ikona"
+ "na početnom ekranu"
"Koristi podrazumevano sistemsko podešavanje"
"Kvadrat"
"Zaobljeni kvadrat"
@@ -120,9 +122,6 @@
"Napravite direktorijum sa: %1$s"
"Direktorijum je napravljen"
"Premesti na početni ekran"
- "Pomeri ekran ulevo"
- "Pomeri ekran udesno"
- "Ekran je pomeren"
"Promeni veličinu"
"Povećaj širinu"
"Povećaj visinu"
@@ -138,8 +137,9 @@
"Poslovne"
"Profil za Work"
"Pronađite poslovne aplikacije ovde"
-
-
+ "Svaka poslovna aplikacija ima značku i štiti je vaša organizacija. Premestite aplikacije na početni ekran da biste im lakše pristupali."
"Ovim upravlja organizacija"
"Obaveštenja i aplikacije su isključeni"
+ "Zatvori"
+ "Zatvoreno"
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 155ac3cdfe..a1f1d8912a 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -40,9 +40,13 @@
"Праграм, якія адпавядаюць запыту \"%1$s\", не знойдзена"
"Шукаць іншыя праграмы"
"Апавяшчэнні"
+ "Дакраніцеся і ўтрымлiвайце ярлык, каб дадаць яго."
+ "Дакраніцеся двойчы і ўтрымлівайце, каб выбраць ярлык або выкарыстоўваць спецыяльныя дзеянні."
"На гэтым Галоўным экране больш няма месца."
"У латку \"Абранае\" больш няма месца"
"Спіс праграм"
+ "Спіс персанальных праграм"
+ "Спіс працоўных праграм"
"Галоўная"
"Выдаліць"
"Выдаліць"
@@ -79,19 +83,17 @@
"Шпалеры"
"Налады галоўнага экрана"
"Адключаная адміністратарам"
- "Агляд"
- "Дазволіць паварот галоўнага экрана"
- "Пры павароце тэлефона"
- "Бягучая налада дысплэя не прадугледжвае паварот"
"Значкі апавяшчэнняў"
"Уключана"
"Выключана"
"Патрабуецца доступ да апавяшчэнняў"
"Каб паказваліся значкі апавяшчэнняў, уключыце апавяшчэнні праграм для %1$s"
"Змяніць налады"
+ "Паказаць значкі апавяшчэнняў"
"Дадаць значок на Галоўны экран"
"Для новых праграм"
"Змяніць форму значка"
+ "на галоўным экране"
"Выкарыстоўваць стандартныя формы"
"Квадрат"
"Прамавугольнік са скругленымі вугламі"
@@ -121,9 +123,6 @@
"Стварыць папку з: %1$s"
"Папка створана"
"Перамясціць на Галоўны экран"
- "Перамясціць экран налева"
- "Перамясціць экран направа"
- "Экран перамешчаны"
"Змяніць памер"
"Павялічыць шырыню"
"Павялічыць вышыню"
@@ -139,8 +138,9 @@
"Праца"
"Працоўны профіль"
"Знайдзіце працоўныя праграмы тут"
-
-
+ "Кожная працоўная праграма мае значок і знаходзіцца пад аховай вашай арганізацыі. Для больш простага доступу перамясціце праграмы на Галоўны экран."
"Пад кіраваннем вашай арганізацыі"
"Апавяшчэнні і праграмы выключаны"
+ "Закрыць"
+ "Закрытыя"
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index e664570527..3c04905775 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -40,10 +40,8 @@
"Няма намерени приложения, съответстващи на „%1$s“"
"Търсене на още приложения"
"Известия"
-
-
-
-
+ "Докоснете и задръжте за избор на пряк път."
+ "Докоснете двукратно и задръжте за избор на пряк път или използвайте персонализирани действия."
"На този начален екран няма повече място."
"Няма повече място в областта с любимите"
"Списък с приложения"
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 46a9a39026..a0e4812cc3 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\" এর সাথে মেলে এমন কোনো অ্যাপ পাওয়া যায়নি"
"আরও অ্যাপ্লিকেশানের জন্য খুঁজুন"
"বিজ্ঞপ্তি"
-
-
-
-
+ "কোনও শর্টকাট বেছে নিতে টাচ করে ধরে থাকুন।"
+ "কোনও শর্টকাট বেছে নিতে ডবল ট্যাপ করে ধরে থাকুন অথবা কাস্টম অ্যাকশন ব্যবহার করুন।"
"এই হোম স্ক্রীনে আর কোনো জায়গা নেই৷"
"পছন্দসই ট্রে-তে আর কোনো জায়গা নেই"
"অ্যাপ্লিকেশানগুলির তালিকা"
@@ -141,8 +139,6 @@
"প্রতিটি কাজের অ্যাপে একটি করে ব্যাজ রয়েছে এবং অ্যাপগুলি আপনার প্রতিষ্ঠানের দ্বারা সুরক্ষিত। সহজে অ্যাক্সেস করার জন্য অ্যাপগুলি হোম স্ক্রিনে রাখুন।"
"আপনার প্রতিষ্ঠানের দ্বারা পরিচালিত"
"বিজ্ঞপ্তি এবং অ্যাপ বন্ধ আছে"
-
-
-
-
+ "বন্ধ করুন"
+ "বন্ধ"
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index a96abdee8e..08a453360d 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -40,9 +40,13 @@
"Nije pronađena nijedna aplikacija za upit \"%1$s\""
"Pretraži više aplikacija"
"Obavještenja"
+ "Dodirnite i držite da uzmete prečicu."
+ "Dvaput dodirnite i držite da uzmete prečicu ili koristite prilagođene akcije."
"Na ovom početnom ekranu nema više prostora."
"Nema više prostora u ladici Omiljeno"
"Spisak aplikacija"
+ "Lista ličnih aplikacija"
+ "Lista poslovnih aplikacija"
"Početna"
"Ukloni"
"Deinstaliraj"
@@ -78,19 +82,17 @@
"Pozadinske slike"
"Postavke za Home"
"Onemogućio vaš administrator"
- "Pregled"
- "Dozvoli rotiranje početnog ekrana"
- "Kada se telefon zarotira"
- "Trenutne postavke ekrana ne dozvoljavaju rotiranje"
"Tačke za obavještenja"
"Uključeno"
"Isključeno"
"Potreban je pristup obavještenjima"
"Za prikaz tačaka obavještenja, uključite obavještenja za aplikacije za aplikaciju %1$s"
"Promijeni postavke"
+ "Prikaži tačke za obavještenja"
"Dodaj ikonu na početni ekran"
"Za nove aplikacije"
"Promjena oblika ikona"
+ "na Početnom ekranu"
"Koristite sistemski zadano"
"Kvadrat"
"Zaobljeni kvadrat"
@@ -120,9 +122,6 @@
"Kreirajte folder sa stavkom: %1$s"
"Folder je kreiran"
"Pomjeri na početni ekran"
- "Pomjeri ekran ulijevo"
- "Pomjeri ekran udesno"
- "Ekran je pomjeren"
"Promijeni veličinu"
"Povećaj širinu"
"Povećaj visinu"
@@ -138,8 +137,9 @@
"Poslovne"
"Radni profil"
"Pronađite poslovne aplikacije ovdje"
-
-
+ "Svaka poslovna aplikacija ima značku i osigurava je vaša organizacija. Premjestite aplikacije na Početni ekran, radi lakšeg pristupa."
"Upravlja vaša organizacija"
"Notifikacije i aplikacije su isključene"
+ "Zatvori"
+ "Zatvoreno"
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 57736296ba..27b2979e15 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -40,10 +40,8 @@
"No s\'ha trobat cap aplicació que coincideixi amb \"%1$s\""
"Cerca més aplicacions"
"Notificacions"
-
-
-
-
+ "Mantén premuda una drecera per seleccionar-la."
+ "Fes doble toc i mantén premut per seleccionar una drecera o per utilitzar accions personalitzades."
"Ja no queda espai en aquesta pantalla d\'inici."
"No hi ha més espai a la safata Preferits."
"Llista d\'aplicacions"
@@ -142,5 +140,5 @@
"Gestionat per la teva organització"
"Les notificacions i les aplicacions estan desactivades"
"Tanca"
- "Tancada"
+ "S\'ha tancat"
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 608d297ff5..eee945c209 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -40,9 +40,13 @@
"Dotazu „%1$s“ neodpovídají žádné aplikace"
"Vyhledat další aplikace"
"Oznámení"
+ "Zkratku vyberete podržením."
+ "Dvojitým klepnutím a podržením vyberte zkratku, případně použijte vlastní akce."
"Na této ploše již není místo."
"Na panelu Oblíbené položky již není místo."
"Seznam aplikací"
+ "Seznam osobních aplikací"
+ "Seznam pracovních aplikací"
"Plocha"
"Odstranit"
"Odinstalovat"
@@ -79,19 +83,17 @@
"Tapety"
"Nastavení plochy"
"Zakázáno administrátorem"
- "Přehled"
- "Povolit otáčení plochy"
- "Při otočení telefonu"
- "Aktuální nastavení displeje neumožňuje otáčení"
"Puntíky s oznámením"
"Zapnuto"
"Vypnuto"
"Je třeba udělit přístup k oznámením"
"Chcete-li zobrazovat puntíky s oznámením, zapněte oznámení z aplikace %1$s"
"Změnit nastavení"
+ "Zobrazovat puntíky s oznámením"
"Přidat ikonu na plochu"
"Pro nové aplikace"
"Změnit tvar ikony"
+ "na ploše"
"Použít výchozí nastavení systému"
"Čtverec"
"Kruh/čtverec"
@@ -121,9 +123,6 @@
"Vytvořit složku s položkou %1$s"
"Složka byla vytvořena"
"Přesunout na plochu"
- "Přesunout obrazovku doleva"
- "Přesunout obrazovku doprava"
- "Obrazovka byla přesunuta"
"Změnit velikost"
"Zvýšit šířku"
"Zvýšit výšku"
@@ -139,8 +138,9 @@
"Pracovní"
"Pracovní profil"
"Zde naleznete pracovní aplikace"
-
-
+ "Každá pracovní aplikace má odznak a je zabezpečena vaší organizací. Aplikace si můžete pro jednoduchost přesunout na plochu."
"Spravováno vaší organizací"
"Oznámení a aplikace jsou vypnuty"
+ "Zavřít"
+ "Zavřeno"
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 79fa9f12d2..203a9da7d4 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -40,13 +40,13 @@
"Der blev ikke fundet nogen apps, som matcher \"%1$s\""
"Søg efter flere apps"
"Underretninger"
+ "Hold en genvej nede for at samle den op."
+ "Tryk to gange, og hold en genvej nede for at samle den op eller bruge tilpassede handlinger."
"Der er ikke mere plads på denne startskærm."
"Der er ikke mere plads i bakken Foretrukne"
"Liste med apps"
-
-
-
-
+ "Liste over personlige apps"
+ "Liste over apps til arbejdet"
"Startskærm"
"Fjern"
"Afinstaller"
@@ -91,8 +91,7 @@
"Føj ikon til startskærmen"
"For nye apps"
"Skift ikonform"
-
-
+ "på startskærmen"
"Brug systemstandarden"
"Kvadrat"
"Kvadrat med runde hjørner"
@@ -140,4 +139,6 @@
"Alle arbejdsapps har et badge og beskyttes af din organisation. Flyt apps til din startskærm, så du nemmere kan få adgang til dem."
"Administreret af din organisation"
"Underretninger og apps er slået fra"
+ "Luk"
+ "Lukket"
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 5cc1451b3b..f012a9ee63 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -40,9 +40,13 @@
"Keine Apps für \"%1$s\" gefunden"
"Weitere Apps suchen"
"Benachrichtigungen"
+ "Tippen und halten, um eine Verknüpfung auszuwählen."
+ "Doppeltippen und halten, um eine Verknüpfung auszuwählen oder benutzerdefinierte Aktionen zu nutzen."
"Auf diesem Startbildschirm ist kein Platz mehr vorhanden."
"Ablage \"Favoriten\" ist voll."
"Liste der Apps"
+ "Liste der privaten Apps"
+ "Liste der geschäftlichen Apps"
"Startseite"
"Entfernen"
"Deinstallieren"
@@ -77,19 +81,17 @@
"Hintergründe"
"Einstellungen für den Startbildschirm"
"Von deinem Administrator deaktiviert"
- "Übersicht"
- "Drehung des Startbildschirms zulassen"
- "Bei Drehung des Smartphones"
- "Die aktuelle \"Display\"-Einstellung verhindert eine Drehung der Anzeige"
"App-Benachrichtigungspunkte"
"Aktiviert"
"Deaktiviert"
"Benachrichtigungszugriff erforderlich"
"Um dir Benachrichtigungspunkte anzeigen zu lassen, aktiviere die Benachrichtigungen für die App \"%1$s\""
"Einstellungen ändern"
+ "App-Benachrichtigungspunkte anzeigen"
"Symbol zu Startbildschirm hinzufügen"
"Für neue Apps"
"Form des Symbols ändern"
+ "auf dem Startbildschirm"
"Systemstandardeinstellung verwenden"
"Quadrat"
"Superkreis"
@@ -119,9 +121,6 @@
"Anhand von %1$s Ordner erstellen"
"Ordner erstellt"
"Auf Startbildschirm verschieben"
- "Bildschirm nach links"
- "Bildschirm nach rechts"
- "Bildschirm verschoben"
"Größe anpassen"
"Breite vergrößern"
"Höhe vergrößern"
@@ -137,8 +136,9 @@
"Geschäftlich"
"Arbeitsprofil"
"Hier findest du Apps für die Arbeit"
-
-
+ "Jede App für die Arbeit ist mit einem Logo gekennzeichnet. Deine Organisation kümmert sich um den entsprechenden Schutz. Damit du leichter auf Apps zugreifen kannst, verschiebe sie auf deinen Startbildschirm."
"Wird von deiner Organisation verwaltet"
"Benachrichtigungen und Apps sind deaktiviert"
+ "Schließen"
+ "Geschlossen"
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index e139e44064..18eec841fa 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -40,10 +40,8 @@
"Δεν βρέθηκαν εφαρμογές αντιστοίχισης για \"%1$s\""
"Αναζήτηση περισσότερων εφαρμογών"
"Ειδοποιήσεις"
-
-
-
-
+ "Αγγίξτε παρατεταμένα για επιλογή συντόμευσης."
+ "Πατήσετε δύο φορές παρατεταμένα για επιλογή συντόμευσης ή χρήση προσαρμοσμένων ενεργειών."
"Δεν υπάρχει χώρος σε αυτήν την αρχική οθόνη."
"Δεν υπάρχει επιπλέον χώρος στην περιοχή Αγαπημένα"
"Λίστα εφαρμογών"
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 5b1e39adf7..c2e37b8e51 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -40,10 +40,8 @@
"No apps found matching \'%1$s\'"
"Search for more apps"
"Notifications"
-
-
-
-
+ "Touch & hold to pick up a shortcut."
+ "Double-tap & hold to pick up a shortcut or use custom actions."
"No more room on this Home screen."
"No more room in the Favourites tray"
"Apps list"
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 5b1e39adf7..c2e37b8e51 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -40,10 +40,8 @@
"No apps found matching \'%1$s\'"
"Search for more apps"
"Notifications"
-
-
-
-
+ "Touch & hold to pick up a shortcut."
+ "Double-tap & hold to pick up a shortcut or use custom actions."
"No more room on this Home screen."
"No more room in the Favourites tray"
"Apps list"
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 5b1e39adf7..c2e37b8e51 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -40,10 +40,8 @@
"No apps found matching \'%1$s\'"
"Search for more apps"
"Notifications"
-
-
-
-
+ "Touch & hold to pick up a shortcut."
+ "Double-tap & hold to pick up a shortcut or use custom actions."
"No more room on this Home screen."
"No more room in the Favourites tray"
"Apps list"
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 23bf97d5e9..989cd619e7 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -40,9 +40,13 @@
"No hay apps que coincidan con \"%1$s\""
"Buscar más apps"
"Notificaciones"
+ "Mantén presionado para elegir un acceso directo."
+ "Presiona dos veces y mantén presionado para elegir un acceso directo o usar acciones personalizadas."
"No hay más espacio en esta pantalla principal."
"La bandeja de favoritos está llena."
"Lista de apps"
+ "Lista de apps personales"
+ "Lista de apps del trabajo"
"Pantalla principal"
"Quitar"
"Desinstalar"
@@ -77,19 +81,17 @@
"Fondos de pantalla"
"Configuración de Home"
"El administrador inhabilitó esta función"
- "Recientes"
- "Permitir la rotación de la pantalla principal"
- "Al girar el teléfono"
- "La configuración actual no permite la rotación de la pantalla"
"Puntos de notificación"
"Activada"
"Desactivada"
"Se necesita acceso a las notificaciones"
"Para mostrar los puntos de notificación, activa las notificaciones de la app para %1$s"
"Cambiar la configuración"
+ "Mostrar puntos de notificación"
"Agregar ícono a la pantalla principal"
"Para nuevas apps"
"Cambiar forma de los íconos"
+ "en la pantalla principal"
"Usar el sistema predeterminado"
"Cuadrado"
"Cuadrado con esquinas redondeadas"
@@ -119,9 +121,6 @@
"Crear carpeta con: %1$s"
"Carpeta creada"
"Mover a la pantalla principal"
- "Mover pantalla a la izquierda"
- "Mover pantalla a la derecha"
- "Se movió la pantalla."
"Ajustar tamaño"
"Aumentar el ancho"
"Aumentar la altura"
@@ -137,8 +136,9 @@
"Laborales"
"Perfil de trabajo"
"Apps de trabajo"
-
-
+ "Cada app de trabajo tiene una insignia y está protegida por tu organización. Transfiere las apps a la pantalla principal para acceder a ellas con mayor facilidad."
"Administrado por tu organización"
"Las notificaciones y las apps están desactivadas"
+ "Cerrar"
+ "Cerrado"
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index f6337fcb2c..5b948da351 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -40,10 +40,8 @@
"No se han encontrado aplicaciones que contengan \"%1$s\""
"Buscar más aplicaciones"
"Notificaciones"
-
-
-
-
+ "Mantén pulsado para elegir un acceso directo."
+ "Toca dos veces y mantén pulsado para elegir un acceso directo o utilizar acciones personalizadas."
"No queda espacio en la pantalla de inicio."
"La bandeja de favoritos está completa"
"Lista de aplicaciones"
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index fb24c2ab0d..2946076f5d 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -40,10 +40,8 @@
"Päringule „%1$s” ei vastanud ükski rakendus"
"Otsi rohkem rakendusi"
"Märguanded"
-
-
-
-
+ "Otsetee valimiseks puudutage seda pikalt."
+ "Topeltpuudutage ja hoidke otsetee valimiseks või kohandatud toimingute kasutamiseks."
"Sellel avaekraanil pole enam ruumi."
"Salves Lemmikud pole rohkem ruumi"
"Rakenduste loend"
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 45aa3f77cd..c3099bd98e 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -40,10 +40,8 @@
"Ez da aurkitu \"%1$s\" bilaketaren emaitzarik"
"Bilatu aplikazio gehiago"
"Jakinarazpenak"
-
-
-
-
+ "Eduki sakatuta lasterbide bat aukeratzeko."
+ "Sakatu birritan eta eduki sakatuta lasterbide bat aukeratzeko edo ekintza pertsonalizatuak erabiltzeko."
"Hasierako pantaila honetan ez dago toki gehiago."
"Ez dago toki gehiago Gogokoak erretiluan"
"Aplikazioen zerrenda"
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 5528119723..4843d6d9e4 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -40,9 +40,13 @@
"هیچ برنامهای در مطابقت با «%1$s» پیدا نشد"
"جستجوی برنامههای بیشتر"
"اعلانها"
+ "برای انتخاب میانبر، لمس کنید و نگهدارید."
+ "برای انتخاب میانبر، دو ضربه سریع بزنید و نگهدارید یا از کنشهای سفارشی استفاده کنید."
"فضای بیشتری در این صفحه اصلی موجود نیست."
"فضای بیشتری در سینی موارد دلخواه وجود ندارد"
"فهرست برنامهها"
+ "فهرست برنامههای شخصی"
+ "فهرست برنامههای کاری"
"صفحه اصلی"
"برداشتن"
"حذف نصب"
@@ -77,19 +81,17 @@
"کاغذدیواریها"
"تنظیمات صفحه اصلی"
"توسط سرپرست سیستم غیرفعال شده است"
- "نمای کلی"
- "امکان دادن به چرخش صفحه اصلی"
- "وقتی تلفن چرخانده میشود"
- "تنظیم نمایشگر کنونی اجازه چرخش نمیدهد"
"نقطههای اعلان"
"روشن"
"خاموش"
"دسترسی به اعلان نیاز است"
"برای نمایش «نقطههای اعلان»، اعلانهای برنامه را برای %1$s روشن کنید"
"تغییر تنظیمات"
+ "نمایش نقطههای اعلان"
"افزودن نماد به صفحه اصلی"
"برای برنامههای جدید"
"تغییر شکل نماد"
+ "در صفحه اصلی"
"استفاده از پیشفرض سیستم"
"مربع"
"مربع با گوشههای گرد"
@@ -119,9 +121,6 @@
"ایجاد پوشه با: %1$s"
"پوشه ایجاد شد"
"انتقال به صفحه اصلی"
- "انتقال صفحه به چپ"
- "انتقال صفحه به راست"
- "صفحه منتقل شد"
"تغییر اندازه"
"افزایش عرض"
"افزایش ارتفاع"
@@ -137,8 +136,9 @@
"محل کار"
"نمایه کاری"
"اینجا برنامههای کاری را پیدا کنید"
-
-
+ "همه برنامههای کاری نشانی دارند و توسط سازمانتان ایمن نگه داشته میشوند. برنامههای کاری را برای دسترسی آسانتر به صفحه اصلی انتقال دهید."
"توسط سازمانتان مدیریت میشود"
"اعلانها و برنامهها خاموش هستند"
+ "بستن"
+ "بستهشده"
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 0a7d455846..5ffc414558 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -40,10 +40,8 @@
"%1$s ei palauttanut sovelluksia."
"Hae lisää sovelluksia"
"Ilmoitukset"
-
-
-
-
+ "Valitse pikakuvake painamalla sitä pitkään."
+ "Valitse pikakuvake tai käytä muokattuja toimintoja kaksoisnapauttamalla ja painamalla pitkään."
"Tässä aloitusruudussa ei ole enää tilaa."
"Suosikit-valikossa ei ole enää tilaa"
"Sovellusluettelo"
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index c6961805fd..d6903efb1a 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -40,9 +40,13 @@
"Aucune application trouvée correspondant à « %1$s »"
"Rechercher plus d\'applications"
"Notifications"
+ "Maintenez un doigt sur le raccourci pour l\'ajouter"
+ "Touchez 2x un raccourci et maintenez doigt dessus pour l’aj. ou utiliser des actions personnalisées."
"Pas d\'espace libre sur l\'écran d\'accueil."
"Il n\'y a plus d\'espace dans la zone des favoris"
"Liste des applications"
+ "Liste des applications personnelles"
+ "Liste des applications professionnelles"
"Accueil"
"Supprimer"
"Désinstaller"
@@ -77,19 +81,17 @@
"Fonds d\'écran"
"Paramètres d\'accueil"
"Cette fonction est désactivée par votre administrateur"
- "Présentation"
- "Autoriser la rotation de l\'écran d\'accueil"
- "Lorsque vous faites pivoter le téléphone"
- "Le mode d\'affichage actuel ne permet pas le pivotement"
"Points de notification"
"Activé"
"Désactivé"
"L\'accès aux notifications est requis"
"Pour afficher les points de notification, activez les notifications d\'application pour %1$s"
"Modifier les paramètres"
+ "Afficher les points de notification"
"Ajouter l\'icône à l\'écran d\'accueil"
"Pour les nouvelles applications"
"Modifier la forme de l\'icône"
+ "sur l\'écran d\'accueil"
"Utiliser les valeurs système par défaut"
"Carré"
"Carré aux coins ronds"
@@ -119,9 +121,6 @@
"Créer un dossier avec : %1$s"
"Dossier créé"
"Déplacer sur l\'écran d\'accueil"
- "Déplacer l\'écran à gauche"
- "Déplacer l\'écran à droite"
- "Écran déplacé"
"Redimensionner"
"Augmenter la largeur"
"Augmenter la hauteur"
@@ -137,8 +136,9 @@
"Travail"
"Profil professionnel"
"Trouvez ici des applications professionnelles"
-
-
+ "Chaque application professionnelle comporte un badge, ce qui signifie qu\'elle est sécurisée par votre organisation. Vous pouvez déplacer vos applications vers l\'écran d\'accueil afin d\'y accéder plus facilement."
"Géré par votre organisation"
"Les notifications et les applications sont désactivées"
+ "Fermer"
+ "Fermé"
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index e0997fc85a..e1b758124d 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -40,9 +40,13 @@
"Aucune application ne correspond à la requête \"%1$s\""
"Rechercher plus d\'applications"
"Notifications"
+ "Appui prolongé pour sélectionner un raccourci."
+ "Appuyez 2X et maintenez la pression pour choisir un raccourci ou utilisez les actions personnalisées"
"Pas d\'espace libre sur cet écran d\'accueil."
"Plus d\'espace disponible dans la zone de favoris."
"Liste d\'applications"
+ "Liste des applications personnelles"
+ "Liste des applications professionnelles"
"Accueil"
"Supprimer"
"Désinstaller"
@@ -77,19 +81,17 @@
"Fonds d\'écran"
"Paramètres de l\'écran d\'accueil"
"Désactivé par votre administrateur"
- "Vue d\'ensemble"
- "Autoriser la rotation de l\'écran d\'accueil"
- "Lorsque vous faites pivoter le téléphone"
- "Le paramètre d\'affichage actuel n\'autorise pas la rotation."
"Pastilles de notification"
"Activé"
"Désactivé"
"Accès aux notifications requis"
"Pour afficher les pastilles de notification, activez les notifications de l\'application %1$s"
"Modifier les paramètres"
+ "Afficher les pastilles de notification"
"Ajouter l\'icône à l\'écran d\'accueil"
"Pour les nouvelles applications"
"Modifier la forme des icônes"
+ "sur l\'écran d\'accueil"
"Utiliser la valeur système par défaut"
"Carré"
"Squircle"
@@ -119,9 +121,6 @@
"Créer un dossier avec \"%1$s\""
"Dossier créé"
"Déplacer vers l\'écran d\'accueil"
- "Déplacer l\'écran vers la gauche"
- "Déplacer l\'écran vers la droite"
- "L\'écran a bien été déplacé."
"Redimensionner"
"Augmenter la largeur"
"Augmenter la hauteur"
@@ -137,8 +136,9 @@
"Professionnelles"
"Profil professionnel"
"Retrouvez ici vos applications professionnelles"
-
-
+ "Les applications professionnelles sont accompagnées d\'un badge et sont sécurisées par votre organisation. Vous pouvez les déplacer vers votre écran d\'accueil pour y accéder plus facilement."
"Géré par votre organisation"
"Les notifications et les applications sont désactivées"
+ "Fermer"
+ "Fermé"
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 9feb1bd3b6..0cfdfa8991 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -40,10 +40,8 @@
"Non se atoparon aplicacións que coincidan con \"%1$s\""
"Buscar máis aplicacións"
"Notificacións"
-
-
-
-
+ "Mantén premido un atallo para seleccionalo."
+ "Toca dúas veces e mantén premido para seleccionar un atallo ou utiliza accións personalizadas."
"Non hai máis espazo nesta pantalla de inicio."
"Non hai máis espazo na bandexa de favoritos"
"Lista de aplicacións"
@@ -142,5 +140,5 @@
"Perfil xestionado pola túa organización"
"As notificacións e as aplicacións están desactivadas"
"Pechar"
- "Pechado"
+ "Pechada"
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 53627180ab..efc953c809 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\"થી મેળ ખાતી કોઈ ઍપ્લિકેશનો મળી નથી"
"વધુ ઍપ્લિકેશનો શોધો"
"નોટિફિકેશનો"
-
-
-
-
+ "એક શૉર્ટકટ ચૂંટવા માટે સ્પર્શ કરી રાખો."
+ "એક શૉર્ટકટ ચૂંટવા અથવા કોઈ કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટૅપ કરીને દબાવી રાખો."
"આ હોમ સ્ક્રીન પર વધુ જગ્યા નથી."
"મનપસંદ ટ્રે પર વધુ જગ્યા નથી"
"ઍપ્લિકેશનોની સૂચિ"
@@ -141,8 +139,6 @@
"દરેક કાર્ય ઍપ પાસે એક બૅજ હોય છે અને તમારી સંસ્થા દ્વારા તેને સુરક્ષિત રાખવામાં આવે છે. વધુ સરળ ઍક્સેસ માટે ઍપને તમારી હોમ સ્ક્રીન પર ખસેડો."
"તમારી સંસ્થા દ્વારા મેનેજ કરેલ"
"નોટિફિકેશન અને ઍપ બંધ છે"
-
-
-
-
+ "બંધ કરો"
+ "બંધ"
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 15a4deb945..f98859df8c 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -40,9 +40,13 @@
"\"%1$s\" से मिलता-जुलता कोई ऐप्लिकेशन नहीं मिला"
"और ऐप सर्च करें"
"सूचनाएं"
+ "शॉर्टकट चुनने के लिए दबाकर रखें."
+ "शॉर्टकट चुनने या पसंद के मुताबिक कार्रवाई करने के लिए दो बार टैप करें और कुछ देर दबाए रखें."
"इस होम स्क्रीन पर जगह नहीं बची है"
"पसंदीदा ट्रे में और जगह नहीं है"
"ऐप्लिकेशन सूची"
+ "निजी ऐप्लिकेशन की सूची"
+ "काम से जुड़े ऐप्लिकेशन की सूची"
"होम पेज"
"निकालें"
"अनइंस्टॉल करें"
@@ -77,19 +81,17 @@
"वॉलपेपर"
"होम पेज की सेटिंग"
"आपके एडमिन ने बंद किया हुआ है"
- "खास जानकारी"
- "होमस्क्रीन घुमाने की अनुमति दें"
- "फ़ोन घुुमाए जाने पर"
- "इस डिसप्ले सेटिंग में रोटेशन (स्क्रीन पर सामग्री को घुमाकर देखने) की सुविधा काम नहीं करती"
"सूचना बिंदु"
"चालू"
"बंद"
"सूचना के एक्सेस की ज़रूरत है"
"सूचना बिंदु दिखाने के लिए, %1$s के ऐप्लिकेशन सूचना चालू करें"
"सेटिंग बदलें"
+ "नए नोटिफ़िकेशन बताने वाला गोल निशान दिखाएं"
"होम स्क्रीन में आइकॉन जोड़ें"
"नए ऐप के लिए"
"आइकॉन का आकार बदलें"
+ "होम स्क्रीन पर"
"सिस्टम डिफ़ॉल्ट का उपयोग करें"
"वर्ग"
"गोल कोनों वाला वर्ग"
@@ -119,9 +121,6 @@
"इसके साथ फ़ोल्डर बनाएं: %1$s"
"फ़ोल्डर बनाया गया"
"होम स्क्रीन पर ले जाएं"
- "स्क्रीन को बाएं ले जाएं"
- "स्क्रीन को दाएं ले जाएं"
- "स्क्रीन ले जाई गई"
"आकार बदलें"
"चौड़ाई बढ़ाएं"
"ऊंचाई बढ़ाएं"
@@ -137,8 +136,9 @@
"काम से जुड़े ऐप"
"कार्य प्रोफ़ाइल"
"काम से जुड़े सभी ऐप्लिकेशन यहां पाएं"
-
-
+ "काम से जुड़े हर ऐप्लिकेशन पर एक बैज (निशान) होता है और इन ऐप्लिकेशन की सुरक्षा आपका संगठन करता है. आसानी से इस्तेमाल करने के लिए ऐप्लिकेशन को अपनी होम स्क्रीन पर ले जाएं."
"आपका संगठन प्रबंधित कर रहा है"
"सूचनाएं और ऐप्लिकेशन बंद हैं"
+ "बंद करें"
+ "बंद कर दिया गया"
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index d28c108b1b..35a7963936 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -40,9 +40,13 @@
"Nema aplikacija podudarnih s upitom \"%1$s\""
"Traži više aplikacija"
"Obavijesti"
+ "Dodirnite i zadržite kako biste podigli prečac."
+ "Dvaput dodirnite i zadržite pritisak kako biste podigli prečac ili pokušajte prilagođenim radnjama."
"Na ovom početnom zaslonu više nema mjesta."
"Nema više prostora na traci Favoriti"
"Popis aplikacija"
+ "Popis osobnih aplikacija"
+ "Popis radnih aplikacija"
"Početna"
"Ukloni"
"Deinstaliraj"
@@ -78,19 +82,17 @@
"Pozadine"
"Postavke Homea"
"Onemogućio administrator"
- "Pregled"
- "Dopusti zakretanje početnog zaslona"
- "Kada se telefon zakrene"
- "Trenutačna postavka zaslona ne dopušta zakretanje"
"Točke obavijesti"
"Uključeno"
"Isključeno"
"Potreban je pristup obavijestima"
"Za prikaz točaka obavijesti uključite obavijesti aplikacije %1$s"
"Promjena postavki"
+ "Prikaži točke obavijesti"
"Dodaj ikonu na početni zaslon"
"Za nove aplikacije"
"Promijeni oblik ikona"
+ "na početnom zaslonu"
"Upotrijebi zadane postavke sustava"
"Kvadrat"
"Zaobljeni kvadrat"
@@ -120,9 +122,6 @@
"Izrada mape pomoću stavke: %1$s"
"Mapa izrađena"
"Premještanje na početni zaslon"
- "Premještanje zaslona ulijevo"
- "Premještanje zaslona udesno"
- "Zaslon je premješten"
"Promjena veličine"
"Povećanje širine"
"Povećanje visine"
@@ -138,8 +137,9 @@
"Posao"
"Radni profil"
"Ovdje možete pronaći radne aplikacije"
-
-
+ "Svaka radna aplikacija ima značku i štiti je vaša organizacija. Premjestite aplikacije na početni zaslon radi lakšeg pristupa."
"Pod upravljanjem vaše organizacije"
"Obavijesti i aplikacije isključeni su"
+ "Zatvori"
+ "Zatvoreno"
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 997918bca4..4972e81924 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -40,10 +40,8 @@
"Nem található alkalmazás a(z) „%1$s” lekérdezésre"
"További alkalmazások keresése"
"Értesítések"
-
-
-
-
+ "Felvételhez tartsa nyomva a parancsikont."
+ "Parancsikon felvételéhez koppintson rá duplán és tartsa nyomva, vagy használjon egyéni műveleteket."
"Nincs több hely ezen a kezdőképernyőn."
"Nincs több hely a Kedvencek tálcán"
"Alkalmazások listája"
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index e233a4404a..8c3ae2591d 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -40,9 +40,13 @@
"«%1$s» հարցմանը համապատասխանող հավելվածներ չեն գտնվել"
"Որոնել այլ հավելվածներ"
"Ծանուցումներ"
+ "Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար։"
+ "Կրկնակի հպեք և պահեք՝ դյուրանցում ընտրելու համար կամ օգտվեք հարմարեցրած գործողություններից:"
"Այլևս տեղ չկա այս հիմնական էկրանին:"
"Ընտրյալների ցուցակում այլևս ազատ տեղ չկա"
"Հավելվածների ցանկ"
+ "Անձնական հավելվածների ցանկ"
+ "Աշխատանքային հավելվածների ցանկ"
"Հիմնական"
"Հեռացնել"
"Հեռացնել"
@@ -77,19 +81,17 @@
"Պաստառներ"
"Գլխավոր էջի կարգավորումներ"
"Անջատվել է ձեր ադմինիստրատորի կողմից"
- "Համատեսք"
- "Թույլ տալ հիմնական էկրանի պտտումը"
- "Հեռախոսը պտտելու դեպքում"
- "Ցուցադրման ընթացիկ կարգավորումներն արգելում են պտտումը"
"Ծանուցումների կետիկներ"
"Միացված է"
"Անջատված է"
"Անհրաժեշտ է ծանուցման թույլտվություն"
"Ծանուցումների կետիկները ցուցադրելու համար միացրեք ծանուցումները %1$s-ի համար"
"Փոխել կարգավորումները"
+ "Ցուցադրել ծանուցումների կետիկները"
"Ավելացնել պատկերակը Հիմնական էկրանին"
"Նոր հավելվածների համար"
"Փոխել պատկերակների տեսքը"
+ "հիմնական էկրանին"
"Օգտագործել համակարգի կանխադրված կարգավորումը"
"Քառակուսի"
"Քառանկյուն"
@@ -119,9 +121,6 @@
"Ստեղծել թղթապանակ, օգտագործելով՝ %1$s"
"Պանակը ստեղծվեց"
"Տեղափոխել Հիմնական էկրան"
- "Տեղափոխել էկրանը ձախ"
- "Տեղափոխել էկրանը աջ"
- "Էկրանը տեղափոխվեց"
"Չափափոխել"
"Ավելացնել լայնությունը"
"Ավելացնել բարձրությունը"
@@ -137,8 +136,9 @@
"Աշխատանքային"
"Աշխատանքային պրոֆիլ"
"Գտեք աշխատանքային հավելվածներ այստեղ"
-
-
+ "Աշխատանքային հավելվածները նշված են հատուկ նշանով: Նման հավելվածների անվտանգությունը ապահովում է ձեր կազմակերպությունը։ Հարմարության համար աշխատանքային հավելվածները կարող եք տեղափոխել հիմնական էկրան։"
"Կառավարվում է ձեր կազմակերպության կողմից"
"Ծանուցումներն ու հավելվածներն անջատված են"
+ "Փակել"
+ "Փակվեց"
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 29a15f5376..ea0ea4af12 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -40,10 +40,8 @@
"Tidak ditemukan aplikasi yang cocok dengan \"%1$s\""
"Telusuri aplikasi lainnya"
"Notifikasi"
-
-
-
-
+ "Tap lama untuk memilih pintasan."
+ "Tap dua kali & tahan untuk memilih pintasan atau menggunakan tindakan khusus."
"Tidak ada ruang lagi pada layar Utama ini."
"Tidak ada ruang tersisa di baki Favorit"
"Daftar aplikasi"
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 1e89142cb1..3dc2d22118 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -40,9 +40,13 @@
"Ekki fundust forrit sem samsvara „%1$s“"
"Leita að fleiri forritum"
"Tilkynningar"
+ "Haltu fingri á flýtileið til að grípa hana."
+ "Ýttu tvisvar og haltu fingri á flýtileið til að grípa hana eða notaðu sérsniðnar aðgerðir."
"Ekki meira pláss á þessum heimaskjá."
"Ekki meira pláss í bakka fyrir uppáhald"
"Forritalisti"
+ "Listi yfir eigin forrit"
+ "Listi yfir vinnuforrit"
"Heim"
"Fjarlægja"
"Fjarlægja"
@@ -77,19 +81,17 @@
"Veggfóður"
"Heimastillingar"
"Gert óvirkt af kerfisstjóra"
- "Yfirlit"
- "Leyfa snúning fyrir heimaskjá"
- "Þegar símanum er snúið"
- "Núverandi skjástilling leyfir ekki snúning"
"Tilkynningapunktar"
"Kveikt"
"Slökkt"
"Aðgangs að tilkynningum er krafist"
"Til að sýna tilkynningarpunkta skaltu kveikja á forritstilkynningum fyrir %1$s"
"Breyta stillingum"
+ "Sýna tilkynningapunkta"
"Bæta tákni á heimaskjáinn"
"Fyrir ný forrit"
"Breyta formi tákns"
+ "á heimaskjá"
"Nota sjálfgildi kerfis"
"Ferningur"
"Ferhringur"
@@ -119,9 +121,6 @@
"Búa til möppu með: %1$s"
"Mappa búin til"
"Færa á heimaskjá"
- "Færa skjá til vinstri"
- "Færa skjá til hægri"
- "Skjár færður"
"Breyta stærð"
"Auka breidd"
"Auka hæð"
@@ -137,8 +136,9 @@
"Vinna"
"Vinnusnið"
"Hér finnurðu vinnuforrit"
-
-
+ "Öll vinnuforrit eru með merki og fyrirtækið þitt tryggir öryggi þeirra. Færðu forrit yfir á heimaskjáinn til að fá auðveldari aðgang að þeim."
"Stjórnað af fyrirtækinu þínu"
"Slökkt er á tilkynningum og forritum"
+ "Loka"
+ "Lokað"
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 03f98aebd7..44e12c0e40 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -40,10 +40,8 @@
"Nessuna app trovata corrispondente a \"%1$s\""
"Cerca altre app"
"Notifiche"
-
-
-
-
+ "Tocca e tieni premuto per scegliere la scorciatoia"
+ "Tocca due volte e tieni premuto per scegliere una scorciatoia o per usare azioni personalizzate."
"Spazio nella schermata Home esaurito."
"Spazio esaurito nella barra dei Preferiti"
"Elenco di app"
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 961bd01117..bc2061ba28 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -40,9 +40,13 @@
"לא נמצאו אפליקציות התואמות ל-\"%1$s\""
"חפש אפליקציות נוספות"
"הודעות"
+ "כדי להוסיף קיצור דרך, יש לגעת בו ולהחזיק אותו."
+ "כדי להוסיף קיצור דרך או להשתמש בפעולות מותאמות אישית, יש להקיש על קיצור הדרך פעמיים ולהחזיק אותו."
"אין עוד מקום במסך דף הבית הזה."
"אין עוד מקום במגש המועדפים"
"רשימת אפליקציות"
+ "רשימת אפליקציות אישיות"
+ "רשימת אפליקציות עבודה"
"דף הבית"
"הסר"
"הסר התקנה"
@@ -79,19 +83,17 @@
"טפטים"
"הגדרות דף הבית"
"הושבת על ידי מנהל המערכת שלך"
- "סקירה"
- "אפשרות סיבוב של מסך דף הבית"
- "כאשר הטלפון מסובב"
- "הגדרת התצוגה הנוכחית אינה מאפשרת סיבוב"
"סימני הודעות"
"מופעלת"
"כבויה"
"נדרשת גישה להודעות"
"כדי להציג את סימני ההודעות, יש להפעיל הודעות מהאפליקציה %1$s"
"שנה את ההגדרות"
+ "הצגה של סימן ההודעות"
"הוספת סמל במסך דף הבית"
"לאפליקציות חדשות"
"שינוי הצורה של הסמלים"
+ "במסך דף הבית"
"השתמש בברירת המחדל של המערכת"
"ריבוע"
"ריבוע בעל פינות מעוגלות"
@@ -121,9 +123,6 @@
"צור תיקייה עם: %1$s"
"התיקייה נוצרה"
"העבר אל מסך דף הבית"
- "הזז את המסך שמאלה"
- "הזז את המסך ימינה"
- "המסך הועבר"
"שנה גודל"
"הגדל רוחב"
"הגדל גובה"
@@ -139,8 +138,9 @@
"עבודה"
"פרופיל עבודה"
"ניתן למצוא כאן את אפליקציות העבודה"
-
-
+ "לכל אפליקציית עבודה יש תג ואבטחתה מטופלת בידי הארגון. אפשר להעביר אפליקציות אל מסך דף הבית כדי להקל את הגישה אליהן."
"מנוהל בידי הארגון"
"הודעות ואפליקציות כבויות"
+ "סגירה"
+ "סגור"
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 19a9d3cbcc..c5ab31039c 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -40,10 +40,8 @@
"「%1$s」に一致するアプリは見つかりませんでした"
"他のアプリを検索"
"通知"
-
-
-
-
+ "ショートカットを追加するには押し続けます。"
+ "ダブルタップ後に押し続けてショートカットを選択するか、カスタム操作を使用してください。"
"このホーム画面に空きスペースがありません。"
"お気に入りトレイに空きスペースがありません"
"アプリのリスト"
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index c9d4d26cf9..02ca8628ed 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -40,10 +40,8 @@
"„%1$s“-ის თანხვედრი აპები არ მოიძებნა"
"მეტი აპის პოვნა"
"შეტყობინებები"
-
-
-
-
+ "შეეხეთ და დააყოვნეთ მალსახმობის ასარჩევად."
+ "ორმაგად შეეხეთ და გეჭიროთ მალსახმობის ასარჩევად ან მორგებული მოქმედებების გამოსაყენებლად."
"ამ მთავარ ეკრანზე ადგილი აღარ არის."
"რჩეულების თაროზე ადგილი არ არის"
"აპების სია"
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 8a05cc0919..b66fe69a39 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\" сұрауына сәйкес келетін қолданбалар жоқ"
"Қосымша қолданбалар іздеу"
"Хабарландырулар"
-
-
-
-
+ "Таңбашаны таңдау үшін оны басып, ұстап тұрыңыз."
+ "Екі рет басып, ұстап тұрып, таңбашаны таңдаңыз немесе арнаулы әрекеттерді пайдаланыңыз."
"Бұл Негізгі экранда орын қалмады."
"Қалаулылар науасында орын қалмады"
"Қолданбалар тізімі"
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 9b7fa87c23..6b56372160 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -40,10 +40,8 @@
"រកមិនឃើញកម្មវិធីដែលត្រូវគ្នាជាមួយ \"%1$s\" ទេ"
"ស្វែងរកកម្មវិធីច្រើនទៀត"
"ការជូនដំណឹង"
-
-
-
-
+ "ចុចឱ្យជាប់ដើម្បីជ្រើសរើសផ្លូវកាត់មួយ។"
+ "ចុចពីរដង ហើយចុចឱ្យជាប់ដើម្បីជ្រើសរើសផ្លូវកាត់មួយ ឬប្រើសកម្មភាពផ្ទាល់ខ្លួន។"
"គ្មានបន្ទប់នៅលើអេក្រង់ដើមនេះទៀតទេ។"
"គ្មានបន្ទប់ក្នុងថាសនិយមប្រើ"
"បញ្ជីកម្មវិធី"
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 0e314bb121..d4813b5760 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"
"ಮತ್ತಷ್ಟು ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಹುಡುಕಿ"
"ಅಧಿಸೂಚನೆಗಳು"
-
-
-
-
+ "ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಲು ಹೋಲ್ಡ್ ಮಾಡಿ."
+ "ಡಬಲ್ ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಶಾರ್ಟ್ಕಟ್ ಆರಿಸಿಕೊಳ್ಳಲು ಹೋಲ್ಡ್ ಮಾಡಿ ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಿ."
"ಈ ಮುಖಪುಟದ ಪರದೆಯಲ್ಲಿ ಹೆಚ್ಚು ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ."
"ಮೆಚ್ಚಿನವುಗಳ ಟ್ರೇನಲ್ಲಿ ಹೆಚ್ಚಿನ ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ"
"ಅಪ್ಲಿಕೇಶನ್ಗಳ ಪಟ್ಟಿ"
@@ -141,8 +139,6 @@
"ಕೆಲಸದ ಪ್ರತಿ ಅಪ್ಲಿಕೇಶನ್ ಬ್ಯಾಡ್ಜ್ ಹೊಂದಿದೆ ಮತ್ತು ನಿಮ್ಮ ಸಂಸ್ಥೆಯಿಂದ ಸುರಕ್ಷಿತವಾಗಿ ಇರಿಸಲಾಗುತ್ತದೆ. ಸುಲಭ ಪ್ರವೇಶಕ್ಕಾಗಿ ನಿಮ್ಮ ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಸರಿಸಿ."
"ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ಮೂಲಕ ನಿರ್ವಹಿಸಲಾಗಿದೆ"
"ಅಧಿಸೂಚನೆಗಳು ಮತ್ತು ಅಪ್ಲಿಕೇಶನ್ಗಳು ಆಫ್ ಆಗಿವೆ"
-
-
-
-
+ "ಮುಚ್ಚಿ"
+ "ಮುಚ್ಚಲಾಗಿದೆ"
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 60c3e4f6b4..9275abfe1f 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -40,10 +40,8 @@
"\'%1$s\'과(와) 일치하는 앱이 없습니다."
"더 많은 앱 검색"
"알림"
-
-
-
-
+ "바로가기를 선택하려면 길게 터치하세요."
+ "바로가기를 선택하려면 두 번 탭한 다음 길게 터치하거나 맞춤 동작을 사용하세요."
"홈 화면에 더 이상 공간이 없습니다."
"즐겨찾기 트레이에 더 이상 공간이 없습니다."
"앱 목록"
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 84bee66e31..e0e740346a 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\" сурамына дал келген колдонмолор табылган жок"
"Көбүрөөк колдонмолорду издөө"
"Эскертмелер"
-
-
-
-
+ "Кыска жолду тандоо үчүн басып туруңуз."
+ "Кыска жолду тандоо үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."
"Бул Үй экранында бош орун жок."
"Тандамалдар тайпасында орун калган жок"
"Колдонмолор тизмеси"
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 6cf23ad10a..7b5252949a 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -31,9 +31,6 @@
0dp
5.5dp
-
- 2dp
-
0dp
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index bd89e6e926..2b73628978 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -40,10 +40,8 @@
"ບໍ່ພົບແອັບທີ່ກົງກັບ \"%1$s\""
"ຊອກຫາແອັບເພີ່ມເຕີມ"
"ການແຈ້ງເຕືອນ"
-
-
-
-
+ "ແຕະຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ."
+ "ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຮັບປຸ່ມລັດ ຫຼື ໃຊ້ຄຳສັ່ງແບບກຳນົດເອງ."
"ບໍ່ມີຫ້ອງເຫຼືອໃນໜ້າຈໍຫຼັກນີ້."
"ບໍ່ມີບ່ອນຫວ່າງໃນຖາດສຳລັບເກັບສິ່ງທີ່ໃຊ້ເປັນປະຈຳ"
"ລາຍຊື່ແອັບ"
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 3e985cb094..db751dae6a 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -40,9 +40,13 @@
"Nerasta jokių užklausą „%1$s“ atitinkančių programų"
"Ieškoti daugiau programų"
"Pranešimai"
+ "Paliesk. ir palaikyk., kad pasirinkt. spart. klav."
+ "Dukart palieskite ir palaikykite, kad pasirinkt. spartųjį klavišą ar naudotumėte tinkintus veiksmus."
"Šiame pagrindiniame ekrane vietos nebėra."
"Mėgstamiausių dėkle nebėra vietos"
"Programų sąrašas"
+ "Asmeninių programų sąrašas"
+ "Darbo programų sąrašas"
"Pagrindinis"
"Ištrinti"
"Pašalinti"
@@ -79,19 +83,17 @@
"Ekrano fonai"
"„Home“ nustatymai"
"Išjungė administratorius"
- "Apžvalga"
- "Leisti pasukti pagrindinį ekraną"
- "Kai telefonas pasukamas"
- "Naudojant dabartinį pateikties nustatymą neleidžiama pasukti"
"Pranešimų taškai"
"Įjungta"
"Išjungta"
"Reikalinga prieiga prie pranešimų"
"Kad būtų rodomi pranešimų taškai, įjunkite programos „%1$s“ pranešimus."
"Keisti nustatymus"
+ "Rodyti pranešimų taškus"
"Pridėti piktogr. prie pagrindinio ekrano"
"Skirta naujoms programoms"
"Pakeisti piktogramos formą"
+ "pagrindiniame ekrane"
"Naudoti numatytuosius sistemos nustatymus"
"Kvadratas"
"Kvadratais suapvalintais kampais"
@@ -121,9 +123,6 @@
"Kurti aplanką naudojant: „%1$s“"
"Aplankas sukurtas"
"Perkelti į pagrindinį ekraną"
- "Perkelti ekraną į kairę"
- "Perkelti ekraną į dešinę"
- "Ekranas perkeltas"
"Pakeisti dydį"
"Padidinti plotį"
"Padidinti aukštį"
@@ -139,8 +138,9 @@
"Darbo"
"Darbo profilis"
"Darbo programas rasite čia"
-
-
+ "Kiekvienai darbo programai priskirtas ženklelis, o tokių programų sauga rūpinasi jūsų organizacija. Perkelkite programas į pagrindinį ekraną, kad galėtumėte lengviau jas pasiekti."
"Tvarko jūsų organizacija"
"Programos ir pranešimai išjungti"
+ "Uždaryti"
+ "Uždaryta"
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 6a9d15791b..a6e16deeef 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -40,9 +40,13 @@
"Vaicājumam “%1$s” neatbilda neviena lietotne"
"Meklēt citas lietotnes"
"Paziņojumi"
+ "Lai atlasītu saīsni, pieskarieties un turiet to."
+ "Lai atlasītu saīsni, veiciet dubultskārienu uz tās un turiet to. Varat arī veikt pielāgotas darbības."
"Šajā sākuma ekrānā vairs nav vietas."
"Izlases joslā vairs nav vietas."
"Lietotņu saraksts"
+ "Personīgo lietotņu saraksts"
+ "Darba lietotņu saraksts"
"Sākums"
"Noņemt"
"Atinstalēt"
@@ -78,19 +82,17 @@
"Fona tapetes"
"Sākumlapas iestatījumi"
"Atspējojis administrators"
- "Kopsavilkums"
- "Atļaut sākuma ekrāna pagriešanu"
- "Pagriežot tālruni"
- "Pašreizējā displeja iestatījumā nav atļauta pagriešana."
"Paziņojumu punkti"
"Ieslēgts"
"Izslēgts"
"Nepieciešama piekļuve paziņojumiem"
"Lai tiktu rādīti paziņojumu punkti, ieslēdziet paziņojumus lietotnei %1$s."
"Mainīt iestatījumus"
+ "Rādīt paziņojumu punktus"
"Pievienot ikonu sākuma ekrānā"
"Jaunām lietotnēm"
"Mainīt ikonu formu"
+ "sākuma ekrānā"
"Izmantot sistēmas noklusējumu"
"Kvadrāts"
"Kvadrāts ar noapaļotiem stūriem"
@@ -120,9 +122,6 @@
"Izveidot mapi ar: %1$s"
"Mape izveidota"
"Pārvietot uz sākuma ekrānu"
- "Pārvietot ekrānu pa kreisi"
- "Pārvietot ekrānu pa labi"
- "Ekrāns pārvietots"
"Mainīt lielumu"
"Palielināt platumu"
"Palielināt augstumu"
@@ -138,8 +137,9 @@
"Darba lietotnes"
"Darba profils"
"Meklējiet darba lietotnes šeit"
-
-
+ "Katrai darba lietotnei ir emblēma, un jūsu organizācija aizsargā šīs lietotnes. Lai varētu ērtāk piekļūt lietotnēm, pārvietojiet tās uz sākuma ekrānu."
"Pārvalda jūsu organizācija"
"Paziņojumi un lietotnes ir izslēgtas"
+ "Aizvērt"
+ "Aizvērta"
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 9eedfeb881..29e837b27c 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -40,10 +40,8 @@
"Не се најдени апликации што одговараат на „%1$s“"
"Пребарај други апликации"
"Известувања"
-
-
-
-
+ "Допрете двапати и задржете за избор на кратенка."
+ "Допрете двапати и задржете за избор на кратенка или користете приспособени дејства."
"Нема повеќе простор на овој екран на почетната страница."
"Нема повеќе простор на лентата „Омилени“"
"Список со апликации"
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 9455688038..5ccac13e4a 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\" എന്നതുമായി പൊരുത്തപ്പെടുന്ന ആപ്പുകളൊന്നും കണ്ടെത്തിയില്ല"
"കൂടുതൽ ആപ്പുകൾക്ക് തിരയുക"
"അറിയിപ്പുകൾ"
-
-
-
-
+ "തിരഞ്ഞെടുക്കുന്നതിന് കുറുക്കുവഴി സ്പർശിച്ച് പിടിക്കുക."
+ "കുറുക്കുവഴി തിരഞ്ഞെടുക്കാനോ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കാനോ 2 തവണ ടാപ്പ് ചെയ്ത് പിടിക്കുക."
"ഈ ഹോം സ്ക്രീനിൽ ഒഴിവൊന്നുമില്ല."
"പ്രിയപ്പെട്ടവയുടെ ട്രേയിൽ ഒഴിവൊന്നുമില്ല"
"അപ്ലിക്കേഷനുകളുടെ ലിസ്റ്റ്"
@@ -141,8 +139,6 @@
"എല്ലാ ഔദ്യോഗിക ആപ്പിനും ഒരു ബാഡ്ജ് ഉണ്ട്, നിങ്ങളുടെ സ്ഥാപനം അത് സുരക്ഷിതമായി സൂക്ഷിക്കുന്നു. എളുപ്പത്തിൽ ആക്സസ് ചെയ്യാൻ ആപ്പുകളെ ഹോം സ്ക്രീനിലേക്ക് നീക്കുക."
"നിങ്ങളുടെ സ്ഥാപനം നിയന്ത്രിക്കുന്നത്"
"അറിയിപ്പുകളും ആപ്പുകളും ഓഫാണ്"
-
-
-
-
+ "അടയ്ക്കുക"
+ "അടച്ചു"
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 7d0c0ef2ca..7c0b00ec7b 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\"-д тохирох апп олдсонгүй"
"Бусад апп-г хайх"
"Мэдэгдэл"
-
-
-
-
+ "Товчлол авах бол удаан дарна уу."
+ "Товчлол авах эсвэл тохируулсан үйлдлийг ашиглахын тулд давхар товшоод хүлээнэ үү."
"Энэ Нүүр дэлгэц зайгүй."
"\"Дуртай\" трей дээр өөр зай байхгүй байна"
"Апп-н жагсаалт"
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index d843d37082..0e2f9c808c 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"
"अधिक अॅप्स शोधा"
"सूचना"
-
-
-
-
+ "शॉर्टकट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."
+ "शॉर्टकट निवडण्यासाठी किंवा कस्टम क्रिया वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."
"या मुख्य स्क्रीनवर आणखी जागा नाही."
"आवडीच्या ट्रे मध्ये आणखी जागा नाही"
"अॅप्स सूची"
@@ -141,8 +139,6 @@
"प्रत्येक कार्य अॅपला एक बॅज असतो आणि तो तुमच्या संस्थेकडून सुरक्षित ठेवला जातो. अधिक सहज अॅक्सेससाठी अॅप्स तुमच्या होम स्क्रीनवर हलवा."
"तुमच्या संस्थेकडून व्यवस्थापित"
"सूचना आणि अॅप्स बंद आहेत"
-
-
-
-
+ "बंद करा"
+ "बंद केले"
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index d403de0629..130e008389 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -40,10 +40,8 @@
"Tiada apl yang ditemui sepadan dengan \"%1$s\""
"Cari lagi apl"
"Pemberitahuan"
-
-
-
-
+ "Sentuh & tahan untuk mengambil pintasan."
+ "Ketik dua kali & tahan untuk mengambil pintasan atau menggunakan tindakan tersuai."
"Tiada lagi ruang pada skrin Laman Utama ini."
"Tiada ruang dalam dulang Kegemaran lagi"
"Senarai apl"
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 3c2d91f572..778402ac27 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\" နှင့်ကိုက်ညီသည့် အပ်ပ်များကို မတွေ့ပါ"
"နောက်ထပ် အက်ပ်များကို ရှာပါ"
"အကြောင်းကြားချက်များ"
-
-
-
-
+ "ဖြတ်လမ်းလင့်ခ်တစ်ခုကို ရွေးရန် ထိပြီး ဖိထားပါ။"
+ "ဖြတ်လမ်းလင့်ခ်ကို ရွေးရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန် နှစ်ချက်တို့ပြီး ဖိထားပါ။"
"ဤပင်မမျက်နှာစာတွင် နေရာလွတ် မကျန်တော့ပါ"
"အနှစ်သက်ဆုံးများ ထားရာတွင် နေရာလွတ် မကျန်တော့ပါ"
"အက်ပ်စာရင်း"
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index f7cac37dad..5542079640 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -40,10 +40,8 @@
"Fant ingen apper som samsvarer med «%1$s»"
"Søk etter flere apper"
"Varsler"
-
-
-
-
+ "Trykk og hold for å velge en snarvei."
+ "Dobbelttrykk og hold for å velge en snarvei eller bruke tilpassede handlinger."
"Denne startsiden er full."
"Favoritter-skuffen er full"
"App-liste"
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index e7990c88b7..fa2f9cf0b8 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\" सँग मिल्दो कुनै अनुप्रयोग भेटिएन"
"थप अनुप्रयोगहरू खोज्नुहोस्"
"सूचनाहरू"
-
-
-
-
+ "कुनै सर्टकट छनौट गर्न छोइराख्नुहोस्।"
+ "कुनै सर्टकट छनौट गर्न वा रोजेका कारबाहीहरू प्रयोग गर्न डबल ट्याप गरेर छोइराख्नुहोस्।"
"यो गृह स्क्रिनमा कुनै थप ठाउँ छैन।"
"मनपर्ने ट्रे अब कुनै ठाँउ छैन"
"अनुप्रयोगको सूची"
@@ -141,8 +139,6 @@
"कार्यसम्बन्धी प्रत्येक अनुप्रयोगमा एउटा ब्याज छ र तपाईंको संगठनले यसलाई सुरक्षित राखेको छ । अझ सजिलो गरी पहुँच राख्नका लागि अनुप्रयोगहरूलाई आफ्नो गृहस्क्रिनमा सार्नुहोस्।"
"तपाईंको सङ्गठनले व्यवस्थापन गरेको"
"सूचना र अनुप्रयोगहरू निष्क्रिय छन्"
-
-
-
-
+ "बन्द गर्नुहोस्"
+ "बन्द गरियो"
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index b926a8d747..458b6dd993 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -40,10 +40,8 @@
"Er zijn geen apps gevonden die overeenkomen met \'%1$s\'"
"Zoeken naar meer apps"
"Meldingen"
-
-
-
-
+ "Tik en houd vast om snelkoppeling toe te voegen."
+ "Dubbeltik en houd vast om een snelkoppeling toe te voegen of aangepaste acties te gebruiken."
"Er is geen ruimte meer op dit startscherm."
"Geen ruimte meer in het vak \'Favorieten\'"
"Lijst met apps"
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 26de62ac6b..02424031bf 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\" ਨਾਲ ਮੇਲ ਖਾਂਦੀਆਂ ਕੋਈ ਐਪਾਂ ਨਹੀਂ ਮਿਲੀਆਂ"
"ਹੋਰ ਐਪਾਂ ਖੋਜੋ"
"ਸੂਚਨਾਵਾਂ"
-
-
-
-
+ "ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਸਪੱਰਸ਼ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ।"
+ "ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਡਬਲ ਟੈਪ ਕਰਕੇ ਦਬਾਈ ਰੱਖੋ ਜਾਂ ਵਿਉਂਤੀਆਂ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।"
"ਇਸ ਹੋਮ ਸਕ੍ਰੀਨ ਲਈ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ ਹੈ।"
"ਮਨਪਸੰਦ ਟ੍ਰੇ ਵਿੱਚ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ।"
"ਐਪ ਸੂਚੀ"
@@ -141,8 +139,6 @@
"ਹਰੇਕ ਕਾਰਜ-ਸਥਾਨ ਐਪ ਦਾ ਇੱਕ ਬੈਜ ਹੁੰਦਾ ਹੈ ਅਤੇ ਉਸਨੂੰ ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਸੁਰੱਖਿਅਤ ਰੱਖਿਆ ਜਾਂਦਾ ਹੈ। ਵਧੇਰੇ ਆਸਾਨ ਪਹੁੰਚ ਲਈ ਐਪਾਂ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਲਿਜਾਓ।"
"ਤੁਹਾਡੀ ਸੰਸਥਾ ਵੱਲੋਂ ਪ੍ਰਬੰਧਿਤ ਕੀਤਾ ਜਾਂਦਾ ਹੈ"
"ਸੂਚਨਾਵਾਂ ਅਤੇ ਐਪਾਂ ਬੰਦ ਹਨ"
-
-
-
-
+ "ਬੰਦ ਕਰੋ"
+ "ਬੰਦ ਕੀਤਾ ਗਿਆ"
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index e9b4cc93d8..558fab2590 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -40,6 +40,8 @@
"Nie znaleziono aplikacji pasujących do zapytania „%1$s”"
"Wyszukaj więcej aplikacji"
"Powiadomienia"
+ "Kliknij i przytrzymaj, by wybrać skrót."
+ "Kliknij dwukrotnie i przytrzymaj, by wybrać skrót lub użyć działań niestandardowych."
"Brak miejsca na tym ekranie głównym."
"Brak miejsca w Ulubionych"
"Lista aplikacji"
@@ -139,4 +141,6 @@
"Każda aplikacja do pracy ma plakietkę, a o jej bezpieczeństwo dba Twoja organizacja. Aplikacje można przenieść na ekran główny, by były łatwiej dostępne."
"Profil zarządzany przez Twoją organizację"
"Powiadomienia i aplikacje są wyłączone"
+ "Zamknij"
+ "Zamknięto"
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 9517baf035..0d3224d39d 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -40,10 +40,8 @@
"Nenhuma aplicação correspondente a \"%1$s\""
"Pesquisar mais aplicações"
"Notificações"
-
-
-
-
+ "Toque sem soltar para escolher um atalho."
+ "Toque duas vezes sem soltar para escolher um atalho ou utilize ações personalizadas."
"Sem espaço suficiente neste Ecrã principal."
"Não existe mais espaço no tabuleiro de Favoritos"
"Lista de aplicações"
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 48e37efb64..73dad35bbb 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -40,9 +40,13 @@
"Nenhum app encontrado que corresponda a \"%1$s\""
"Pesquisar mais apps"
"Notificações"
+ "Toque e segure para selecionar um atalho."
+ "Toque duas vezes na tela e segure para selecionar um atalho ou usar ações personalizadas."
"Não há mais espaço na tela inicial."
"Sem espaço na bandeja de favoritos"
"Lista de apps"
+ "Lista de apps pessoais"
+ "Lista de apps profissionais"
"Início"
"Remover"
"Desinstalar"
@@ -77,19 +81,17 @@
"Planos de fundo"
"Configurações da página inicial"
"Desativado pelo administrador"
- "Visão geral"
- "Permitir rotação da tela inicial"
- "Quando o smartphone for girado"
- "A configuração atual de exibição não permite rotação"
"Pontos de notificação"
"Ativado"
"Desativado"
"Acesso a notificações necessário"
"Para mostrar pontos de notificação, ative as notificações de app para %1$s"
"Alterar configurações"
+ "Mostrar pontos de notificação"
"Adicionar ícone à tela inicial"
"Para novos apps"
"Alterar forma de ícones"
+ "na tela inicial"
"Usar padrão do sistema"
"Quadrado"
"Quadrado arredondado"
@@ -119,9 +121,6 @@
"Criar pasta com: %1$s"
"Pasta criada"
"Mover para a tela inicial"
- "Mover tela para a esquerda"
- "Mover tela para a direita"
- "Tela movida"
"Redimensionar"
"Aumentar largura"
"Aumentar altura"
@@ -137,8 +136,9 @@
"Comerciais"
"Perfil de trabalho"
"Localizar apps de trabalho aqui"
-
-
+ "Cada app de trabalho tem um selo e é mantido em segurança pela sua organização. Mova os apps para sua tela inicial para facilitar o acesso."
"Gerenciados pela sua organização"
"As notificações e os apps estão desativados"
+ "Fechar"
+ "Fechado"
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 88118d9fe7..500512ac31 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -40,10 +40,8 @@
"Nu s-a găsit nicio aplicație pentru „%1$s\""
"Căutați mai multe aplicații"
"Notificări"
-
-
-
-
+ "Atingeți lung pentru a selecta o comandă rapidă."
+ "Atingeți lung pentru a selecta o comandă rapidă sau folosiți acțiuni personalizate."
"Nu mai este loc pe acest Ecran de pornire."
"Spațiu epuizat în bara Preferate"
"Lista de aplicații"
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 10490f38b5..d04ca5c04a 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -40,9 +40,13 @@
"По запросу \"%1$s\" ничего не найдено"
"Искать другие приложения"
"Уведомления"
+ "Нажмите и удерживайте, чтобы выбрать ярлык."
+ "Нажмите дважды и удерживайте, чтобы выбрать ярлык или использовать специальные действия."
"На этом экране все занято"
"В разделе \"Избранное\" больше нет места"
"Список приложений"
+ "Открыть список личных приложений"
+ "Открыть список приложений для работы"
"Главный экран"
"Убрать"
"Удалить"
@@ -79,19 +83,17 @@
"Обои"
"Настройки главного экрана"
"Функция отключена администратором"
- "Обзор"
- "Разрешить поворачивать главный экран"
- "Когда телефон повернут"
- "В настройках отключен поворот экрана"
"Значки уведомлений"
"ВКЛ"
"ВЫКЛ"
"Нет доступа к уведомлениям"
"Чтобы показывать значки уведомлений, включите уведомления в приложении \"%1$s\""
"Изменить настройки"
+ "Показывать значки уведомлений"
"Добавлять значки"
"Добавлять значки установленных приложений на главный экран."
"Изменить форму значков"
+ "на главном экране"
"Использовать системные настройки по умолчанию"
"Квадрат"
"Квадрат с закругленными краями"
@@ -121,9 +123,6 @@
"Создать папку с элементом %1$s."
"Папка создана."
"Переместить на главный экран"
- "Переместить экран влево"
- "Переместить экран вправо"
- "Экран перемещен"
"Изменить размер"
"Увеличить ширину"
"Увеличить высоту"
@@ -139,8 +138,9 @@
"Рабочие"
"Рабочий профиль"
"Приложения для работы"
-
-
+ "Рабочие приложения отмечены специальным значком. Их безопасность обеспечивает ваша организация. Для удобства перенесите эти приложения на главный экран."
"Управляется вашей организацией"
"Уведомления и приложения отключены."
+ "Закрыть"
+ "Закрыта"
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index f1ffba4a4b..7a4771e611 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\" සමග ගැළපෙන යෙදුම් හමු නොවිණි"
"තව යෙදුම් සඳහා සොයන්න"
"දැනුම්දීම්"
-
-
-
-
+ "කෙටි මගක් තෝරා ගැනීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න."
+ "විජට් එකක් තෝරා ගැනීමට හෝ අභිරුචි භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."
"මෙම මුල් පිටු තිරය මත තවත් අවසර නැත."
"ප්රියතම දෑ ඇති තැටියේ තවත් ඉඩ නොමැත"
"යෙදුම් ලැයිස්තුව"
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 546787f9a5..4d90dee09f 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -40,10 +40,8 @@
"Nenašli sa žiadne aplikácie zodpovedajúce dopytu %1$s"
"Hľadať ďalšie aplikácie"
"Upozornenia"
-
-
-
-
+ "Skratku pridáte pridržaním."
+ "Skratku pridáte dvojitým klepnutím a pridržaním alebo pomocou vlastných akcií."
"Na tejto ploche už nie je miesto"
"Na paneli Obľúbené položky už nie je miesto"
"Zoznam aplikácií"
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 488295e9d4..82b79125b4 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -40,10 +40,8 @@
"Ni aplikacij, ki bi ustrezale poizvedbi »%1$s«"
"Iskanje več aplikacij"
"Obvestila"
-
-
-
-
+ "Pridržite bližnjico, da jo izberete."
+ "Dvakrat se dotaknite bližnjice in jo pridržite, da jo izberete, ali pa uporabite dejanja po meri."
"Na tem začetnem zaslonu ni več prostora."
"V vrstici za priljubljene ni več prostora"
"Seznam aplikacij"
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 8d58d1c2de..a4ad7a0543 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -40,10 +40,8 @@
"Nuk u gjet asnjë aplikacion që përputhet me \"%1$s\""
"Kërko për më shumë aplikacione"
"Njoftimet"
-
-
-
-
+ "Prek dhe mbaj prekur për të zgjedhur një shkurtore."
+ "Prek dy herë dhe mbaj prekur për të zgjedhur një shkurtore ose për të përdorur veprimet e personalizuara."
"Nuk ka më hapësirë në këtë ekran bazë."
"Nuk ka më hapësirë në tabakanë \"Të preferuarat\""
"Lista e aplikacioneve"
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index c190e758e1..3ae87f9e55 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -40,9 +40,13 @@
"Није пронађена ниједна апликација за „%1$s“"
"Претражи још апликација"
"Обавештења"
+ "Додирните и задржите да бисте изабрали пречицу."
+ "Двапут додирните и задржите да бисте изабрали пречицу или користите прилагођене радње."
"Нема више простора на овом почетном екрану."
"Нема више простора на траци Омиљено"
"Листа апликација"
+ "Листа личних апликација"
+ "Листа пословних апликација"
"Почетна"
"Уклони"
"Деинсталирај"
@@ -78,19 +82,17 @@
"Позадине"
"Подешавања почетног екрана"
"Администратор је онемогућио"
- "Преглед"
- "Дозволи ротацију почетног екрана"
- "Када се телефон ротира"
- "Актуелно подешавање приказа не дозвољава ротацију"
"Тачке за обавештења"
"Укључено"
"Искључено"
"Потребан је приступ за обавештења"
"Да бисте приказали тачке за обавештења, укључите обавештења за апликацију %1$s"
"Промените подешавања"
+ "Приказуј тачке за обавештења"
"Додај икону на почетни екран"
"За нове апликације"
"Промените облик икона"
+ "на почетном екрану"
"Користи подразумевано системско подешавање"
"Квадрат"
"Заобљени квадрат"
@@ -120,9 +122,6 @@
"Направите директоријум са: %1$s"
"Директоријум је направљен"
"Премести на почетни екран"
- "Помери екран улево"
- "Помери екран удесно"
- "Екран је померен"
"Промени величину"
"Повећај ширину"
"Повећај висину"
@@ -138,8 +137,9 @@
"Пословне"
"Профил за Work"
"Пронађите пословне апликације овде"
-
-
+ "Свака пословна апликација има значку и штити је ваша организација. Преместите апликације на почетни екран да бисте им лакше приступали."
"Овим управља организација"
"Обавештења и апликације су искључени"
+ "Затвори"
+ "Затворено"
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index e58e1987a7..3c91c30b66 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -40,10 +40,8 @@
"Inga appar som matchar %1$s hittades"
"Sök efter fler appar"
"Aviseringar"
-
-
-
-
+ "Tryck länge om du vill ta upp en genväg."
+ "Tryck snabbt två gånger och håll kvar om du vill ta upp en genväg eller använda anpassade åtgärder."
"Det finns inte plats för mer på den här startskärmen."
"Favoritfältet är fullt"
"Applista"
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 80666e97c2..61d7f8bed3 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -40,10 +40,8 @@
"Haikupata programu zozote zinazolingana na \"%1$s\""
"Tafuta programu zaidi"
"Arifa"
-
-
-
-
+ "Gusa na ushikilie ili uchague njia ya mkato."
+ "Gusa mara mbili na ushikilie ili uchague njia ya mkato au utumie vitendo maalum."
"Hakuna nafasi katika skrini hii ya Mwanzo."
"Hakuna nafasi zaidi katika treya ya Vipendeleo"
"Orodha ya programu"
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 8a7d66622e..13358c09ce 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -141,8 +141,6 @@
"ஒவ்வொரு பணிப் பயன்பாடும் ஒரு பேட்ஜைக் கொண்டிருக்கும். இவை, ஆப்ஸ் உங்கள் நிறுவனத்தால் பாதுகாப்பாக வைக்கப்பட்டுள்ளன என்பதைக் குறிக்கின்றன. இந்த ஆப்ஸை எளிதாக அணுக, முகப்புத் திரைக்கு நகர்த்திக்கொள்ளவும்."
"உங்கள் நிறுவனம் நிர்வகிக்கிறது"
"ஆப்ஸும் அறிவிப்புகளும் ஆஃப் செய்யப்பட்டுள்ளன"
-
-
-
-
+ "மூடுக"
+ "மூடப்பட்டது"
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index b69afdc4e6..3f1762d00d 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\"కి సరిపోలే అప్లికేషన్లేవీ కనుగొనబడలేదు"
"మరిన్ని యాప్ల కోసం వెతుకు"
"నోటిఫికేషన్లు"
-
-
-
-
+ "షార్ట్కట్ని ఎంచుకోవడం కోసం నొక్కి, పట్టుకోండి."
+ "రెండుసార్లు నొక్కి, పట్టుకోవడం ద్వారా షార్ట్కట్ని ఎంచుకోండి లేదా అనుకూల చర్యలను ఉపయోగించండి."
"ఈ హోమ్ స్క్రీన్లో ఖాళీ లేదు."
"ఇష్టమైనవి ట్రేలో ఖాళీ లేదు"
"అనువర్తనాల జాబితా"
@@ -141,8 +139,6 @@
"ప్రతి కార్యాలయ యాప్కు బ్యాడ్జ్ ఉంది మరియు మీ సంస్థ ద్వారా సురక్షితంగా ఉంచబడుతుంది. సులభ యాక్సెస్ కోసం యాప్లను మీ హోమ్ స్క్రీన్కి తరలించండి."
"మీ సంస్థ ద్వారా నిర్వహించబడతాయి"
"నోటిఫికేషన్లు మరియు యాప్లు ఆఫ్ చేయబడ్డాయి"
-
-
-
-
+ "మూసివేయి"
+ "మూసివేయబడింది"
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index c032305af8..cac2333509 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -40,10 +40,8 @@
"ไม่พบแอปที่ตรงกับ \"%1$s\""
"ค้นหาแอปเพิ่มเติม"
"การแจ้งเตือน"
-
-
-
-
+ "แตะค้างไว้เพื่อเลือกทางลัด"
+ "แตะสองครั้งค้างไว้เพื่อเลือกทางลัดหรือใช้การกระทำที่กำหนดเอง"
"ไม่มีที่ว่างในหน้าจอหลักนี้"
"ไม่มีพื้นที่เหลือในถาดรายการโปรด"
"รายชื่อแอป"
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index d0a820d917..0b90214225 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -40,9 +40,13 @@
"Walang nahanap na app na tumutugma sa \"%1$s\""
"Maghanap ng higit pang mga app"
"Mga Notification"
+ "Pindutin nang matagal para kumuha ng shortcut."
+ "I-double tap nang matagal para kumuha ng shortcut o gumamit ng mga custom na pagkilos."
"Wala nang lugar sa Home screen na ito."
"Wala nang lugar sa tray ng Mga Paborito"
"Listahan ng mga app"
+ "Listahan ng mga personal na app"
+ "Listahan ng mga app sa trabaho"
"Home"
"Alisin"
"I-uninstall"
@@ -77,19 +81,17 @@
"Mga Wallpaper"
"Mga setting ng Home"
"Na-disable ng iyong admin"
- "Pangkalahatang-ideya"
- "Payagan ang pag-rotate ng Home screen"
- "Kailan maro-rotate ang telepono"
- "Hindi pinahihintulutan ng kasalukuyang setting ng Display ang pag-rotate"
"Mga notification dot"
"Naka-on"
"Naka-off"
"Kinakailangan ng access sa notification"
"Upang ipakita ang Mga Notification Dot, i-on ang mga notification ng app para sa %1$s"
"Baguhin ang mga setting"
+ "Ipakita ang mga notification dot"
"Idagdag ang icon sa Home screen"
"Para sa mga bagong app"
"Baguhin ang hugis ng icon"
+ "sa Home screen"
"Gamitin ang default ng system"
"Parisukat"
"Squircle"
@@ -119,9 +121,6 @@
"Gumawa ng folder na may: %1$s"
"Nagawa ang folder"
"Ilipat sa Home screen"
- "Ilipat sa kaliwa ang screen"
- "Ilipat sa kanan ang screen"
- "Nailipat ang screen"
"I-resize"
"Dagdagan ang lapad"
"Dagdagan ang taas"
@@ -137,8 +136,9 @@
"Trabaho"
"Profile sa trabaho"
"Maghanap ng mga app para sa trabaho rito"
-
-
+ "Ang bawat app para sa trabaho ay may badge at pinapanatiling ligtas ng iyong organisasyon. Ilipat ang mga app sa iyong Home screen para mas madaling ma-access."
"Pinamamahalaan ng iyong organisasyon"
"Naka-off ang mga notification at app"
+ "Isara"
+ "Nakasara"
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 22e6bda95f..972554424c 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\" ile eşleşen uygulama bulunamadı"
"Başka uygulamalar ara"
"Bildirimler"
-
-
-
-
+ "Kısayol seçmek için dokunun ve basılı tutun."
+ "Bir kısayolu seçmek veya özel işlemleri kullanmak için iki kez dokunun ve basılı tutun."
"Bu Ana ekranda yer kalmadı."
"Favoriler tepsisinde başka yer kalmadı"
"Uygulamalar listesi"
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 095ff5ba30..47ddc7c944 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -40,9 +40,13 @@
"Немає додатків для запиту \"%1$s\""
"Шукати ще додатки"
"Сповіщення"
+ "Натисніть і втримуйте, щоб вибрати ярлик."
+ "Двічі натисніть і втримуйте, щоб вибрати ярлик, або виконайте іншу дію."
"На цьому головному екрані більше немає місця."
"В області \"Вибране\" немає місця"
"Список додатків"
+ "Список особистих додатків"
+ "Список робочих додатків"
"Головний екран"
"Видалити"
"Видалити"
@@ -79,19 +83,17 @@
"Фонові малюнки"
"Налаштування Home"
"Вимкнув адміністратор"
- "Огляд"
- "Дозволити обертання головного екрана"
- "Коли телефон обертається"
- "Поточні налаштування дисплея не підтримують обертання"
"Значки сповіщень"
"Увімкнено"
"Вимкнено"
"Потрібен доступ до сповіщень"
"Щоб показувати значки сповіщень, увімкніть сповіщення в додатку %1$s"
"Змінити налаштування"
+ "Показувати значки сповіщень"
"Додати значок на головний екран"
"Для нових додатків"
"Змінити форму значка"
+ "на головному екрані"
"Використовувати налаштування системи за умовчанням"
"Квадрат"
"Квадрат із заокругленими кутами"
@@ -121,9 +123,6 @@
"Створити папку з: %1$s"
"Папку створено"
"Перемістити на головний екран"
- "Перемістити екран ліворуч"
- "Перемістити екран праворуч"
- "Екран переміщено"
"Змінити розміри"
"Збільшити ширину"
"Збільшити висоту"
@@ -139,8 +138,9 @@
"Робочі додатки"
"Робочий профіль"
"Робочі додатки містяться тут"
-
-
+ "Кожний робочий додаток має значок і перебуває під захистом організації. Перенесіть додатки на головний екран, щоб швидко запускати їх."
"Профілем керує ваша організація"
"Сповіщення та додатки вимкнено"
+ "Закрити"
+ "Закрито"
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 0344cc0d2f..2558076469 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -40,10 +40,8 @@
"\"%1$s\" سے مماثل کوئی ایپس نہیں ملیں"
"مزید ایپس تلاش کریں"
"اطلاعات"
-
-
-
-
+ "ایک شارٹ کٹ منتخب کرنے کیلئے ٹچ کر کے دبائے رکھیں۔"
+ "ایک شارٹ کٹ منتخب کرنے یا حسب ضرورت کارروائیاں استعمال کرنے کیلئے دو بار تھپتھپائیں اور دبائے رکھیں۔"
"اس ہوم اسکرین پر مزید کوئی گنجائش نہیں ہے۔"
"پسندیدہ ٹرے میں مزید کوئی گنجائش نہیں ہے"
"ایپس کی فہرست"
@@ -141,8 +139,6 @@
"ہر دفتری ایپ میں ایک بَیج ہوتا ہے اور اسے آپ کی تنظیم محفوظ رکھتی ہے۔ زیادہ آسان رسائی کیلئے ایپس کو اپنی ہوم اسکرین پر منتقل کریں۔"
"آپ کی تنظیم کے زیر انتظام"
"اطلاعات اور ایپس آف ہیں"
-
-
-
-
+ "بند کریں"
+ "بند"
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index ea4cf6d475..e9f36a842a 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -40,10 +40,8 @@
"“%1$s” bilan mos hech qanday ilova topilmadi"
"Boshqa ilovalarni qidirish"
"Bildirishnomalar"
-
-
-
-
+ "Yorliqni tanlab olish uchun bosib turing."
+ "Ikki marta bosib va bosib turgan holatda yorliqni tanlang yoki maxsus amaldan foydalaning."
"Uy ekranida bitta ham xona yo‘q."
"Ajratilganlarda birorta ham xona yo‘q"
"Ilovalar ro‘yxati"
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 27a9f80d01..65a5eccf82 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -40,10 +40,8 @@
"Không tìm thấy ứng dụng nào phù hợp với \"%1$s\""
"Tìm kiếm thêm ứng dụng"
"Thông báo"
-
-
-
-
+ "Chạm và giữ để chọn lối tắt."
+ "Nhấn đúp và giữ để chọn lối tắt hoặc sử dụng hành động tùy chỉnh."
"Không còn chỗ trên Màn hình chính này."
"Không còn chỗ trong khay Mục yêu thích"
"Danh sách ứng dụng"
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 694125711d..f8dd3cd05f 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -40,9 +40,13 @@
"未找到与“%1$s”相符的应用"
"搜索更多应用"
"通知"
+ "触摸并按住快捷方式即可选择快捷方式。"
+ "点按两次并按住快捷方式即可选择快捷方式,您也可以使用自定义操作。"
"此主屏幕上已没有空间。"
"收藏栏已满"
"应用列表"
+ "个人应用列表"
+ "工作应用列表"
"主屏幕"
"移除"
"卸载"
@@ -77,19 +81,17 @@
"壁纸"
"主屏幕设置"
"已被您的管理员停用"
- "概览"
- "允许旋转主屏幕"
- "手机旋转时"
- "当前的显示设置不允许旋转设备"
"通知圆点"
"开启"
"关闭"
"需要获取通知使用权"
"要显示通知圆点,请开启%1$s的应用通知功能"
"更改设置"
+ "显示通知圆点"
"将图标添加到主屏幕"
"适用于新应用"
"更改图标形状"
+ "在主屏幕上"
"使用系统默认设置"
"方形"
"方圆形"
@@ -119,9 +121,6 @@
"创建“%1$s”文件夹"
"文件夹已创建"
"移至主屏幕"
- "将屏幕向左移动"
- "将屏幕向右移动"
- "屏幕已移动"
"调整大小"
"增加宽度"
"增加高度"
@@ -137,8 +136,9 @@
"工作"
"工作资料"
"请在此处查找工作应用"
-
-
+ "每个工作应用均有一个徽标,并由贵单位负责确保其安全。请将工作应用移到主屏幕,以便轻松访问。"
"由贵单位管理"
"通知和应用均已关闭"
+ "关闭"
+ "已关闭"
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 85d644af54..4828006cbb 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -40,10 +40,8 @@
"找不到與「%1$s」相符的應用程式"
"搜尋更多應用程式"
"通知"
-
-
-
-
+ "按住捷徑即可選取。"
+ "撳兩下之後撳住,就可以揀選捷徑或者用自訂嘅操作。"
"主畫面已無空間。"
"我的收藏寄存區沒有足夠空間"
"應用程式清單"
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 07917b649d..1a8d515348 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -40,10 +40,8 @@
"找不到與「%1$s」相符的應用程式"
"搜尋更多應用程式"
"通知"
-
-
-
-
+ "按住捷徑即可選取。"
+ "輕觸兩下並按住捷徑即可選取,你也可以使用自訂動作。"
"這個主螢幕已無空間。"
"「我的最愛」匣已無可用空間"
"應用程式清單"
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 323144bd23..126145eac5 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -40,9 +40,13 @@
"Azikho izinhlelo zokusebenza ezitholiwe ezifana ne-\"%1$s\""
"Sesha izinhlelo zokusebenza eziningi"
"Izaziso"
+ "Thinta futhi ubambe ukuze ukhethe isinqamuleli."
+ "Thepha kabili uphinde ubambe ukuze uphakamise isinqamuleli noma usebenzise izenzo zangokwezifiso."
"Asisekho isikhala kulesi sikrini Sasekhaya."
"Asisekho isikhala kwitreyi lezintandokazi"
"Uhlu lwezinhlelo zokusebenza"
+ "Uhlu lwezinhlelo zokusebenza zomuntu siqu"
+ "Uhlu lwezinhlelo zokusebenza zomsebenzi"
"Ikhaya"
"Susa"
"Khipha"
@@ -77,19 +81,17 @@
"Izithombe zangemuva"
"Izilungiselelo zasekhaya"
"Kukhutshazwe umlawuli wakho"
- "Ukubuka konke"
- "Vumela ukuphendukiswa kwesikrini sasekhaya"
- "Uma ifoni iphendukiswa"
- "Isilungiselelo sesiboniso samanje asivumeli ukuzungezisa"
"Amachashazi esaziso"
"Kuvuliwe"
"Kuvaliwe"
"Ukufinyelela izaziso kuyadingeka"
"Ukuze ubonisa amcashazi esaziso, vula izaziso zohlelo lokusebenza ze-%1$s"
"Shintsha izilungiselelo"
+ "Bonisa amacashazi esaziso"
"Engeza isithonjana eskrinini sasekhaya"
"Kwezinhlelo zokusebenza ezintsha"
"Shintsha isimo sesithonjana"
+ "kusikrini sasekhaya"
"Sebenzisa okuzenzakalelayo kwesistimu"
"Isikwele"
"I-Squircle"
@@ -119,9 +121,6 @@
"Dala ifolda nge-: %1$s"
"Ifolda idaliwe"
"Hambisa kusikrini sasekhaya"
- "Hambisa isikrini kwesokunxele"
- "Hambisa isikrini kwesokudla"
- "Isikrini sihanjisiwe"
"Shintsha usayizi"
"Khuphula ububanzi"
"Khuphula ubude"
@@ -137,8 +136,9 @@
"Umsebenzi"
"Iphrofayela yomsebenzi"
"Thola izinhlelo zokusebenza lapha"
-
-
+ "Uhlo lokusebenza ngalunye lomsebenzi linebheji futhi igcinwa iphephile inhlangano yakho. Hambisa izinhlelo zokusebenza esikrinini sakho sasekhaya ngokufinyelela okulula."
"Kuphethwe inhlangano yakho"
"Izaziso nezinhlelo zokusebenza kuvaliwe"
+ "Vala"
+ "Kuvaliwe"
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 3a06cdd815..b1ad11ef05 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -37,7 +37,6 @@
2dp
80dp
0dp
- 24dp
8dp
@@ -96,12 +95,7 @@
8dp
-
- 56dp
-
- 106dp
-
-
+
8dp
16dp
@@ -143,8 +137,6 @@
1dp
-
- 10dp
8dp
9dp
@@ -230,4 +222,5 @@
24dp
+ 32dp
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 7d5d81c60e..bcb90e3fdf 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -74,7 +74,7 @@
Touch & hold to pick up a shortcut.
-
+
Double-tap & hold to pick up a shortcut or use custom actions.
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index f34cf0dc50..b0c5baf6b5 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -68,7 +68,7 @@ public abstract class AbstractFloatingView extends LinearLayout implements Touch
// Type of popups which should be kept open during launcher rebind
public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
- | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP | TYPE_OPTIONS_POPUP;
+ | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP;
protected boolean mIsOpen;
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 02d70c42ca..ae631a4466 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -39,6 +39,10 @@ public abstract class BaseActivity extends Activity {
protected SystemUiController mSystemUiController;
private boolean mStarted;
+ // When the recents animation is running, the visibility of the Launcher is managed by the
+ // animation
+ private boolean mForceInvisible;
+ private boolean mUserActive;
public DeviceProfile getDeviceProfile() {
return mDeviceProfile;
@@ -84,9 +88,22 @@ public abstract class BaseActivity extends Activity {
super.onStart();
}
+ @Override
+ protected void onResume() {
+ mUserActive = true;
+ super.onResume();
+ }
+
+ @Override
+ protected void onUserLeaveHint() {
+ mUserActive = false;
+ super.onUserLeaveHint();
+ }
+
@Override
protected void onStop() {
mStarted = false;
+ mForceInvisible = false;
super.onStop();
}
@@ -94,6 +111,10 @@ public abstract class BaseActivity extends Activity {
return mStarted;
}
+ public boolean isUserActive() {
+ return mUserActive;
+ }
+
public void addOnDeviceProfileChangeListener(OnDeviceProfileChangeListener listener) {
mDPChangeListeners.add(listener);
}
@@ -108,6 +129,22 @@ public abstract class BaseActivity extends Activity {
}
}
+ /**
+ * Used to set the override visibility state, used only to handle the transition home with the
+ * recents animation.
+ * @see LauncherAppTransitionManagerImpl.getWallpaperOpenRunner()
+ */
+ public void setForceInvisible(boolean invisible) {
+ mForceInvisible = invisible;
+ }
+
+ /**
+ * @return Wether this activity should be considered invisible regardless of actual visibility.
+ */
+ public boolean isForceInvisible() {
+ return mForceInvisible;
+ }
+
/**
* Sets the device profile, adjusting it accordingly in case of multi-window
*/
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index 458f7b280f..bde9ad3109 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -34,18 +34,20 @@ import android.widget.Toast;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.compat.LauncherAppsCompat;
+import com.android.launcher3.dynamicui.WallpaperColorInfo;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.views.BaseDragLayer;
/**
* Extension of BaseActivity allowing support for drag-n-drop
*/
-public abstract class BaseDraggingActivity extends BaseActivity {
+public abstract class BaseDraggingActivity extends BaseActivity
+ implements WallpaperColorInfo.OnChangeListener {
private static final String TAG = "BaseDraggingActivity";
// The Intent extra that defines whether to ignore the launch animation
- private static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
+ public static final String INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION =
"com.android.launcher3.intent.extra.shortcut.INGORE_LAUNCH_ANIMATION";
// When starting an action mode, setting this tag will cause the action mode to be cancelled
@@ -57,10 +59,38 @@ public abstract class BaseDraggingActivity extends BaseActivity {
private OnStartCallback mOnStartCallback;
+ private int mThemeRes = R.style.LauncherTheme;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mIsSafeModeEnabled = getPackageManager().isSafeMode();
+
+ // Update theme
+ WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
+ wallpaperColorInfo.addOnChangeListener(this);
+ int themeRes = getThemeRes(wallpaperColorInfo);
+ if (themeRes != mThemeRes) {
+ mThemeRes = themeRes;
+ setTheme(themeRes);
+ }
+ }
+
+ @Override
+ public void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo) {
+ if (mThemeRes != getThemeRes(wallpaperColorInfo)) {
+ recreate();
+ }
+ }
+
+ protected int getThemeRes(WallpaperColorInfo wallpaperColorInfo) {
+ if (wallpaperColorInfo.isDark()) {
+ return R.style.LauncherThemeDark;
+ } else if (wallpaperColorInfo.supportsDarkText()) {
+ return R.style.LauncherThemeDarkText;
+ } else {
+ return R.style.LauncherTheme;
+ }
}
@Override
@@ -203,6 +233,12 @@ public abstract class BaseDraggingActivity extends BaseActivity {
}
}
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ WallpaperColorInfo.getInstance(this).removeOnChangeListener(this);
+ }
+
public void setOnStartCallback(OnStartCallback callback) {
mOnStartCallback = callback;
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 13971ad95a..4deed73b69 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -28,6 +28,7 @@ import android.util.DisplayMetrics;
import com.android.launcher3.CellLayout.ContainerType;
import com.android.launcher3.badge.BadgeRenderer;
+import com.android.launcher3.graphics.IconNormalizer;
public class DeviceProfile {
@@ -40,7 +41,7 @@ public class DeviceProfile {
public final boolean transposeLayoutWithOrientation;
// Device properties in current orientation
- private final boolean isLandscape;
+ public final boolean isLandscape;
public final boolean isMultiWindowMode;
public final int widthPx;
@@ -81,9 +82,8 @@ public class DeviceProfile {
public int workspaceCellPaddingXPx;
// Folder
- public int folderBackgroundOffset;
public int folderIconSizePx;
- public int folderIconPreviewPadding;
+ public int folderIconOffsetYPx;
// Folder cell
public int folderCellWidthPx;
@@ -117,6 +117,7 @@ public class DeviceProfile {
// Insets
private final Rect mInsets = new Rect();
public final Rect workspacePadding = new Rect();
+ private final Rect mHotseatPadding = new Rect();
// Icon badges
public BadgeRenderer mBadgeRenderer;
@@ -339,9 +340,8 @@ public class DeviceProfile {
}
// Folder icon
- folderBackgroundOffset = -iconDrawablePaddingPx;
- folderIconSizePx = iconSizePx + 2 * -folderBackgroundOffset;
- folderIconPreviewPadding = res.getDimensionPixelSize(R.dimen.folder_preview_padding);
+ folderIconSizePx = IconNormalizer.getNormalizedCircleSize(iconSizePx);
+ folderIconOffsetYPx = (iconSizePx - folderIconSizePx) / 2;
}
private void updateAvailableFolderCellDimensions(DisplayMetrics dm, Resources res) {
@@ -456,6 +456,33 @@ public class DeviceProfile {
}
}
+ public Rect getHotseatLayoutPadding() {
+ if (isVerticalBarLayout()) {
+ if (isSeascape()) {
+ mHotseatPadding.set(
+ mInsets.left, mInsets.top, hotseatBarSidePaddingPx, mInsets.bottom);
+ } else {
+ mHotseatPadding.set(
+ hotseatBarSidePaddingPx, mInsets.top, mInsets.right, mInsets.bottom);
+ }
+ } else {
+
+ // We want the edges of the hotseat to line up with the edges of the workspace, but the
+ // icons in the hotseat are a different size, and so don't line up perfectly. To account
+ // for this, we pad the left and right of the hotseat with half of the difference of a
+ // workspace cell vs a hotseat cell.
+ float workspaceCellWidth = (float) widthPx / inv.numColumns;
+ float hotseatCellWidth = (float) widthPx / inv.numHotseatIcons;
+ int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2);
+ mHotseatPadding.set(
+ hotseatAdjustment + workspacePadding.left + cellLayoutPaddingLeftRightPx,
+ hotseatBarTopPaddingPx,
+ hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx,
+ hotseatBarBottomPaddingPx + mInsets.bottom + cellLayoutBottomPaddingPx);
+ }
+ return mHotseatPadding;
+ }
+
/**
* @return the bounds for which the open folders should be contained within
*/
diff --git a/src/com/android/launcher3/DropTargetBar.java b/src/com/android/launcher3/DropTargetBar.java
index dec6cb452e..d025a9b992 100644
--- a/src/com/android/launcher3/DropTargetBar.java
+++ b/src/com/android/launcher3/DropTargetBar.java
@@ -20,7 +20,6 @@ import static com.android.launcher3.ButtonDropTarget.TOOLTIP_DEFAULT;
import static com.android.launcher3.ButtonDropTarget.TOOLTIP_LEFT;
import static com.android.launcher3.ButtonDropTarget.TOOLTIP_RIGHT;
import static com.android.launcher3.anim.AlphaUpdateListener.updateVisibility;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import android.animation.TimeInterpolator;
import android.content.Context;
@@ -47,7 +46,7 @@ public class DropTargetBar extends FrameLayout
protected static final TimeInterpolator DEFAULT_INTERPOLATOR = Interpolators.ACCEL;
private final Runnable mFadeAnimationEndRunnable =
- () -> updateVisibility(DropTargetBar.this, isAccessibilityEnabled(getContext()));
+ () -> updateVisibility(DropTargetBar.this);
@ViewDebug.ExportedProperty(category = "launcher")
protected boolean mDeferOnDragEnd;
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 211a75656b..c6025fe5f7 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -81,12 +81,17 @@ public class Hotseat extends FrameLayout implements LogContainerProvider, Insett
protected void onFinishInflate() {
super.onFinishInflate();
mContent = findViewById(R.id.layout);
-
- resetLayout();
}
- void resetLayout() {
+ void resetLayout(boolean hasVerticalHotseat) {
mContent.removeAllViewsInLayout();
+ mHasVerticalHotseat = hasVerticalHotseat;
+ InvariantDeviceProfile idp = mLauncher.getDeviceProfile().inv;
+ if (hasVerticalHotseat) {
+ mContent.setGridSize(1, idp.numHotseatIcons);
+ } else {
+ mContent.setGridSize(idp.numHotseatIcons, 1);
+ }
if (!FeatureFlags.NO_ALL_APPS_ICON) {
// Add the Apps button
@@ -148,46 +153,24 @@ public class Hotseat extends FrameLayout implements LogContainerProvider, Insett
public void setInsets(Rect insets) {
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
DeviceProfile grid = mLauncher.getDeviceProfile();
- mHasVerticalHotseat = mLauncher.getDeviceProfile().isVerticalBarLayout();
-
- if (mHasVerticalHotseat) {
- mContent.setGridSize(1, grid.inv.numHotseatIcons);
+ if (grid.isVerticalBarLayout()) {
lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
if (grid.isSeascape()) {
lp.gravity = Gravity.LEFT;
lp.width = grid.hotseatBarSizePx + insets.left + grid.hotseatBarSidePaddingPx;
- getLayout().setPadding(
- insets.left, insets.top, grid.hotseatBarSidePaddingPx, insets.bottom);
-
} else {
lp.gravity = Gravity.RIGHT;
lp.width = grid.hotseatBarSizePx + insets.right + grid.hotseatBarSidePaddingPx;
- getLayout().setPadding(
- grid.hotseatBarSidePaddingPx, insets.top, insets.right, insets.bottom);
}
} else {
- mContent.setGridSize(grid.inv.numHotseatIcons, 1);
-
lp.gravity = Gravity.BOTTOM;
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
lp.height = grid.hotseatBarSizePx + insets.bottom;
-
- // We want the edges of the hotseat to line up with the edges of the workspace, but the
- // icons in the hotseat are a different size, and so don't line up perfectly. To account for
- // this, we pad the left and right of the hotseat with half of the difference of a workspace
- // cell vs a hotseat cell.
- float workspaceCellWidth = (float) grid.widthPx / grid.inv.numColumns;
- float hotseatCellWidth = (float) grid.widthPx / grid.inv.numHotseatIcons;
- int hotseatAdjustment = Math.round((workspaceCellWidth - hotseatCellWidth) / 2);
- Rect workspacePadding = grid.workspacePadding;
-
- getLayout().setPadding(
- hotseatAdjustment + workspacePadding.left + grid.cellLayoutPaddingLeftRightPx,
- grid.hotseatBarTopPaddingPx,
- hotseatAdjustment + workspacePadding.right + grid.cellLayoutPaddingLeftRightPx,
- grid.hotseatBarBottomPaddingPx + insets.bottom + grid.cellLayoutBottomPaddingPx);
}
+ Rect padding = grid.getHotseatLayoutPadding();
+ getLayout().setPadding(padding.left, padding.top, padding.right, padding.bottom);
+
setLayoutParams(lp);
InsettableFrameLayout.dispatchInsets(this, insets);
}
diff --git a/src/com/android/launcher3/ItemInfoWithIcon.java b/src/com/android/launcher3/ItemInfoWithIcon.java
index bf985c38da..4677d31819 100644
--- a/src/com/android/launcher3/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/ItemInfoWithIcon.java
@@ -90,6 +90,11 @@ public abstract class ItemInfoWithIcon extends ItemInfo {
*/
public static final int FLAG_ADAPTIVE_ICON = 1 << 8;
+ /**
+ * Flag indicating that the icon is badged.
+ */
+ public static final int FLAG_ICON_BADGED = 1 << 9;
+
/**
* Status associated with the system state of the underlying item. This is calculated every
* time a new info is created and not persisted on the disk.
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index ed94aa4382..90c55c983a 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -22,7 +22,6 @@ import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
import android.animation.Animator;
@@ -136,8 +135,8 @@ import java.util.Set;
/**
* Default launcher application.
*/
-public class Launcher extends BaseDraggingActivity implements LauncherExterns, LauncherModel.Callbacks,
- LauncherProviderChangeListener, WallpaperColorInfo.OnThemeChangeListener {
+public class Launcher extends BaseDraggingActivity
+ implements LauncherExterns, LauncherModel.Callbacks, LauncherProviderChangeListener {
public static final String TAG = "Launcher";
static final boolean LOGD = false;
@@ -147,7 +146,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
private static final int REQUEST_CREATE_APPWIDGET = 5;
private static final int REQUEST_PICK_APPWIDGET = 9;
- private static final int REQUEST_PICK_WALLPAPER = 10;
private static final int REQUEST_BIND_APPWIDGET = 11;
public static final int REQUEST_BIND_PENDING_APPWIDGET = 12;
@@ -197,6 +195,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
private final int[] mTmpAddItemCellCoordinates = new int[2];
@Thunk Hotseat mHotseat;
+ private View mDragHandleIndicator;
+ @Nullable private View mHotseatSearchBox;
private DropTargetBar mDropTargetBar;
@@ -266,10 +266,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
}
TraceHelper.beginSection("Launcher-onCreate");
- WallpaperColorInfo wallpaperColorInfo = WallpaperColorInfo.getInstance(this);
- wallpaperColorInfo.setOnThemeChangeListener(this);
- overrideTheme(wallpaperColorInfo.isDark(), wallpaperColorInfo.supportsDarkText());
-
super.onCreate(savedInstanceState);
TraceHelper.partitionSection("Launcher-onCreate", "super call");
@@ -298,6 +294,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
mPopupDataProvider = new PopupDataProvider(this);
mRotationHelper = new RotationHelper(this);
+ mAppTransitionManager = LauncherAppTransitionManager.newInstance(this);
boolean internalStateHandled = InternalStateHandler.handleCreate(this, getIntent());
if (internalStateHandled) {
@@ -345,8 +342,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
- mAppTransitionManager = LauncherAppTransitionManager.newInstance(this);
-
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onCreate(savedInstanceState);
}
@@ -361,11 +356,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
if ((diff & (CONFIG_ORIENTATION | CONFIG_SCREEN_SIZE)) != 0) {
mUserEventDispatcher = null;
initDeviceProfile(mDeviceProfile.inv);
- FileLog.d(TAG, "Config changed, my orientation=" +
- getResources().getConfiguration().orientation +
- ", new orientation=" + newConfig.orientation +
- ", old orientation=" + mOldConfig.orientation +
- ", isTransposed=" + mDeviceProfile.isVerticalBarLayout());
dispatchDeviceProfileChanged();
getRootView().dispatchInsets();
@@ -379,6 +369,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
}
mOldConfig.setTo(newConfig);
+ UiFactory.onLauncherStateOrResumeChanged(this);
super.onConfigurationChanged(newConfig);
}
@@ -401,23 +392,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
return mRotationHelper;
}
- @Override
- public void onThemeChanged() {
- recreate();
- }
-
public LauncherStateManager getStateManager() {
return mStateManager;
}
- protected void overrideTheme(boolean isDark, boolean supportsDarkText) {
- if (isDark) {
- setTheme(R.style.LauncherThemeDark);
- } else if (supportsDarkText) {
- setTheme(R.style.LauncherThemeDarkText);
- }
- }
-
@Override
public T findViewById(int id) {
return mLauncherView.findViewById(id);
@@ -571,14 +549,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
ON_ACTIVITY_RESULT_ANIMATION_DELAY);
}
return;
- } else if (requestCode == REQUEST_PICK_WALLPAPER) {
- if (resultCode == RESULT_OK && isInState(OVERVIEW)) {
- // User could have free-scrolled between pages before picking a wallpaper; make sure
- // we move to the closest one now.
- mWorkspace.setCurrentPage(mWorkspace.getPageNearestToCenterOfScreen());
- mStateManager.goToState(NORMAL, false);
- }
- return;
}
boolean isWidgetDrop = (requestCode == REQUEST_PICK_APPWIDGET ||
@@ -820,6 +790,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onResume();
}
+ UiFactory.onLauncherStateOrResumeChanged(this);
TraceHelper.endSection("ON_RESUME");
}
@@ -838,6 +809,12 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
}
}
+ @Override
+ protected void onUserLeaveHint() {
+ super.onUserLeaveHint();
+ UiFactory.onLauncherStateOrResumeChanged(this);
+ }
+
@Override
public void onWindowFocusChanged(boolean hasFocus) {
super.onWindowFocusChanged(hasFocus);
@@ -938,6 +915,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
mWorkspace.initParentViews(mDragLayer);
mOverviewPanel = findViewById(R.id.overview_panel);
mHotseat = findViewById(R.id.hotseat);
+ mDragHandleIndicator = findViewById(R.id.drag_indicator);
+ mHotseatSearchBox = findViewById(R.id.search_container_hotseat);
mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
@@ -1201,6 +1180,14 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
return mHotseat;
}
+ public View getDragHandleIndicator() {
+ return mDragHandleIndicator;
+ }
+
+ public View getHotseatSearchBox() {
+ return mHotseatSearchBox;
+ }
+
public T getOverviewPanel() {
return (T) mOverviewPanel;
}
@@ -1357,7 +1344,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
}
TextKeyListener.getInstance().release();
- WallpaperColorInfo.getInstance(this).setOnThemeChangeListener(null);
LauncherAnimUtils.onDestroyActivity();
@@ -1642,46 +1628,6 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
}
}
- /**
- * Event handler for the wallpaper picker button that appears after a long press
- * on the home screen.
- */
- public void onClickWallpaperPicker(View v) {
- if (!Utilities.isWallpaperAllowed(this)) {
- Toast.makeText(this, R.string.msg_disabled_by_admin, Toast.LENGTH_SHORT).show();
- return;
- }
-
- int pageScroll = mWorkspace.getScrollForPage(mWorkspace.getPageNearestToCenterOfScreen());
- float offset = mWorkspace.mWallpaperOffset.wallpaperOffsetForScroll(pageScroll);
- setWaitingForResult(new PendingRequestArgs(new ItemInfo()));
- Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER)
- .putExtra(Utilities.EXTRA_WALLPAPER_OFFSET, offset);
-
- String pickerPackage = getString(R.string.wallpaper_picker_package);
- boolean hasTargetPackage = !TextUtils.isEmpty(pickerPackage);
- if (hasTargetPackage) {
- intent.setPackage(pickerPackage);
- }
-
- final Bundle launchOptions;
- if (v != null) {
- intent.setSourceBounds(getViewBounds(v));
- // If there is no target package, use the default intent chooser animation
- launchOptions = hasTargetPackage
- ? getActivityLaunchOptionsAsBundle(v, isInMultiWindowModeCompat())
- : null;
- } else {
- launchOptions = null;
- }
- try {
- startActivityForResult(intent, REQUEST_PICK_WALLPAPER, launchOptions);
- } catch (ActivityNotFoundException e) {
- setWaitingForResult(null);
- Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- }
- }
-
@TargetApi(Build.VERSION_CODES.M)
@Override
public ActivityOptions getActivityLaunchOptions(View v, boolean useDefaultLaunchOptions) {
@@ -1690,6 +1636,10 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
: mAppTransitionManager.getActivityLaunchOptions(this, v);
}
+ public LauncherAppTransitionManager getAppTransitionManager() {
+ return mAppTransitionManager;
+ }
+
@TargetApi(Build.VERSION_CODES.M)
@Override
protected boolean onErrorStartingShortcut(Intent intent, ItemInfo info) {
@@ -1828,7 +1778,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
mAppWidgetHost.clearViews();
if (mHotseat != null) {
- mHotseat.resetLayout();
+ mHotseat.resetLayout(mDeviceProfile.isVerticalBarLayout());
}
TraceHelper.endSection("startBinding");
}
@@ -1982,6 +1932,8 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
mWorkspace.postDelayed(new Runnable() {
public void run() {
if (mWorkspace != null) {
+ AbstractFloatingView.closeAllOpenViews(Launcher.this, false);
+
mWorkspace.snapToPage(newScreenIndex);
mWorkspace.postDelayed(startBounceAnimRunnable,
NEW_APPS_ANIMATION_DELAY);
@@ -2433,7 +2385,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, L
// Setting the touch point to (-1, -1) will show the options popup in the center of
// the screen.
- OptionsPopupView.show(this, -1, -1);
+ OptionsPopupView.showDefaultOptions(this, -1, -1);
}
return true;
}
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 8b7ba20b49..7d208d48d3 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -34,7 +34,6 @@ import android.content.res.Resources;
import android.database.Cursor;
import android.database.SQLException;
import android.database.sqlite.SQLiteDatabase;
-import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.database.sqlite.SQLiteStatement;
import android.net.Uri;
@@ -56,7 +55,6 @@ import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.DbDowngradeHelper;
-import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
import com.android.launcher3.provider.RestoreDbTask;
@@ -320,11 +318,6 @@ public class LauncherProvider extends ContentProvider {
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
- if (ModelWriter.DEBUG_DELETE) {
- String args = selectionArgs == null ? null : TextUtils.join(",", selectionArgs);
- FileLog.d(TAG, "Delete uri=" + uri + ", selection=" + selection
- + ", selectionArgs=" + args, new Exception());
- }
createDbIfNotExists();
SqlArguments args = new SqlArguments(uri, selection, selectionArgs);
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index b1bf6ec6ef..4697b82f81 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -18,7 +18,6 @@ package com.android.launcher3;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_AUTO;
import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-
import static com.android.launcher3.anim.Interpolators.ACCEL_2;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
@@ -47,10 +46,11 @@ public class LauncherState {
*/
public static final int NONE = 0;
public static final int HOTSEAT_ICONS = 1 << 0;
- public static final int HOTSEAT_EXTRA = 1 << 1; // e.g. a search box
+ public static final int HOTSEAT_SEARCH_BOX = 1 << 1;
public static final int ALL_APPS_HEADER = 1 << 2;
public static final int ALL_APPS_HEADER_EXTRA = 1 << 3; // e.g. app predictions
public static final int ALL_APPS_CONTENT = 1 << 4;
+ public static final int DRAG_HANDLE_INDICATOR = 1 << 5;
protected static final int FLAG_SHOW_SCRIM = 1 << 0;
protected static final int FLAG_MULTI_PAGE = 1 << 1;
@@ -181,12 +181,12 @@ public class LauncherState {
}
/**
- * Returns 2 floats designating how much to translate overview:
- * X factor is based on width, e.g. 0 is fully onscreen and 1 is fully offscreen
- * Y factor is based on padding, e.g. 0 is top aligned and 0.5 is centered vertically
+ * Returns 2 floats designating how to transition overview:
+ * scale for the current and adjacent pages
+ * translationY factor where 0 is top aligned and 0.5 is centered vertically
*/
- public float[] getOverviewTranslationFactor(Launcher launcher) {
- return new float[] {1f, 0f};
+ public float[] getOverviewScaleAndTranslationYFactor(Launcher launcher) {
+ return new float[] {1.2f, 0.2f};
}
public void onStateEnabled(Launcher launcher) {
@@ -201,9 +201,9 @@ public class LauncherState {
public int getVisibleElements(Launcher launcher) {
if (launcher.getDeviceProfile().isVerticalBarLayout()) {
- return HOTSEAT_ICONS;
+ return HOTSEAT_ICONS | DRAG_HANDLE_INDICATOR;
}
- return HOTSEAT_ICONS | HOTSEAT_EXTRA;
+ return HOTSEAT_ICONS | DRAG_HANDLE_INDICATOR | HOTSEAT_SEARCH_BOX;
}
/**
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 7d50a5263a..534c8ae351 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -294,6 +294,7 @@ public class LauncherStateManager {
// Only disable clipping if needed, otherwise leave it as previous value.
mLauncher.getWorkspace().setClipChildren(false);
}
+ UiFactory.onLauncherStateOrResumeChanged(mLauncher);
}
private void onStateTransitionEnd(LauncherState state) {
@@ -312,6 +313,7 @@ public class LauncherStateManager {
}
UiFactory.onLauncherStateOrFocusChanged(mLauncher);
+ UiFactory.onLauncherStateOrResumeChanged(mLauncher);
}
public void onWindowFocusChanged() {
@@ -354,7 +356,11 @@ public class LauncherStateManager {
* starting another animation and may block some launcher interactions while running.
*/
public void setCurrentAnimation(AnimatorSet anim) {
+ boolean reapplyNeeded = mConfig.mCurrentAnimation != null;
cancelAnimation();
+ if (reapplyNeeded) {
+ reapplyState();
+ }
mConfig.setAnimation(anim);
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index a1ac122d87..15bf76da50 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -41,6 +41,7 @@ import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.animation.Interpolator;
+import android.widget.ScrollView;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.pageindicators.PageIndicator;
@@ -187,7 +188,6 @@ public abstract class PagedView extends ViewGrou
mFlingThresholdVelocity = (int) (FLING_THRESHOLD_VELOCITY * density);
mMinFlingVelocity = (int) (MIN_FLING_VELOCITY * density);
mMinSnapVelocity = (int) (MIN_SNAP_VELOCITY * density);
- setWillNotDraw(false);
if (Utilities.ATLEAST_OREO) {
setDefaultFocusHighlightEnabled(false);
@@ -424,6 +424,13 @@ public abstract class PagedView extends ViewGrou
return computeScrollHelper(true);
}
+ protected void announcePageForAccessibility() {
+ if (isAccessibilityEnabled(getContext())) {
+ // Notify the user when the page changes
+ announceForAccessibility(getCurrentPageDescription());
+ }
+ }
+
protected boolean computeScrollHelper(boolean shouldInvalidate) {
if (mScroller.computeScrollOffset()) {
// Don't bother scrolling if the page does not need to be moved
@@ -452,9 +459,8 @@ public abstract class PagedView extends ViewGrou
pageEndTransition();
}
- if (isAccessibilityEnabled(getContext())) {
- // Notify the user when the page changes
- announceForAccessibility(getCurrentPageDescription());
+ if (canAnnouncePageDescription()) {
+ announcePageForAccessibility();
}
}
return false;
@@ -1468,6 +1474,13 @@ public abstract class PagedView extends ViewGrou
if (getNextPage() < getChildCount() -1) snapToPage(getNextPage() + 1);
}
+ @Override
+ public CharSequence getAccessibilityClassName() {
+ // Some accessibility services have special logic for ScrollView. Since we provide same
+ // accessibility info as ScrollView, inform the service to handle use the same way.
+ return ScrollView.class.getName();
+ }
+
/* Accessibility */
@SuppressWarnings("deprecation")
@Override
@@ -1480,7 +1493,6 @@ public abstract class PagedView extends ViewGrou
if (getCurrentPage() > 0) {
info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);
}
- info.setClassName(getClass().getName());
// Accessibility-wise, PagedView doesn't support long click, so disabling it.
// Besides disabling the accessibility long-click, this also prevents this view from getting
@@ -1529,6 +1541,10 @@ public abstract class PagedView extends ViewGrou
return getCurrentPageDescription();
}
+ protected boolean canAnnouncePageDescription() {
+ return true;
+ }
+
protected String getCurrentPageDescription() {
return getContext().getString(R.string.default_scroll_format,
getNextPage() + 1, getChildCount());
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index 7fa0e52259..c9bd32b086 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import android.annotation.TargetApi;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
@@ -26,22 +27,25 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
+import android.os.Build;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
+import android.preference.PreferenceScreen;
import android.provider.Settings;
import android.text.TextUtils;
-import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.Adapter;
+import android.widget.ListView;
import com.android.launcher3.graphics.IconShapeOverride;
import com.android.launcher3.notification.NotificationListener;
+import com.android.launcher3.util.ListViewHighlighter;
import com.android.launcher3.util.SettingsObserver;
import com.android.launcher3.views.ButtonPreference;
-import com.android.launcher3.views.HighlightableListView;
+
+import java.util.Objects;
/**
* Settings activity for Launcher. Currently implements the following setting: Allow rotation
@@ -84,12 +88,6 @@ public class SettingsActivity extends Activity {
private String mPreferenceKey;
private boolean mPreferenceHighlighted = false;
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- return inflater.inflate(R.layout.launcher_preference, container, false);
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
@@ -145,12 +143,25 @@ public class SettingsActivity extends Activity {
}
private void highlightPreference() {
- HighlightableListView list = getView().findViewById(android.R.id.list);
Preference pref = findPreference(mPreferenceKey);
- Adapter adapter = list.getAdapter();
- if (adapter == null) {
+ if (pref == null || getPreferenceScreen() == null) {
return;
}
+ PreferenceScreen screen = getPreferenceScreen();
+ if (Utilities.ATLEAST_OREO) {
+ screen = selectPreferenceRecursive(pref, screen);
+ }
+ if (screen == null) {
+ return;
+ }
+
+ View root = screen.getDialog() != null
+ ? screen.getDialog().getWindow().getDecorView() : getView();
+ ListView list = root.findViewById(android.R.id.list);
+ if (list == null || list.getAdapter() == null) {
+ return;
+ }
+ Adapter adapter = list.getAdapter();
// Find the position
int position = -1;
@@ -160,7 +171,7 @@ public class SettingsActivity extends Activity {
break;
}
}
- list.highlightPosition(position);
+ new ListViewHighlighter(list, position);
mPreferenceHighlighted = true;
}
@@ -172,6 +183,25 @@ public class SettingsActivity extends Activity {
}
super.onDestroy();
}
+
+ @TargetApi(Build.VERSION_CODES.O)
+ private PreferenceScreen selectPreferenceRecursive(
+ Preference pref, PreferenceScreen topParent) {
+ if (!(pref.getParent() instanceof PreferenceScreen)) {
+ return null;
+ }
+
+ PreferenceScreen parent = (PreferenceScreen) pref.getParent();
+ if (Objects.equals(parent.getKey(), topParent.getKey())) {
+ return parent;
+ } else if (selectPreferenceRecursive(parent, topParent) != null) {
+ ((PreferenceScreen) parent.getParent())
+ .onItemClick(null, null, parent.getOrder(), 0);
+ return parent;
+ } else {
+ return null;
+ }
+ }
}
/**
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index 1a63326dd2..baf6d876b2 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -16,9 +16,12 @@
package com.android.launcher3;
+import static android.view.MotionEvent.ACTION_DOWN;
+
import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Rect;
+import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
@@ -173,6 +176,15 @@ public class ShortcutAndWidgetContainer extends ViewGroup {
}
}
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ if (ev.getAction() == ACTION_DOWN && getAlpha() == 0) {
+ // Dont let children handle touch, if we are not visible.
+ return true;
+ }
+ return super.onInterceptTouchEvent(ev);
+ }
+
@Override
public boolean shouldDelayChildPressedState() {
return false;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 68ad253700..1e2e3b10bf 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -349,6 +349,11 @@ public class Workspace extends PagedView
}
}
+ public float getWallpaperOffsetForCenterPage() {
+ int pageScroll = getScrollForPage(getPageNearestToCenterOfScreen());
+ return mWallpaperOffset.wallpaperOffsetForScroll(pageScroll);
+ }
+
public Rect estimateItemPosition(CellLayout cl, int hCell, int vCell, int hSpan, int vSpan) {
Rect r = new Rect();
cl.cellToRect(hCell, vCell, hSpan, vSpan, r);
@@ -443,12 +448,6 @@ public class Workspace extends PagedView
setWallpaperDimension();
}
- @Override
- public void initParentViews(View parent) {
- super.initParentViews(parent);
- mPageIndicator.setAccessibilityDelegate(UiFactory.newPageIndicatorAccessibilityDelegate());
- }
-
private void setupLayoutTransition() {
// We want to show layout transitions when pages are deleted, to close the gap.
mLayoutTransition = new LayoutTransition();
@@ -1149,30 +1148,37 @@ public class Workspace extends PagedView
* The overlay scroll is being controlled locally, just update our overlay effect
*/
public void onOverlayScrollChanged(float scroll) {
-
if (Float.compare(scroll, 1f) == 0) {
if (!mOverlayShown) {
mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
Action.Direction.LEFT, ContainerType.WORKSPACE, 0);
}
mOverlayShown = true;
+ // Not announcing the overlay page for accessibility since it announces itself.
} else if (Float.compare(scroll, 0f) == 0) {
if (mOverlayShown) {
mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
Action.Direction.RIGHT, ContainerType.WORKSPACE, -1);
+ } else if (Float.compare(mOverlayTranslation, 0f) != 0) {
+ // When arriving to 0 overscroll from non-zero overscroll, announce page for
+ // accessibility since default announcements were disabled while in overscroll
+ // state.
+ // Not doing this if mOverlayShown because in that case the accessibility service
+ // will announce the launcher window description upon regaining focus after
+ // switching from the overlay screen.
+ announcePageForAccessibility();
}
mOverlayShown = false;
tryRunOverlayCallback();
}
+
float offset = 0f;
- float slip = 0f;
scroll = Math.max(scroll - offset, 0);
scroll = Math.min(1, scroll / (1 - offset));
float alpha = 1 - Interpolators.DEACCEL_3.getInterpolation(scroll);
float transX = mLauncher.getDragLayer().getMeasuredWidth() * scroll;
- transX *= 1 - slip;
if (mIsRtl) {
transX = -transX;
@@ -3351,8 +3357,10 @@ public class Workspace extends PagedView
}
@Override
- protected String getPageIndicatorDescription() {
- return getResources().getString(R.string.all_apps_button_label);
+ protected boolean canAnnouncePageDescription() {
+ // Disable announcements while overscrolling potentially to overlay screen because if we end
+ // up on the overlay screen, it will take care of announcing itself.
+ return Float.compare(mOverlayTranslation, 0f) == 0;
}
@Override
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 3a222c261c..420a7c4182 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -18,8 +18,9 @@ package com.android.launcher3;
import static com.android.launcher3.LauncherAnimUtils.DRAWABLE_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
-import static com.android.launcher3.LauncherState.HOTSEAT_EXTRA;
+import static com.android.launcher3.LauncherState.DRAG_HANDLE_INDICATOR;
import static com.android.launcher3.LauncherState.HOTSEAT_ICONS;
+import static com.android.launcher3.LauncherState.HOTSEAT_SEARCH_BOX;
import static com.android.launcher3.anim.PropertySetter.NO_ANIM_PROPERTY_SETTER;
import android.view.View;
@@ -30,7 +31,6 @@ import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.graphics.ViewScrim;
-import com.android.launcher3.uioverrides.UiFactory;
/**
* Manages the animations between each of the workspace states.
@@ -73,24 +73,27 @@ public class WorkspaceStateTransitionAnimation {
propertySetter);
}
- propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, Interpolators.ZOOM_IN);
+ propertySetter.setFloat(mWorkspace, SCALE_PROPERTY, mNewScale, Interpolators.ZOOM_OUT);
propertySetter.setFloat(mWorkspace, View.TRANSLATION_X,
- scaleAndTranslation[1], Interpolators.ZOOM_IN);
+ scaleAndTranslation[1], Interpolators.ZOOM_OUT);
propertySetter.setFloat(mWorkspace, View.TRANSLATION_Y,
- scaleAndTranslation[2], Interpolators.ZOOM_IN);
+ scaleAndTranslation[2], Interpolators.ZOOM_OUT);
int elements = state.getVisibleElements(mLauncher);
float hotseatIconsAlpha = (elements & HOTSEAT_ICONS) != 0 ? 1 : 0;
- float hotseatExtraAlpha = (elements & HOTSEAT_EXTRA) != 0 ? 1 : 0;
propertySetter.setViewAlpha(mLauncher.getHotseat().getLayout(), hotseatIconsAlpha,
pageAlphaProvider.interpolator);
- for (View hotseatExtraContent : UiFactory.getHotseatExtraContent(mLauncher.getHotseat())) {
- propertySetter.setViewAlpha(hotseatExtraContent, hotseatExtraAlpha,
- pageAlphaProvider.interpolator);
- }
propertySetter.setViewAlpha(mLauncher.getWorkspace().getPageIndicator(),
hotseatIconsAlpha, pageAlphaProvider.interpolator);
+ propertySetter.setViewAlpha(mLauncher.getHotseatSearchBox(),
+ (elements & HOTSEAT_SEARCH_BOX) != 0 ? 1 : 0,
+ pageAlphaProvider.interpolator);
+
+ propertySetter.setViewAlpha(mLauncher.getDragHandleIndicator(),
+ (elements & DRAG_HANDLE_INDICATOR) != 0 ? 1 : 0,
+ pageAlphaProvider.interpolator);
+
// Set scrim
propertySetter.setFloat(ViewScrim.get(mWorkspace), ViewScrim.PROGRESS,
state.hasScrim ? 1 : 0, Interpolators.LINEAR);
@@ -109,7 +112,7 @@ public class WorkspaceStateTransitionAnimation {
int drawableAlpha = Math.round(pageAlpha * (state.hasWorkspacePageBackground ? 255 : 0));
propertySetter.setInt(cl.getScrimBackground(),
- DRAWABLE_ALPHA, drawableAlpha, Interpolators.ZOOM_IN);
+ DRAWABLE_ALPHA, drawableAlpha, Interpolators.ZOOM_OUT);
propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
pageAlpha, pageAlphaProvider.interpolator);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 9be123f973..ed9873eaf6 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -23,7 +23,6 @@ import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.R;
-import com.android.launcher3.allapps.SearchUiManager.OnScrollRangeChangeListener;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.PropertySetter;
@@ -39,8 +38,7 @@ import com.android.launcher3.util.Themes;
* If release velocity < THRES1, snap according to either top or bottom depending on whether it's
* closer to top or closer to the page indicator.
*/
-public class AllAppsTransitionController
- implements OnScrollRangeChangeListener, StateHandler, OnDeviceProfileChangeListener {
+public class AllAppsTransitionController implements StateHandler, OnDeviceProfileChangeListener {
public static final Property ALL_APPS_PROGRESS =
new Property(Float.class, "allAppsProgress") {
@@ -71,11 +69,11 @@ public class AllAppsTransitionController
private float mShiftRange; // changes depending on the orientation
private float mProgress; // [0, 1], mShiftRange * mProgress = shiftCurrent
- private static final float DEFAULT_SHIFT_RANGE = 10;
+ private float mScrollRangeDelta = 0;
public AllAppsTransitionController(Launcher l) {
mLauncher = l;
- mShiftRange = DEFAULT_SHIFT_RANGE;
+ mShiftRange = mLauncher.getDeviceProfile().heightPx;
mProgress = 1f;
mIsDarkTheme = Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark);
@@ -95,11 +93,13 @@ public class AllAppsTransitionController
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
mIsVerticalLayout = dp.isVerticalBarLayout();
+ setScrollRangeDelta(mScrollRangeDelta);
if (mIsVerticalLayout) {
mAppsView.setAlpha(1);
mLauncher.getHotseat().setTranslationY(0);
mLauncher.getWorkspace().getPageIndicator().setTranslationY(0);
+ mLauncher.getDragHandleIndicator().setTranslationY(0);
}
}
@@ -122,6 +122,7 @@ public class AllAppsTransitionController
if (!mIsVerticalLayout) {
mLauncher.getHotseat().setTranslationY(hotseatTranslation);
mLauncher.getWorkspace().getPageIndicator().setTranslationY(hotseatTranslation);
+ mLauncher.getDragHandleIndicator().setTranslationY(hotseatTranslation);
}
// Use a light system UI (dark icons) if all apps is behind at least half of the
@@ -204,13 +205,14 @@ public class AllAppsTransitionController
public void setupViews(AllAppsContainerView appsView) {
mAppsView = appsView;
- mAppsView.getSearchUiManager().addOnScrollRangeChangeListener(this);
}
- @Override
- public void onScrollRangeChanged(int scrollRange) {
- mShiftRange = scrollRange;
- setProgress(mProgress);
+ /**
+ * Updates the total scroll range but does not update the UI.
+ */
+ public void setScrollRangeDelta(float delta) {
+ mScrollRangeDelta = delta;
+ mShiftRange = mLauncher.getDeviceProfile().heightPx - mScrollRangeDelta;
}
/**
diff --git a/src/com/android/launcher3/allapps/SearchUiManager.java b/src/com/android/launcher3/allapps/SearchUiManager.java
index d8568f8eaf..68193f5c1c 100644
--- a/src/com/android/launcher3/allapps/SearchUiManager.java
+++ b/src/com/android/launcher3/allapps/SearchUiManager.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.allapps;
-import android.support.animation.SpringAnimation;
-import android.support.annotation.NonNull;
import android.view.KeyEvent;
/**
@@ -29,11 +27,6 @@ public interface SearchUiManager {
*/
void initialize(AllAppsContainerView containerView);
- /**
- * A {@link SpringAnimation} that will be used when the user flings.
- */
- @NonNull SpringAnimation getSpringForFling();
-
/**
* Notifies the search manager to close any active search session.
*/
@@ -44,14 +37,4 @@ public interface SearchUiManager {
* some UI beforehand.
*/
void preDispatchKeyEvent(KeyEvent keyEvent);
-
- void addOnScrollRangeChangeListener(OnScrollRangeChangeListener listener);
-
- /**
- * Callback for listening to changes in the vertical scroll range when opening all-apps.
- */
- interface OnScrollRangeChangeListener {
-
- void onScrollRangeChanged(int scrollRange);
- }
}
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index dd80dace34..ad61c55db7 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -23,10 +23,6 @@ import static com.android.launcher3.graphics.IconNormalizer.ICON_VISIBLE_AREA_FA
import android.content.Context;
import android.graphics.Rect;
-import android.support.animation.FloatValueHolder;
-import android.support.animation.SpringAnimation;
-import android.support.animation.SpringForce;
-import android.support.annotation.NonNull;
import android.text.Selection;
import android.text.Spannable;
import android.text.SpannableString;
@@ -39,6 +35,7 @@ import android.view.ViewGroup.MarginLayoutParams;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ExtendedEditText;
+import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.allapps.AllAppsContainerView;
@@ -55,7 +52,7 @@ import java.util.ArrayList;
*/
public class AppsSearchContainerLayout extends ExtendedEditText
implements SearchUiManager, AllAppsSearchBarController.Callbacks,
- AllAppsStore.OnUpdateListener {
+ AllAppsStore.OnUpdateListener, Insettable {
private final Launcher mLauncher;
@@ -64,7 +61,6 @@ public class AppsSearchContainerLayout extends ExtendedEditText
private AlphabeticalAppsList mApps;
private AllAppsContainerView mAppsView;
- private SpringAnimation mSpring;
public AppsSearchContainerLayout(Context context) {
this(context, null);
@@ -91,9 +87,6 @@ public class AppsSearchContainerLayout extends ExtendedEditText
spanned.setSpan(new TintedDrawableSpan(getContext(), R.drawable.ic_allapps_search),
0, 1, Spannable.SPAN_EXCLUSIVE_INCLUSIVE);
setHint(spanned);
-
- // Note: This spring does nothing.
- mSpring = new SpringAnimation(new FloatValueHolder()).setSpring(new SpringForce(0));
}
@Override
@@ -145,11 +138,6 @@ public class AppsSearchContainerLayout extends ExtendedEditText
new DefaultAppSearchAlgorithm(mApps.getApps()), this, mLauncher, this);
}
- @Override
- public @NonNull SpringAnimation getSpringForFling() {
- return mSpring;
- }
-
@Override
public void onAppsUpdated() {
mSearchBarController.refreshSearchResult();
@@ -206,22 +194,15 @@ public class AppsSearchContainerLayout extends ExtendedEditText
}
@Override
- public void addOnScrollRangeChangeListener(final OnScrollRangeChangeListener listener) {
- mLauncher.getHotseat().addOnLayoutChangeListener(new OnLayoutChangeListener() {
- @Override
- public void onLayoutChange(View v, int left, int top, int right, int bottom,
- int oldLeft, int oldTop, int oldRight, int oldBottom) {
- DeviceProfile dp = mLauncher.getDeviceProfile();
- if (!dp.isVerticalBarLayout()) {
- Rect insets = dp.getInsets();
- int hotseatBottom = bottom - dp.hotseatBarBottomPaddingPx - insets.bottom;
- MarginLayoutParams mlp = ((MarginLayoutParams) getLayoutParams());
- int myBot = mlp.topMargin + (int) getTranslationY() + mlp.height;
- listener.onScrollRangeChanged(hotseatBottom - myBot);
- } else {
- listener.onScrollRangeChanged(bottom);
- }
- }
- });
+ public void setInsets(Rect insets) {
+ DeviceProfile dp = mLauncher.getDeviceProfile();
+ if (dp.isVerticalBarLayout()) {
+ mLauncher.getAllAppsController().setScrollRangeDelta(0);
+ } else {
+ MarginLayoutParams mlp = ((MarginLayoutParams) getLayoutParams());
+ int myBot = mlp.topMargin + (int) getTranslationY() + mlp.height;
+ mLauncher.getAllAppsController().setScrollRangeDelta(
+ dp.hotseatBarBottomPaddingPx + myBot);
+ }
}
}
diff --git a/src/com/android/launcher3/anim/AlphaUpdateListener.java b/src/com/android/launcher3/anim/AlphaUpdateListener.java
index 04d97a7282..a3d02d9492 100644
--- a/src/com/android/launcher3/anim/AlphaUpdateListener.java
+++ b/src/com/android/launcher3/anim/AlphaUpdateListener.java
@@ -17,7 +17,6 @@
package com.android.launcher3.anim;
import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.view.View;
@@ -25,44 +24,24 @@ import android.view.View;
/**
* A convenience class to update a view's visibility state after an alpha animation.
*/
-public class AlphaUpdateListener extends AnimatorListenerAdapter implements AnimatorUpdateListener {
+public class AlphaUpdateListener extends AnimationSuccessListener
+ implements AnimatorUpdateListener {
private static final float ALPHA_CUTOFF_THRESHOLD = 0.01f;
private View mView;
- private boolean mAccessibilityEnabled;
- private boolean mCanceled = false;
- public AlphaUpdateListener(View v, boolean accessibilityEnabled) {
+ public AlphaUpdateListener(View v) {
mView = v;
- mAccessibilityEnabled = accessibilityEnabled;
}
@Override
public void onAnimationUpdate(ValueAnimator arg0) {
- updateVisibility(mView, mAccessibilityEnabled);
- }
-
- public static void updateVisibility(View view, boolean accessibilityEnabled) {
- // We want to avoid the extra layout pass by setting the views to GONE unless
- // accessibility is on, in which case not setting them to GONE causes a glitch.
- int invisibleState = accessibilityEnabled ? View.GONE : View.INVISIBLE;
- if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != invisibleState) {
- view.setVisibility(invisibleState);
- } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
- && view.getVisibility() != View.VISIBLE) {
- view.setVisibility(View.VISIBLE);
- }
+ updateVisibility(mView);
}
@Override
- public void onAnimationCancel(Animator animation) {
- mCanceled = true;
- }
-
- @Override
- public void onAnimationEnd(Animator arg0) {
- if (mCanceled) return;
- updateVisibility(mView, mAccessibilityEnabled);
+ public void onAnimationSuccess(Animator animator) {
+ updateVisibility(mView);
}
@Override
@@ -70,4 +49,13 @@ public class AlphaUpdateListener extends AnimatorListenerAdapter implements Anim
// We want the views to be visible for animation, so fade-in/out is visible
mView.setVisibility(View.VISIBLE);
}
+
+ public static void updateVisibility(View view) {
+ if (view.getAlpha() < ALPHA_CUTOFF_THRESHOLD && view.getVisibility() != View.INVISIBLE) {
+ view.setVisibility(View.INVISIBLE);
+ } else if (view.getAlpha() > ALPHA_CUTOFF_THRESHOLD
+ && view.getVisibility() != View.VISIBLE) {
+ view.setVisibility(View.VISIBLE);
+ }
+ }
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/anim/AnimatorPlaybackController.java b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
index 68e98479b0..087752df1e 100644
--- a/src/com/android/launcher3/anim/AnimatorPlaybackController.java
+++ b/src/com/android/launcher3/anim/AnimatorPlaybackController.java
@@ -18,6 +18,7 @@ package com.android.launcher3.anim;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
+import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import java.util.ArrayList;
@@ -184,10 +185,14 @@ public abstract class AnimatorPlaybackController implements ValueAnimator.Animat
private void getAnimationsRecur(AnimatorSet anim, ArrayList out) {
long forceDuration = anim.getDuration();
+ TimeInterpolator forceInterpolator = anim.getInterpolator();
for (Animator child : anim.getChildAnimations()) {
if (forceDuration > 0) {
child.setDuration(forceDuration);
}
+ if (forceInterpolator != null) {
+ child.setInterpolator(forceInterpolator);
+ }
if (child instanceof ValueAnimator) {
out.add((ValueAnimator) child);
} else if (child instanceof AnimatorSet) {
@@ -206,7 +211,6 @@ public abstract class AnimatorPlaybackController implements ValueAnimator.Animat
anim.setCurrentPlayTime(Math.min(playPos, anim.getDuration()));
}
}
-
}
private class OnAnimationEndDispatcher extends AnimationSuccessListener {
diff --git a/src/com/android/launcher3/anim/AnimatorSetBuilder.java b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
index 919104886a..b209a2deeb 100644
--- a/src/com/android/launcher3/anim/AnimatorSetBuilder.java
+++ b/src/com/android/launcher3/anim/AnimatorSetBuilder.java
@@ -16,6 +16,7 @@
package com.android.launcher3.anim;
import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.util.SparseArray;
import android.view.animation.Interpolator;
@@ -23,6 +24,7 @@ import android.view.animation.Interpolator;
import com.android.launcher3.LauncherAnimUtils;
import java.util.ArrayList;
+import java.util.List;
/**
* Utility class for building animator set
@@ -35,7 +37,7 @@ public class AnimatorSetBuilder {
protected final ArrayList mAnims = new ArrayList<>();
private final SparseArray mInterpolators = new SparseArray<>();
- private long mStartDelay = 0;
+ private List mOnFinishRunnables = new ArrayList<>();
/**
* Associates a tag with all the animations added after this call.
@@ -46,14 +48,24 @@ public class AnimatorSetBuilder {
mAnims.add(anim);
}
- public void setStartDelay(long startDelay) {
- mStartDelay = startDelay;
+ public void addOnFinishRunnable(Runnable onFinishRunnable) {
+ mOnFinishRunnables.add(onFinishRunnable);
}
public AnimatorSet build() {
AnimatorSet anim = LauncherAnimUtils.createAnimatorSet();
anim.playTogether(mAnims);
- anim.setStartDelay(mStartDelay);
+ if (!mOnFinishRunnables.isEmpty()) {
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ for (Runnable onFinishRunnable : mOnFinishRunnables) {
+ onFinishRunnable.run();
+ }
+ mOnFinishRunnables.clear();
+ }
+ });
+ }
return anim;
}
diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java
index 6078776e0d..06ddf22086 100644
--- a/src/com/android/launcher3/anim/Interpolators.java
+++ b/src/com/android/launcher3/anim/Interpolators.java
@@ -65,15 +65,22 @@ public class Interpolators {
new PathInterpolator(0.3f, 0f, 0.1f, 1f);
/**
- * Inversion of zInterpolate, compounded with an ease-out.
+ * Inversion of ZOOM_OUT, compounded with an ease-out.
*/
public static final Interpolator ZOOM_IN = new Interpolator() {
+ @Override
+ public float getInterpolation(float v) {
+ return DEACCEL_3.getInterpolation(1 - ZOOM_OUT.getInterpolation(1 - v));
+ }
+ };
+
+ public static final Interpolator ZOOM_OUT = new Interpolator() {
private static final float FOCAL_LENGTH = 0.35f;
@Override
public float getInterpolation(float v) {
- return DEACCEL_3.getInterpolation(1 - zInterpolate(1 - v));
+ return zInterpolate(v);
}
/**
diff --git a/src/com/android/launcher3/anim/PropertySetter.java b/src/com/android/launcher3/anim/PropertySetter.java
index 1f11f7e631..757edff74d 100644
--- a/src/com/android/launcher3/anim/PropertySetter.java
+++ b/src/com/android/launcher3/anim/PropertySetter.java
@@ -16,8 +16,6 @@
package com.android.launcher3.anim;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
-
import android.animation.Animator;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
@@ -34,7 +32,7 @@ public class PropertySetter {
public void setViewAlpha(View view, float alpha, TimeInterpolator interpolator) {
if (view != null) {
view.setAlpha(alpha);
- AlphaUpdateListener.updateVisibility(view, isAccessibilityEnabled(view.getContext()));
+ AlphaUpdateListener.updateVisibility(view);
}
}
@@ -64,8 +62,7 @@ public class PropertySetter {
return;
}
ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, alpha);
- anim.addListener(new AlphaUpdateListener(
- view, isAccessibilityEnabled(view.getContext())));
+ anim.addListener(new AlphaUpdateListener(view));
anim.setDuration(mDuration).setInterpolator(interpolator);
mStateAnimator.play(anim);
}
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompat.java b/src/com/android/launcher3/compat/PackageInstallerCompat.java
index 112cca5402..3270ba2005 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompat.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompat.java
@@ -45,7 +45,7 @@ public abstract class PackageInstallerCompat {
/**
* @return a map of active installs to their progress
*/
- public abstract HashMap updateAndGetActiveSessionCache();
+ public abstract HashMap updateAndGetActiveSessionCache();
public abstract void onStop();
diff --git a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
index 1ffd3da014..dd17916f0d 100644
--- a/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
+++ b/src/com/android/launcher3/compat/PackageInstallerCompatVL.java
@@ -59,13 +59,13 @@ public class PackageInstallerCompatVL extends PackageInstallerCompat {
}
@Override
- public HashMap updateAndGetActiveSessionCache() {
- HashMap activePackages = new HashMap<>();
+ public HashMap updateAndGetActiveSessionCache() {
+ HashMap activePackages = new HashMap<>();
UserHandle user = Process.myUserHandle();
for (SessionInfo info : getAllVerifiedSessions()) {
addSessionInfoToCache(info, user);
if (info.getAppPackageName() != null) {
- activePackages.put(info.getAppPackageName(), (int) (info.getProgress() * 100));
+ activePackages.put(info.getAppPackageName(), info);
mActiveSessions.put(info.getSessionId(), info.getAppPackageName());
}
}
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 78ea419b82..f4c6380b74 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -51,4 +51,8 @@ abstract class BaseFlags {
// When enabled shows a work profile tab in all apps
public static final boolean ALL_APPS_TABS_ENABLED = true;
+
+ // When true, overview shows screenshots in the orientation they were taken rather than
+ // trying to make them fit the orientation the device is in.
+ public static final boolean OVERVIEW_USE_SCREENSHOT_ORIENTATION = true;
}
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index 95e1034365..278eefdd92 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -53,6 +53,7 @@ import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.widget.PendingAddShortcutInfo;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.WidgetHostViewLoader;
@@ -82,6 +83,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
private Bundle mWidgetOptions;
private boolean mFinishOnPause = false;
+ private InstantAppResolver mInstantAppResolver;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -95,6 +97,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
mApp = LauncherAppState.getInstance(this);
mIdp = mApp.getInvariantDeviceProfile();
+ mInstantAppResolver = InstantAppResolver.newInstance(this);
// Use the application context to get the device profile, as in multiwindow-mode, the
// confirmation activity might be rotated.
@@ -298,7 +301,7 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener
private void logCommand(int command) {
getUserEventDispatcher().dispatchUserEvent(newLauncherEvent(
newCommandAction(command),
- newItemTarget(mWidgetCell.getWidgetView()),
+ newItemTarget(mWidgetCell.getWidgetView(), mInstantAppResolver),
newContainerTarget(ContainerType.PINITEM)), null);
}
}
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 8d4f2ef0a3..e1e1f83a7c 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -46,6 +46,7 @@ import android.view.View;
import com.android.launcher3.FastBitmapDrawable;
import com.android.launcher3.ItemInfo;
+import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherAppState;
@@ -69,6 +70,8 @@ import com.android.launcher3.widget.PendingAddShortcutInfo;
import java.util.Arrays;
import java.util.List;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED;
+
public class DragView extends View {
private static final ColorMatrix sTempMatrix1 = new ColorMatrix();
private static final ColorMatrix sTempMatrix2 = new ColorMatrix();
@@ -364,7 +367,10 @@ public class DragView extends View {
private Drawable getBadge(ItemInfo info, LauncherAppState appState, Object obj) {
int iconSize = appState.getInvariantDeviceProfile().iconBitmapSize;
if (info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- if (info.id == ItemInfo.NO_ID || !(obj instanceof ShortcutInfoCompat)) {
+ boolean iconBadged = (info instanceof ItemInfoWithIcon)
+ && (((ItemInfoWithIcon) info).runtimeStatusFlags & FLAG_ICON_BADGED) > 0;
+ if ((info.id == ItemInfo.NO_ID && !iconBadged)
+ || !(obj instanceof ShortcutInfoCompat)) {
// The item is not yet added on home screen.
return new FixedSizeEmptyDrawable(iconSize);
}
diff --git a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
index 267e9301a7..32605a2ebe 100644
--- a/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
+++ b/src/com/android/launcher3/dynamicui/WallpaperColorInfo.java
@@ -33,7 +33,8 @@ public class WallpaperColorInfo implements WallpaperManagerCompat.OnColorsChange
private int mSecondaryColor;
private boolean mIsDark;
private boolean mSupportsDarkText;
- private OnThemeChangeListener mOnThemeChangeListener;
+
+ private OnChangeListener[] mTempListeners;
private WallpaperColorInfo(Context context) {
mWallpaperManager = WallpaperManagerCompat.getInstance(context);
@@ -61,10 +62,8 @@ public class WallpaperColorInfo implements WallpaperManagerCompat.OnColorsChange
@Override
public void onColorsChanged(WallpaperColorsCompat colors, int which) {
if ((which & FLAG_SYSTEM) != 0) {
- boolean wasDarkTheme = mIsDark;
- boolean didSupportDarkText = mSupportsDarkText;
update(colors);
- notifyChange(wasDarkTheme != mIsDark || didSupportDarkText != mSupportsDarkText);
+ notifyChange();
}
}
@@ -85,10 +84,6 @@ public class WallpaperColorInfo implements WallpaperManagerCompat.OnColorsChange
& WallpaperColorsCompat.HINT_SUPPORTS_DARK_THEME) > 0 : false;
}
- public void setOnThemeChangeListener(OnThemeChangeListener onThemeChangeListener) {
- this.mOnThemeChangeListener = onThemeChangeListener;
- }
-
public void addOnChangeListener(OnChangeListener listener) {
mListeners.add(listener);
}
@@ -97,23 +92,19 @@ public class WallpaperColorInfo implements WallpaperManagerCompat.OnColorsChange
mListeners.remove(listener);
}
- public void notifyChange(boolean themeChanged) {
- if (themeChanged) {
- if (mOnThemeChangeListener != null) {
- mOnThemeChangeListener.onThemeChanged();
- }
- } else {
- for (OnChangeListener listener : mListeners) {
- listener.onExtractedColorsChanged(this);
- }
+ private void notifyChange() {
+ OnChangeListener[] copy =
+ mTempListeners != null && mTempListeners.length == mListeners.size() ?
+ mTempListeners : new OnChangeListener[mListeners.size()];
+
+ // Create a new array to avoid concurrent modification when the activity destroys itself.
+ mTempListeners = mListeners.toArray(copy);
+ for (OnChangeListener listener : mTempListeners) {
+ listener.onExtractedColorsChanged(this);
}
}
public interface OnChangeListener {
void onExtractedColorsChanged(WallpaperColorInfo wallpaperColorInfo);
}
-
- public interface OnThemeChangeListener {
- void onThemeChanged();
- }
}
diff --git a/src/com/android/launcher3/folder/PreviewBackground.java b/src/com/android/launcher3/folder/PreviewBackground.java
index a0912a4a06..069ec4ba11 100644
--- a/src/com/android/launcher3/folder/PreviewBackground.java
+++ b/src/com/android/launcher3/folder/PreviewBackground.java
@@ -129,18 +129,15 @@ public class PreviewBackground {
};
public void setup(Launcher launcher, View invalidateDelegate,
- int availableSpace, int topPadding) {
+ int availableSpaceX, int topPadding) {
mInvalidateDelegate = invalidateDelegate;
mBgColor = Themes.getAttrColor(launcher, android.R.attr.colorPrimary);
DeviceProfile grid = launcher.getDeviceProfile();
- final int previewSize = grid.folderIconSizePx;
- final int previewPadding = grid.folderIconPreviewPadding;
+ previewSize = grid.folderIconSizePx;
- this.previewSize = (previewSize - 2 * previewPadding);
-
- basePreviewOffsetX = (availableSpace - this.previewSize) / 2;
- basePreviewOffsetY = previewPadding + grid.folderBackgroundOffset + topPadding;
+ basePreviewOffsetX = (availableSpaceX - previewSize) / 2;
+ basePreviewOffsetY = topPadding + grid.folderIconOffsetYPx;
// Stroke width is 1dp
mStrokeWidth = launcher.getResources().getDisplayMetrics().density;
diff --git a/src/com/android/launcher3/graphics/DragPreviewProvider.java b/src/com/android/launcher3/graphics/DragPreviewProvider.java
index e60a2c70b1..5094280f6a 100644
--- a/src/com/android/launcher3/graphics/DragPreviewProvider.java
+++ b/src/com/android/launcher3/graphics/DragPreviewProvider.java
@@ -76,7 +76,7 @@ public class DragPreviewProvider {
/**
* Draws the {@link #mView} into the given {@param destCanvas}.
*/
- private void drawDragView(Canvas destCanvas, float scale) {
+ protected void drawDragView(Canvas destCanvas, float scale) {
destCanvas.save();
destCanvas.scale(scale, scale);
diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java
index 5d99ba09ff..680c020228 100644
--- a/src/com/android/launcher3/graphics/IconNormalizer.java
+++ b/src/com/android/launcher3/graphics/IconNormalizer.java
@@ -376,4 +376,12 @@ public class IconNormalizer {
last = i;
}
}
+
+ /**
+ * @return The diameter of the normalized circle that fits inside of the square (size x size).
+ */
+ public static int getNormalizedCircleSize(int size) {
+ float area = size * size * MAX_CIRCLE_AREA_FACTOR;
+ return (int) Math.round(Math.sqrt((4 * area) / Math.PI));
+ }
}
diff --git a/src/com/android/launcher3/logging/LoggerUtils.java b/src/com/android/launcher3/logging/LoggerUtils.java
index d68ac15966..01b1424a02 100644
--- a/src/com/android/launcher3/logging/LoggerUtils.java
+++ b/src/com/android/launcher3/logging/LoggerUtils.java
@@ -15,10 +15,12 @@
*/
package com.android.launcher3.logging;
+import android.content.Context;
import android.util.ArrayMap;
import android.util.SparseArray;
import android.view.View;
+import com.android.launcher3.AppInfo;
import com.android.launcher3.ButtonDropTarget;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.LauncherSettings;
@@ -29,6 +31,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.util.InstantAppResolver;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
@@ -127,18 +130,21 @@ public class LoggerUtils {
return t;
}
- public static Target newItemTarget(View v) {
+ public static Target newItemTarget(View v, InstantAppResolver instantAppResolver) {
return (v.getTag() instanceof ItemInfo)
- ? newItemTarget((ItemInfo) v.getTag())
+ ? newItemTarget((ItemInfo) v.getTag(), instantAppResolver)
: newTarget(Target.Type.ITEM);
}
- public static Target newItemTarget(ItemInfo info) {
+ public static Target newItemTarget(ItemInfo info, InstantAppResolver instantAppResolver) {
Target t = newTarget(Target.Type.ITEM);
switch (info.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
- t.itemType = ItemType.APP_ICON;
+ t.itemType = (instantAppResolver != null && info instanceof AppInfo
+ && instantAppResolver.isInstantApp(((AppInfo) info)) )
+ ? ItemType.WEB_APP
+ : ItemType.APP_ICON;
t.predictedRank = -100; // Never assigned
break;
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java
index 627115d878..bf870cca01 100644
--- a/src/com/android/launcher3/logging/UserEventDispatcher.java
+++ b/src/com/android/launcher3/logging/UserEventDispatcher.java
@@ -16,6 +16,14 @@
package com.android.launcher3.logging;
+import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
+import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
+import static com.android.launcher3.logging.LoggerUtils.newDropTarget;
+import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
+import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
+import static com.android.launcher3.logging.LoggerUtils.newTarget;
+import static com.android.launcher3.logging.LoggerUtils.newTouchAction;
+
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
@@ -38,19 +46,13 @@ import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.LauncherEvent;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.InstantAppResolver;
import com.android.launcher3.util.LogConfig;
import java.util.Locale;
import java.util.UUID;
-import static com.android.launcher3.logging.LoggerUtils.newCommandAction;
-import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
-import static com.android.launcher3.logging.LoggerUtils.newDropTarget;
-import static com.android.launcher3.logging.LoggerUtils.newItemTarget;
-import static com.android.launcher3.logging.LoggerUtils.newLauncherEvent;
-import static com.android.launcher3.logging.LoggerUtils.newTarget;
-import static com.android.launcher3.logging.LoggerUtils.newTouchAction;
-
/**
* Manages the creation of {@link LauncherEvent}.
* To debug this class, execute following command before side loading a new apk.
@@ -78,6 +80,7 @@ public class UserEventDispatcher {
ued.mIsInLandscapeMode = dp.isVerticalBarLayout();
ued.mIsInMultiWindowMode = dp.isMultiWindowMode;
ued.mUuidStr = uuidStr;
+ ued.mInstantAppResolver = InstantAppResolver.newInstance(context);
return ued;
}
@@ -126,6 +129,7 @@ public class UserEventDispatcher {
private boolean mIsInMultiWindowMode;
private boolean mIsInLandscapeMode;
private String mUuidStr;
+ protected InstantAppResolver mInstantAppResolver;
// APP_ICON SHORTCUT WIDGET
// --------------------------------------------------------------
@@ -151,7 +155,7 @@ public class UserEventDispatcher {
public void logAppLaunch(View v, Intent intent) {
LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP),
- newItemTarget(v), newTarget(Target.Type.CONTAINER));
+ newItemTarget(v, mInstantAppResolver), newTarget(Target.Type.CONTAINER));
if (fillInLogContainerData(event, v)) {
fillIntentInfo(event.srcTarget[0], intent);
@@ -159,14 +163,15 @@ public class UserEventDispatcher {
dispatchUserEvent(event, intent);
}
- public void logTaskLaunch(int action, int direction, ComponentName componentName){
- LauncherEvent event = newLauncherEvent(newTouchAction(action), // TAP or SWIPE
+ public void logTaskLaunchOrDismiss(int action, int direction, ComponentKey componentKey) {
+ LauncherEvent event = newLauncherEvent(newTouchAction(action), // TAP or SWIPE or FLING
newTarget(Target.Type.ITEM));
if (action == Action.Touch.SWIPE || action == Action.Touch.FLING) {
+ // Direction DOWN means the task was launched, UP means it was dismissed.
event.action.dir = direction;
}
event.srcTarget[0].itemType = LauncherLogProto.ItemType.TASK;
- fillComponentInfo(event.srcTarget[0], componentName);
+ fillComponentInfo(event.srcTarget[0], componentKey.componentName);
dispatchUserEvent(event, null);
}
@@ -184,7 +189,7 @@ public class UserEventDispatcher {
public void logNotificationLaunch(View v, PendingIntent intent) {
LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.TAP),
- newItemTarget(v), newTarget(Target.Type.CONTAINER));
+ newItemTarget(v, mInstantAppResolver), newTarget(Target.Type.CONTAINER));
if (fillInLogContainerData(event, v)) {
event.srcTarget[0].packageNameHash = (mUuidStr + intent.getCreatorPackage()).hashCode();
}
@@ -215,7 +220,7 @@ public class UserEventDispatcher {
*/
public void logActionCommand(int command, View itemView, int srcContainerType) {
LauncherEvent event = newLauncherEvent(newCommandAction(command),
- newItemTarget(itemView), newTarget(Target.Type.CONTAINER));
+ newItemTarget(itemView, mInstantAppResolver), newTarget(Target.Type.CONTAINER));
if (fillInLogContainerData(event, itemView)) {
// TODO: Remove the following two lines once fillInLogContainerData can take in a
@@ -320,7 +325,7 @@ public class UserEventDispatcher {
}
ItemInfo info = (ItemInfo) icon.getTag();
LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.LONGPRESS),
- newItemTarget(info), newTarget(Target.Type.CONTAINER));
+ newItemTarget(info, mInstantAppResolver), newTarget(Target.Type.CONTAINER));
provider.fillInLogContainerData(icon, info, event.srcTarget[0], event.srcTarget[1]);
dispatchUserEvent(event, null);
@@ -338,9 +343,11 @@ public class UserEventDispatcher {
public void logDragNDrop(DropTarget.DragObject dragObj, View dropTargetAsView) {
LauncherEvent event = newLauncherEvent(newTouchAction(Action.Touch.DRAGDROP),
- newItemTarget(dragObj.originalDragInfo), newTarget(Target.Type.CONTAINER));
+ newItemTarget(dragObj.originalDragInfo, mInstantAppResolver),
+ newTarget(Target.Type.CONTAINER));
event.destTarget = new Target[] {
- newItemTarget(dragObj.originalDragInfo), newDropTarget(dropTargetAsView)
+ newItemTarget(dragObj.originalDragInfo, mInstantAppResolver),
+ newDropTarget(dropTargetAsView)
};
dragObj.dragSource.fillInLogContainerData(null, dragObj.originalDragInfo,
diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java
new file mode 100644
index 0000000000..1149b553f6
--- /dev/null
+++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.model;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageInstaller.SessionInfo;
+import android.util.Log;
+
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.util.MultiHashMap;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * Helper class to send broadcasts to package installers that have:
+ * - Items on the first screen
+ * - Items with an active install session
+ *
+ * The packages are broken down by: folder items, workspace items, hotseat items, and widgets.
+ *
+ * Package installers only receive data for items that they are installing.
+ */
+public class FirstScreenBroadcast {
+
+ private static final String TAG = "FirstScreenBroadcast";
+ private static final boolean DEBUG = false;
+
+ private static final String ACTION_FIRST_SCREEN_ACTIVE_INSTALLS
+ = "com.android.launcher3.action.FIRST_SCREEN_ACTIVE_INSTALLS";
+
+ private static final String FOLDER_ITEM_EXTRA = "folderItem";
+ private static final String WORKSPACE_ITEM_EXTRA = "workspaceItem";
+ private static final String HOTSEAT_ITEM_EXTRA = "hotseatItem";
+ private static final String WIDGET_ITEM_EXTRA = "widgetItem";
+
+ private static final String VERIFICATION_TOKEN_EXTRA = "verificationToken";
+
+ private final MultiHashMap mPackagesForInstaller;
+
+ public FirstScreenBroadcast(HashMap sessionInfoForPackage) {
+ mPackagesForInstaller = getPackagesForInstaller(sessionInfoForPackage);
+ }
+
+ /**
+ * @return Map where the key is the package name of the installer, and the value is a list
+ * of packages with active sessions for that installer.
+ */
+ private MultiHashMap getPackagesForInstaller(
+ HashMap sessionInfoForPackage) {
+ MultiHashMap packagesForInstaller = new MultiHashMap<>();
+ for (Map.Entry entry : sessionInfoForPackage.entrySet()) {
+ packagesForInstaller.addToList(entry.getValue().getInstallerPackageName(),
+ entry.getKey());
+ }
+ return packagesForInstaller;
+ }
+
+ /**
+ * Sends a broadcast to all package installers that have items with active sessions on the users
+ * first screen.
+ */
+ public void sendBroadcasts(Context context, List firstScreenItems) {
+ for (Map.Entry> entry : mPackagesForInstaller.entrySet()) {
+ sendBroadcastToInstaller(context, entry.getKey(), entry.getValue(), firstScreenItems);
+ }
+ }
+
+ /**
+ * @param installerPackageName Package name of the package installer.
+ * @param packages List of packages with active sessions for this package installer.
+ * @param firstScreenItems List of items on the first screen.
+ */
+ private void sendBroadcastToInstaller(Context context, String installerPackageName,
+ List packages, List firstScreenItems) {
+ Set folderItems = new HashSet<>();
+ Set workspaceItems = new HashSet<>();
+ Set hotseatItems = new HashSet<>();
+ Set widgetItems = new HashSet<>();
+
+ for (ItemInfo info : firstScreenItems) {
+ if (info instanceof FolderInfo) {
+ FolderInfo folderInfo = (FolderInfo) info;
+ String folderItemInfoPackage;
+ for (ItemInfo folderItemInfo : folderInfo.contents) {
+ folderItemInfoPackage = getPackageName(folderItemInfo);
+ if (folderItemInfoPackage != null
+ && packages.contains(folderItemInfoPackage)) {
+ folderItems.add(folderItemInfoPackage);
+ }
+ }
+ }
+
+ String packageName = getPackageName(info);
+ if (packageName == null || !packages.contains(packageName)) {
+ continue;
+ }
+ if (info instanceof LauncherAppWidgetInfo) {
+ widgetItems.add(packageName);
+ } else if (info.container == LauncherSettings.Favorites.CONTAINER_HOTSEAT) {
+ hotseatItems.add(packageName);
+ } else if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
+ workspaceItems.add(packageName);
+ }
+ }
+
+ if (DEBUG) {
+ printList(installerPackageName, "Folder item", folderItems);
+ printList(installerPackageName, "Workspace item", workspaceItems);
+ printList(installerPackageName, "Hotseat item", hotseatItems);
+ printList(installerPackageName, "Widget item", widgetItems);
+ }
+
+ context.sendBroadcast(new Intent(ACTION_FIRST_SCREEN_ACTIVE_INSTALLS)
+ .setPackage(installerPackageName)
+ .putStringArrayListExtra(FOLDER_ITEM_EXTRA, new ArrayList<>(folderItems))
+ .putStringArrayListExtra(WORKSPACE_ITEM_EXTRA, new ArrayList<>(workspaceItems))
+ .putStringArrayListExtra(HOTSEAT_ITEM_EXTRA, new ArrayList<>(hotseatItems))
+ .putStringArrayListExtra(WIDGET_ITEM_EXTRA, new ArrayList<>(widgetItems))
+ .putExtra(VERIFICATION_TOKEN_EXTRA, PendingIntent.getActivity(context, 0,
+ new Intent(), PendingIntent.FLAG_ONE_SHOT)));
+ }
+
+ private static String getPackageName(ItemInfo info) {
+ String packageName = null;
+ if (info instanceof LauncherAppWidgetInfo) {
+ LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) info;
+ if (widgetInfo.providerName != null) {
+ packageName = widgetInfo.providerName.getPackageName();
+ }
+ } else if (info.getTargetComponent() != null){
+ packageName = info.getTargetComponent().getPackageName();
+ }
+ return packageName;
+ }
+
+ private static void printList(String packageInstaller, String label, Set packages) {
+ for (String pkg : packages) {
+ Log.d(TAG, packageInstaller + ":" + label + ":" + pkg);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/model/LoaderResults.java b/src/com/android/launcher3/model/LoaderResults.java
index 5d4a352994..0fd9b735ed 100644
--- a/src/com/android/launcher3/model/LoaderResults.java
+++ b/src/com/android/launcher3/model/LoaderResults.java
@@ -209,7 +209,7 @@ public class LoaderResults {
/** Filters the set of items who are directly or indirectly (via another container) on the
* specified screen. */
- private void filterCurrentWorkspaceItems(long currentScreenId,
+ public static void filterCurrentWorkspaceItems(long currentScreenId,
ArrayList allWorkspaceItems,
ArrayList currentScreenItems,
ArrayList otherScreenItems) {
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 9d1ff83168..06da843f7f 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -20,6 +20,7 @@ import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
import static com.android.launcher3.folder.ClippedFolderIconLayoutRule.MAX_NUM_ITEMS_IN_PREVIEW;
+import static com.android.launcher3.model.LoaderResults.filterCurrentWorkspaceItems;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
@@ -29,6 +30,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.PackageInstaller;
+import android.content.pm.PackageInstaller.SessionInfo;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Process;
@@ -92,6 +94,8 @@ public class LoaderTask implements Runnable {
private final AllAppsList mBgAllAppsList;
private final BgDataModel mBgDataModel;
+ private FirstScreenBroadcast mFirstScreenBroadcast;
+
private final LoaderResults mResults;
private final LauncherAppsCompat mLauncherApps;
@@ -134,6 +138,22 @@ public class LoaderTask implements Runnable {
}
}
+ private void sendFirstScreenActiveInstallsBroadcast() {
+ ArrayList firstScreenItems = new ArrayList<>();
+
+ ArrayList allItems = new ArrayList<>();
+ synchronized (mBgDataModel) {
+ allItems.addAll(mBgDataModel.workspaceItems);
+ allItems.addAll(mBgDataModel.appWidgets);
+ }
+ long firstScreen = mBgDataModel.workspaceScreens.isEmpty()
+ ? -1 // In this case, we can still look at the items in the hotseat.
+ : mBgDataModel.workspaceScreens.get(0);
+ filterCurrentWorkspaceItems(firstScreen, allItems, firstScreenItems,
+ new ArrayList<>() /* otherScreenItems are ignored */);
+ mFirstScreenBroadcast.sendBroadcasts(mApp.getContext(), firstScreenItems);
+ }
+
public void run() {
synchronized (this) {
// Skip fast if we are already stopped.
@@ -151,6 +171,10 @@ public class LoaderTask implements Runnable {
TraceHelper.partitionSection(TAG, "step 1.2: bind workspace workspace");
mResults.bindWorkspace();
+ // Notify the installer packages of packages with active installs on the first screen.
+ TraceHelper.partitionSection(TAG, "step 1.3: send first screen broadcast");
+ sendFirstScreenActiveInstallsBroadcast();
+
// Take a break
TraceHelper.partitionSection(TAG, "step 1 completed, wait for idle");
waitForIdle();
@@ -242,8 +266,9 @@ public class LoaderTask implements Runnable {
synchronized (mBgDataModel) {
mBgDataModel.clear();
- final HashMap installingPkgs =
+ final HashMap installingPkgs =
mPackageInstaller.updateAndGetActiveSessionCache();
+ mFirstScreenBroadcast = new FirstScreenBroadcast(installingPkgs);
mBgDataModel.workspaceScreens.addAll(LauncherModel.loadWorkspaceScreensDb(context));
Map shortcutKeyToPinnedShortcuts = new HashMap<>();
@@ -511,11 +536,11 @@ public class LoaderTask implements Runnable {
}
if (c.restoreFlag != 0 && !TextUtils.isEmpty(targetPkg)) {
- Integer progress = installingPkgs.get(targetPkg);
- if (progress != null) {
- info.setInstallProgress(progress);
- } else {
+ SessionInfo si = installingPkgs.get(targetPkg);
+ if (si == null) {
info.status &= ~ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE;
+ } else {
+ info.setInstallProgress((int) (si.getProgress() * 100));
}
}
@@ -605,7 +630,11 @@ public class LoaderTask implements Runnable {
appWidgetInfo = new LauncherAppWidgetInfo(appWidgetId,
component);
appWidgetInfo.restoreStatus = c.restoreFlag;
- Integer installProgress = installingPkgs.get(component.getPackageName());
+ SessionInfo si =
+ installingPkgs.get(component.getPackageName());
+ Integer installProgress = si == null
+ ? null
+ : (int) (si.getProgress() * 100);
if (c.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_RESTORE_STARTED)) {
// Restore has started once.
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 72c703b2e5..eba7515248 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -50,7 +50,6 @@ import java.util.concurrent.Executor;
public class ModelWriter {
private static final String TAG = "ModelWriter";
- public static final boolean DEBUG_DELETE = true;
private final Context mContext;
private final LauncherModel mModel;
@@ -257,14 +256,6 @@ public class ModelWriter {
* Removes the specified items from the database
*/
public void deleteItemsFromDatabase(final Iterable extends ItemInfo> items) {
- if (DEBUG_DELETE) {
- // Log it on the colling thread to get the proper stack trace
- FileLog.d(TAG, "Starting item deletion", new Exception());
- for (ItemInfo item : items) {
- FileLog.d(TAG, "deleting item " + item);
- }
- FileLog.d(TAG, "Finished deleting items");
- }
ModelVerifier verifier = new ModelVerifier();
mWorkerExecutor.execute(() -> {
@@ -282,11 +273,6 @@ public class ModelWriter {
* Remove the specified folder and all its contents from the database.
*/
public void deleteFolderAndContentsFromDatabase(final FolderInfo info) {
- if (DEBUG_DELETE) {
- // Log it on the colling thread to get the proper stack trace
- FileLog.d(TAG, "Deleting folder " + info, new Exception());
- }
-
ModelVerifier verifier = new ModelVerifier();
mWorkerExecutor.execute(() -> {
diff --git a/src/com/android/launcher3/notification/NotificationItemView.java b/src/com/android/launcher3/notification/NotificationItemView.java
index 2fefa85ea3..32410a64b8 100644
--- a/src/com/android/launcher3/notification/NotificationItemView.java
+++ b/src/com/android/launcher3/notification/NotificationItemView.java
@@ -20,7 +20,6 @@ import android.app.Notification;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Rect;
-import android.support.annotation.Nullable;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup.MarginLayoutParams;
@@ -83,7 +82,7 @@ public class NotificationItemView {
public void addGutter() {
if (mGutter == null) {
- mGutter = mContainer.inflateAndAdd(R.layout.notification_gutter);
+ mGutter = mContainer.inflateAndAdd(R.layout.notification_gutter, mContainer);
}
}
diff --git a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
index 94ae39bb5c..4ad7feb903 100644
--- a/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
+++ b/src/com/android/launcher3/pageindicators/WorkspacePageIndicator.java
@@ -1,9 +1,5 @@
package com.android.launcher3.pageindicators;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-
-import static com.android.launcher3.LauncherState.ALL_APPS;
-
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ObjectAnimator;
@@ -20,9 +16,7 @@ import android.util.AttributeSet;
import android.util.Property;
import android.view.Gravity;
import android.view.View;
-import android.view.View.OnClickListener;
import android.view.ViewConfiguration;
-import android.view.accessibility.AccessibilityManager;
import android.widget.FrameLayout;
import com.android.launcher3.DeviceProfile;
@@ -31,18 +25,13 @@ import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.dynamicui.WallpaperColorInfo;
-import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
/**
- * A PageIndicator that briefly shows a fraction of a line when moving between pages in
- * portrait mode. In Landscape simply draws the caret drawable bottom-corner aligned in
- * the drag-layer.
+ * A PageIndicator that briefly shows a fraction of a line when moving between pages
*
* The fraction is 1 / number of pages and the position is based on the progress of the page scroll.
*/
-public class WorkspacePageIndicator extends View
- implements Insettable, OnClickListener, PageIndicator {
+public class WorkspacePageIndicator extends View implements Insettable, PageIndicator {
private static final int LINE_ANIMATE_DURATION = ViewConfiguration.getScrollBarFadeDuration();
private static final int LINE_FADE_DELAY = ViewConfiguration.getScrollDefaultDelay();
@@ -57,7 +46,6 @@ public class WorkspacePageIndicator extends View
private final Handler mDelayedLineFadeHandler = new Handler(Looper.getMainLooper());
private final Launcher mLauncher;
- private final AccessibilityManager mAccessibilityManager;
private boolean mShouldAutoHide = true;
@@ -72,8 +60,6 @@ public class WorkspacePageIndicator extends View
private Paint mLinePaint;
private final int mLineHeight;
- private boolean mIsLandscapeUi;
-
private static final Property PAINT_ALPHA
= new Property(Integer.class, "paint_alpha") {
@Override
@@ -84,7 +70,7 @@ public class WorkspacePageIndicator extends View
@Override
public void set(WorkspacePageIndicator obj, Integer alpha) {
obj.mLinePaint.setAlpha(alpha);
- obj.invalidateIfPortrait();
+ obj.invalidate();
}
};
@@ -98,7 +84,7 @@ public class WorkspacePageIndicator extends View
@Override
public void set(WorkspacePageIndicator obj, Float numPages) {
obj.mNumPagesFloat = numPages;
- obj.invalidateIfPortrait();
+ obj.invalidate();
}
};
@@ -112,7 +98,7 @@ public class WorkspacePageIndicator extends View
@Override
public void set(WorkspacePageIndicator obj, Integer totalScroll) {
obj.mTotalScroll = totalScroll;
- obj.invalidateIfPortrait();
+ obj.invalidate();
}
};
@@ -139,24 +125,23 @@ public class WorkspacePageIndicator extends View
boolean darkText = WallpaperColorInfo.getInstance(context).supportsDarkText();
mActiveAlpha = darkText ? BLACK_ALPHA : WHITE_ALPHA;
mLinePaint.setColor(darkText ? Color.BLACK : Color.WHITE);
- mAccessibilityManager = (AccessibilityManager)
- getContext().getSystemService(Context.ACCESSIBILITY_SERVICE);
}
@Override
protected void onDraw(Canvas canvas) {
- if (mTotalScroll == 0 || mNumPagesFloat == 0 || mIsLandscapeUi) {
+ if (mTotalScroll == 0 || mNumPagesFloat == 0) {
return;
}
// Compute and draw line rect.
float progress = Utilities.boundToRange(((float) mCurrentScroll) / mTotalScroll, 0f, 1f);
- int availableWidth = canvas.getWidth();
+ int availableWidth = getWidth();
int lineWidth = (int) (availableWidth / mNumPagesFloat);
int lineLeft = (int) (progress * (availableWidth - lineWidth));
int lineRight = lineLeft + lineWidth;
- canvas.drawRoundRect(lineLeft, canvas.getHeight() / 2 - mLineHeight / 2, lineRight,
- canvas.getHeight() / 2 + mLineHeight / 2, mLineHeight, mLineHeight, mLinePaint);
+
+ canvas.drawRoundRect(lineLeft, getHeight() / 2 - mLineHeight / 2, lineRight,
+ getHeight() / 2 + mLineHeight / 2, mLineHeight, mLineHeight, mLinePaint);
}
@Override
@@ -172,7 +157,7 @@ public class WorkspacePageIndicator extends View
} else if (mTotalScroll != totalScroll) {
animateToTotalScroll(totalScroll);
} else {
- invalidateIfPortrait();
+ invalidate();
}
if (mShouldAutoHide) {
@@ -191,7 +176,13 @@ public class WorkspacePageIndicator extends View
@Override
public void setMarkersCount(int numMarkers) {
if (Float.compare(numMarkers, mNumPagesFloat) != 0) {
- animateToNumPages(numMarkers);
+ setupAndRunAnimation(ObjectAnimator.ofFloat(this, NUM_PAGES, numMarkers),
+ NUM_PAGES_ANIMATOR_INDEX);
+ } else {
+ if (mAnimators[NUM_PAGES_ANIMATOR_INDEX] != null) {
+ mAnimators[NUM_PAGES_ANIMATOR_INDEX].cancel();
+ mAnimators[NUM_PAGES_ANIMATOR_INDEX] = null;
+ }
}
}
@@ -219,11 +210,6 @@ public class WorkspacePageIndicator extends View
LINE_ALPHA_ANIMATOR_INDEX);
}
- private void animateToNumPages(int numPages) {
- setupAndRunAnimation(ObjectAnimator.ofFloat(this, NUM_PAGES, numPages),
- NUM_PAGES_ANIMATOR_INDEX);
- }
-
private void animateToTotalScroll(int totalScroll) {
setupAndRunAnimation(ObjectAnimator.ofInt(this, TOTAL_SCROLL, totalScroll),
TOTAL_SCROLL_ANIMATOR_INDEX);
@@ -254,54 +240,18 @@ public class WorkspacePageIndicator extends View
@Override
public void setInsets(Rect insets) {
DeviceProfile grid = mLauncher.getDeviceProfile();
- mIsLandscapeUi = grid.isVerticalBarLayout();
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
- if (mIsLandscapeUi) {
- if (grid.isSeascape()) {
- lp.leftMargin = grid.hotseatBarSidePaddingPx;
- lp.rightMargin = insets.right;
- lp.gravity = Gravity.RIGHT | Gravity.BOTTOM;
- } else {
- lp.leftMargin = insets.left;
- lp.rightMargin = grid.hotseatBarSidePaddingPx;
- lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
- }
- lp.bottomMargin = grid.workspacePadding.bottom;
- lp.width = lp.height = getResources()
- .getDimensionPixelSize(R.dimen.dynamic_grid_min_page_indicator_size);
-
- setBackgroundResource(R.drawable.all_apps_handle_landscape);
- setOnFocusChangeListener(mLauncher.mFocusHandler);
- setOnClickListener(this);
-
+ if (grid.isVerticalBarLayout()) {
+ Rect padding = grid.workspacePadding;
+ lp.leftMargin = padding.left + grid.workspaceCellPaddingXPx;
+ lp.rightMargin = padding.right + grid.workspaceCellPaddingXPx;
+ lp.bottomMargin = padding.bottom;
} else {
lp.leftMargin = lp.rightMargin = 0;
lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
- lp.height = grid.pageIndicatorSizePx;
lp.bottomMargin = grid.hotseatBarSizePx + insets.bottom;
- lp.width = MATCH_PARENT;
-
- setBackgroundResource(0);
- setOnFocusChangeListener(null);
- setOnClickListener(mAccessibilityManager.isTouchExplorationEnabled() ? this : null);
}
-
setLayoutParams(lp);
}
-
- private void invalidateIfPortrait() {
- if (!mIsLandscapeUi) {
- invalidate();
- }
- }
-
- @Override
- public void onClick(View view) {
- if (!mLauncher.isInState(ALL_APPS)) {
- mLauncher.getUserEventDispatcher().logActionOnControl(
- Action.Touch.TAP, ControlType.ALL_APPS_BUTTON);
- mLauncher.getStateManager().goToState(ALL_APPS);
- }
- }
}
diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java
new file mode 100644
index 0000000000..bd08aaa0eb
--- /dev/null
+++ b/src/com/android/launcher3/popup/ArrowPopup.java
@@ -0,0 +1,470 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.popup;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.animation.TimeInterpolator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.CornerPathEffect;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.drawable.ShapeDrawable;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewOutlineProvider;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.animation.AccelerateDecelerateInterpolator;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.RevealOutlineAnimation;
+import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.graphics.TriangleShape;
+import com.android.launcher3.util.Themes;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
+
+/**
+ * A container for shortcuts to deep links and notifications associated with an app.
+ */
+public abstract class ArrowPopup extends AbstractFloatingView {
+
+ private final Rect mTempRect = new Rect();
+
+ protected final LayoutInflater mInflater;
+ private final float mOutlineRadius;
+ protected final Launcher mLauncher;
+ protected final boolean mIsRtl;
+
+ private final int mArrayOffset;
+ private final View mArrow;
+
+ protected boolean mIsLeftAligned;
+ protected boolean mIsAboveIcon;
+ private int mGravity;
+
+ protected Animator mOpenCloseAnimator;
+ protected boolean mDeferContainerRemoval;
+ private final Rect mStartRect = new Rect();
+ private final Rect mEndRect = new Rect();
+
+ public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mInflater = LayoutInflater.from(context);
+ mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius);
+ mLauncher = Launcher.getLauncher(context);
+ mIsRtl = Utilities.isRtl(getResources());
+
+ setClipToOutline(true);
+ setOutlineProvider(new ViewOutlineProvider() {
+ @Override
+ public void getOutline(View view, Outline outline) {
+ outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius);
+ }
+ });
+
+ // Initialize arrow view
+ final Resources resources = getResources();
+ final int arrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width);
+ final int arrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height);
+ mArrow = new View(context);
+ mArrow.setLayoutParams(new DragLayer.LayoutParams(arrowWidth, arrowHeight));
+ mArrayOffset = resources.getDimensionPixelSize(R.dimen.popup_arrow_vertical_offset);
+ }
+
+ public ArrowPopup(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public ArrowPopup(Context context) {
+ this(context, null, 0);
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ if (animate) {
+ animateClose();
+ } else {
+ closeComplete();
+ }
+ }
+
+ public T inflateAndAdd(int resId, ViewGroup container) {
+ View view = mInflater.inflate(resId, container, false);
+ container.addView(view);
+ return (T) view;
+ }
+
+ /**
+ * Called when all view inflation and reordering in complete.
+ */
+ protected void onInflationComplete(boolean isReversed) { }
+
+ /**
+ * Shows the popup at the desired location, optionally reversing the children.
+ * @param viewsToFlip number of views from the top to to flip in case of reverse order
+ */
+ protected void reorderAndShow(int viewsToFlip) {
+ setVisibility(View.INVISIBLE);
+ mIsOpen = true;
+ mLauncher.getDragLayer().addView(this);
+ orientAboutObject();
+
+ boolean reverseOrder = mIsAboveIcon;
+ if (reverseOrder) {
+ int count = getChildCount();
+ ArrayList allViews = new ArrayList<>(count);
+ for (int i = 0; i < count; i++) {
+ if (i == viewsToFlip) {
+ Collections.reverse(allViews);
+ }
+ allViews.add(getChildAt(i));
+ }
+ Collections.reverse(allViews);
+ removeAllViews();
+ for (int i = 0; i < count; i++) {
+ addView(allViews.get(i));
+ }
+
+ orientAboutObject();
+ }
+ onInflationComplete(reverseOrder);
+
+ // Add the arrow.
+ final Resources res = getResources();
+ final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart()
+ ? R.dimen.popup_arrow_horizontal_center_start
+ : R.dimen.popup_arrow_horizontal_center_end);
+ final int halfArrowWidth = res.getDimensionPixelSize(R.dimen.popup_arrow_width) / 2;
+ mLauncher.getDragLayer().addView(mArrow);
+ DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams();
+ if (mIsLeftAligned) {
+ mArrow.setX(getX() + arrowCenterOffset - halfArrowWidth);
+ } else {
+ mArrow.setX(getX() + getMeasuredWidth() - arrowCenterOffset - halfArrowWidth);
+ }
+
+ if (Gravity.isVertical(mGravity)) {
+ // This is only true if there wasn't room for the container next to the icon,
+ // so we centered it instead. In that case we don't want to showDefaultOptions the arrow.
+ mArrow.setVisibility(INVISIBLE);
+ } else {
+ ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create(
+ arrowLp.width, arrowLp.height, !mIsAboveIcon));
+ Paint arrowPaint = arrowDrawable.getPaint();
+ arrowPaint.setColor(Themes.getAttrColor(mLauncher, R.attr.popupColorPrimary));
+ // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
+ int radius = getResources().getDimensionPixelSize(R.dimen.popup_arrow_corner_radius);
+ arrowPaint.setPathEffect(new CornerPathEffect(radius));
+ mArrow.setBackground(arrowDrawable);
+ mArrow.setElevation(getElevation());
+ }
+
+ mArrow.setPivotX(arrowLp.width / 2);
+ mArrow.setPivotY(mIsAboveIcon ? 0 : arrowLp.height);
+
+ animateOpen();
+ }
+
+ protected boolean isAlignedWithStart() {
+ return mIsLeftAligned && !mIsRtl || !mIsLeftAligned && mIsRtl;
+ }
+
+ /**
+ * Provide the location of the target object relative to the dragLayer.
+ */
+ protected abstract void getTargetObjectLocation(Rect outPos);
+
+ /**
+ * Orients this container above or below the given icon, aligning with the left or right.
+ *
+ * These are the preferred orientations, in order (RTL prefers right-aligned over left):
+ * - Above and left-aligned
+ * - Above and right-aligned
+ * - Below and left-aligned
+ * - Below and right-aligned
+ *
+ * So we always align left if there is enough horizontal space
+ * and align above if there is enough vertical space.
+ */
+ protected void orientAboutObject() {
+ measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
+ int width = getMeasuredWidth();
+ int extraVerticalSpace = mArrow.getLayoutParams().height + mArrayOffset
+ + getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
+ int height = getMeasuredHeight() + extraVerticalSpace;
+
+ getTargetObjectLocation(mTempRect);
+ DragLayer dragLayer = mLauncher.getDragLayer();
+ Rect insets = dragLayer.getInsets();
+
+ // Align left (right in RTL) if there is room.
+ int leftAlignedX = mTempRect.left;
+ int rightAlignedX = mTempRect.right - width;
+ int x = leftAlignedX;
+ boolean canBeLeftAligned = leftAlignedX + width + insets.left
+ < dragLayer.getRight() - insets.right;
+ boolean canBeRightAligned = rightAlignedX > dragLayer.getLeft() + insets.left;
+ if (!canBeLeftAligned || (mIsRtl && canBeRightAligned)) {
+ x = rightAlignedX;
+ }
+ mIsLeftAligned = x == leftAlignedX;
+
+ // Offset x so that the arrow and shortcut icons are center-aligned with the original icon.
+ int iconWidth = mTempRect.width();
+ Resources resources = getResources();
+ int xOffset;
+ if (isAlignedWithStart()) {
+ // Aligning with the shortcut icon.
+ int shortcutIconWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcut_icon_size);
+ int shortcutPaddingStart = resources.getDimensionPixelSize(
+ R.dimen.popup_padding_start);
+ xOffset = iconWidth / 2 - shortcutIconWidth / 2 - shortcutPaddingStart;
+ } else {
+ // Aligning with the drag handle.
+ int shortcutDragHandleWidth = resources.getDimensionPixelSize(
+ R.dimen.deep_shortcut_drag_handle_size);
+ int shortcutPaddingEnd = resources.getDimensionPixelSize(
+ R.dimen.popup_padding_end);
+ xOffset = iconWidth / 2 - shortcutDragHandleWidth / 2 - shortcutPaddingEnd;
+ }
+ x += mIsLeftAligned ? xOffset : -xOffset;
+
+ // Open above icon if there is room.
+ int iconHeight = mTempRect.height();
+ int y = mTempRect.top - height;
+ mIsAboveIcon = y > dragLayer.getTop() + insets.top;
+ if (!mIsAboveIcon) {
+ y = mTempRect.top + iconHeight + extraVerticalSpace;
+ }
+
+ // Insets are added later, so subtract them now.
+ if (mIsRtl) {
+ x += insets.right;
+ } else {
+ x -= insets.left;
+ }
+ y -= insets.top;
+
+ mGravity = 0;
+ if (y + height > dragLayer.getBottom() - insets.bottom) {
+ // The container is opening off the screen, so just center it in the drag layer instead.
+ mGravity = Gravity.CENTER_VERTICAL;
+ // Put the container next to the icon, preferring the right side in ltr (left in rtl).
+ int rightSide = leftAlignedX + iconWidth - insets.left;
+ int leftSide = rightAlignedX - iconWidth - insets.left;
+ if (!mIsRtl) {
+ if (rightSide + width < dragLayer.getRight()) {
+ x = rightSide;
+ mIsLeftAligned = true;
+ } else {
+ x = leftSide;
+ mIsLeftAligned = false;
+ }
+ } else {
+ if (leftSide > dragLayer.getLeft()) {
+ x = leftSide;
+ mIsLeftAligned = false;
+ } else {
+ x = rightSide;
+ mIsLeftAligned = true;
+ }
+ }
+ mIsAboveIcon = true;
+ }
+
+ setX(x);
+ if (Gravity.isVertical(mGravity)) {
+ return;
+ }
+
+ DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
+ DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams();
+ if (mIsAboveIcon) {
+ arrowLp.gravity = lp.gravity = Gravity.BOTTOM;
+ lp.bottomMargin =
+ mLauncher.getDragLayer().getHeight() - y - getMeasuredHeight() - insets.top;
+ arrowLp.bottomMargin = lp.bottomMargin - arrowLp.height - mArrayOffset - insets.bottom;
+ } else {
+ arrowLp.gravity = lp.gravity = Gravity.TOP;
+ lp.topMargin = y + insets.top;
+ arrowLp.topMargin = lp.topMargin - insets.top - arrowLp.height - mArrayOffset;
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+
+ // enforce contained is within screen
+ DragLayer dragLayer = mLauncher.getDragLayer();
+ if (getTranslationX() + l < 0 || getTranslationX() + r > dragLayer.getWidth()) {
+ // If we are still off screen, center horizontally too.
+ mGravity |= Gravity.CENTER_HORIZONTAL;
+ }
+
+ if (Gravity.isHorizontal(mGravity)) {
+ setX(dragLayer.getWidth() / 2 - getMeasuredWidth() / 2);
+ mArrow.setVisibility(INVISIBLE);
+ }
+ if (Gravity.isVertical(mGravity)) {
+ setY(dragLayer.getHeight() / 2 - getMeasuredHeight() / 2);
+ }
+ }
+
+ private void animateOpen() {
+ setVisibility(View.VISIBLE);
+
+ final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
+ final Resources res = getResources();
+ final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration);
+ final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
+
+ // Rectangular reveal.
+ final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
+ .createRevealAnimator(this, false);
+ revealAnim.setDuration(revealDuration);
+ revealAnim.setInterpolator(revealInterpolator);
+
+ Animator fadeIn = ObjectAnimator.ofFloat(this, ALPHA, 0, 1);
+ fadeIn.setDuration(revealDuration);
+ fadeIn.setInterpolator(revealInterpolator);
+ openAnim.play(fadeIn);
+
+ // Animate the arrow.
+ mArrow.setScaleX(0);
+ mArrow.setScaleY(0);
+ Animator arrowScale = ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 1)
+ .setDuration(res.getInteger(R.integer.config_popupArrowOpenDuration));
+
+ openAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mOpenCloseAnimator = null;
+ sendCustomAccessibilityEvent(
+ ArrowPopup.this,
+ AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
+ getContext().getString(R.string.action_deep_shortcut));
+ }
+ });
+
+ mOpenCloseAnimator = openAnim;
+ openAnim.playSequentially(revealAnim, arrowScale);
+ openAnim.start();
+ }
+
+ protected void animateClose() {
+ if (!mIsOpen) {
+ return;
+ }
+ mEndRect.setEmpty();
+ if (getOutlineProvider() instanceof RevealOutlineAnimation) {
+ ((RevealOutlineAnimation) getOutlineProvider()).getOutline(mEndRect);
+ }
+ if (mOpenCloseAnimator != null) {
+ mOpenCloseAnimator.cancel();
+ }
+ mIsOpen = false;
+
+ final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
+ // Hide the arrow
+ closeAnim.play(ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 0));
+ closeAnim.play(ObjectAnimator.ofFloat(mArrow, ALPHA, 0));
+
+ final Resources res = getResources();
+ final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
+
+ // Rectangular reveal (reversed).
+ final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
+ .createRevealAnimator(this, true);
+ revealAnim.setInterpolator(revealInterpolator);
+ closeAnim.play(revealAnim);
+
+ Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0);
+ fadeOut.setInterpolator(revealInterpolator);
+ closeAnim.play(fadeOut);
+
+ onCreateCloseAnimation(closeAnim);
+ closeAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration));
+ closeAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mOpenCloseAnimator = null;
+ if (mDeferContainerRemoval) {
+ setVisibility(INVISIBLE);
+ } else {
+ closeComplete();
+ }
+ }
+ });
+ mOpenCloseAnimator = closeAnim;
+ closeAnim.start();
+ }
+
+ /**
+ * Called when creating the close transition allowing subclass can add additional animations.
+ */
+ protected void onCreateCloseAnimation(AnimatorSet anim) { }
+
+ private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
+ int arrowCenterX = getResources().getDimensionPixelSize(mIsLeftAligned ^ mIsRtl ?
+ R.dimen.popup_arrow_horizontal_center_start:
+ R.dimen.popup_arrow_horizontal_center_end);
+ if (!mIsLeftAligned) {
+ arrowCenterX = getMeasuredWidth() - arrowCenterX;
+ }
+ int arrowCenterY = mIsAboveIcon ? getMeasuredHeight() : 0;
+
+ mStartRect.set(arrowCenterX, arrowCenterY, arrowCenterX, arrowCenterY);
+ if (mEndRect.isEmpty()) {
+ mEndRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
+ }
+
+ return new RoundedRectRevealOutlineProvider
+ (mOutlineRadius, mOutlineRadius, mStartRect, mEndRect);
+ }
+
+ /**
+ * Closes the popup without animation.
+ */
+ protected void closeComplete() {
+ if (mOpenCloseAnimator != null) {
+ mOpenCloseAnimator.cancel();
+ mOpenCloseAnimator = null;
+ }
+ mIsOpen = false;
+ mDeferContainerRemoval = false;
+ mLauncher.getDragLayer().removeView(this);
+ mLauncher.getDragLayer().removeView(mArrow);
+ }
+}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index 033fdf8889..b522b55137 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -16,36 +16,28 @@
package com.android.launcher3.popup;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
+import static com.android.launcher3.notification.NotificationMainView.NOTIFICATION_ITEM_INFO;
+import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
+import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
+import static com.android.launcher3.userevent.nano.LauncherLogProto.Target;
+
import android.animation.AnimatorSet;
import android.animation.LayoutTransition;
-import android.animation.ObjectAnimator;
-import android.animation.TimeInterpolator;
-import android.animation.ValueAnimator;
import android.annotation.TargetApi;
import android.content.Context;
-import android.content.res.Resources;
-import android.graphics.CornerPathEffect;
-import android.graphics.Outline;
-import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
-import android.graphics.drawable.ShapeDrawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
-import android.view.Gravity;
-import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
-import android.view.accessibility.AccessibilityEvent;
-import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.ImageView;
import com.android.launcher3.AbstractFloatingView;
@@ -56,20 +48,15 @@ import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.ItemInfoWithIcon;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.accessibility.ShortcutMenuAccessibilityDelegate;
-import com.android.launcher3.anim.RevealOutlineAnimation;
-import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.badge.BadgeInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
-import com.android.launcher3.graphics.TriangleShape;
import com.android.launcher3.logging.LoggerUtils;
import com.android.launcher3.notification.NotificationInfo;
import com.android.launcher3.notification.NotificationItemView;
@@ -79,85 +66,38 @@ import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.PackageUserKey;
-import com.android.launcher3.util.Themes;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
-import static com.android.launcher3.notification.NotificationMainView.NOTIFICATION_ITEM_INFO;
-import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
-import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.ItemType;
-import static com.android.launcher3.userevent.nano.LauncherLogProto.Target;
-
/**
* A container for shortcuts to deep links and notifications associated with an app.
*/
@TargetApi(Build.VERSION_CODES.N)
-public class PopupContainerWithArrow extends AbstractFloatingView implements DragSource,
+public class PopupContainerWithArrow extends ArrowPopup implements DragSource,
DragController.DragListener, View.OnLongClickListener,
View.OnTouchListener {
private final List mShortcuts = new ArrayList<>();
private final PointF mInterceptTouchDown = new PointF();
- private final Rect mTempRect = new Rect();
private final Point mIconLastTouchPos = new Point();
private final int mStartDragThreshold;
- private final LayoutInflater mInflater;
- private final float mOutlineRadius;
- private final Launcher mLauncher;
private final LauncherAccessibilityDelegate mAccessibilityDelegate;
- private final boolean mIsRtl;
-
- private final int mArrayOffset;
- private final View mArrow;
private BubbleTextView mOriginalIcon;
private NotificationItemView mNotificationItemView;
+ private int mNumNotifications;
private ViewGroup mSystemShortcutContainer;
- private boolean mIsLeftAligned;
- protected boolean mIsAboveIcon;
- private int mNumNotifications;
- private int mGravity;
-
- protected Animator mOpenCloseAnimator;
- protected boolean mDeferContainerRemoval;
- private final Rect mStartRect = new Rect();
- private final Rect mEndRect = new Rect();
-
public PopupContainerWithArrow(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mStartDragThreshold = getResources().getDimensionPixelSize(
R.dimen.deep_shortcuts_start_drag_threshold);
- mInflater = LayoutInflater.from(context);
- mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius);
- mLauncher = Launcher.getLauncher(context);
mAccessibilityDelegate = new ShortcutMenuAccessibilityDelegate(mLauncher);
- mIsRtl = Utilities.isRtl(getResources());
-
- setClipToOutline(true);
- setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius);
- }
- });
-
- // Initialize arrow view
- final Resources resources = getResources();
- final int arrowWidth = resources.getDimensionPixelSize(R.dimen.popup_arrow_width);
- final int arrowHeight = resources.getDimensionPixelSize(R.dimen.popup_arrow_height);
- mArrow = new View(context);
- mArrow.setLayoutParams(new DragLayer.LayoutParams(arrowWidth, arrowHeight));
- mArrayOffset = resources.getDimensionPixelSize(R.dimen.popup_arrow_vertical_offset);
}
public PopupContainerWithArrow(Context context, AttributeSet attrs) {
@@ -189,7 +129,7 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
@Override
public boolean onTouchEvent(MotionEvent ev) {
if (mNotificationItemView != null) {
- return mNotificationItemView.onTouchEvent(ev);
+ return mNotificationItemView.onTouchEvent(ev) || super.onTouchEvent(ev);
}
return super.onTouchEvent(ev);
}
@@ -222,21 +162,6 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
return false;
}
- @Override
- protected void handleClose(boolean animate) {
- if (animate) {
- animateClose();
- } else {
- closeComplete();
- }
- }
-
- public T inflateAndAdd(int resId) {
- View view = mInflater.inflate(resId, this, false);
- addView(view);
- return (T) view;
- }
-
/**
* Shows the notifications and deep shortcuts associated with {@param icon}.
* @return the container if shown or null.
@@ -267,13 +192,30 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
return container;
}
+ @Override
+ protected void onInflationComplete(boolean isReversed) {
+ if (isReversed && mNotificationItemView != null) {
+ mNotificationItemView.inverseGutterMargin();
+ }
+
+ // Update dividers
+ int count = getChildCount();
+ DeepShortcutView lastView = null;
+ for (int i = 0; i < count; i++) {
+ View view = getChildAt(i);
+ if (view.getVisibility() == VISIBLE && view instanceof DeepShortcutView) {
+ if (lastView != null) {
+ lastView.setDividerVisibility(VISIBLE);
+ }
+ lastView = (DeepShortcutView) view;
+ lastView.setDividerVisibility(INVISIBLE);
+ }
+ }
+ }
+
private void populateAndShow(final BubbleTextView originalIcon, final List shortcutIds,
final List notificationKeys, List systemShortcuts) {
mNumNotifications = notificationKeys.size();
-
- setVisibility(View.INVISIBLE);
- mLauncher.getDragLayer().addView(this);
-
mOriginalIcon = originalIcon;
// Add views
@@ -295,17 +237,15 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
}
for (int i = shortcutIds.size(); i > 0; i--) {
- mShortcuts.add(inflateAndAdd(R.layout.deep_shortcut));
+ mShortcuts.add(inflateAndAdd(R.layout.deep_shortcut, this));
}
updateHiddenShortcuts();
if (!systemShortcuts.isEmpty()) {
- mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons);
+ mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons, this);
for (SystemShortcut shortcut : systemShortcuts) {
- View view = mInflater.inflate(R.layout.system_shortcut_icon_only,
- mSystemShortcutContainer, false);
- mSystemShortcutContainer.addView(view);
- initializeSystemShortcut(view, shortcut);
+ initializeSystemShortcut(
+ R.layout.system_shortcut_icon_only, mSystemShortcutContainer, shortcut);
}
}
} else if (!systemShortcuts.isEmpty()) {
@@ -314,68 +254,11 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
}
for (SystemShortcut shortcut : systemShortcuts) {
- initializeSystemShortcut(inflateAndAdd(R.layout.system_shortcut), shortcut);
+ initializeSystemShortcut(R.layout.system_shortcut, this, shortcut);
}
}
- orientAboutIcon();
- boolean reverseOrder = mIsAboveIcon;
- if (reverseOrder) {
- int count = getChildCount();
- ArrayList allViews = new ArrayList<>(count);
- for (int i = 0; i < count; i++) {
- if (i == viewsToFlip) {
- Collections.reverse(allViews);
- }
- allViews.add(getChildAt(i));
- }
- Collections.reverse(allViews);
- removeAllViews();
- for (int i = 0; i < count; i++) {
- addView(allViews.get(i));
- }
- if (mNotificationItemView != null) {
- mNotificationItemView.inverseGutterMargin();
- }
-
- orientAboutIcon();
- }
- updateDividers();
-
- // Add the arrow.
- final Resources res = getResources();
- final int arrowCenterOffset = res.getDimensionPixelSize(isAlignedWithStart()
- ? R.dimen.popup_arrow_horizontal_center_start
- : R.dimen.popup_arrow_horizontal_center_end);
- final int halfArrowWidth = res.getDimensionPixelSize(R.dimen.popup_arrow_width) / 2;
- mLauncher.getDragLayer().addView(mArrow);
- DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams();
- if (mIsLeftAligned) {
- mArrow.setX(getX() + arrowCenterOffset - halfArrowWidth);
- } else {
- mArrow.setX(getX() + getMeasuredWidth() - arrowCenterOffset - halfArrowWidth);
- }
-
- if (Gravity.isVertical(mGravity)) {
- // This is only true if there wasn't room for the container next to the icon,
- // so we centered it instead. In that case we don't want to show the arrow.
- mArrow.setVisibility(INVISIBLE);
- } else {
- ShapeDrawable arrowDrawable = new ShapeDrawable(TriangleShape.create(
- arrowLp.width, arrowLp.height, !mIsAboveIcon));
- Paint arrowPaint = arrowDrawable.getPaint();
- arrowPaint.setColor(Themes.getAttrColor(mLauncher, R.attr.popupColorPrimary));
- // The corner path effect won't be reflected in the shadow, but shouldn't be noticeable.
- int radius = getResources().getDimensionPixelSize(R.dimen.popup_arrow_corner_radius);
- arrowPaint.setPathEffect(new CornerPathEffect(radius));
- mArrow.setBackground(arrowDrawable);
- mArrow.setElevation(getElevation());
- }
-
- mArrow.setPivotX(arrowLp.width / 2);
- mArrow.setPivotY(mIsAboveIcon ? 0 : arrowLp.height);
-
- animateOpen();
+ reorderAndShow(viewsToFlip);
ItemInfo originalItemInfo = (ItemInfo) originalIcon.getTag();
int numShortcuts = mShortcuts.size() + systemShortcuts.size();
@@ -401,189 +284,15 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
this, shortcutIds, mShortcuts, notificationKeys));
}
- protected boolean isAlignedWithStart() {
- return mIsLeftAligned && !mIsRtl || !mIsLeftAligned && mIsRtl;
- }
-
- /**
- * Orients this container above or below the given icon, aligning with the left or right.
- *
- * These are the preferred orientations, in order (RTL prefers right-aligned over left):
- * - Above and left-aligned
- * - Above and right-aligned
- * - Below and left-aligned
- * - Below and right-aligned
- *
- * So we always align left if there is enough horizontal space
- * and align above if there is enough vertical space.
- */
- protected void orientAboutIcon() {
- measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
- int width = getMeasuredWidth();
- int extraVerticalSpace = mArrow.getLayoutParams().height + mArrayOffset
- + getResources().getDimensionPixelSize(R.dimen.popup_vertical_padding);
- int height = getMeasuredHeight() + extraVerticalSpace;
-
- DragLayer dragLayer = mLauncher.getDragLayer();
- dragLayer.getDescendantRectRelativeToSelf(mOriginalIcon, mTempRect);
- Rect insets = dragLayer.getInsets();
-
- // Align left (right in RTL) if there is room.
- int leftAlignedX = mTempRect.left + mOriginalIcon.getPaddingLeft();
- int rightAlignedX = mTempRect.right - width - mOriginalIcon.getPaddingRight();
- int x = leftAlignedX;
- boolean canBeLeftAligned = leftAlignedX + width + insets.left
- < dragLayer.getRight() - insets.right;
- boolean canBeRightAligned = rightAlignedX > dragLayer.getLeft() + insets.left;
- if (!canBeLeftAligned || (mIsRtl && canBeRightAligned)) {
- x = rightAlignedX;
- }
- mIsLeftAligned = x == leftAlignedX;
-
- // Offset x so that the arrow and shortcut icons are center-aligned with the original icon.
- int iconWidth = mOriginalIcon.getWidth()
- - mOriginalIcon.getTotalPaddingLeft() - mOriginalIcon.getTotalPaddingRight();
- iconWidth *= mOriginalIcon.getScaleX();
- Resources resources = getResources();
- int xOffset;
- if (isAlignedWithStart()) {
- // Aligning with the shortcut icon.
- int shortcutIconWidth = resources.getDimensionPixelSize(R.dimen.deep_shortcut_icon_size);
- int shortcutPaddingStart = resources.getDimensionPixelSize(
- R.dimen.popup_padding_start);
- xOffset = iconWidth / 2 - shortcutIconWidth / 2 - shortcutPaddingStart;
- } else {
- // Aligning with the drag handle.
- int shortcutDragHandleWidth = resources.getDimensionPixelSize(
- R.dimen.deep_shortcut_drag_handle_size);
- int shortcutPaddingEnd = resources.getDimensionPixelSize(
- R.dimen.popup_padding_end);
- xOffset = iconWidth / 2 - shortcutDragHandleWidth / 2 - shortcutPaddingEnd;
- }
- x += mIsLeftAligned ? xOffset : -xOffset;
-
- // Open above icon if there is room.
- int iconHeight = getIconHeightForPopupPlacement();
- int y = mTempRect.top + mOriginalIcon.getPaddingTop() - height;
- mIsAboveIcon = y > dragLayer.getTop() + insets.top;
- if (!mIsAboveIcon) {
- y = mTempRect.top + mOriginalIcon.getPaddingTop() + iconHeight + extraVerticalSpace;
- }
-
- // Insets are added later, so subtract them now.
- if (mIsRtl) {
- x += insets.right;
- } else {
- x -= insets.left;
- }
- y -= insets.top;
-
- mGravity = 0;
- if (y + height > dragLayer.getBottom() - insets.bottom) {
- // The container is opening off the screen, so just center it in the drag layer instead.
- mGravity = Gravity.CENTER_VERTICAL;
- // Put the container next to the icon, preferring the right side in ltr (left in rtl).
- int rightSide = leftAlignedX + iconWidth - insets.left;
- int leftSide = rightAlignedX - iconWidth - insets.left;
- if (!mIsRtl) {
- if (rightSide + width < dragLayer.getRight()) {
- x = rightSide;
- mIsLeftAligned = true;
- } else {
- x = leftSide;
- mIsLeftAligned = false;
- }
- } else {
- if (leftSide > dragLayer.getLeft()) {
- x = leftSide;
- mIsLeftAligned = false;
- } else {
- x = rightSide;
- mIsLeftAligned = true;
- }
- }
- mIsAboveIcon = true;
- }
-
- setX(x);
- if (Gravity.isVertical(mGravity)) {
- return;
- }
-
- DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
- DragLayer.LayoutParams arrowLp = (DragLayer.LayoutParams) mArrow.getLayoutParams();
- if (mIsAboveIcon) {
- arrowLp.gravity = lp.gravity = Gravity.BOTTOM;
- lp.bottomMargin =
- mLauncher.getDragLayer().getHeight() - y - getMeasuredHeight() - insets.top;
- arrowLp.bottomMargin = lp.bottomMargin - arrowLp.height - mArrayOffset - insets.bottom;
- } else {
- arrowLp.gravity = lp.gravity = Gravity.TOP;
- lp.topMargin = y + insets.top;
- arrowLp.topMargin = lp.topMargin - insets.top - arrowLp.height - mArrayOffset;
- }
- }
-
@Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
-
- // enforce contained is within screen
- DragLayer dragLayer = mLauncher.getDragLayer();
- if (getTranslationX() + l < 0 || getTranslationX() + r > dragLayer.getWidth()) {
- // If we are still off screen, center horizontally too.
- mGravity |= Gravity.CENTER_HORIZONTAL;
- }
-
- if (Gravity.isHorizontal(mGravity)) {
- setX(dragLayer.getWidth() / 2 - getMeasuredWidth() / 2);
- mArrow.setVisibility(INVISIBLE);
- }
- if (Gravity.isVertical(mGravity)) {
- setY(dragLayer.getHeight() / 2 - getMeasuredHeight() / 2);
- }
- }
-
- protected void animateOpen() {
- setVisibility(View.VISIBLE);
- mIsOpen = true;
-
- final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
- final Resources res = getResources();
- final long revealDuration = (long) res.getInteger(R.integer.config_popupOpenCloseDuration);
- final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
-
- // Rectangular reveal.
- final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
- .createRevealAnimator(this, false);
- revealAnim.setDuration(revealDuration);
- revealAnim.setInterpolator(revealInterpolator);
-
- Animator fadeIn = ObjectAnimator.ofFloat(this, ALPHA, 0, 1);
- fadeIn.setDuration(revealDuration);
- fadeIn.setInterpolator(revealInterpolator);
- openAnim.play(fadeIn);
-
- // Animate the arrow.
- mArrow.setScaleX(0);
- mArrow.setScaleY(0);
- Animator arrowScale = ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 1)
- .setDuration(res.getInteger(R.integer.config_popupArrowOpenDuration));
-
- openAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mOpenCloseAnimator = null;
- sendCustomAccessibilityEvent(
- PopupContainerWithArrow.this,
- AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED,
- getContext().getString(R.string.action_deep_shortcut));
- }
- });
-
- mOpenCloseAnimator = openAnim;
- openAnim.playSequentially(revealAnim, arrowScale);
- openAnim.start();
+ protected void getTargetObjectLocation(Rect outPos) {
+ mLauncher.getDragLayer().getDescendantRectRelativeToSelf(mOriginalIcon, outPos);
+ outPos.top += mOriginalIcon.getPaddingTop();
+ outPos.left += mOriginalIcon.getPaddingLeft();
+ outPos.right -= mOriginalIcon.getPaddingRight();
+ outPos.bottom = outPos.top + (mOriginalIcon.getIcon() != null
+ ? mOriginalIcon.getIcon().getBounds().height()
+ : mOriginalIcon.getHeight());
}
public void applyNotificationInfos(List notificationInfos) {
@@ -642,10 +351,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
if (onClickListener != null && widgetsView == null) {
// We didn't have any widgets cached but now there are some, so enable the shortcut.
if (mSystemShortcutContainer != this) {
- View view = mInflater.inflate(R.layout.system_shortcut_icon_only,
- mSystemShortcutContainer, false);
- mSystemShortcutContainer.addView(view);
- initializeSystemShortcut(view, widgetInfo);
+ initializeSystemShortcut(
+ R.layout.system_shortcut_icon_only, mSystemShortcutContainer, widgetInfo);
} else {
// If using the expanded system shortcut (as opposed to just the icon), we need to
// reopen the container to ensure measurements etc. all work out. While this could
@@ -665,7 +372,8 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
}
}
- private void initializeSystemShortcut(View view, SystemShortcut info) {
+ private void initializeSystemShortcut(int resId, ViewGroup container, SystemShortcut info) {
+ View view = inflateAndAdd(resId, container);
if (view instanceof DeepShortcutView) {
// Expanded system shortcut, with both icon and text shown on white background.
final DeepShortcutView shortcutView = (DeepShortcutView) view;
@@ -682,12 +390,6 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
(ItemInfo) mOriginalIcon.getTag()));
}
- protected int getIconHeightForPopupPlacement() {
- return mOriginalIcon.getIcon() != null
- ? mOriginalIcon.getIcon().getBounds().height()
- : mOriginalIcon.getHeight();
- }
-
/**
* Determines when the deferred drag should be started.
*
@@ -807,91 +509,17 @@ public class PopupContainerWithArrow extends AbstractFloatingView implements Dra
targetParent.containerType = ContainerType.DEEPSHORTCUTS;
}
- protected void animateClose() {
- if (!mIsOpen) {
- return;
- }
- mEndRect.setEmpty();
- if (getOutlineProvider() instanceof RevealOutlineAnimation) {
- ((RevealOutlineAnimation) getOutlineProvider()).getOutline(mEndRect);
- }
- if (mOpenCloseAnimator != null) {
- mOpenCloseAnimator.cancel();
- }
- mIsOpen = false;
-
- final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
- // Hide the arrow
- closeAnim.play(ObjectAnimator.ofFloat(mArrow, LauncherAnimUtils.SCALE_PROPERTY, 0));
- closeAnim.play(ObjectAnimator.ofFloat(mArrow, ALPHA, 0));
-
+ @Override
+ protected void onCreateCloseAnimation(AnimatorSet anim) {
// Animate original icon's text back in.
- closeAnim.play(mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */));
+ anim.play(mOriginalIcon.createTextAlphaAnimator(true /* fadeIn */));
mOriginalIcon.forceHideBadge(false);
-
- final Resources res = getResources();
- final TimeInterpolator revealInterpolator = new AccelerateDecelerateInterpolator();
-
- // Rectangular reveal (reversed).
- final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
- .createRevealAnimator(this, true);
- revealAnim.setInterpolator(revealInterpolator);
- closeAnim.play(revealAnim);
-
- Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0);
- fadeOut.setInterpolator(revealInterpolator);
- closeAnim.play(fadeOut);
- closeAnim.setDuration((long) res.getInteger(R.integer.config_popupOpenCloseDuration));
-
- closeAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mOpenCloseAnimator = null;
- if (mDeferContainerRemoval) {
- setVisibility(INVISIBLE);
- } else {
- closeComplete();
- }
- }
- });
- mOpenCloseAnimator = closeAnim;
- closeAnim.start();
}
- private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
- int arrowCenterX = getResources().getDimensionPixelSize(mIsLeftAligned ^ mIsRtl ?
- R.dimen.popup_arrow_horizontal_center_start:
- R.dimen.popup_arrow_horizontal_center_end);
- if (!mIsLeftAligned) {
- arrowCenterX = getMeasuredWidth() - arrowCenterX;
- }
- int arrowCenterY = mIsAboveIcon ? getMeasuredHeight() : 0;
-
- mStartRect.set(arrowCenterX, arrowCenterY, arrowCenterX, arrowCenterY);
- if (mEndRect.isEmpty()) {
- mEndRect.set(0, 0, getMeasuredWidth(), getMeasuredHeight());
- }
-
- return new RoundedRectRevealOutlineProvider
- (mOutlineRadius, mOutlineRadius, mStartRect, mEndRect);
- }
-
- /**
- * Closes the popup without animation.
- */
- private void closeComplete() {
+ @Override
+ protected void closeComplete() {
+ super.closeComplete();
mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible());
- mOriginalIcon.forceHideBadge(false);
-
- mLauncher.getDragController().removeDragListener(this);
- if (mOpenCloseAnimator != null) {
- mOpenCloseAnimator.cancel();
- mOpenCloseAnimator = null;
- }
- mIsOpen = false;
- mDeferContainerRemoval = false;
- mLauncher.getDragLayer().removeView(this);
- mLauncher.getDragLayer().removeView(mArrow);
}
@Override
diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
index a22f450e3b..f1195edf34 100644
--- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
+++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java
@@ -19,7 +19,6 @@ import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelo
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.util.Log;
import android.view.MotionEvent;
@@ -31,6 +30,7 @@ import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.util.TouchController;
+import com.android.launcher3.util.PendingAnimation;
/**
* TouchController for handling state changes
@@ -54,10 +54,12 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene
protected LauncherState mFromState;
protected LauncherState mToState;
protected AnimatorPlaybackController mCurrentAnimation;
+ protected PendingAnimation mPendingAnimation;
private float mStartProgress;
// Ratio of transition process [0, 1] to drag displacement (px)
private float mProgressMultiplier;
+ private float mDisplacementShift;
public AbstractStateChangeTouchController(Launcher l, SwipeDetector.Direction dir) {
mLauncher = l;
@@ -68,7 +70,7 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene
/**
* Initializes the {@code mFromState} and {@code mToState} and swipe direction to use for
- * the detector. In can of disabling swipe, return 0.
+ * the detector. In case of disabling swipe, return 0.
*/
protected abstract int getSwipeDirection(MotionEvent ev);
@@ -122,16 +124,40 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene
return mLauncher.getAllAppsController().getShiftRange();
}
+ /**
+ * Returns the state to go to from fromState given the drag direction. If there is no state in
+ * that direction, returns fromState.
+ */
+ protected abstract LauncherState getTargetState(LauncherState fromState,
+ boolean isDragTowardPositive);
+
protected abstract float initCurrentAnimation();
+ private boolean reinitCurrentAnimation(boolean reachedToState, boolean isDragTowardPositive) {
+ LauncherState newFromState = mFromState == null ? mLauncher.getStateManager().getState()
+ : reachedToState ? mToState : mFromState;
+ LauncherState newToState = getTargetState(newFromState, isDragTowardPositive);
+
+ if (newFromState == mFromState && newToState == mToState || (newFromState == newToState)) {
+ return false;
+ }
+
+ mFromState = newFromState;
+ mToState = newToState;
+
+ mStartProgress = 0;
+ mProgressMultiplier = initCurrentAnimation();
+ mCurrentAnimation.getTarget().addListener(this);
+ mCurrentAnimation.dispatchOnStart();
+ return true;
+ }
+
@Override
public void onDragStart(boolean start) {
if (mCurrentAnimation == null) {
- mStartProgress = 0;
- mProgressMultiplier = initCurrentAnimation();
-
- mCurrentAnimation.getTarget().addListener(this);
- mCurrentAnimation.dispatchOnStart();
+ mFromState = mToState = null;
+ reinitCurrentAnimation(false, mDetector.wasInitialTouchPositive());
+ mDisplacementShift = 0;
} else {
mCurrentAnimation.pause();
mStartProgress = mCurrentAnimation.getProgressFraction();
@@ -140,8 +166,19 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene
@Override
public boolean onDrag(float displacement, float velocity) {
- float deltaProgress = mProgressMultiplier * displacement;
- updateProgress(deltaProgress + mStartProgress);
+ float deltaProgress = mProgressMultiplier * (displacement - mDisplacementShift);
+ float progress = deltaProgress + mStartProgress;
+ updateProgress(progress);
+ boolean isDragTowardPositive = (displacement - mDisplacementShift) < 0;
+ if (progress <= 0) {
+ if (reinitCurrentAnimation(false, isDragTowardPositive)) {
+ mDisplacementShift = displacement;
+ }
+ } else if (progress >= 1) {
+ if (reinitCurrentAnimation(true, isDragTowardPositive)) {
+ mDisplacementShift = displacement;
+ }
+ }
return true;
}
@@ -213,17 +250,26 @@ public abstract class AbstractStateChangeTouchController extends AnimatorListene
}
protected void onSwipeInteractionCompleted(LauncherState targetState, int logAction) {
- if (targetState != mFromState) {
- // Transition complete. log the action
- mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
- getDirectionForLog(),
- mStartContainerType,
- mFromState.containerType,
- mToState.containerType,
- mLauncher.getWorkspace().getCurrentPage());
- }
clearState();
- mLauncher.getStateManager().goToState(targetState, false /* animated */);
+ boolean shouldGoToTargetState = true;
+ if (mPendingAnimation != null) {
+ boolean reachedTarget = mToState == targetState;
+ mPendingAnimation.finish(reachedTarget, logAction);
+ mPendingAnimation = null;
+ shouldGoToTargetState = !reachedTarget;
+ }
+ if (shouldGoToTargetState) {
+ if (targetState != mFromState) {
+ // Transition complete. log the action
+ mLauncher.getUserEventDispatcher().logStateChangeAction(logAction,
+ getDirectionForLog(),
+ mStartContainerType,
+ mFromState.containerType,
+ mToState.containerType,
+ mLauncher.getWorkspace().getCurrentPage());
+ }
+ mLauncher.getStateManager().goToState(targetState, false /* animated */);
+ }
}
protected void clearState() {
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 2f9cf3aab6..23f55aa17e 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -144,7 +144,7 @@ public class WorkspaceTouchListener implements OnTouchListener, Runnable {
mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
Action.Direction.NONE, ContainerType.WORKSPACE,
mWorkspace.getCurrentPage());
- OptionsPopupView.show(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y);
+ OptionsPopupView.showDefaultOptions(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y);
}
}
}
diff --git a/src/com/android/launcher3/views/HighlightableListView.java b/src/com/android/launcher3/util/ListViewHighlighter.java
similarity index 55%
rename from src/com/android/launcher3/views/HighlightableListView.java
rename to src/com/android/launcher3/util/ListViewHighlighter.java
index 7da979fe14..ecad2afe2e 100644
--- a/src/com/android/launcher3/views/HighlightableListView.java
+++ b/src/com/android/launcher3/util/ListViewHighlighter.java
@@ -13,70 +13,92 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-
-package com.android.launcher3.views;
+package com.android.launcher3.util;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
-import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.support.v4.graphics.ColorUtils;
-import android.util.AttributeSet;
import android.view.View;
-import android.view.ViewGroup;
-import android.widget.HeaderViewListAdapter;
-import android.widget.ListAdapter;
+import android.view.View.OnLayoutChangeListener;
+import android.widget.AbsListView;
+import android.widget.AbsListView.OnScrollListener;
+import android.widget.AbsListView.RecyclerListener;
import android.widget.ListView;
import com.android.launcher3.R;
-import com.android.launcher3.util.Themes;
-
-import java.util.ArrayList;
/**
- * Extension of list view with support for element highlighting.
+ * Utility class to scroll and highlight a list view item
*/
-public class HighlightableListView extends ListView {
+public class ListViewHighlighter implements OnScrollListener, RecyclerListener,
+ OnLayoutChangeListener {
+
+ private final ListView mListView;
+ private int mPosHighlight;
- private int mPosHighlight = -1;
private boolean mColorAnimated = false;
- public HighlightableListView(Context context) {
- super(context);
- }
+ public ListViewHighlighter(ListView listView, int posHighlight) {
+ mListView = listView;
+ mPosHighlight = posHighlight;
+ mListView.setOnScrollListener(this);
+ mListView.setRecyclerListener(this);
+ mListView.addOnLayoutChangeListener(this);
- public HighlightableListView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
-
- public HighlightableListView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
+ mListView.post(this::tryHighlight);
}
@Override
- public void setAdapter(ListAdapter adapter) {
- super.setAdapter(new HighLightAdapter(adapter));
+ public void onLayoutChange(View v, int left, int top, int right, int bottom,
+ int oldLeft, int oldTop, int oldRight, int oldBottom) {
+ mListView.post(this::tryHighlight);
}
- public void highlightPosition(int pos) {
- if (mPosHighlight == pos) {
+ private void tryHighlight() {
+ if (mPosHighlight < 0 || mListView.getChildCount() == 0) {
return;
}
-
- mColorAnimated = false;
- mPosHighlight = pos;
- setSelection(mPosHighlight);
-
- int start = getFirstVisiblePosition();
- int end = getLastVisiblePosition();
- if (start <= mPosHighlight && mPosHighlight <= end) {
- highlightView(getChildAt(mPosHighlight - start));
+ if (!highlightIfVisible(mListView.getFirstVisiblePosition(),
+ mListView.getLastVisiblePosition())) {
+ mListView.smoothScrollToPosition(mPosHighlight);
}
}
+ @Override
+ public void onScrollStateChanged(AbsListView absListView, int i) { }
+
+ @Override
+ public void onScroll(AbsListView view, int firstVisibleItem,
+ int visibleItemCount, int totalItemCount) {
+ highlightIfVisible(firstVisibleItem, firstVisibleItem + visibleItemCount);
+ }
+
+ private boolean highlightIfVisible(int start, int end) {
+ if (mPosHighlight < 0 || mListView.getChildCount() == 0) {
+ return false;
+ }
+ if (start > mPosHighlight || mPosHighlight > end) {
+ return false;
+ }
+ highlightView(mListView.getChildAt(mPosHighlight - start));
+
+ // finish highlight
+ mListView.setOnScrollListener(null);
+ mListView.removeOnLayoutChangeListener(this);
+
+ mPosHighlight = -1;
+ return true;
+ }
+
+ @Override
+ public void onMovedToScrapHeap(View view) {
+ unhighlightView(view);
+ }
+
private void highlightView(View view) {
if (Boolean.TRUE.equals(view.getTag(R.id.view_highlighted))) {
// already highlighted
@@ -85,7 +107,6 @@ public class HighlightableListView extends ListView {
view.setTag(R.id.view_unhighlight_background, view.getBackground());
view.setBackground(getHighlightBackground());
view.postDelayed(() -> {
- mPosHighlight = -1;
unhighlightView(view);
}, 15000L);
}
@@ -102,26 +123,8 @@ public class HighlightableListView extends ListView {
}
}
- private class HighLightAdapter extends HeaderViewListAdapter {
- public HighLightAdapter(ListAdapter adapter) {
- super(new ArrayList<>(), new ArrayList<>(), adapter);
- }
-
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- View view = super.getView(position, convertView, parent);
-
- if (position == mPosHighlight) {
- highlightView(view);
- } else {
- unhighlightView(view);
- }
- return view;
- }
- }
-
private ColorDrawable getHighlightBackground() {
- int color = ColorUtils.setAlphaComponent(Themes.getColorAccent(getContext()), 26);
+ int color = ColorUtils.setAlphaComponent(Themes.getColorAccent(mListView.getContext()), 26);
if (mColorAnimated) {
return new ColorDrawable(color);
}
diff --git a/quickstep/src/com/android/quickstep/PendingAnimation.java b/src/com/android/launcher3/util/PendingAnimation.java
similarity index 67%
rename from quickstep/src/com/android/quickstep/PendingAnimation.java
rename to src/com/android/launcher3/util/PendingAnimation.java
index d22ef61053..617a38bbed 100644
--- a/quickstep/src/com/android/quickstep/PendingAnimation.java
+++ b/src/com/android/launcher3/util/PendingAnimation.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.quickstep;
+package com.android.launcher3.util;
import android.animation.AnimatorSet;
import android.annotation.TargetApi;
@@ -32,7 +32,7 @@ import java.util.function.Consumer;
@TargetApi(Build.VERSION_CODES.O)
public class PendingAnimation {
- private final ArrayList> mEndListeners = new ArrayList<>();
+ private final ArrayList> mEndListeners = new ArrayList<>();
public final AnimatorSet anim;
@@ -40,14 +40,24 @@ public class PendingAnimation {
this.anim = anim;
}
- public void finish(boolean isSuccess) {
- for (Consumer listeners : mEndListeners) {
- listeners.accept(isSuccess);
+ public void finish(boolean isSuccess, int logAction) {
+ for (Consumer listeners : mEndListeners) {
+ listeners.accept(new OnEndListener(isSuccess, logAction));
}
mEndListeners.clear();
}
- public void addEndListener(Consumer listener) {
+ public void addEndListener(Consumer listener) {
mEndListeners.add(listener);
}
+
+ public static class OnEndListener {
+ public boolean isSuccess;
+ public int logAction;
+
+ public OnEndListener(boolean isSuccess, int logAction) {
+ this.isSuccess = isSuccess;
+ this.logAction = logAction;
+ }
+ }
}
diff --git a/src/com/android/launcher3/util/PendingRequestArgs.java b/src/com/android/launcher3/util/PendingRequestArgs.java
index dabd40df12..b8bcfeda85 100644
--- a/src/com/android/launcher3/util/PendingRequestArgs.java
+++ b/src/com/android/launcher3/util/PendingRequestArgs.java
@@ -57,7 +57,7 @@ public class PendingRequestArgs extends ItemInfo implements Parcelable {
mArg1 = parcel.readInt();
mObjectType = parcel.readInt();
- mObject = parcel.readParcelable(null);
+ mObject = parcel.readParcelable(getClass().getClassLoader());
}
@Override
diff --git a/src/com/android/launcher3/util/TraceHelper.java b/src/com/android/launcher3/util/TraceHelper.java
index ac381cc18c..4aa2f37885 100644
--- a/src/com/android/launcher3/util/TraceHelper.java
+++ b/src/com/android/launcher3/util/TraceHelper.java
@@ -24,7 +24,6 @@ import android.util.ArrayMap;
import android.util.Log;
import android.util.MutableLong;
-import com.android.launcher3.Utilities;
import com.android.launcher3.config.FeatureFlags;
/**
@@ -35,8 +34,7 @@ import com.android.launcher3.config.FeatureFlags;
*/
public class TraceHelper {
- private static final boolean FORCE_LOG = Utilities.IS_DEBUG_DEVICE;
- private static final boolean ENABLED = FORCE_LOG || FeatureFlags.IS_DOGFOOD_BUILD;
+ private static final boolean ENABLED = FeatureFlags.IS_DOGFOOD_BUILD;
private static final boolean SYSTEM_TRACE = false;
private static final ArrayMap sUpTimes = ENABLED ? new ArrayMap<>() : null;
@@ -45,7 +43,7 @@ public class TraceHelper {
if (ENABLED) {
MutableLong time = sUpTimes.get(sectionName);
if (time == null) {
- time = new MutableLong((FORCE_LOG || isLoggable(sectionName, VERBOSE)) ? 0 : -1);
+ time = new MutableLong(isLoggable(sectionName, VERBOSE) ? 0 : -1);
sUpTimes.put(sectionName, time);
}
if (time.value >= 0) {
diff --git a/src/com/android/launcher3/views/LauncherDragIndicator.java b/src/com/android/launcher3/views/LauncherDragIndicator.java
new file mode 100644
index 0000000000..986e4bee31
--- /dev/null
+++ b/src/com/android/launcher3/views/LauncherDragIndicator.java
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.views;
+
+import static com.android.launcher3.LauncherState.ALL_APPS;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
+import android.widget.FrameLayout;
+import android.widget.ImageView;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
+
+public class LauncherDragIndicator extends ImageView implements Insettable, OnClickListener {
+
+ private static final int WALLPAPERS = R.string.wallpaper_button_text;
+ private static final int WIDGETS = R.string.widget_button_text;
+ private static final int SETTINGS = R.string.settings_button_text;
+
+ protected final Launcher mLauncher;
+
+ public LauncherDragIndicator(Context context) {
+ this(context, null);
+ }
+
+ public LauncherDragIndicator(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public LauncherDragIndicator(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mLauncher = Launcher.getLauncher(context);
+ setOnClickListener(this);
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ DeviceProfile grid = mLauncher.getDeviceProfile();
+ FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
+
+ if (grid.isVerticalBarLayout()) {
+ if (grid.isSeascape()) {
+ lp.leftMargin = grid.hotseatBarSidePaddingPx;
+ lp.rightMargin = insets.right;
+ lp.gravity = Gravity.RIGHT | Gravity.BOTTOM;
+ } else {
+ lp.leftMargin = insets.left;
+ lp.rightMargin = grid.hotseatBarSidePaddingPx;
+ lp.gravity = Gravity.LEFT | Gravity.BOTTOM;
+ }
+ lp.bottomMargin = grid.workspacePadding.bottom;
+ setImageResource(R.drawable.all_apps_handle_landscape);
+ } else {
+ lp.leftMargin = lp.rightMargin = 0;
+ lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
+ lp.bottomMargin = getPortraitBottomMargin(grid, insets);
+ setImageResource(R.drawable.ic_drag_indicator);
+ }
+
+ lp.width = lp.height = grid.pageIndicatorSizePx;
+ setLayoutParams(lp);
+ }
+
+ protected int getPortraitBottomMargin(DeviceProfile grid, Rect insets) {
+ return grid.hotseatBarSizePx + insets.bottom - grid.pageIndicatorSizePx;
+ }
+
+ @Override
+ public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfo(info);
+ initCustomActions(info);
+ }
+
+ protected void initCustomActions(AccessibilityNodeInfo info) {
+ Context context = getContext();
+ if (Utilities.isWallpaperAllowed(context)) {
+ info.addAction(new AccessibilityAction(WALLPAPERS, context.getText(WALLPAPERS)));
+ }
+ info.addAction(new AccessibilityAction(WIDGETS, context.getText(WIDGETS)));
+ info.addAction(new AccessibilityAction(SETTINGS, context.getText(SETTINGS)));
+ }
+
+ @Override
+ public boolean performAccessibilityAction(int action, Bundle arguments) {
+ if (action == WALLPAPERS) {
+ return OptionsPopupView.startWallpaperPicker(this);
+ } else if (action == WIDGETS) {
+ return OptionsPopupView.onWidgetsClicked(this);
+ } else if (action == SETTINGS) {
+ return OptionsPopupView.startSettings(this);
+ }
+ return super.performAccessibilityAction(action, arguments);
+ }
+
+ @Override
+ public void onClick(View view) {
+ if (!mLauncher.isInState(ALL_APPS)) {
+ mLauncher.getUserEventDispatcher().logActionOnControl(
+ Action.Touch.TAP, ControlType.ALL_APPS_BUTTON);
+ mLauncher.getStateManager().goToState(ALL_APPS);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java
index dc86aec463..56b92c7c62 100644
--- a/src/com/android/launcher3/views/OptionsPopupView.java
+++ b/src/com/android/launcher3/views/OptionsPopupView.java
@@ -15,52 +15,42 @@
*/
package com.android.launcher3.views;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.ObjectAnimator;
-import android.animation.ValueAnimator;
+import static com.android.launcher3.BaseDraggingActivity.INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION;
+import static com.android.launcher3.Utilities.EXTRA_WALLPAPER_OFFSET;
+
import android.content.Context;
import android.content.Intent;
-import android.graphics.Outline;
-import android.graphics.PointF;
import android.graphics.Rect;
+import android.graphics.RectF;
+import android.text.TextUtils;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
-import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
import android.widget.Toast;
-import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
-import com.android.launcher3.anim.RevealOutlineAnimation;
-import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
-import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.graphics.ColorScrim;
+import com.android.launcher3.popup.ArrowPopup;
+import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.widget.WidgetsFullSheet;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Popup shown on long pressing an empty space in launcher
*/
-public class OptionsPopupView extends AbstractFloatingView
+public class OptionsPopupView extends ArrowPopup
implements OnClickListener, OnLongClickListener {
- private final float mOutlineRadius;
- private final Launcher mLauncher;
- private final PointF mTouchPoint = new PointF();
-
- private final ColorScrim mScrim;
-
- protected Animator mOpenCloseAnimator;
+ private final ArrayMap mItemMap = new ArrayMap<>();
+ private RectF mTargetRect;
public OptionsPopupView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
@@ -68,31 +58,6 @@ public class OptionsPopupView extends AbstractFloatingView
public OptionsPopupView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
-
- mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius);
- setClipToOutline(true);
- setOutlineProvider(new ViewOutlineProvider() {
- @Override
- public void getOutline(View view, Outline outline) {
- outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius);
- }
- });
-
- mLauncher = Launcher.getLauncher(context);
- mScrim = ColorScrim.createExtractedColorScrim(this);
- }
-
- @Override
- protected void onFinishInflate() {
- super.onFinishInflate();
- attachListeners(findViewById(R.id.wallpaper_button));
- attachListeners(findViewById(R.id.widget_button));
- attachListeners(findViewById(R.id.settings_button));
- }
-
- private void attachListeners(View view) {
- view.setOnClickListener(this);
- view.setOnLongClickListener(this);
}
@Override
@@ -106,20 +71,14 @@ public class OptionsPopupView extends AbstractFloatingView
}
private boolean handleViewClick(View view, int action) {
- if (view.getId() == R.id.wallpaper_button) {
- mLauncher.onClickWallpaperPicker(null);
- logTap(action, ControlType.WALLPAPER_BUTTON);
- close(true);
- return true;
- } else if (view.getId() == R.id.widget_button) {
- logTap(action, ControlType.WIDGETS_BUTTON);
- if (onWidgetsClicked(mLauncher)) {
- close(true);
- return true;
- }
- } else if (view.getId() == R.id.settings_button) {
- startSettings(mLauncher);
- logTap(action, ControlType.SETTINGS_BUTTON);
+ OptionItem item = mItemMap.get(view);
+ if (item == null) {
+ return false;
+ }
+ if (item.mControlTypeForLog > 0) {
+ logTap(action, item.mControlTypeForLog);
+ }
+ if (item.mClickListener.onLongClick(view)) {
close(true);
return true;
}
@@ -142,63 +101,6 @@ public class OptionsPopupView extends AbstractFloatingView
return true;
}
- @Override
- protected void handleClose(boolean animate) {
- if (animate) {
- animateClose();
- } else {
- closeComplete();
- }
- }
-
- protected void animateClose() {
- if (!mIsOpen) {
- return;
- }
- mIsOpen = false;
-
- final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet();
- closeAnim.setDuration(getResources().getInteger(R.integer.config_popupOpenCloseDuration));
-
- // Rectangular reveal (reversed).
- final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
- .createRevealAnimator(this, true);
- closeAnim.play(revealAnim);
-
- Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0);
- fadeOut.setInterpolator(Interpolators.DEACCEL);
- closeAnim.play(fadeOut);
-
- Animator gradientAlpha = ObjectAnimator.ofFloat(mScrim, ColorScrim.PROGRESS, 0);
- gradientAlpha.setInterpolator(Interpolators.DEACCEL);
- closeAnim.play(gradientAlpha);
-
- closeAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mOpenCloseAnimator = null;
- closeComplete();
- }
- });
- if (mOpenCloseAnimator != null) {
- mOpenCloseAnimator.cancel();
- }
- mOpenCloseAnimator = closeAnim;
- closeAnim.start();
- }
-
- /**
- * Closes the popup without animation.
- */
- private void closeComplete() {
- if (mOpenCloseAnimator != null) {
- mOpenCloseAnimator.cancel();
- mOpenCloseAnimator = null;
- }
- mIsOpen = false;
- mLauncher.getDragLayer().removeView(this);
- }
-
@Override
public void logActionCommand(int command) {
// TODO:
@@ -209,90 +111,49 @@ public class OptionsPopupView extends AbstractFloatingView
return (type & TYPE_OPTIONS_POPUP) != 0;
}
- private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
- DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams();
- Rect startRect = new Rect();
- startRect.offset((int) (mTouchPoint.x - lp.x), (int) (mTouchPoint.y - lp.y));
-
- Rect endRect = new Rect(0, 0, lp.width, lp.height);
- if (getOutlineProvider() instanceof RevealOutlineAnimation) {
- ((RevealOutlineAnimation) getOutlineProvider()).getOutline(endRect);
- }
-
- return new RoundedRectRevealOutlineProvider
- (mOutlineRadius, mOutlineRadius, startRect, endRect);
+ @Override
+ protected void getTargetObjectLocation(Rect outPos) {
+ mTargetRect.roundOut(outPos);
}
- private void animateOpen() {
- mIsOpen = true;
- final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet();
- openAnim.setDuration(getResources().getInteger(R.integer.config_popupOpenCloseDuration));
+ public static void show(Launcher launcher, RectF targetRect, List items) {
+ OptionsPopupView popup = (OptionsPopupView) launcher.getLayoutInflater()
+ .inflate(R.layout.longpress_options_menu, launcher.getDragLayer(), false);
+ popup.mTargetRect = targetRect;
- final ValueAnimator revealAnim = createOpenCloseOutlineProvider()
- .createRevealAnimator(this, false);
- openAnim.play(revealAnim);
-
- Animator gradientAlpha = ObjectAnimator.ofFloat(mScrim, ColorScrim.PROGRESS, 1);
- gradientAlpha.setInterpolator(Interpolators.ACCEL);
- openAnim.play(gradientAlpha);
-
- mOpenCloseAnimator = openAnim;
-
- openAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mOpenCloseAnimator = null;
- }
- });
- openAnim.start();
+ for (OptionItem item : items) {
+ DeepShortcutView view = popup.inflateAndAdd(R.layout.system_shortcut, popup);
+ view.getIconView().setBackgroundResource(item.mIconRes);
+ view.getBubbleText().setText(item.mLabelRes);
+ view.setDividerVisibility(View.INVISIBLE);
+ view.setOnClickListener(popup);
+ view.setOnLongClickListener(popup);
+ popup.mItemMap.put(view, item);
+ }
+ popup.reorderAndShow(popup.getChildCount());
}
- public static void show(Launcher launcher, float x, float y) {
- DragLayer dl = launcher.getDragLayer();
- OptionsPopupView view = (OptionsPopupView) launcher.getLayoutInflater()
- .inflate(R.layout.longpress_options_menu, dl, false);
- DragLayer.LayoutParams lp = (DragLayer.LayoutParams) view.getLayoutParams();
-
- int maxWidth = dl.getWidth();
- int maxHeight = dl.getHeight();
- if (x <= 0 || y <= 0 || x >= maxWidth || y >= maxHeight) {
- x = maxWidth / 2;
- y = maxHeight / 2;
+ public static void showDefaultOptions(Launcher launcher, float x, float y) {
+ float halfSize = launcher.getResources().getDimension(R.dimen.options_menu_thumb_size) / 2;
+ if (x < 0 || y < 0) {
+ x = launcher.getDragLayer().getWidth() / 2;
+ y = launcher.getDragLayer().getHeight() / 2;
}
- view.mTouchPoint.set(x, y);
+ RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize);
- int height = lp.height;
+ ArrayList options = new ArrayList<>();
+ options.add(new OptionItem(R.string.wallpaper_button_text, R.drawable.ic_wallpaper,
+ ControlType.WALLPAPER_BUTTON, OptionsPopupView::startWallpaperPicker));
+ options.add(new OptionItem(R.string.widget_button_text, R.drawable.ic_widget,
+ ControlType.WIDGETS_BUTTON, OptionsPopupView::onWidgetsClicked));
+ options.add(new OptionItem(R.string.settings_button_text, R.drawable.ic_setting,
+ ControlType.SETTINGS_BUTTON, OptionsPopupView::startSettings));
- // Find a good width;
- int childCount = view.getChildCount();
- int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
- int widthSpec = MeasureSpec.makeMeasureSpec(maxWidth / childCount, MeasureSpec.AT_MOST);
- int maxChildWidth = 0;
-
- for (int i = 0; i < childCount; i ++) {
- View child = ((ViewGroup) view.getChildAt(i)).getChildAt(0);
- child.measure(widthSpec, heightSpec);
- maxChildWidth = Math.max(maxChildWidth, child.getMeasuredWidth());
- }
- Rect insets = dl.getInsets();
- int margin = (int) (2 * view.getElevation());
-
- int width = Math.min(maxWidth - insets.left - insets.right - 2 * margin,
- maxChildWidth * childCount);
- lp.width = width;
-
- // Position is towards the finger
- lp.customPosition = true;
- lp.x = Utilities.boundToRange((int) (x - width / 2), insets.left + margin,
- maxWidth - insets.right - width - margin);
- lp.y = Utilities.boundToRange((int) (y - height / 2), insets.top + margin,
- maxHeight - insets.bottom - height - margin);
-
- view.animateOpen();
- launcher.getDragLayer().addView(view);
+ show(launcher, target, options);
}
- public static boolean onWidgetsClicked(Launcher launcher) {
+ public static boolean onWidgetsClicked(View view) {
+ Launcher launcher = Launcher.getLauncher(view.getContext());
if (launcher.getPackageManager().isSafeMode()) {
Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
return false;
@@ -302,9 +163,51 @@ public class OptionsPopupView extends AbstractFloatingView
}
}
- public static void startSettings(Launcher launcher) {
+ public static boolean startSettings(View view) {
+ Launcher launcher = Launcher.getLauncher(view.getContext());
launcher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES)
.setPackage(launcher.getPackageName())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
+ return true;
+ }
+
+ /**
+ * Event handler for the wallpaper picker button that appears after a long press
+ * on the home screen.
+ */
+ public static boolean startWallpaperPicker(View v) {
+ Launcher launcher = Launcher.getLauncher(v.getContext());
+ if (!Utilities.isWallpaperAllowed(launcher)) {
+ Toast.makeText(launcher, R.string.msg_disabled_by_admin, Toast.LENGTH_SHORT).show();
+ return false;
+ }
+ Intent intent = new Intent(Intent.ACTION_SET_WALLPAPER)
+ .putExtra(EXTRA_WALLPAPER_OFFSET,
+ launcher.getWorkspace().getWallpaperOffsetForCenterPage());
+
+ String pickerPackage = launcher.getString(R.string.wallpaper_picker_package);
+ if (!TextUtils.isEmpty(pickerPackage)) {
+ intent.setPackage(pickerPackage);
+ } else {
+ // If there is no target package, use the default intent chooser animation
+ intent.putExtra(INTENT_EXTRA_IGNORE_LAUNCH_ANIMATION, true);
+ }
+ return launcher.startActivitySafely(v, intent, null);
+ }
+
+ public static class OptionItem {
+
+ private final int mLabelRes;
+ private final int mIconRes;
+ private final int mControlTypeForLog;
+ private final OnLongClickListener mClickListener;
+
+ public OptionItem(int labelRes, int iconRes, int controlTypeForLog,
+ OnLongClickListener clickListener) {
+ mLabelRes = labelRes;
+ mIconRes = iconRes;
+ mControlTypeForLog = controlTypeForLog;
+ mClickListener = clickListener;
+ }
}
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java
index e495477f57..d1cddc18f6 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java
@@ -7,6 +7,7 @@ import android.view.MotionEvent;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
import com.android.launcher3.touch.AbstractStateChangeTouchController;
import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -43,18 +44,24 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController {
protected int getSwipeDirection(MotionEvent ev) {
if (mLauncher.isInState(ALL_APPS)) {
mStartContainerType = ContainerType.ALLAPPS;
- mFromState = ALL_APPS;
- mToState = NORMAL;
return SwipeDetector.DIRECTION_NEGATIVE;
} else {
- mFromState = NORMAL;
- mToState = ALL_APPS;
mStartContainerType = mLauncher.getDragLayer().isEventOverHotseat(ev) ?
ContainerType.HOTSEAT : ContainerType.WORKSPACE;
return SwipeDetector.DIRECTION_POSITIVE;
}
}
+ @Override
+ protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) {
+ if (fromState == NORMAL && isDragTowardPositive) {
+ return ALL_APPS;
+ } else if (fromState == ALL_APPS && !isDragTowardPositive) {
+ return NORMAL;
+ }
+ return fromState;
+ }
+
@Override
protected float initCurrentAnimation() {
float range = getShiftRange();
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java
deleted file mode 100644
index d9ce87c7c5..0000000000
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewAccessibilityDelegate.java
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.uioverrides;
-
-import android.content.Context;
-import android.os.Bundle;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
-import android.view.accessibility.AccessibilityNodeInfo;
-import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.views.OptionsPopupView;
-
-/**
- * Accessibility delegate with actions pointing to various Overview entry points.
- */
-public class OverviewAccessibilityDelegate extends AccessibilityDelegate {
-
- private static final int WALLPAPERS = R.string.wallpaper_button_text;
- private static final int WIDGETS = R.string.widget_button_text;
- private static final int SETTINGS = R.string.settings_button_text;
-
- @Override
- public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
- super.onInitializeAccessibilityNodeInfo(host, info);
-
- Context context = host.getContext();
-
- if (Utilities.isWallpaperAllowed(context)) {
- info.addAction(new AccessibilityAction(WALLPAPERS, context.getText(WALLPAPERS)));
- }
- info.addAction(new AccessibilityAction(WIDGETS, context.getText(WIDGETS)));
- info.addAction(new AccessibilityAction(SETTINGS, context.getText(SETTINGS)));
- }
-
- @Override
- public boolean performAccessibilityAction(View host, int action, Bundle args) {
- Launcher launcher = Launcher.getLauncher(host.getContext());
- if (action == WALLPAPERS) {
- launcher.onClickWallpaperPicker(host);
- return true;
- } else if (action == WIDGETS) {
- return OptionsPopupView.onWidgetsClicked(launcher);
- } else if (action == SETTINGS) {
- OptionsPopupView.startSettings(launcher);
- return true;
- }
- return super.performAccessibilityAction(host, action, args);
- }
-}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
index 2f1de7bf64..be9d5b734b 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java
@@ -16,13 +16,8 @@
package com.android.launcher3.uioverrides;
-import android.view.View;
-import android.view.View.AccessibilityDelegate;
-
-import com.android.launcher3.Hotseat;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.R;
import com.android.launcher3.util.TouchController;
public class UiFactory {
@@ -32,10 +27,6 @@ public class UiFactory {
launcher.getDragController(), new AllAppsSwipeController(launcher)};
}
- public static AccessibilityDelegate newPageIndicatorAccessibilityDelegate() {
- return new OverviewAccessibilityDelegate();
- }
-
public static StateHandler[] getStateHandler(Launcher launcher) {
return new StateHandler[] {
launcher.getAllAppsController(), launcher.getWorkspace() };
@@ -47,11 +38,7 @@ public class UiFactory {
public static void onStart(Launcher launcher) { }
- public static void onTrimMemory(Launcher launcher, int level) { }
+ public static void onLauncherStateOrResumeChanged(Launcher launcher) { }
- public static View[] getHotseatExtraContent(Hotseat hotseat) {
- return new View[] {
- hotseat.findViewById(R.id.drag_indicator),
- };
- }
+ public static void onTrimMemory(Launcher launcher, int level) { }
}