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/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-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-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-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-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..bc057760fb
--- /dev/null
+++ b/go/res/values-hi/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "शॉर्टकट चुनने के लिए छूकर रखें."
+ "शॉर्टकट चुनने के लिए डबल टैप करके रखें या कस्टम कार्रवाइयों का उपयोग करें."
+ "शॉर्टकट"
+ "%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-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-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-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-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-pa/strings.xml b/go/res/values-pa/strings.xml
new file mode 100644
index 0000000000..f3982ab71b
--- /dev/null
+++ b/go/res/values-pa/strings.xml
@@ -0,0 +1,26 @@
+
+
+
+
+ "ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ।"
+ "ਕੋਈ ਸ਼ਾਰਟਕੱਟ ਚੁਣਨ ਲਈ ਡਬਲ-ਟੈਪ ਕਰੋ ਅਤੇ ਦਬਾ ਕੇ ਰੱਖੋ ਜਾਂ ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ ਕਾਰਵਾਈਆਂ ਵਰਤੋ।"
+ "ਸ਼ਾਰਟਕੱਟ"
+ "%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-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-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-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/xml/device_profiles.xml b/go/res/xml/device_profiles.xml
new file mode 100644
index 0000000000..094fc745c4
--- /dev/null
+++ b/go/res/xml/device_profiles.xml
@@ -0,0 +1,33 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/go/src_flags/com/android/launcher3/config/FeatureFlags.java b/go/src_flags/com/android/launcher3/config/FeatureFlags.java
index 5bb2ac9a2e..b11bb7c6aa 100644
--- a/go/src_flags/com/android/launcher3/config/FeatureFlags.java
+++ b/go/src_flags/com/android/launcher3/config/FeatureFlags.java
@@ -25,4 +25,5 @@ public final class FeatureFlags extends BaseFlags {
// Features to control Launcher3Go behavior
public static final boolean GO_DISABLE_WIDGETS = true;
+ public static final boolean LAUNCHER3_SPRING_ICONS = false;
}
diff --git a/res/layout-land/all_apps_fast_scroller.xml b/res/layout-land/all_apps_fast_scroller.xml
index 957c331741..6a68f84e98 100644
--- a/res/layout-land/all_apps_fast_scroller.xml
+++ b/res/layout-land/all_apps_fast_scroller.xml
@@ -22,7 +22,8 @@
style="@style/FastScrollerPopup"
android:layout_alignParentEnd="true"
android:layout_alignTop="@+id/apps_list_view"
- android:layout_marginEnd="-5dp" />
+ android:layout_marginTop="-5dp"
+ android:layout_marginEnd="-45dp" />
\ No newline at end of file
diff --git a/res/layout-land/launcher.xml b/res/layout-land/launcher.xml
index dab074391d..ac440fc01e 100644
--- a/res/layout-land/launcher.xml
+++ b/res/layout-land/launcher.xml
@@ -42,12 +42,7 @@
android:layout_gravity="center"
launcher:pageIndicator="@id/page_indicator" />
-
+
-
+
-
+
+
+
+
\ No newline at end of file
diff --git a/res/layout/notification_pref_warning.xml b/res/layout/notification_pref_warning.xml
index 795699e99d..100fac5e41 100644
--- a/res/layout/notification_pref_warning.xml
+++ b/res/layout/notification_pref_warning.xml
@@ -17,8 +17,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="48dp"
android:layout_height="match_parent"
- android:background="?android:attr/selectableItemBackgroundBorderless"
- android:contentDescription="@string/title_missing_notification_access"
+ android:importantForAccessibility="no"
android:scaleType="center"
android:src="@drawable/ic_warning"
android:tint="?android:attr/textColorSecondary" />
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index a8791b7353..18f87bcf33 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -35,9 +35,9 @@
"%2$d hündürlük %1$d enində"
"Manual olaraq yerləşdirmək üçün toxunaraq basıb saxlayın"
"Avtomatik əlavə edin"
- "Tətbiq Axtarın"
- "Tətbiqlər endirilir..."
- "\"%1$s\" sorğusuna uyğun Tətbiqlər tapılmadı"
+ "Tətbiqləri axtarın"
+ "Tətbiqlər yüklənir…"
+ "%1$s sorğusuna uyğun tətbiq tapılmadı"
"Daha çox tətbiq üçün axtarış edin"
"Bildirişlər"
"Bu Əsas ekranda boş yer yoxdur."
@@ -79,17 +79,18 @@
"Bildiriş nişanı"
"Aktiv"
"Deaktiv"
+ "Bildiriş girişi tələb edilir"
+ "Bildiriş Nöqtələrini göstərmək üçün %1$s bildirişlərini aktiv edin"
+ "Ayarları dəyişin"
"Əsas ekrana ikona əlavə edin"
"Yeni tətbiqlər üçün"
-
-
+ "İkona formasını dəyişin"
"Sistem defoltu istifadə edin"
"Kvadrat"
"Kənarları dairəvi kvadrat"
"Çevrə"
"Gözyaşı damlası"
-
-
+ "İkona formasına etdiyiniz dəyişikliklər tətbiq edilir"
"Naməlum"
"Yığışdır"
"Axtarış"
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 615fd57041..4b4e95f1fc 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -31,9 +31,11 @@
"Дакраніцеся двойчы і ўтрымлівайце, каб выбраць віджэт або выкарыстоўваць карыстальніцкія дзеянні."
"%1$d × %2$d"
"Шырына: %1$d, вышыня: %2$d"
- "Пошук у Праграмах"
- "Ідзе загрузка праграм…"
- "Праграм, якія адпавядаюць запыту \"%1$s\", не знойдзена"
+ "Каб размясціць уручную, дакраніцеся і ўтрымлівайце"
+ "Дадаць аўтаматычна"
+ "Пошук праграм"
+ "Праграмы загружаюцца…"
+ "Праграм, якія адпавядаюць запыту \"%1$s\", не знойдзена"
"Шукаць іншыя праграмы"
"На гэтым Галоўным экране больш няма месца."
"У латку \"Абранае\" больш няма месца"
@@ -74,17 +76,18 @@
"Значкі апавяшчэнняў"
"Уключана"
"Выключана"
+ "Патрабуецца доступ да апавяшчэнняў"
+ "Каб паказваліся значкі апавяшчэнняў, уключыце апавяшчэнні праграм для %1$s"
+ "Змяніць налады"
"Дадаць значок на Галоўны экран"
"Для новых праграм"
-
-
+ "Змяніць форму значка"
"Выкарыстоўваць стандартныя формы"
"Квадрат"
"Прамавугольнік са скругленымі вугламі"
"Круг"
"Сляза"
-
-
+ "Змены формы значка прымяняюцца"
"Невядома"
"Выдаліць"
"Шукаць"
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index d4c5210593..471602f47d 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -27,7 +27,7 @@
"ডাউনলোড করা অ্যাপ্লিকেশান নিরাপদ মোডে অক্ষম রয়েছে"
"সুরক্ষিত মোডে উইজেট নিষ্ক্রিয় থাকে"
"শর্টকাটগুলি অনুপলব্ধ"
- "হোম স্ক্রীন"
+ "হোম স্ক্রিন"
"কাস্টম অ্যাকশন"
"একটি উইজেট তুলতে তা স্পর্শ করে ধরে রাখুন৷"
"কোনো উইজেট বেছে নিতে দুবার-আলতো চেপে ধরে থাকুন অথবা কাস্টম ক্রিয়াগুলি ব্যবহার করুন৷"
@@ -35,9 +35,9 @@
"%2$d উচ্চতা অনুযায়ী %1$d প্রস্থ"
"নিজে যোগ করতে টাচ করে ধরে রাখুন"
"স্বয়ংক্রিয়ভাবে যোগ করুন"
- "অ্যাপ্লিকেশানগুলি অনুসন্ধান করুন"
- "অ্যাপ্লিকেশানগুলি লোড হচ্ছে..."
- "\"%1$s\" এর সাথে মেলে এমন কোনো অ্যাপ্লিকেশান পাওয়া যায়নি"
+ "অ্যাপ অনুসন্ধান করুন"
+ "অ্যাপ লোড হচ্ছে…"
+ "\"%1$s\" এর সাথে মেলে এমন কোনো অ্যাপ পাওয়া যায়নি"
"আরো অ্যাপ্লিকেশানের জন্য অনুসন্ধান করুন"
"বিজ্ঞপ্তি"
"এই হোম স্ক্রীনে আর কোনো জায়গা নেই৷"
@@ -60,7 +60,7 @@
"নামবিহীন ফোল্ডার"
"%1$s অক্ষম করা হয়েছে"
"%2$dটির মধ্যে %1$dটি পৃষ্ঠা"
- "%2$dটির %1$d নম্বর হোম স্ক্রীন"
+ "%2$dটির %1$d নম্বর হোম স্ক্রিন"
"নতুন হোম স্ক্রীনের পৃষ্ঠা"
"ফোল্ডার খোলা হয়েছে, %1$d বাই %2$d"
"ফোল্ডার বন্ধ করতে আলতো চাপ দিন"
@@ -79,6 +79,9 @@
"বিজ্ঞপ্তি ডট"
"চালু হয়েছে"
"বন্ধ আছে"
+ "বিজ্ঞপ্তিতে অ্যাক্সেস প্রয়োজন"
+ "বিজ্ঞপ্তির ডটগুলি দেখানোর জন্য, %1$s এর অ্যাপ বিজ্ঞপ্তি চালু করুন"
+ "সেটিংস পরিবর্তন করুন"
"হোম স্ক্রিনে আইকন যোগ করুন"
"নতুন অ্যাপ্লিকেশানগুলির জন্যে"
"আইকনের আকৃতি পরিবর্তন করুন"
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index d91106bb20..49c862a8cd 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -35,9 +35,9 @@
"Širina %1$d, visina %2$d"
"Dodirnite i držite da postavite ručno"
"Dodaj automatski"
- "Pretraži aplikacije"
- "Aplikacije se učitavaju…"
- "Nije pronađena nijedna aplikacija koja odgovara upitu \"%1$s\""
+ "Pretražite aplikacije"
+ "Aplikacije se učitavaju…"
+ "Nije pronađena nijedna aplikacija za upit \"%1$s\""
"Pretraži više aplikacija"
"Obavještenja"
"Na ovom početnom ekranu nema više prostora."
@@ -79,17 +79,18 @@
"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"
"Dodajte ikonu na početni ekran"
"Za nove aplikacije"
-
-
+ "Promjena oblika ikona"
"Koristite sistemski zadano"
"Kvadrat"
"Zaobljeni kvadrat"
"Krug"
"Suza"
-
-
+ "Primjenjivanje promjena oblika ikona"
"Nepoznato"
"Ukloni"
"Traži"
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index abc44c7142..e6dee3c3b3 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -76,11 +76,11 @@
"Povolit otáčení plochy"
"Při otočení telefonu"
"Aktuální nastavení displeje neumožňuje otáčení"
- "Puntíky s oznámeními"
+ "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ími, zapněte oznámení z aplikace %1$s"
+ "Chcete-li zobrazovat puntíky s oznámením, zapněte oznámení z aplikace %1$s"
"Změnit nastavení"
"Přidat ikonu na plochu"
"Pro nové aplikace"
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 6eca89e5ce..4c90bdc5e3 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -31,9 +31,11 @@
"Topeltpuudutage ja hoidke vidina valimiseks või kohandatud toimingute kasutamiseks."
"%1$d × %2$d"
"%1$d lai ja %2$d kõrge"
- "Otsige rakendustest"
- "Rakenduste laadimine ..."
- "Päringule „%1$s” ei vastanud ükski rakendus"
+ "Puudutage pikalt, et käsitsi asetada"
+ "Lisa automaatselt"
+ "Otsige rakendusi"
+ "Rakenduste laadimine …"
+ "Päringule „%1$s” ei vastanud ükski rakendus"
"Otsi rohkem rakendusi"
"Sellel avaekraanil pole enam ruumi."
"Salves Lemmikud pole rohkem ruumi"
@@ -74,17 +76,18 @@
"Märguandetäpid"
"Sees"
"Väljas"
+ "Vaja on juurdepääsu märguannetele"
+ "Märguandetäppide kuvamiseks lülitage sisse rakenduse %1$s märguanded"
+ "Seadete muutmine"
"Lisa ikoon avaekraanile"
"Uute rakenduste puhul"
-
-
+ "Ikooni kuju muutmine"
"Kasuta süsteemi vaikeseadet"
"Ruut"
"Ümarate nurkadega ruut"
"Ring"
"Tilk"
-
-
+ "Ikooni kuju muudatuste rakendamine"
"Teadmata"
"Eemalda"
"Otsing"
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 59fc221566..b6082fadab 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -35,9 +35,9 @@
"%1$d zabal eta %2$d luze"
"Eduki sakatuta eskuz gehitzeko"
"Gehitu automatikoki"
- "Bilatu aplikazioetan"
- "Aplikazioak kargatzen…"
- "Ez da aurkitu \"%1$s\" bilaketarekin bat datorren aplikaziorik"
+ "Bilatu aplikazioetan"
+ "Aplikazioak kargatzen…"
+ "Ez da aurkitu \"%1$s\" bilaketaren emaitzarik"
"Bilatu aplikazio gehiago"
"Jakinarazpenak"
"Hasierako pantaila honetan ez dago toki gehiago."
@@ -79,17 +79,18 @@
"Jakinarazteko biribiltxoak"
"Aktibatuta"
"Desaktibatuta"
+ "Jakinarazpenetarako sarbidea behar da"
+ "Jakinarazteko biribiltxoak ikusteko, aktibatu %1$s aplikazioaren jakinarazpenak"
+ "Aldatu ezarpenak"
"Gehitu ikonoa hasierako pantailan"
"Aplikazio berrietan"
-
-
+ "Aldatu ikonoaren forma"
"Erabili sistemaren balio lehenetsiak"
"Karratua"
"Ertz biribilduko karratua"
"Zirkulua"
"Malkoa"
-
-
+ "Ikonoaren forman egindako aldaketak aplikatzen"
"Ezezaguna"
"Kendu"
"Bilatu"
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 9211ba1a15..d55514d1e9 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -35,9 +35,9 @@
"%1$d de largo por %2$d de alto"
"Mantén premido o elemento para colocalo manualmente"
"Engadir automaticamente"
- "Aplicacións de busca"
- "Cargando aplicacións..."
- "Non se atoparon aplicacións que coincidan con \"%1$s\""
+ "Buscar aplicacións"
+ "Cargando aplicacións…"
+ "Non se atoparon aplicacións que coincidan con \"%1$s\""
"Buscar máis aplicacións"
"Notificacións"
"Non hai máis espazo nesta pantalla de inicio."
@@ -79,17 +79,18 @@
"Puntos de notificacións"
"Activado"
"Desactivado"
+ "Necesítase acceso ás notificacións"
+ "Para que se mostren os puntos de notificacións, activa as notificacións da aplicación %1$s"
+ "Cambiar configuración"
"Engadir icona á pantalla de inicio"
"Para novas aplicacións"
-
-
+ "Cambiar forma das iconas"
"Usar valores predeterminados do sistema"
"Cadrado"
"Cadrado de bordos redondeados"
"Círculo"
"Bágoa"
-
-
+ "Aplicando cambios na forma das iconas"
"Descoñecido"
"Eliminar"
"Buscar"
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index b491e42984..7096a3ee0a 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -29,15 +29,15 @@
"શૉર્ટકટ ઉપલબ્ધ નથી"
"હોમ સ્ક્રીન"
"કસ્ટમ ક્રિયાઓ"
- "વિજેટ ચૂંટવા માટે ટચ કરો અને પકડી રાખો."
+ "વિજેટ ચૂંટવા માટે સ્પર્શ કરો અને પકડી રાખો."
"વિજેટ ચૂંટવા અથવા કસ્ટમ ક્રિયાઓનો ઉપયોગ કરવા માટે બે વાર ટેપ કરો અને પકડી રાખો."
"%1$d × %2$d"
"%1$d પહોળાઈ X %2$d ઊંચાઈ"
"મેન્યુઅલી મૂકવા માટે ટચ કરી દબાવી રાખો"
"આપમેળે ઉમેરો"
- "શોધ ઍપ્લિકેશનો"
- "ઍપ્લિકેશનો લોડ કરી રહ્યું છે…"
- "\"%1$s\" થી મેળ ખાતી કોઈ ઍપ્લિકેશનો મળી નથી"
+ "શોધ ઍપ્લિકેશનો"
+ "ઍપ્લિકેશનો લોડ કરી રહ્યું છે…"
+ "\"%1$s\"થી મેળ ખાતી કોઈ ઍપ્લિકેશનો મળી નથી"
"વધુ ઍપ્લિકેશનો શોધો"
"સૂચનાઓ"
"આ હોમ સ્ક્રીન પર વધુ જગ્યા નથી."
@@ -72,13 +72,16 @@
"વૉલપેપર્સ"
"હોમ સેટિંગ્સ"
"તમારા વ્યવસ્થાપક દ્વારા અક્ષમ કરેલ"
- "વિહંગાવલોકન"
+ "ઝલક"
"હોમ સ્ક્રીનને ફેરવવાની મંજૂરી આપો"
"જ્યારે ફોન ફેરવવામાં આવે ત્યારે"
"વર્તમાન પ્રદર્શન સેટિંગ ફેરવવાની પરવાનગી આપતી નથી"
"સૂચના બિંદુઓ"
"ચાલુ"
"બંધ"
+ "નોટિફિકેશનનો ઍક્સેસની જરૂરી છે"
+ "નોટિફિકેશન માટેનું ચિહ્ન બતાવવા હેતુ, %1$s માટેની ઍપ્લિકેશન નોટિફિકેશન ચાલુ કરો"
+ "સેટિંગ્સ બદલો"
"હોમ સ્ક્રીન પર આઇકન ઉમેરો"
"નવી ઍપ્લિકેશનો માટે"
"આઇકનનો આકાર બદલો"
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 02c470ba07..f1ee0f2366 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -72,7 +72,7 @@
"वॉलपेपर"
"होम सेटिंग"
"आपके व्यवस्थापक द्वारा अक्षम"
- "अवलोकन"
+ "खास जानकारी"
"होमस्क्रीन घुमाने की अनुमति दें"
"फ़ोन घुुमाए जाने पर"
"वर्तमान प्रदर्शन सेटिंग घुमाने की अनुमति नहीं देती"
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 1646f9e33e..2b55e966a4 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -35,9 +35,9 @@
"Լայնությունը՝ %1$d, բարձրությունը՝ %2$d"
"Հպեք և պահեք՝ ձեռքով տեղադրելու համար"
"Ավելացնել ավտոմատ կերպով"
- "Հավելվածների որոնում"
- "Հավելվածների բեռնում…"
- "«%1$s» հարցմանը համապատասխանող հավելվածներ չեն գտնվել"
+ "Որոնել հավելվածներ"
+ "Հավելվածների բեռնում…"
+ "«%1$s» հարցմանը համապատասխանող հավելվածներ չեն գտնվել"
"Որոնել այլ հավելվածներ"
"Ծանուցումներ"
"Այլևս տեղ չկա այս հիմնական էկրանին:"
@@ -79,17 +79,18 @@
"Ծանուցման կետեր"
"Միացված է"
"Անջատված է"
+ "Անհրաժեշտ է ծանուցման թույլտվություն"
+ "Ծանուցման կետերը ցուցադրելու համար միացրեք հավելվածի ծանուցումները %1$s-ի համար"
+ "Փոխել կարգավորումները"
"Ավելացնել պատկերակը Հիմնական էկրանին"
"Նոր հավելվածների համար"
-
-
+ "Փոխել պատկերակների տեսքը"
"Օգտագործել համակարգի կանխադրված կարգավորումը"
"Քառակուսի"
"Քառանկյուն"
"Օղակ"
"Արցունքաձև"
-
-
+ "Պատկերակների տեսքի փոփոխությունները կիրառվում են"
"Անհայտ է"
"Հեռացնել"
"Գտնել"
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 853cd3b41c..cf178a56ad 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -35,9 +35,9 @@
"%1$d á breidd og %2$d á hæð"
"Haltu inni til að staðsetja handvirkt"
"Bæta sjálfkrafa við"
- "Leita í forritum"
- "Hleður forrit…"
- "Ekki fundust forrit sem samsvara „%1$s“"
+ "Leita í forritum"
+ "Hleður forrit…"
+ "Ekki fundust forrit sem samsvara „%1$s“"
"Leita að fleiri forritum"
"Tilkynningar"
"Ekki meira pláss á þessum heimaskjá."
@@ -79,17 +79,18 @@
"Tilkynningapunktar"
"Kveikt"
"Slökkt"
+ "Aðgangs að tilkynningum er krafist"
+ "Til að sýna tilkynningarpunkta skaltu kveikja á forritstilkynningum fyrir %1$s"
+ "Breyta stillingum"
"Bæta tákni á heimaskjáinn"
"Fyrir ný forrit"
-
-
+ "Breyta formi tákns"
"Nota sjálfgildi kerfis"
"Ferningur"
"Ferhringur"
"Hringur"
"Dropi"
-
-
+ "Breytir formi tákns"
"Óþekkt"
"Fjarlægja"
"Leita"
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 2634cdf431..7e8b46ce88 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -35,9 +35,9 @@
"სიგრძე: %1$d, სიგანე: %2$d"
"ხანგრძლივად შეეხეთ ხელით განსათავსებლად"
"ავტომატურად დამატება"
- "აპების ძიება"
- "აპები იტვირთება..."
- "„%1$s“-ის თანხვედრი აპები არ მოიძებნა"
+ "აპების ძიება"
+ "აპები იტვირთება…"
+ "„%1$s“-ის თანხვედრი აპები არ მოიძებნა"
"მეტი აპის პოვნა"
"შეტყობინებები"
"ამ მთავარ ეკრანზე ადგილი აღარ არის."
@@ -79,17 +79,18 @@
"შეტყობინების ნიშნულები"
"ჩართული"
"გამორთული"
+ "საჭიროა შეტყობინებებზე წვდომა"
+ "შეტყობინებათა ნიშნულების საჩვენებლად, ჩართეთ აპის შეტყობინებები %1$s-ისთვის"
+ "პარამეტრების შეცვლა"
"ხატულას მთავარ ეკრანზე დამატება"
"ახალი აპებისთვის"
-
-
+ "ხატულას ფორმის შეცვლა"
"ნაგულისხმევი სისტემური პარამეტრების გამოყენება"
"კვადრატი"
"წრეკუთხედი"
"წრე"
"წვეთი"
-
-
+ "მიმდინარეობს ხატულას ფორმის ცვლილებების მიყენება"
"უცნობი"
"ამოშლა"
"ძიება"
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 66766b6dba..50ed9aa680 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -35,9 +35,9 @@
"Ені: %1$d, биіктігі: %2$d"
"Қолмен қою үшін басып тұрыңыз"
"Автоматты енгізу"
- "Қолданбаларды іздеу"
- "Қолданбалар жүктелуде…"
- "«%1$s» сұрауына сәйкес келетін қолданбалар жоқ"
+ "Қолданбаларды іздеу"
+ "Қолданбалар жүктелуде…"
+ "\"%1$s\" сұрауына сәйкес келетін қолданбалар жоқ"
"Қосымша қолданбалар іздеу"
"Хабарландырулар"
"Бұл Негізгі экранда орын қалмады."
@@ -79,17 +79,18 @@
"Хабарландыру белгілері"
"Қосулы"
"Өшірулі"
+ "Хабарландыруға кіру рұқсаты қажет"
+ "Хабарландыру белгілерін көрсету үшін %1$s қолданбасының қолданба хабарландыруларын қосыңыз"
+ "Параметрлерді өзгерту"
"Негізгі экранға белгіше енгізу"
"Жаңа қолданбаларға арналған"
-
-
+ "Белгіше пішінін өзгерту"
"Жүйенің әдепкі параметрін пайдалану"
"Шаршы"
"Жұмыр төртбұрыш"
"Шеңбер"
"Тамшы"
-
-
+ "Белгіше пішіні өзгерістері күшіне енуде"
"Белгісіз"
"Алып тастау"
"Іздеу"
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index ee44302eaf..7028f7e3ae 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -35,9 +35,9 @@
"ទទឺង %1$d គុណនឹងកម្ពស់ %2$d"
"ចុចឲ្យជាប់ដើម្បីបញ្ចូលវាដោយផ្ទាល់"
"បញ្ចូលដោយស្វ័យប្រវត្តិ"
- "ស្វែងរកកម្មវិធី"
- "កំពុងដំណើរការកម្មវិធី..."
- "គ្មានកម្មវិធីដែលត្រូវជាមួយ \"%1$s\" ទេ"
+ "ស្វែងរកកម្មវិធី"
+ "កំពុងផ្ទុកកម្មវិធី…"
+ "រកមិនឃើញកម្មវិធីដែលត្រូវគ្នាជាមួយ \"%1$s\" ទេ"
"ស្វែងរកកម្មវិធីច្រើនទៀត"
"ការជូនដំណឹង"
"គ្មានបន្ទប់នៅលើអេក្រង់ដើមនេះទៀតទេ។"
@@ -79,17 +79,18 @@
"ស្លាកជូនដំណឹង"
"បើក"
"បិទ"
+ "តម្រូវឲ្យមានសិទ្ធិចូលប្រើប្រាស់ការជូនដំណឹង"
+ "ដើម្បីបង្ហាញស្លាកជូនដំណឹង សូមបើកការជូនដំណឹងកម្មវិធីសម្រាប់ %1$s"
+ "ប្ដូរការកំណត់"
"បញ្ចូលរូបតំណាងទៅអេក្រង់ដើម"
"សម្រាប់កម្មវិធីថ្មី"
-
-
+ "ប្តូររូបរាងរូបតំណាង"
"ប្រើលំនាំដើមរបស់ប្រព័ន្ធ"
"ការ៉េ"
"ការ៉េជ្រុងកោង"
"រង្វង់"
"តំណក់ទឹកភ្នែក"
-
-
+ "កំពុងអនុវត្តការប្តូររូបរាងរូបតំណាង"
"មិនស្គាល់"
"លុបចេញ"
"ស្វែងរក"
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 6c89b7bd13..9a31649be3 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -35,9 +35,9 @@
"%1$d ಅಗಲ ಮತ್ತು %2$d ಎತ್ತರ"
"ಹಸ್ತಚಾಲಿತವಾಗಿ ಸೇರಿಸಲು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹೋಲ್ಡ್ ಮಾಡಿ"
"ಸ್ವಯಂಚಾಲಿತವಾಗಿ ಸೇರಿಸಿ"
- "ಅಪ್ಲಿಕೇಷನ್ಗಳನ್ನು ಹುಡುಕಿ"
- "ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."
- "\"%1$s\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"
+ "ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಹುಡುಕಿ"
+ "ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಲೋಡ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."
+ "\"%1$s\" ಹೊಂದಿಕೆಯ ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್ಗಳು ಕಂಡುಬಂದಿಲ್ಲ"
"ಮತ್ತಷ್ಟು ಅಪ್ಲಿಕೇಶನ್ಗಳನ್ನು ಹುಡುಕಿ"
"ಅಧಿಸೂಚನೆಗಳು"
"ಈ ಮುಖಪುಟದ ಪರದೆಯಲ್ಲಿ ಹೆಚ್ಚು ಸ್ಥಳಾವಕಾಶವಿಲ್ಲ."
@@ -79,6 +79,9 @@
"ಅಧಿಸೂಚನೆ ಡಾಟ್ಗಳು"
"ಆನ್"
"ಆಫ್"
+ "ಅಧಿಸೂಚನೆ ಪ್ರವೇಶ ಅಗತ್ಯವಿದೆ"
+ "ಅಧಿಸೂಚನೆ ಚುಕ್ಕೆಗಳನ್ನು ತೋರಿಸಲು, %1$s ಗೆ ಅಪ್ಲಿಕೇಶನ್ ಅಧಿಸೂಚನೆಗಳನ್ನು ಆನ್ ಮಾಡಿ"
+ "ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬದಲಾಯಿಸಿ"
"ಮುಖಪುಟದ ಪರದೆಗೆ ಐಕಾನ್ ಸೇರಿಸಿ"
"ಹೊಸ ಅಪ್ಲಿಕೇಶನ್ಗಳಿಗೆ"
"ಐಕಾನ್ ಆಕಾರವನ್ನು ಬದಲಿಸಿ"
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index cc15f04479..85ba8be3c3 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -35,9 +35,9 @@
"Туурасы: %1$d, бийиктиги: %2$d"
"Кол менен жайгаштыруу үчүн басып туруп, таштаңыз"
"Автоматтык түрдө кошуу"
- "Колдонмолорду издөө"
- "Колдонмолор жүктөлүүдө…"
- "\"%1$s\" дал келген колдонмолор табылган жок"
+ "Колдонмолорду издөө"
+ "Колдонмолор жүктөлүүдө…"
+ "\"%1$s\" сурамына дал келген колдонмолор табылган жок"
"Көбүрөөк колдонмолорду издөө"
"Эскертмелер"
"Бул Үй экранында бош орун жок."
@@ -79,17 +79,18 @@
"Эскертме белгилери"
"Күйүк"
"Өчүк"
+ "Эскертмелерге уруксат берилиши керек"
+ "Эскертме белгилерин көрсөтүү максатында, %1$s үчүн колдонмонун эскертмелерин күйгүзүү керек"
+ "Жөндөөлөрдү өзгөртүү"
"Башкы экранга сүрөтчө кошуу"
"Жаңы колдонмолор үчүн"
-
-
+ "Сүрөтчөнүн формасын өзгөртүү"
"Тутум сушунтаган демейкисин колдонуу"
"Чарчы"
"Бурчтары жумуру төрт бурчтук"
"Тегерек"
"Тамчы"
-
-
+ "Өзгөртүлгөн сүрөтчөнүн формасы колдонулууда"
"Белгисиз"
"Алып салуу"
"Издөө"
diff --git a/res/values-land/dimens.xml b/res/values-land/dimens.xml
index 1b58e17754..92420a2f12 100644
--- a/res/values-land/dimens.xml
+++ b/res/values-land/dimens.xml
@@ -30,12 +30,24 @@
4dp
0dp
+ 5.5dp
+
2dp
+
+ 50dp
+ 74dp
+
+
+ 0dp
+
+ 50dp
+ 44dp
18dp
+
+ 56dp
+ 32dp
6dp
- 24dp
- 32dp
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 0b294344e7..9a50c4b517 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -35,9 +35,9 @@
"ກວ້າງ %1$d ຄູນສູງ %2$d"
"ແຕະຄ້າງໄວ້ເພື່ອວາງດ້ວຍຕົນເອງ"
"ເພີ່ມໂດຍອັດຕະໂນມັດ"
- "ຊອກຫາແອັບ"
- "ກຳລັງໂຫລດແອັບ..."
- "ບໍ່ພົບແອັບໃດທີ່ກົງກັນ \"%1$s\""
+ "ຊອກຫາແອັບ"
+ "ກໍາລັງໂຫຼດແອັບ…"
+ "ບໍ່ພົບແອັບທີ່ກົງກັບ \"%1$s\""
"ຊອກຫາແອັບເພີ່ມເຕີມ"
"ການແຈ້ງເຕືອນ"
"ບໍ່ມີຫ້ອງເຫຼືອໃນໜ້າຈໍຫຼັກນີ້."
@@ -79,17 +79,18 @@
"ຈຸດການແຈ້ງເຕືອນ"
"ເປີດ"
"ປິດ"
+ "ຕ້ອງໃຊ້ການເຂົ້າເຖິງການແຈ້ງເຕືອນ"
+ "ເພື່ອສະແດງຈຸດການແຈ້ງເຕືອນ, ໃຫ້ເປີດການແຈ້ງເຕືອນສຳລັບ %1$s"
+ "ບັນທຶກການຕັ້ງຄ່າ"
"ເພີ່ມໄອຄອນໃສ່ໜ້າຈໍຫຼັກ"
"ສຳລັບແອັບໃໝ່"
-
-
+ "ປ່ຽນຮູບຮ່າງໄອຄອນ"
"ໃຊ້ຄ່າເລີ່ມຕົ້ນລະບົບ"
"ສີ່ຫຼ່ຽມຈັດຕຸລັດ"
"ສີ່ຫຼ່ຽມຂອບມົນ"
"ວົງມົນ"
"ນ້ຳຢອດ"
-
-
+ "ນຳໃຊ້ການປ່ຽນແປງຮູບຮ່າງໄອຄອນ"
"ບໍ່ຮູ້ຈັກ"
"ລຶບ"
"ຊອກຫາ"
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index abd1d35dde..7d95a23a6c 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -35,9 +35,9 @@
"%1$d широк на %2$d висок"
"Допрете и задржете за рачно поставување"
"Додај автоматски"
- "Пребарување апликации"
- "Се вчитуваат апликации…"
- "Не се најдени апликации што одговараат на „%1$s“"
+ "Пребарувајте апликации"
+ "Се вчитуваат апликации…"
+ "Не се најдени апликации што одговараат на „%1$s“"
"Пребарај други апликации"
"Известувања"
"Нема повеќе простор на овој екран на почетната страница."
@@ -79,17 +79,18 @@
"Точки за известување"
"Вклучено"
"Исклучено"
+ "Потребен е пристап до известувањата"
+ "За да се прикажуваат „Точки за известување“, вклучете ги известувањата за апликацијата %1$s"
+ "Промени ги поставките"
"Додајте икона на почетниот екран"
"За нови апликации"
-
-
+ "Променете ја формата на иконата"
"Користи ја стандардната поставка на системот"
"Квадрат"
"Заоблен квадрат"
"Круг"
"Солза"
-
-
+ "Се применуваат промените на формата на иконата"
"Непознато"
"Отстрани"
"Барај"
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index bad7e480a1..0cc7aa023c 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -35,9 +35,9 @@
"%1$d വീതിയും %2$d ഉയരവും"
"സ്വമേധയാ സ്ഥാപിക്കുന്നതിന് സ്പർശിച്ചുപിടിക്കുക"
"സ്വയമേവ ചേർക്കുക"
- "ആപ്പുകളെ തിരയുക"
- "ആപ്പുകൾ ലോഡുചെയ്യുന്നു..."
- "\"%1$s\" എന്നതുമായി പൊരുത്തപ്പെടുന്ന ആപ്പ്സൊന്നും കണ്ടെത്തിയില്ല"
+ "ആപ്പുകൾ തിരയുക"
+ "ആപ്പുകൾ ലോഡുചെയ്യുന്നു..."
+ "\"%1$s\" എന്നതുമായി പൊരുത്തപ്പെടുന്ന ആപ്പുകളൊന്നും കണ്ടെത്തിയില്ല"
"കൂടുതൽ ആപ്പുകൾക്ക് തിരയുക"
"അറിയിപ്പുകൾ"
"ഈ ഹോം സ്ക്രീനിൽ ഒഴിവൊന്നുമില്ല."
@@ -72,13 +72,16 @@
"വാൾപേപ്പർ"
"ഹോം ക്രമീകരണം"
"അഡ്മിൻ പ്രവർത്തനരഹിതമാക്കിയിരിക്കുന്നു"
- "കാഴ്ച"
+ "അവലോകനം"
"ഹോം സ്ക്രീൻ തിരിക്കൽ അനുവദിക്കുക"
"ഫോൺ തിരിച്ച നിലയിലായിരിക്കുമ്പോൾ"
"നിലവിലെ ഡിസ്പ്ലേ ക്രമീകരണം തിരിക്കൽ അനുവദിക്കുന്നില്ല"
"അറിയിപ്പ് ഡോട്ടുകൾ"
"ഓൺ"
"ഓഫ്"
+ "അറിയിപ്പിനായുള്ള ആക്സസ് ആവശ്യമാണ്"
+ "അറിയിപ്പ് ഡോട്ടുകൾ കാണിക്കുന്നതിന്, %1$s എന്നയാളിനായുള്ള ആപ്പ് അറിയിപ്പുകൾ ഓണാക്കുക"
+ "ക്രമീകരണം മാറ്റുക"
"ഹോം സ്ക്രീനിലേക്ക് ഐക്കൺ ചേർക്കുക"
"പുതിയ ആപ്പുകൾക്ക്"
"ഐക്കണിന്റെ ആകാരം മാറ്റുക"
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 264e55a86e..22479cc3e4 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -35,9 +35,9 @@
"%1$d өргөн %2$d өндөр"
"Гараар байршуулахын тулд дараад хүлээнэ үү"
"Автоматаар нэмэх"
- "Апп хайх"
- "Аппликейшныг ачаалж байна..."
- "\"%1$s\"-д нийцэх апп олдсонгүй"
+ "Апп хайх"
+ "Аппыг ачааллаж байна..."
+ "\"%1$s\"-д тохирох апп олдсонгүй"
"Бусад апп-г хайх"
"Мэдэгдэл"
"Энэ Нүүр дэлгэц зайгүй."
@@ -79,17 +79,18 @@
"Мэдэгдлийн цэг"
"Асаалттай"
"Унтраалттай"
+ "Мэдэгдлийн хандалт шаардлагатай"
+ "Мэдэгдлийн цэгийг харуулахын тулд %1$s-д аппын мэдэгдлийг асаана уу"
+ "Тохиргоог өөрчлөх"
"Нүүр хуудаст дүрс тэмдэг нэмэх"
"Шинэ аппад зориулсан"
-
-
+ "Дүрс тэмдгийн хэлбэрийг өөрчлөх"
"Системийн өгөгдмөл тохиргоог ашиглах"
"Дөрвөлжин"
"Мохоо өнцөгтэй дөрвөлжин"
"Дугуй"
"Дусал"
-
-
+ "Дүрс тэмдгийн хэлбэрийг өөрчилж байна"
"Тодорхойгүй"
"Устгах"
"Хайх"
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index b23ea965d1..751ad227ab 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -27,31 +27,31 @@
"डाउनलोड केलेला अॅप सुरक्षित मोड मध्ये अक्षम केला"
"विजेट सुरक्षित मोडमध्ये अक्षम झाले"
"शॉर्टकट उपलब्ध नाही"
- "मुख्यपृष्ठ"
+ "होम स्क्रीन"
"सानुकूल क्रिया"
"विजेट निवडण्यासाठी स्पर्श करा आणि धरून ठेवा."
"एक विजेट निवडण्यासाठी दोनदा टॅप करा आणि धरून ठेवा किंवा सानुकूल क्रिया वापरा."
"%1$d × %2$d"
"%1$d रूंद बाय %2$d उंच"
"स्वतः ठेवण्यासाठी स्पर्श करा आणि धरून ठेवा"
- "स्वयंचलितपणे जोडा"
- "अॅप्स शोधा"
- "अॅप्स लोड करीत आहे..."
- "\"%1$s\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"
+ "अापोआप जोडा"
+ "अॅप्स शोधा"
+ "अॅप्स लोड करत आहे…"
+ "\"%1$s\" शी जुळणारे कोणतेही अॅप्स आढळले नाहीत"
"अधिक अॅप्स शोधा"
"सूचना"
"या मुख्य स्क्रीनवर आणखी जागा नाही."
"आवडीच्या ट्रे मध्ये आणखी जागा नाही"
"अॅप्स सूची"
- "मुख्यपृष्ठ"
+ "होम"
"काढा"
"विस्थापित करा"
"अॅप माहिती"
"शॉर्टकट स्थापित करा"
"वापरकर्ता हस्तक्षेपाशिवाय शॉर्टकट जोडण्यास अॅप ला अनुमती देते."
- "मुख्यपृष्ठ सेटिंग्ज आणि शॉर्टकट वाचा"
+ "होम सेटिग्ज आणि शॉर्टकट वाचा"
"मुख्यपृष्ठातील सेटिंग्ज आणि शॉर्टकट वाचण्यास अॅप ला अनुमती देते."
- "मुख्यपृष्ठ सेटिंग्ज आणि शॉर्टकट लिहा"
+ "होम स्क्रीन सेटिंग्ज आणि शॉर्टकट लिहा"
"मुख्यपृष्ठातील सेटिंग्ज आणि शॉर्टकट बदलण्यास अॅप ला अनुमती देते."
"%1$s ला फोन कॉल करण्याची अनुमती नाही"
"विजेट लोड करण्यात समस्या"
@@ -72,14 +72,17 @@
"वॉलपेपर"
"होम सेटिंग्ज"
"आपल्या प्रशासकाने अक्षम केले"
- "विहंगावलोकन"
+ "अवलोकन"
"मुख्यस्क्रीन फिरविण्यास अनुमती द्या"
"फोन फिरविला जातो तेव्हा"
"वर्तमान प्रदर्शन सेटिंग फिरविण्यास परवानगी देत नाही"
"सूचना बिंदू"
"चालू"
"बंद"
- "मुख्य स्क्रीनवर चिन्ह जोडा"
+ "सूचनांच्या अॅक्सेसची आवश्यकता आहे"
+ "सूचना बिंदू दाखवण्यासाठी, %1$s साठी अॅप सूचना चालू करा"
+ "सेटिंग्ज बदला"
+ "होम स्क्रीनवर आयकन जोडा"
"नवीन अॅप्ससाठी"
"चिन्हाचा आकार बदला"
"सिस्टमचे डीफॉल्ट वापरा"
@@ -96,7 +99,7 @@
"%1$s डाउनलोड होत आहे , %2$s पूर्ण झाले"
"%1$s स्थापित करण्याची प्रतिक्षा करीत आहे"
"%1$s विजेट"
- "मुख्य स्क्रीनवर जोडा"
+ "होम स्क्रीनवर जोडा"
"आयटम येथे हलवा"
"आयटम मुख्य स्क्रीनवर जोडला"
"आयटम काढला"
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index f7237a01d2..e142b0b6e8 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -31,9 +31,11 @@
"Ketik dua kali & tahan untuk mengambil widget atau menggunakan tindakan tersuai"
"%1$d × %2$d"
"Lebar %1$d kali tinggi %2$d"
- "Cari Apl"
- "Memuatkan Apl…"
- "Tiada Apl yang ditemui sepadan dengan \"%1$s\""
+ "Sentuh & tahan untuk meletakkan widget/ikon secara manual"
+ "Tambahkan secara automatik"
+ "Cari apl"
+ "Memuatkan apl…"
+ "Tiada apl yang ditemui sepadan dengan \"%1$s\""
"Cari lagi apl"
"Tiada lagi ruang pada skrin Laman Utama ini."
"Tiada ruang dalam dulang Kegemaran lagi"
@@ -74,17 +76,18 @@
"Titik pemberitahuan"
"Hidup"
"Mati"
+ "Akses pemberitahuan diperlukan"
+ "Untuk menunjukkan Titik Pemberitahuan, hidupkan pemberitahuan apl untuk %1$s"
+ "Tukar tetapan"
"Tambahkan ikon pada Skrin Utama"
"Untuk apl baharu"
-
-
+ "Tukar bentuk ikon"
"Gunakan lalai sistem"
"Segi empat sama"
"Segi empat berbucu bulat"
"Bulatan"
"Titisan air mata"
-
-
+ "Menggunakan perubahan bentuk ikon"
"Tidak diketahui"
"Alih keluar"
"Carian"
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index a4648b15a2..74574b9b23 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -35,9 +35,9 @@
"အလျား %1$d နှင့် အမြင့် %2$d"
"ကိုယ်တိုင်ထည့်ရန် ထိထားပါ"
"အလိုအလျောက် ထည့်ရန်"
- "ရှာဖွေမှု အက်ပ်များ"
- "အက်ပ်များ ရယူနေစဉ်..."
- "\"%1$s\" နှင့်ကိုက်ညီသည့် အပ်ဖ်များမတွေ့ပါ"
+ "ရှာဖွေမှု အက်ပ်များ"
+ "အက်ပ်များကို ဖွင့်နေသည်…"
+ "\"%1$s\" နှင့်ကိုက်ညီသည့် အပ်ပ်များကို မတွေ့ပါ"
"နောက်ထပ် အက်ပ်များကို ရှာပါ"
"အကြောင်းကြားချက်များ"
"ဤပင်မမျက်နှာစာတွင် နေရာလွတ် မကျန်တော့ပါ"
@@ -79,17 +79,18 @@
"အကြောင်းကြားချက်အမှတ်အသားများ"
"ဖွင့်ထားသည်"
"ပိတ်ထားသည်"
+ "အကြောင်းကြားချက် အသုံးပြုခွင့် လိုအပ်သည်"
+ "အကြောင်းကြားချက် အစက်များကို ပြသရန် %1$s အတွက် အက်ပ်အကြောင်းကြားချက်များကို ဖွင့်ပါ"
+ "ဆက်တင်များ ပြောင်းရန်"
"ပင်မစာမျက်နှာသို့ သင်္ကေတပုံ ထည့်ရန်"
"အက်ပ်အသစ်များအတွက်"
-
-
+ "သင်္ကေတပုံစံကို ပြောင်းရန်"
"စနစ်၏ မူရင်းပုံကို အသုံးပြုရန်"
"လေးထောင့်"
"စတုရန်းမကျ စက်ဝိုင်းမကျပုံ"
"စက်ဝိုင်း"
"မျက်ရည်စက်ပုံ"
-
-
+ "သင်္ကေတပုံစံကို ပြောင်းလဲနေသည်"
"မသိရ"
"ဖယ်ရှားရန်"
"ရှာဖွေရန်"
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index bd348b0aab..65247c168d 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -84,13 +84,13 @@
"Endre innstillingene"
"Legg til ikon på startsiden"
"For nye apper"
- "Endre ikonets form"
+ "Endre formen på ikonet"
"Bruk systemstandard"
"Kvadrat"
"Superellipse"
"Sirkel"
"Dråpe"
- "Aktiverer endringer av ikonets form"
+ "Aktiverer endringer av formen på ikonet"
"Ukjent"
"Fjern"
"Søk"
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 558b6cf8e5..904dad45e2 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -35,9 +35,9 @@
"%1$d चौडाइ गुणा %2$d उचाइ"
"म्यानुअल तरिकाले थप्न छुनुहोस् र थिची राख्नुहोस्"
"स्वतः थप्नुहोस्"
- "अनुप्रयोगहरू खोज्नुहोस्"
- "अनुप्रयोगहरू लोड गरिँदै..."
- "\"%1$s\" सँग मिल्दो कुनै अनुप्रयोगहरू फेला परेनन्"
+ "खोजसम्बन्धी अनुप्रयोगहरू"
+ "अनुप्रयोगहरू लोड गर्दै…"
+ "\"%1$s\" सँग मिल्दो कुनै अनुप्रयोग भेटिएन"
"थप अनुप्रयोगहरू खोज्नुहोस्"
"सूचनाहरू"
"यो गृह स्क्रिनमा कुनै थप ठाउँ छैन।"
@@ -79,6 +79,9 @@
"सूचनाको प्रतीक जनाउने थोप्लोहरू"
"सक्रिय छ"
"निष्क्रिय छ"
+ "सूचनासम्बन्धी पहुँच आवश्यक हुन्छ"
+ "सूचनाको प्रतीक जनाउने थोप्लाहरू देखाउन %1$s को अनुप्रयोगसम्बन्धी सूचनाहरूलाई सक्रिय गर्नुहोस्"
+ "सेटिङहरू बदल्नुहोस्"
"गृह स्क्रिनमा आइकन थप्नुहोस्"
"नयाँ अनुप्रयोगका लागि"
"आइकनको आकार परिवर्तन गर्नुहोस्"
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 05fe509a27..cf5351c7a7 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -25,7 +25,7 @@
"ਐਪ ਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਹੋਇਆ ਹੈ।"
"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"
"ਡਾਊਨਲੋਡ ਕੀਤਾ ਐਪ ਸੁਰੱਖਿਅਤ ਮੋਡ ਵਿੱਚ ਅਸਮਰਥਿਤ"
- "ਵਿਜਿਟ ਸੁਰੱਖਿਅਤ ਮੋਡ ਵਿੱਚ ਅਸਮਰਥਿਤ"
+ "ਵਿਜੇਟ ਸੁਰੱਖਿਅਤ ਮੋਡ ਵਿੱਚ ਅਸਮਰਥਿਤ"
"ਸ਼ਾਰਟਕੱਟ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"
"ਮੁੱਖ ਸਕ੍ਰੀਨ"
"ਵਿਸ਼ੇਸ਼-ਵਿਉਂਤਬੱਧ ਕਾਰਵਾਈਆਂ"
@@ -35,9 +35,9 @@
"%1$d ਚੌੜਾਈ ਅਤੇ %2$d ਲੰਬਾਈ"
"ਹੱਥੀਂ ਰੱਖਣ ਲਈ ਸਪੱਰਸ਼ ਕਰੋ ਅਤੇ ਦਬਾਈ ਰੱਖੋ"
"ਸਵੈਚਲਿਤ ਤਰੀਕੇ ਨਾਲ ਸ਼ਾਮਲ ਕਰੋ"
- "ਐਪਸ ਖੋਜੋ"
- "ਐਪਾਂ ਨੂੰ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."
- "\"%1$s\" ਨਾਲ ਮਿਲਦੀਆਂ ਕੋਈ ਵੀ ਐਪਾਂ ਨਹੀਂ ਮਿਲੀਆਂ"
+ "ਐਪਾਂ ਖੋਜੋ"
+ "ਐਪਾਂ ਨੂੰ ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ..."
+ "\"%1$s\" ਨਾਲ ਮੇਲ ਖਾਂਦੀਆਂ ਕੋਈ ਐਪਾਂ ਨਹੀਂ ਮਿਲੀਆਂ"
"ਹੋਰ ਐਪਾਂ ਖੋਜੋ"
"ਸੂਚਨਾਵਾਂ"
"ਇਸ ਹੋਮ ਸਕ੍ਰੀਨ ਲਈ ਹੋਰ ਖਾਲੀ ਸਥਾਨ ਨਹੀਂ ਹੈ।"
@@ -68,7 +68,7 @@
"ਫੋਲਡਰ ਬੰਦ ਕੀਤਾ"
"ਫੋਲਡਰ ਨੂੰ %1$s ਮੁੜ ਨਾਮ ਦਿੱਤਾ ਗਿਆ"
"ਫੋਲਡਰ: %1$s"
- "ਵਿਜਿਟ"
+ "ਵਿਜੇਟ"
"ਵਾਲਪੇਪਰ"
"ਹੋਮ ਸੈਟਿੰਗਾਂ"
"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਦੁਆਰਾ ਅਯੋਗ ਬਣਾਈ ਗਈ"
@@ -79,6 +79,9 @@
"ਸੂਚਨਾ ਬਿੰਦੂ"
"ਚਾਲੂ"
"ਬੰਦ"
+ "ਸੂਚਨਾ ਪਹੁੰਚ ਲੋੜੀਂਦੀ ਹੈ"
+ "ਸੂਚਨਾ ਬਿੰਦੀਆਂ ਦਿਖਾਉਣ ਲਈ, %1$s ਲਈ ਐਪ ਸੂਚਨਾਵਾਂ ਚਾਲੂ ਕਰੋ"
+ "ਸੈਟਿੰਗਾਂ ਬਦਲੋ"
"ਮੁੱਖ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰਤੀਕ ਸ਼ਾਮਲ ਕਰੋ"
"ਨਵੀਆਂ ਐਪਾਂ ਲਈ"
"ਆਈਕਨ ਦੀ ਆਕ੍ਰਿਤੀ ਬਦਲੋ"
@@ -95,7 +98,7 @@
"ਇਸ ਆਈਕਨ ਲਈ ਐਪ ਇੰਸਟੌਲ ਨਹੀਂ ਕੀਤਾ ਹੋਇਆ ਹੈ। ਤੁਸੀਂ ਇਸਨੂੰ ਹਟਾ ਸਕਦੇ ਹੋ ਜਾਂ ਐਪ ਖੋਜ ਸਕਦੇ ਹੋ ਅਤੇ ਇਸਨੂੰ ਮੈਨੂਅਲੀ ਇੰਸਟੌਲ ਕਰ ਸਕਦੇ ਹੋ।"
"%1$s ਡਾਉਨਲੋਡ ਹੋਰ ਰਿਹਾ ਹੈ, %2$s ਸੰਪੂਰਣ"
"%1$s ਸਥਾਪਿਤ ਕਰਨ ਦੀ ਉਡੀਕ ਕਰ ਰਿਹਾ ਹੈ"
- "%1$s ਵਿਜਿਟ"
+ "%1$s ਵਿਜੇਟ"
"ਹੋਮ ਸਕ੍ਰੀਨ ਵਿੱਚ ਜੋੜੋ"
"ਆਈਟਮ ਨੂੰ ਇੱਥੇ ਮੂਵ ਕਰੋ"
"ਆਈਟਮ ਨੂੰ ਮੁੱਖ ਸਕ੍ਰੀਨ ਵਿੱਚ ਜੋੜਿਆ ਗਿਆ"
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index aed8f18e00..923f3573b3 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -28,9 +28,9 @@
"Виджеты отключены в безопасном режиме"
"Ярлык недоступен"
"Главный экран"
- "Пользовательские действия"
+ "Специальные действия"
"Чтобы выбрать виджет, нажмите на значок и удерживайте его."
- "Чтобы выбрать виджет, нажмите на него дважды и не отпускайте или выполните предложенные действия."
+ "Чтобы выбрать виджет или использовать специальные действия, нажмите на него дважды и не отпускайте."
"%1$d x %2$d"
"Ширина %1$d, высота %2$d"
"Нажмите и удерживайте, чтобы добавить вручную"
@@ -90,7 +90,7 @@
"Квадрат с закругленными краями"
"Круг"
"Капля"
- "Применение изменений..."
+ "Применение изменений…"
"Неизвестно"
"Удалить"
"Найти"
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 3b0425e33b..f6c42b2d9a 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -35,9 +35,9 @@
"පළල %1$d උස %2$d"
"අතින් ස්ථානගත කිරීමට ස්පර්ශ කර අල්ලාගෙන සිටින්න"
"ස්වයංක්රියව එක් කරන්න"
- "යෙදුම් සෙවීම"
- "යෙදුම් පූරණය වෙමින්…"
- "\"%1$s\" සමග ගැළපෙන යෙදුම් හමු නොවිණි"
+ "යෙදුම් සොයන්න"
+ "යෙදුම් පූරණය වෙමින්…"
+ "\"%1$s\" සමග ගැළපෙන යෙදුම් හමු නොවිණි"
"තව යෙදුම් සඳහා සොයන්න"
"දැනුම්දීම්"
"මෙම මුල් පිටු තිරය මත තවත් අවසර නැත."
@@ -79,17 +79,18 @@
"දැනුම්දීම් තිත්"
"ක්රියාත්මකයි"
"ක්රියාවිරහිතයි"
+ "දැනුම්දීම් ප්රවේශය අවශ්යයි"
+ "දැනුම්දීම් තිත් පෙන්වීමට, %1$s සඳහා යෙදුම් දැනුම්දීම් සබල කරන්න"
+ "සැකසීම් වෙනස් කරන්න"
"මුල් පිටු තිරය වෙත අයිකනය එක් කරන්න"
"නව යෙදුම් සඳහා"
-
-
+ "නිරූපක හැඩය වෙනස් කරන්න"
"පද්ධති පෙරනිමි භාවිත කරන්න"
"සමචතුරස්රය"
"හතරැස් කවය"
"කවය"
"කඳුළු බිංදුව"
-
-
+ "නිරූපක හැඩය වෙනස් කිරීම් යොදමින්"
"නොදනී"
"ඉවත් කරන්න"
"සොයන්න"
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 490f823fe2..4dbc407b9c 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -58,7 +58,7 @@
"Nastavenie"
"Toto je systémová aplikácia a nedá sa odinštalovať."
"Nepomenovaný priečinok"
- "Aplikácia %1$s je zakázaná"
+ "Aplikácia %1$s je deaktivovaná"
"Stránka %1$d z %2$d"
"Plocha %1$d z %2$d"
"Nová stránka plochy"
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 1400557c0c..3e6afee609 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -35,9 +35,9 @@
"%1$d i gjerë me %2$d i lartë"
"Prek dhe mbaj të shtypur për të vendosur në mënyrë manuale"
"Shto automatikisht"
- "Kërko për aplikacione"
- "Po ngarkon aplikacionet..."
- "Nuk u gjet asnjë aplikacion që përputhet me \"%1$s\""
+ "Kërko për aplikacione"
+ "Po ngarkon aplikacionet..."
+ "Nuk u gjet asnjë aplikacion që përputhet me \"%1$s\""
"Kërko për më shumë aplikacione"
"Njoftimet"
"Nuk ka më hapësirë në këtë ekran bazë."
@@ -79,17 +79,18 @@
"Pikat e njoftimeve"
"Aktiv"
"Joaktiv"
+ "Nevojitet qasja në njoftime"
+ "Për të shfaqur \"Pikat e njoftimeve\", aktivizo njoftimet e aplikacionit për %1$s"
+ "Ndrysho cilësimet"
"Shto ikonë në ekranin bazë"
"Për aplikacionet e reja"
-
-
+ "Ndrysho formën e ikonës"
"Përdor parazgjedhjen e sisteit"
"Katror"
"Katror me kënde të rrumbullakëta"
"Rreth"
"Pikë loti"
-
-
+ "Po zbatohen ndryshimet e formës së ikonës"
"I panjohur"
"Hiq"
"Kërko"
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index be8e82df6c..1d92581a05 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -35,9 +35,9 @@
"%1$d அகலத்திற்கு %2$d உயரம்"
"நீங்களே சேர்க்க, தொட்டுப் பிடித்திருக்கவும்"
"தானாகவே சேர்"
- "பயன்பாடுகளில் தேடுக"
- "பயன்பாடுகளை ஏற்றுகிறது..."
- "\"%1$s\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை"
+ "பயன்பாடுகளில் தேடுக"
+ "பயன்பாடுகளை ஏற்றுகிறது…"
+ "\"%1$s\" உடன் பொருந்தும் பயன்பாடுகள் இல்லை"
"கூடுதல் பயன்பாடுகளைத் தேடு"
"அறிவிப்புகள்"
"முகப்புத் திரையில் இடமில்லை."
@@ -79,17 +79,18 @@
"அறிவிப்புப் புள்ளிகள்"
"இயக்கப்பட்டுள்ளது"
"முடக்கப்பட்டுள்ளது"
+ "அறிவிப்பிற்கான அணுகல் தேவை"
+ "அறிவிப்புப் புள்ளிகளைக் காட்ட, %1$s இன் பயன்பாட்டு அறிவிப்புகளை இயக்கவும்"
+ "அமைப்புகளை மாற்று"
"முகப்புத் திரையில் ஐகானைச் சேர்"
"புதிய பயன்பாடுகளுக்கு"
-
-
+ "ஐகான் வடிவத்தை மாற்று"
"அமைப்பின் இயல்புநிலையைப் பயன்படுத்து"
"சதுரம்"
"சதுரவட்டம்"
"வட்டம்"
"கண்ணீர்துளி"
-
-
+ "ஐகான் வடிவத்தை மாற்றுகிறது"
"தெரியாதது"
"அகற்று"
"தேடு"
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 15f3de7dab..6c6669938b 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -22,9 +22,9 @@
"Launcher3"
"కార్యాలయం"
- "అనువర్తనం ఇన్స్టాల్ చేయబడలేదు."
- "అనువర్తనం అందుబాటులో లేదు"
- "డౌన్లోడ్ చేసిన అనువర్తనం సురక్షిత మోడ్లో నిలిపివేయబడింది"
+ "యాప్ ఇన్స్టాల్ చేయబడలేదు."
+ "యాప్ అందుబాటులో లేదు"
+ "డౌన్లోడ్ చేసిన యాప్ సురక్షిత మోడ్లో నిలిపివేయబడింది"
"సురక్షిత మోడ్లో విడ్జెట్లు నిలిపివేయబడ్డాయి"
"సత్వరమార్గం అందుబాటులో లేదు"
"హోమ్ స్క్రీన్"
@@ -35,9 +35,9 @@
"%1$d వెడల్పు X %2$d ఎత్తు"
"మాన్యువల్గా ఉంచడానికి నొక్కి & పట్టుకోండి"
"స్వయంచాలకంగా జోడించు"
- "అనువర్తనాలను శోధించండి"
- "అనువర్తనాలను లోడ్ చేస్తోంది…"
- "\"%1$s\"కి సరిపోలే అనువర్తనాలేవీ కనుగొనబడలేదు"
+ "అప్లికేషన్లను శోధించండి"
+ "అప్లికేషన్లను లోడ్ చేస్తోంది…"
+ "\"%1$s\"కి సరిపోలే అప్లికేషన్లేవీ కనుగొనబడలేదు"
"మరిన్ని అనువర్తనాల కోసం శోధించు"
"నోటిఫికేషన్లు"
"ఈ హోమ్ స్క్రీన్లో ఖాళీ లేదు."
@@ -56,7 +56,7 @@
"ఫోన్ కాల్లను చేసేందుకు %1$sకి అనుమతి లేదు"
"విడ్జెట్ను లోడ్ చేయడంలో సమస్య"
"సెటప్ చేయి"
- "ఇది సిస్టమ్ అనువర్తనం మరియు దీన్ని అన్ఇన్స్టాల్ చేయడం సాధ్యపడదు."
+ "ఇది సిస్టమ్ యాప్ మరియు దీన్ని అన్ఇన్స్టాల్ చేయడం సాధ్యపడదు."
"పేరు లేని ఫోల్డర్"
"%1$s నిలిపివేయబడింది"
"%2$dలో %1$dవ పేజీ"
@@ -79,6 +79,9 @@
"నోటిఫికేషన్ డాట్లు"
"ఆన్"
"ఆఫ్"
+ "నోటిఫికేషన్ యాక్సెస్ అవసరం"
+ "నోటిఫికేషన్ డాట్లను చూపించడానికి %1$sకు యాప్ నోటిఫికేషన్లను ఆన్ చేయండి"
+ "సెట్టింగ్లను మార్చు"
"హోమ్ స్క్రీన్కి చిహ్నాన్ని జోడించు"
"కొత్త అనువర్తనాల కోసం"
"చిహ్న ఆకారాన్ని మార్చు"
@@ -91,8 +94,8 @@
"తెలియదు"
"తీసివేయి"
"శోధించు"
- "ఈ అనువర్తనం ఇన్స్టాల్ చేయబడలేదు"
- "ఈ చిహ్నం యొక్క అనువర్తనం ఇన్స్టాల్ చేయబడలేదు. మీరు దీన్ని తీసివేయవచ్చు లేదా ఆ అనువర్తనం కోసం శోధించి దాన్ని మాన్యువల్గా ఇన్స్టాల్ చేయవచ్చు."
+ "ఈ యాప్ ఇన్స్టాల్ చేయబడలేదు"
+ "ఈ చిహ్నం యొక్క యాప్ ఇన్స్టాల్ చేయబడలేదు. మీరు దీన్ని తీసివేయవచ్చు లేదా ఆ యాప్ కోసం శోధించి దాన్ని మాన్యువల్గా ఇన్స్టాల్ చేయవచ్చు."
"%1$s డౌన్లోడ్ అవుతోంది, %2$s పూర్తయింది"
"%1$s ఇన్స్టాల్ కావడానికి వేచి ఉంది"
"%1$s విడ్జెట్లు"
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 84966b2888..a704fab4ca 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -35,9 +35,9 @@
"%1$d چوڑا اور %2$d اونچا"
"دستی طور پر رکھنے کیلئے & ٹچ کرکے ہولڈ کریں"
"خود کار طور پر شامل کریں"
- "ایپس تلاش کریں"
- "ایپس لوڈ ہو رہی ہیں…"
- "\"%1$s\" سے مماثل کوئی ایپس نہیں ملیں"
+ "ایپس تلاش کریں"
+ "ایپس لوڈ کی جا رہی ہیں…"
+ "\"%1$s\" سے مماثل کوئی ایپس نہیں ملیں"
"مزید ایپس تلاش کریں"
"اطلاعات"
"اس ہوم اسکرین پر مزید کوئی گنجائش نہیں ہے۔"
@@ -79,6 +79,9 @@
"اطلاعاتی ڈاٹس"
"آن"
"آف"
+ "اطلاعاتی رسائی درکار ہے"
+ "اطلاعاتی ڈاٹس دکھانے کی خاطر %1$s کیلئے ایپ کی اطلاعات آن کریں"
+ "ترتیبات تبدیل کریں"
"آئیکن کو ہوم اسکرین میں شامل کریں"
"نئی ایپس کیلئے"
"آئیکن کی شکل تبدیل کریں"
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index a4725db53c..7e31889138 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -35,9 +35,9 @@
"Eni %1$d, bo‘yi %2$d"
"Qo‘lda joylashtirish uchun bosib turing"
"Avtomatik chiqarish"
- "Ilovalar ichidan qidirish"
- "Ilovalar yuklanmoqda…"
- "“%1$s” so‘rovi bo‘yicha hech narsa topilmadi"
+ "Ilovalarni qidirish"
+ "Ilovalar yuklanmoqda…"
+ "“%1$s” bilan mos hech qanday ilova topilmadi"
"Boshqa ilovalarni qidirish"
"Bildirishnomalar"
"Uy ekranida bitta ham xona yo‘q."
@@ -79,17 +79,18 @@
"Bildirishnoma nuqtalari"
"Yoniq"
"O‘chiq"
+ "Bildirishnomalarga ruxsat berilmagan"
+ "Bildirishnoma nuqtalarini ko‘rsatish uchun %1$s ilovasida bildirishnomalarni yoqing"
+ "Sozlamalarni o‘zgartirish"
"Bosh ekranga ikonka qo‘shish"
"Yangi o‘rnatilgan ilovalar ikonkasini bosh ekranga chiqarish"
-
-
+ "Ikonka shaklini o‘zgartirish"
"Standart tizim parametrlaridan foydalanish"
"Kvadrat"
"Qirralari aylana kvadrat"
"Aylana"
"Tomchi"
-
-
+ "Ikonka shakli o‘zgartirilmoqda"
"Noma’lum"
"O‘chirish"
"Qidirish"
diff --git a/res/values/config.xml b/res/values/config.xml
index e9c62a783d..e7ec0a0b1c 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -9,6 +9,8 @@
false
false
+ 191
+
@string/app_name
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 28af705967..3f6efd794d 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -19,7 +19,8 @@
8dp
32dp
1dp
- 50dp
+ 0dp
+ 0dp
8dp
80dp
120dp
@@ -31,16 +32,21 @@
8dp
5.5dp
+ 0dp
8dp
8dp
2dp
- 80dp
+ 80dp
+
0dp
0dp
0dp
0dp
+ 0dp
+ 0dp
+
48dp
diff --git a/src/com/android/launcher3/BaseContainerView.java b/src/com/android/launcher3/BaseContainerView.java
index c55a5860ef..82175b721d 100644
--- a/src/com/android/launcher3/BaseContainerView.java
+++ b/src/com/android/launcher3/BaseContainerView.java
@@ -62,7 +62,7 @@ public abstract class BaseContainerView extends FrameLayout
public BaseContainerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && this instanceof AllAppsContainerView) {
+ if (this instanceof AllAppsContainerView) {
mBaseDrawable = new ColorDrawable();
} else {
TypedArray a = context.obtainStyledAttributes(attrs,
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index aeb82b376a..a63767c5d3 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -592,6 +592,9 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver {
mIconLoadRequest = null;
mDisableRelayout = true;
+ // Optimization: Starting in N, pre-uploads the bitmap to RenderThread.
+ info.iconBitmap.prepareToDraw();
+
if (info instanceof AppInfo) {
applyFromApplicationInfo((AppInfo) info);
} else if (info instanceof ShortcutInfo) {
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java
index aac80052e4..3ebccda9e7 100644
--- a/src/com/android/launcher3/CellLayout.java
+++ b/src/com/android/launcher3/CellLayout.java
@@ -780,7 +780,7 @@ public class CellLayout extends ViewGroup implements BubbleTextShadowHandler {
return mCellWidth;
}
- int getCellHeight() {
+ public int getCellHeight() {
return mCellHeight;
}
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 031bfe115b..150bc5309d 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -63,7 +63,7 @@ public class DeviceProfile {
*/
private static final float MAX_HORIZONTAL_PADDING_PERCENT = 0.14f;
- private static final float TALL_DEVICE_ASPECT_RATIO_THRESHOLD = 1.82f;
+ private static final float TALL_DEVICE_ASPECT_RATIO_THRESHOLD = 2.0f;
// Overview mode
private final int overviewModeMinIconZoneHeightPx;
@@ -75,6 +75,7 @@ public class DeviceProfile {
// Workspace
private final int desiredWorkspaceLeftRightMarginPx;
public final int cellLayoutPaddingLeftRightPx;
+ public final int cellLayoutBottomPaddingPx;
public final int edgeMarginPx;
public final Rect defaultWidgetPadding;
private final int defaultPageSpacingPx;
@@ -84,7 +85,8 @@ public class DeviceProfile {
// Page indicator
private int pageIndicatorSizePx;
- private final int pageIndicatorLandGutterPx;
+ private final int pageIndicatorLandLeftNavBarGutterPx;
+ private final int pageIndicatorLandRightNavBarGutterPx;
private final int pageIndicatorLandWorkspaceOffsetPx;
// Workspace icons
@@ -113,13 +115,16 @@ public class DeviceProfile {
// Hotseat
public int hotseatCellHeightPx;
- public int hotseatBarHeightPx;
+ // In portrait: size = height, in landscape: size = width
+ public int hotseatBarSizePx;
public int hotseatBarTopPaddingPx;
- public int hotseatBarLeftNavBarRightPaddingPx;
- public int hotseatBarRightNavBarRightPaddingPx;
public int hotseatBarBottomPaddingPx;
- public int hotseatLandLeftNavBarGutterPx;
- public int hotseatLandRightNavBarGutterPx;
+
+ public int hotseatBarLeftNavBarLeftPaddingPx;
+ public int hotseatBarLeftNavBarRightPaddingPx;
+
+ public int hotseatBarRightNavBarLeftPaddingPx;
+ public int hotseatBarRightNavBarRightPaddingPx;
// All apps
public int allAppsCellHeightPx;
@@ -177,10 +182,14 @@ public class DeviceProfile {
desiredWorkspaceLeftRightMarginPx = isVerticalBarLayout() ? 0 : edgeMarginPx;
cellLayoutPaddingLeftRightPx =
res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_padding);
+ cellLayoutBottomPaddingPx =
+ res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_layout_bottom_padding);
pageIndicatorSizePx = res.getDimensionPixelSize(
R.dimen.dynamic_grid_min_page_indicator_size);
- pageIndicatorLandGutterPx = res.getDimensionPixelSize(
- R.dimen.dynamic_grid_page_indicator_gutter_width);
+ pageIndicatorLandLeftNavBarGutterPx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_page_indicator_land_left_nav_bar_gutter_width);
+ pageIndicatorLandRightNavBarGutterPx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_page_indicator_land_right_nav_bar_gutter_width);
pageIndicatorLandWorkspaceOffsetPx =
res.getDimensionPixelSize(R.dimen.all_apps_caret_workspace_offset);
defaultPageSpacingPx =
@@ -213,16 +222,15 @@ public class DeviceProfile {
R.dimen.dynamic_grid_hotseat_land_left_nav_bar_right_padding);
hotseatBarRightNavBarRightPaddingPx = res.getDimensionPixelSize(
R.dimen.dynamic_grid_hotseat_land_right_nav_bar_right_padding);
- hotseatBarHeightPx = isVerticalBarLayout()
- ? res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_height)
- : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_height)
+ hotseatBarLeftNavBarLeftPaddingPx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_hotseat_land_left_nav_bar_left_padding);
+ hotseatBarRightNavBarLeftPaddingPx = res.getDimensionPixelSize(
+ R.dimen.dynamic_grid_hotseat_land_right_nav_bar_left_padding);
+ hotseatBarSizePx = isVerticalBarLayout()
+ ? Utilities.pxFromDp(inv.iconSize, dm)
+ : res.getDimensionPixelSize(R.dimen.dynamic_grid_hotseat_size)
+ hotseatBarTopPaddingPx + hotseatBarBottomPaddingPx;
- hotseatLandLeftNavBarGutterPx = res.getDimensionPixelSize(
- R.dimen.dynamic_grid_hotseat_land_left_nav_bar_gutter_width);
- hotseatLandRightNavBarGutterPx = res.getDimensionPixelSize(
- R.dimen.dynamic_grid_hotseat_land_right_nav_bar_gutter_width);
-
// Determine sizes.
widthPx = width;
heightPx = height;
@@ -238,17 +246,17 @@ public class DeviceProfile {
updateAvailableDimensions(dm, res);
// Now that we have all of the variables calculated, we can tune certain sizes.
- float aspectRatio = ((float) Math.max(availableWidthPx, availableHeightPx))
- / Math.min(availableWidthPx, availableHeightPx);
+ float aspectRatio = ((float) Math.max(widthPx, heightPx)) / Math.min(widthPx, heightPx);
boolean isTallDevice = Float.compare(aspectRatio, TALL_DEVICE_ASPECT_RATIO_THRESHOLD) >= 0;
if (!isVerticalBarLayout() && isPhone && isTallDevice) {
- // We increase the page indicator size when there is extra space.
+ // We increase the hotseat size when there is extra space.
// ie. For a display with a large aspect ratio, we can keep the icons on the workspace
- // in portrait mode closer together by increasing the page indicator size.
+ // in portrait mode closer together by adding more height to the hotseat.
// Note: This calculation was created after noticing a pattern in the design spec.
- pageIndicatorSizePx = getCellSize().y - iconSizePx - iconDrawablePaddingPx;
+ int extraSpace = getCellSize().y - iconSizePx - iconDrawablePaddingPx;
+ hotseatBarSizePx += extraSpace - pageIndicatorSizePx;
- // Recalculate the available dimensions using the new page indicator size.
+ // Recalculate the available dimensions using the new hotseat size.
updateAvailableDimensions(dm, res);
}
@@ -301,10 +309,10 @@ public class DeviceProfile {
// In normal cases, All Apps cell height should equal the Workspace cell height.
// Since we are removing labels from the Workspace, we need to manually compute the
// All Apps cell height.
+ int topBottomPadding = allAppsIconDrawablePaddingPx * (isVerticalBarLayout() ? 2 : 1);
allAppsCellHeightPx = allAppsIconSizePx + allAppsIconDrawablePaddingPx
+ Utilities.calculateTextHeight(allAppsIconTextSizePx)
- // Top and bottom padding is equal to the drawable padding
- + allAppsIconDrawablePaddingPx * 2;
+ + topBottomPadding * 2;
}
/**
@@ -332,11 +340,16 @@ public class DeviceProfile {
}
private void updateIconSize(float scale, Resources res, DisplayMetrics dm) {
+ // Workspace
float invIconSizePx = isVerticalBarLayout() ? inv.landscapeIconSize : inv.iconSize;
iconSizePx = (int) (Utilities.pxFromDp(invIconSizePx, dm) * scale);
iconTextSizePx = (int) (Utilities.pxFromSp(inv.iconTextSize, dm) * scale);
iconDrawablePaddingPx = (int) (iconDrawablePaddingOriginalPx * scale);
+ cellWidthPx = iconSizePx + iconDrawablePaddingPx;
+ cellHeightPx = iconSizePx + iconDrawablePaddingPx
+ + Utilities.calculateTextHeight(iconTextSizePx);
+
// All apps
allAppsIconTextSizePx = iconTextSizePx;
allAppsIconSizePx = iconSizePx;
@@ -348,15 +361,14 @@ public class DeviceProfile {
adjustToHideWorkspaceLabels();
}
- cellWidthPx = iconSizePx + iconDrawablePaddingPx;
- cellHeightPx = iconSizePx + iconDrawablePaddingPx
- + Utilities.calculateTextHeight(iconTextSizePx);
-
// Hotseat
- hotseatCellHeightPx = iconSizePx + iconDrawablePaddingPx;
+ if (isVerticalBarLayout()) {
+ hotseatBarSizePx = iconSizePx;
+ }
+ hotseatCellHeightPx = iconSizePx;
if (!isVerticalBarLayout()) {
- int expectedWorkspaceHeight = availableHeightPx - hotseatBarHeightPx
+ int expectedWorkspaceHeight = availableHeightPx - hotseatBarSizePx
- pageIndicatorSizePx - topWorkspacePadding;
float minRequiredHeight = dropTargetBarSizePx + workspaceSpringLoadedBottomSpace;
workspaceSpringLoadShrinkFactor = Math.min(
@@ -449,9 +461,10 @@ public class DeviceProfile {
// Since we are only concerned with the overall padding, layout direction does
// not matter.
Point padding = getTotalWorkspacePadding();
- int cellPadding = cellLayoutPaddingLeftRightPx * 2;
- result.x = calculateCellWidth(availableWidthPx - padding.x - cellPadding, inv.numColumns);
- result.y = calculateCellHeight(availableHeightPx - padding.y, inv.numRows);
+ result.x = calculateCellWidth(availableWidthPx - padding.x
+ - cellLayoutPaddingLeftRightPx * 2, inv.numColumns);
+ result.y = calculateCellHeight(availableHeightPx - padding.y
+ - cellLayoutBottomPaddingPx, inv.numRows);
return result;
}
@@ -467,20 +480,21 @@ public class DeviceProfile {
Rect padding = recycle == null ? new Rect() : recycle;
if (isVerticalBarLayout()) {
if (mInsets.left > 0) {
- padding.set(mInsets.left + pageIndicatorLandGutterPx,
+ padding.set(mInsets.left + pageIndicatorLandLeftNavBarGutterPx,
0,
- hotseatBarHeightPx + hotseatLandLeftNavBarGutterPx
- + hotseatBarLeftNavBarRightPaddingPx - mInsets.left,
+ hotseatBarSizePx + hotseatBarLeftNavBarRightPaddingPx
+ + hotseatBarLeftNavBarLeftPaddingPx
+ - mInsets.left,
edgeMarginPx);
} else {
- padding.set(pageIndicatorLandGutterPx,
+ padding.set(pageIndicatorLandRightNavBarGutterPx,
0,
- hotseatBarHeightPx + hotseatLandRightNavBarGutterPx
- + hotseatBarRightNavBarRightPaddingPx,
+ hotseatBarSizePx + hotseatBarRightNavBarRightPaddingPx
+ + hotseatBarRightNavBarLeftPaddingPx,
edgeMarginPx);
}
} else {
- int paddingBottom = hotseatBarHeightPx + pageIndicatorSizePx;
+ int paddingBottom = hotseatBarSizePx + pageIndicatorSizePx;
if (isTablet) {
// Pad the left and right of the workspace to ensure consistent spacing
// between all icons
@@ -515,14 +529,14 @@ public class DeviceProfile {
// Folders should only appear right of the drop target bar and left of the hotseat
return new Rect(mInsets.left + dropTargetBarSizePx + edgeMarginPx,
mInsets.top,
- mInsets.left + availableWidthPx - hotseatBarHeightPx - edgeMarginPx,
+ mInsets.left + availableWidthPx - hotseatBarSizePx - edgeMarginPx,
mInsets.top + availableHeightPx);
} else {
// Folders should only appear below the drop target bar and above the hotseat
return new Rect(mInsets.left,
mInsets.top + dropTargetBarSizePx + edgeMarginPx,
mInsets.left + availableWidthPx,
- mInsets.top + availableHeightPx - hotseatBarHeightPx
+ mInsets.top + availableHeightPx - hotseatBarSizePx
- pageIndicatorSizePx - edgeMarginPx);
}
}
@@ -609,38 +623,44 @@ public class DeviceProfile {
if (hasVerticalBarLayout) {
// Vertical hotseat -- The hotseat is fixed in the layout to be on the right of the
// screen regardless of RTL
- lp.gravity = Gravity.RIGHT;
- lp.width = hotseatBarHeightPx + mInsets.left + mInsets.right;
- lp.height = LayoutParams.MATCH_PARENT;
-
int paddingRight = mInsets.left > 0
? hotseatBarLeftNavBarRightPaddingPx
: hotseatBarRightNavBarRightPaddingPx;
+ int paddingLeft = mInsets.left > 0
+ ? hotseatBarLeftNavBarLeftPaddingPx
+ : hotseatBarRightNavBarLeftPaddingPx;
- hotseat.getLayout().setPadding(mInsets.left + cellLayoutPaddingLeftRightPx,
- mInsets.top, mInsets.right + paddingRight + cellLayoutPaddingLeftRightPx,
- workspacePadding.bottom);
+ lp.gravity = Gravity.RIGHT;
+ lp.width = hotseatBarSizePx + mInsets.left + mInsets.right
+ + paddingLeft + paddingRight;
+ lp.height = LayoutParams.MATCH_PARENT;
+
+ hotseat.getLayout().setPadding(mInsets.left + cellLayoutPaddingLeftRightPx
+ + paddingLeft,
+ mInsets.top,
+ mInsets.right + cellLayoutPaddingLeftRightPx + paddingRight,
+ workspacePadding.bottom + cellLayoutBottomPaddingPx);
} else if (isTablet) {
// Pad the hotseat with the workspace padding calculated above
lp.gravity = Gravity.BOTTOM;
lp.width = LayoutParams.MATCH_PARENT;
- lp.height = hotseatBarHeightPx + mInsets.bottom;
+ lp.height = hotseatBarSizePx + mInsets.bottom;
hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left
+ cellLayoutPaddingLeftRightPx,
hotseatBarTopPaddingPx,
hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx,
- hotseatBarBottomPaddingPx + mInsets.bottom);
+ hotseatBarBottomPaddingPx + mInsets.bottom + cellLayoutBottomPaddingPx);
} else {
// For phones, layout the hotseat without any bottom margin
// to ensure that we have space for the folders
lp.gravity = Gravity.BOTTOM;
lp.width = LayoutParams.MATCH_PARENT;
- lp.height = hotseatBarHeightPx + mInsets.bottom;
+ lp.height = hotseatBarSizePx + mInsets.bottom;
hotseat.getLayout().setPadding(hotseatAdjustment + workspacePadding.left
+ cellLayoutPaddingLeftRightPx,
hotseatBarTopPaddingPx,
hotseatAdjustment + workspacePadding.right + cellLayoutPaddingLeftRightPx,
- hotseatBarBottomPaddingPx + mInsets.bottom);
+ hotseatBarBottomPaddingPx + mInsets.bottom + cellLayoutBottomPaddingPx);
}
hotseat.setLayoutParams(lp);
@@ -659,7 +679,7 @@ public class DeviceProfile {
// Put the page indicators above the hotseat
lp.gravity = Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM;
lp.height = pageIndicatorSizePx;
- lp.bottomMargin = hotseatBarHeightPx + mInsets.bottom;
+ lp.bottomMargin = hotseatBarSizePx + mInsets.bottom;
}
pageIndicator.setLayoutParams(lp);
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 4b3148626a..8492a7985c 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -119,6 +119,7 @@ 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.util.ActivityResultInfo;
+import com.android.launcher3.util.RunnableWithId;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.MultiHashMap;
@@ -144,6 +145,10 @@ import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.concurrent.Executor;
+
+import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_APPS;
+import static com.android.launcher3.util.RunnableWithId.RUNNABLE_ID_BIND_WIDGETS;
/**
* Default launcher application.
@@ -245,7 +250,6 @@ public class Launcher extends BaseActivity
// Main container view and the model for the widget tray screen.
@Thunk WidgetsContainerView mWidgetsView;
- @Thunk MultiHashMap mAllWidgets;
// We set the state in both onCreate and then onNewIntent in some cases, which causes both
// scroll issues (because the workspace may not have been measured yet) and extra work.
@@ -465,9 +469,6 @@ public class Launcher extends BaseActivity
setOrientation();
setContentView(mLauncherView);
- if (mLauncherCallbacks != null) {
- mLauncherCallbacks.onCreate(savedInstanceState);
- }
// Listen for broadcasts
IntentFilter filter = new IntentFilter();
@@ -478,6 +479,10 @@ public class Launcher extends BaseActivity
getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
+
+ if (mLauncherCallbacks != null) {
+ mLauncherCallbacks.onCreate(savedInstanceState);
+ }
}
@Override
@@ -959,6 +964,9 @@ public class Launcher extends BaseActivity
} else if (mOnResumeState == State.WIDGETS) {
showWidgetsView(false, false);
}
+ if (mOnResumeState != State.APPS) {
+ tryAndUpdatePredictedApps();
+ }
mOnResumeState = State.NONE;
mPaused = false;
@@ -1302,9 +1310,7 @@ public class Launcher extends BaseActivity
mDragController.addDropTarget(mWorkspace);
mDropTargetBar.setup(mDragController);
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
- mAllAppsController.setupViews(mAppsView, mHotseat, mWorkspace);
- }
+ mAllAppsController.setupViews(mAppsView, mHotseat, mWorkspace);
if (TestingUtils.MEMORY_DUMP_ENABLED) {
TestingUtils.addWeightWatcher(this);
@@ -1851,6 +1857,8 @@ public class Launcher extends BaseActivity
LauncherAnimUtils.onDestroyActivity();
+ clearPendingBinds();
+
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onDestroy();
}
@@ -2270,7 +2278,7 @@ public class Launcher extends BaseActivity
if (v instanceof FolderIcon) {
onClickFolderIcon(v);
}
- } else if ((FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && v instanceof PageIndicator) ||
+ } else if ((v instanceof PageIndicator) ||
(v == mAllAppsButton && mAllAppsButton != null)) {
onClickAllAppsButton(v);
} else if (tag instanceof AppInfo) {
@@ -3106,12 +3114,12 @@ public class Launcher extends BaseActivity
*
* @return {@code true} if we are currently paused. The caller might be able to skip some work
*/
- @Thunk boolean waitUntilResume(Runnable run, boolean deletePreviousRunnables) {
+ @Thunk boolean waitUntilResume(Runnable run) {
if (mPaused) {
if (LOGD) Log.d(TAG, "Deferring update until onResume");
- if (deletePreviousRunnables) {
- while (mBindOnResumeCallbacks.remove(run)) {
- }
+ if (run instanceof RunnableWithId) {
+ // Remove any runnables which have the same id
+ while (mBindOnResumeCallbacks.remove(run)) { }
}
mBindOnResumeCallbacks.add(run);
return true;
@@ -3120,10 +3128,6 @@ public class Launcher extends BaseActivity
}
}
- private boolean waitUntilResume(Runnable run) {
- return waitUntilResume(run, false);
- }
-
public void addOnResumeCallback(Runnable run) {
mOnResumeCallbacks.add(run);
}
@@ -3242,13 +3246,13 @@ public class Launcher extends BaseActivity
}
}
+ @Override
public void bindAppsAdded(final ArrayList newScreens,
final ArrayList addNotAnimated,
- final ArrayList addAnimated,
- final ArrayList addedApps) {
+ final ArrayList addAnimated) {
Runnable r = new Runnable() {
public void run() {
- bindAppsAdded(newScreens, addNotAnimated, addAnimated, addedApps);
+ bindAppsAdded(newScreens, addNotAnimated, addAnimated);
}
};
if (waitUntilResume(r)) {
@@ -3263,20 +3267,14 @@ public class Launcher extends BaseActivity
// We add the items without animation on non-visible pages, and with
// animations on the new page (which we will try and snap to).
if (addNotAnimated != null && !addNotAnimated.isEmpty()) {
- bindItems(addNotAnimated, 0,
- addNotAnimated.size(), false);
+ bindItems(addNotAnimated, false);
}
if (addAnimated != null && !addAnimated.isEmpty()) {
- bindItems(addAnimated, 0,
- addAnimated.size(), true);
+ bindItems(addAnimated, true);
}
// Remove the extra empty screen
mWorkspace.removeExtraEmptyScreen(false, false);
-
- if (addedApps != null && mAppsView != null) {
- mAppsView.addApps(addedApps);
- }
}
/**
@@ -3285,11 +3283,10 @@ public class Launcher extends BaseActivity
* Implementation of the method from LauncherModel.Callbacks.
*/
@Override
- public void bindItems(final ArrayList items, final int start, final int end,
- final boolean forceAnimateIcons) {
+ public void bindItems(final List items, final boolean forceAnimateIcons) {
Runnable r = new Runnable() {
public void run() {
- bindItems(items, start, end, forceAnimateIcons);
+ bindItems(items, forceAnimateIcons);
}
};
if (waitUntilResume(r)) {
@@ -3302,7 +3299,8 @@ public class Launcher extends BaseActivity
final boolean animateIcons = forceAnimateIcons && canRunNewAppsAnimation();
Workspace workspace = mWorkspace;
long newItemsScreenId = -1;
- for (int i = start; i < end; i++) {
+ int end = items.size();
+ for (int i = 0; i < end; i++) {
final ItemInfo item = items.get(i);
// Short circuit if we are loading dock items for a configuration which has no dock
@@ -3327,19 +3325,10 @@ public class Launcher extends BaseActivity
break;
}
case LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET: {
- LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) item;
- if (mIsSafeModeEnabled) {
- view = new PendingAppWidgetHostView(this, info, mIconCache, true);
- } else {
- LauncherAppWidgetProviderInfo providerInfo =
- mAppWidgetManager.getLauncherAppWidgetInfo(info.appWidgetId);
- if (providerInfo == null) {
- deleteWidgetInfo(info);
- continue;
- }
- view = mAppWidgetHost.createView(this, info.appWidgetId, providerInfo);
+ view = inflateAppWidget((LauncherAppWidgetInfo) item);
+ if (view == null) {
+ continue;
}
- prepareAppWidget((AppWidgetHostView) view, info);
break;
}
default:
@@ -3409,26 +3398,21 @@ public class Launcher extends BaseActivity
/**
* Add the views for a widget to the workspace.
- *
- * Implementation of the method from LauncherModel.Callbacks.
*/
- public void bindAppWidget(final LauncherAppWidgetInfo item) {
- Runnable r = new Runnable() {
- public void run() {
- bindAppWidget(item);
- }
- };
- if (waitUntilResume(r)) {
- return;
+ public void bindAppWidget(LauncherAppWidgetInfo item) {
+ View view = inflateAppWidget(item);
+ if (view != null) {
+ mWorkspace.addInScreen(view, item);
+ mWorkspace.requestLayout();
}
+ }
+ private View inflateAppWidget(LauncherAppWidgetInfo item) {
if (mIsSafeModeEnabled) {
PendingAppWidgetHostView view =
new PendingAppWidgetHostView(this, item, mIconCache, true);
prepareAppWidget(view, item);
- mWorkspace.addInScreen(view, item);
- mWorkspace.requestLayout();
- return;
+ return view;
}
final long start = DEBUG_WIDGETS ? SystemClock.uptimeMillis() : 0;
@@ -3458,7 +3442,7 @@ public class Launcher extends BaseActivity
+ ", as the provider is null");
}
getModelWriter().deleteItemFromDatabase(item);
- return;
+ return null;
}
// If we do not have a valid id, try to bind an id.
@@ -3526,7 +3510,7 @@ public class Launcher extends BaseActivity
if (appWidgetInfo == null) {
FileLog.e(TAG, "Removing invalid widget: id=" + item.appWidgetId);
deleteWidgetInfo(item);
- return;
+ return null;
}
item.minSpanX = appWidgetInfo.minSpanX;
@@ -3536,13 +3520,12 @@ public class Launcher extends BaseActivity
view = new PendingAppWidgetHostView(this, item, mIconCache, false);
}
prepareAppWidget(view, item);
- mWorkspace.addInScreen(view, item);
- mWorkspace.requestLayout();
if (DEBUG_WIDGETS) {
Log.d(TAG, "bound widget id="+item.appWidgetId+" in "
+ (SystemClock.uptimeMillis()-start) + "ms");
}
+ return view;
}
/**
@@ -3677,30 +3660,29 @@ public class Launcher extends BaseActivity
return LauncherCallbacks.SEARCH_BAR_HEIGHT_NORMAL;
}
- /**
- * A runnable that we can dequeue and re-enqueue when all applications are bound (to prevent
- * multiple calls to bind the same list.)
- */
- @Thunk ArrayList mTmpAppsList;
- private final Runnable mBindAllApplicationsRunnable = new Runnable() {
- public void run() {
- bindAllApplications(mTmpAppsList);
- mTmpAppsList = null;
- }
- };
-
/**
* Add the icons for all apps.
*
* Implementation of the method from LauncherModel.Callbacks.
*/
public void bindAllApplications(final ArrayList apps) {
- if (waitUntilResume(mBindAllApplicationsRunnable, true)) {
- mTmpAppsList = apps;
+ Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_APPS) {
+ public void run() {
+ bindAllApplications(apps);
+ }
+ };
+ if (waitUntilResume(r)) {
return;
}
if (mAppsView != null) {
+ Executor pendingExecutor = getPendingExecutor();
+ if (pendingExecutor != null && mState != State.APPS) {
+ // Wait until the fade in animation has finished before setting all apps list.
+ pendingExecutor.execute(r);
+ return;
+ }
+
mAppsView.setApps(apps);
}
if (mLauncherCallbacks != null) {
@@ -3708,6 +3690,14 @@ public class Launcher extends BaseActivity
}
}
+ /**
+ * Returns an Executor that will run after the launcher is first drawn (including after the
+ * initial fade in animation). Returns null if the first draw has already occurred.
+ */
+ public @Nullable Executor getPendingExecutor() {
+ return mPendingExecutor != null && mPendingExecutor.canQueue() ? mPendingExecutor : null;
+ }
+
/**
* Copies LauncherModel's map of activities to shortcut ids to Launcher's. This is necessary
* because LauncherModel's map is updated in the background, while Launcher runs on the UI.
@@ -3722,10 +3712,10 @@ public class Launcher extends BaseActivity
*
* Implementation of the method from LauncherModel.Callbacks.
*/
- public void bindAppsUpdated(final ArrayList apps) {
+ public void bindAppsAddedOrUpdated(final ArrayList apps) {
Runnable r = new Runnable() {
public void run() {
- bindAppsUpdated(apps);
+ bindAppsAddedOrUpdated(apps);
}
};
if (waitUntilResume(r)) {
@@ -3733,7 +3723,7 @@ public class Launcher extends BaseActivity
}
if (mAppsView != null) {
- mAppsView.updateApps(apps);
+ mAppsView.addOrUpdateApps(apps);
}
}
@@ -3771,16 +3761,12 @@ public class Launcher extends BaseActivity
* Implementation of the method from LauncherModel.Callbacks.
*
* @param updated list of shortcuts which have changed.
- * @param removed list of shortcuts which were deleted in the background. This can happen when
- * an app gets removed from the system or some of its components are no longer
- * available.
*/
@Override
- public void bindShortcutsChanged(final ArrayList updated,
- final ArrayList removed, final UserHandle user) {
+ public void bindShortcutsChanged(final ArrayList updated, final UserHandle user) {
Runnable r = new Runnable() {
public void run() {
- bindShortcutsChanged(updated, removed, user);
+ bindShortcutsChanged(updated, user);
}
};
if (waitUntilResume(r)) {
@@ -3790,31 +3776,6 @@ public class Launcher extends BaseActivity
if (!updated.isEmpty()) {
mWorkspace.updateShortcuts(updated);
}
-
- if (!removed.isEmpty()) {
- HashSet removedComponents = new HashSet<>();
- HashSet removedDeepShortcuts = new HashSet<>();
-
- for (ShortcutInfo si : removed) {
- if (si.itemType == Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
- removedDeepShortcuts.add(ShortcutKey.fromItemInfo(si));
- } else {
- removedComponents.add(si.getTargetComponent());
- }
- }
-
- if (!removedComponents.isEmpty()) {
- ItemInfoMatcher matcher = ItemInfoMatcher.ofComponents(removedComponents, user);
- mWorkspace.removeItemsByMatcher(matcher);
- mDragController.onAppsRemoved(matcher);
- }
-
- if (!removedDeepShortcuts.isEmpty()) {
- ItemInfoMatcher matcher = ItemInfoMatcher.ofShortcutKeys(removedDeepShortcuts);
- mWorkspace.removeItemsByMatcher(matcher);
- mDragController.onAppsRemoved(matcher);
- }
- }
}
/**
@@ -3844,28 +3805,17 @@ public class Launcher extends BaseActivity
* package-removal should clear all items by package name.
*/
@Override
- public void bindWorkspaceComponentsRemoved(
- final HashSet packageNames, final HashSet components,
- final UserHandle user) {
+ public void bindWorkspaceComponentsRemoved(final ItemInfoMatcher matcher) {
Runnable r = new Runnable() {
public void run() {
- bindWorkspaceComponentsRemoved(packageNames, components, user);
+ bindWorkspaceComponentsRemoved(matcher);
}
};
if (waitUntilResume(r)) {
return;
}
- if (!packageNames.isEmpty()) {
- ItemInfoMatcher matcher = ItemInfoMatcher.ofPackages(packageNames, user);
- mWorkspace.removeItemsByMatcher(matcher);
- mDragController.onAppsRemoved(matcher);
-
- }
- if (!components.isEmpty()) {
- ItemInfoMatcher matcher = ItemInfoMatcher.ofComponents(components, user);
- mWorkspace.removeItemsByMatcher(matcher);
- mDragController.onAppsRemoved(matcher);
- }
+ mWorkspace.removeItemsByMatcher(matcher);
+ mDragController.onAppsRemoved(matcher);
}
@Override
@@ -3886,22 +3836,25 @@ public class Launcher extends BaseActivity
}
}
- private final Runnable mBindAllWidgetsRunnable = new Runnable() {
+ @Override
+ public void bindAllWidgets(final MultiHashMap allWidgets) {
+ Runnable r = new RunnableWithId(RUNNABLE_ID_BIND_WIDGETS) {
+ @Override
public void run() {
- bindAllWidgets(mAllWidgets);
+ bindAllWidgets(allWidgets);
}
};
-
- @Override
- public void bindAllWidgets(MultiHashMap allWidgets) {
- if (waitUntilResume(mBindAllWidgetsRunnable, true)) {
- mAllWidgets = allWidgets;
+ if (waitUntilResume(r)) {
return;
}
if (mWidgetsView != null && allWidgets != null) {
+ Executor pendingExecutor = getPendingExecutor();
+ if (pendingExecutor != null && mState != State.WIDGETS) {
+ pendingExecutor.execute(r);
+ return;
+ }
mWidgetsView.setWidgets(allWidgets);
- mAllWidgets = null;
}
AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(this);
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index cf20febd5b..1ffe41bc6c 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -16,6 +16,7 @@
package com.android.launcher3;
+import android.content.ComponentName;
import android.content.ContentProviderClient;
import android.content.Context;
import android.content.Intent;
@@ -28,13 +29,17 @@ import com.android.launcher3.compat.PackageInstallerCompat;
import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dynamicui.ExtractionUtils;
+import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.util.ConfigMonitor;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SettingsObserver;
import com.android.launcher3.util.TestingUtils;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
+import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
+
public class LauncherAppState {
public static final boolean PROFILE_STARTUP = FeatureFlags.IS_DOGFOOD_BUILD;
@@ -47,7 +52,7 @@ public class LauncherAppState {
private final IconCache mIconCache;
private final WidgetPreviewLoader mWidgetCache;
private final InvariantDeviceProfile mInvariantDeviceProfile;
-
+ private final SettingsObserver mNotificationBadgingObserver;
public static LauncherAppState getInstance(final Context context) {
if (INSTANCE == null) {
@@ -117,6 +122,23 @@ public class LauncherAppState {
new ConfigMonitor(mContext).register();
ExtractionUtils.startColorExtractionServiceIfNecessary(mContext);
+
+ if (!mContext.getResources().getBoolean(R.bool.notification_badging_enabled)) {
+ mNotificationBadgingObserver = null;
+ } else {
+ // Register an observer to rebind the notification listener when badging is re-enabled.
+ mNotificationBadgingObserver = new SettingsObserver.Secure(
+ mContext.getContentResolver()) {
+ @Override
+ public void onSettingChanged(boolean isNotificationBadgingEnabled) {
+ if (isNotificationBadgingEnabled) {
+ NotificationListener.requestRebind(new ComponentName(
+ mContext, NotificationListener.class));
+ }
+ }
+ };
+ mNotificationBadgingObserver.register(NOTIFICATION_BADGING);
+ }
}
/**
@@ -127,6 +149,9 @@ public class LauncherAppState {
final LauncherAppsCompat launcherApps = LauncherAppsCompat.getInstance(mContext);
launcherApps.removeOnAppsChangedCallback(mModel);
PackageInstallerCompat.getInstance(mContext).onStop();
+ if (mNotificationBadgingObserver != null) {
+ mNotificationBadgingObserver.unregister();
+ }
}
LauncherModel setLauncher(Launcher launcher) {
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index f1638fda25..a906b00f1f 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -56,6 +56,7 @@ import com.android.launcher3.provider.LauncherDbUtils;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.MultiHashMap;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
@@ -138,26 +139,20 @@ public class LauncherModel extends BroadcastReceiver
public int getCurrentWorkspaceScreen();
public void clearPendingBinds();
public void startBinding();
- public void bindItems(ArrayList shortcuts, int start, int end,
- boolean forceAnimateIcons);
+ public void bindItems(List shortcuts, boolean forceAnimateIcons);
public void bindScreens(ArrayList orderedScreenIds);
public void finishFirstPageBind(ViewOnDrawExecutor executor);
public void finishBindingItems();
- public void bindAppWidget(LauncherAppWidgetInfo info);
public void bindAllApplications(ArrayList apps);
+ public void bindAppsAddedOrUpdated(ArrayList apps);
public void bindAppsAdded(ArrayList newScreens,
ArrayList addNotAnimated,
- ArrayList addAnimated,
- ArrayList addedApps);
- public void bindAppsUpdated(ArrayList apps);
+ ArrayList addAnimated);
public void bindPromiseAppProgressUpdated(PromiseAppInfo app);
- public void bindShortcutsChanged(ArrayList updated,
- ArrayList removed, UserHandle user);
+ public void bindShortcutsChanged(ArrayList updated, UserHandle user);
public void bindWidgetsRestored(ArrayList widgets);
public void bindRestoreItemsChange(HashSet updates);
- public void bindWorkspaceComponentsRemoved(
- HashSet packageNames, HashSet components,
- UserHandle user);
+ public void bindWorkspaceComponentsRemoved(ItemInfoMatcher matcher);
public void bindAppInfosRemoved(ArrayList appInfos);
public void bindAllWidgets(MultiHashMap widgets);
public void onPageBoundSynchronously(int page);
@@ -537,7 +532,7 @@ public class LauncherModel extends BroadcastReceiver
scheduleCallbackTask(new CallbackTask() {
@Override
public void execute(Callbacks callbacks) {
- callbacks.bindAppsAdded(null, null, null, arrayList);
+ callbacks.bindAppsAddedOrUpdated(arrayList);
}
});
}
@@ -689,4 +684,8 @@ public class LauncherModel extends BroadcastReceiver
public static Looper getWorkerLooper() {
return sWorkerThread.getLooper();
}
+
+ public static void setWorkerPriority(final int priority) {
+ Process.setThreadPriority(sWorkerThread.getThreadId(), priority);
+ }
}
diff --git a/src/com/android/launcher3/LauncherRootView.java b/src/com/android/launcher3/LauncherRootView.java
index 643d48adfc..a814323633 100644
--- a/src/com/android/launcher3/LauncherRootView.java
+++ b/src/com/android/launcher3/LauncherRootView.java
@@ -11,6 +11,9 @@ import android.util.AttributeSet;
import android.view.View;
import android.view.ViewDebug;
+import static com.android.launcher3.util.SystemUiController.FLAG_DARK_NAV;
+import static com.android.launcher3.util.SystemUiController.UI_STATE_ROOT_VIEW;
+
public class LauncherRootView extends InsettableFrameLayout {
private final Paint mOpaquePaint;
@@ -44,20 +47,28 @@ public class LauncherRootView extends InsettableFrameLayout {
@TargetApi(23)
@Override
protected boolean fitSystemWindows(Rect insets) {
- boolean rawInsetsChanged = !mInsets.equals(insets);
mDrawSideInsetBar = (insets.right > 0 || insets.left > 0) &&
(!Utilities.ATLEAST_MARSHMALLOW ||
- getContext().getSystemService(ActivityManager.class).isLowRamDevice());
- mRightInsetBarWidth = insets.right;
- mLeftInsetBarWidth = insets.left;
- setInsets(mDrawSideInsetBar ? new Rect(0, insets.top, 0, insets.bottom) : insets);
+ getContext().getSystemService(ActivityManager.class).isLowRamDevice());
+ if (mDrawSideInsetBar) {
+ mLeftInsetBarWidth = insets.left;
+ mRightInsetBarWidth = insets.right;
+ insets = new Rect(0, insets.top, 0, insets.bottom);
+ } else {
+ mLeftInsetBarWidth = mRightInsetBarWidth = 0;
+ }
+ Launcher.getLauncher(getContext()).getSystemUiController().updateUiState(
+ UI_STATE_ROOT_VIEW, mDrawSideInsetBar ? FLAG_DARK_NAV : 0);
- if (mAlignedView != null && mDrawSideInsetBar) {
+ boolean rawInsetsChanged = !mInsets.equals(insets);
+ setInsets(insets);
+
+ if (mAlignedView != null) {
// Apply margins on aligned view to handle left/right insets.
MarginLayoutParams lp = (MarginLayoutParams) mAlignedView.getLayoutParams();
- if (lp.leftMargin != insets.left || lp.rightMargin != insets.right) {
- lp.leftMargin = insets.left;
- lp.rightMargin = insets.right;
+ if (lp.leftMargin != mLeftInsetBarWidth || lp.rightMargin != mRightInsetBarWidth) {
+ lp.leftMargin = mLeftInsetBarWidth;
+ lp.rightMargin = mRightInsetBarWidth;
mAlignedView.setLayoutParams(lp);
}
}
diff --git a/src/com/android/launcher3/LauncherStateTransitionAnimation.java b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
index 44b9704f28..e2474900da 100644
--- a/src/com/android/launcher3/LauncherStateTransitionAnimation.java
+++ b/src/com/android/launcher3/LauncherStateTransitionAnimation.java
@@ -80,13 +80,11 @@ import com.android.launcher3.widget.WidgetsContainerView;
public class LauncherStateTransitionAnimation {
/**
- * animation used for all apps and widget tray when
- *{@link FeatureFlags#LAUNCHER3_ALL_APPS_PULL_UP} is {@code false}
+ * animation used for the widget tray
*/
public static final int CIRCULAR_REVEAL = 0;
/**
- * animation used for all apps and not widget tray when
- *{@link FeatureFlags#LAUNCHER3_ALL_APPS_PULL_UP} is {@code true}
+ * animation used for all apps tray
*/
public static final int PULLUP = 1;
@@ -154,13 +152,9 @@ public class LauncherStateTransitionAnimation {
mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
}
};
- int animType = CIRCULAR_REVEAL;
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
- animType = PULLUP;
- }
// Only animate the search bar if animating from spring loaded mode back to all apps
startAnimationToOverlay(
- Workspace.State.NORMAL_HIDDEN, buttonView, toView, animated, animType, cb);
+ Workspace.State.NORMAL_HIDDEN, buttonView, toView, animated, PULLUP, cb);
}
/**
@@ -193,12 +187,8 @@ public class LauncherStateTransitionAnimation {
if (fromState == Launcher.State.APPS || fromState == Launcher.State.APPS_SPRING_LOADED
|| mAllAppsController.isTransitioning()) {
- int animType = CIRCULAR_REVEAL;
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
- animType = PULLUP;
- }
startAnimationToWorkspaceFromAllApps(fromWorkspaceState, toWorkspaceState,
- animated, animType, onCompleteRunnable);
+ animated, PULLUP, onCompleteRunnable);
} else if (fromState == Launcher.State.WIDGETS ||
fromState == Launcher.State.WIDGETS_SPRING_LOADED) {
startAnimationToWorkspaceFromWidgets(fromWorkspaceState, toWorkspaceState,
@@ -235,8 +225,7 @@ public class LauncherStateTransitionAnimation {
playCommonTransitionAnimations(toWorkspaceState,
animated, initialized, animation, layerViews);
if (!animated || !initialized) {
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
- toWorkspaceState == Workspace.State.NORMAL_HIDDEN) {
+ if (toWorkspaceState == Workspace.State.NORMAL_HIDDEN) {
mAllAppsController.finishPullUp();
}
toView.setTranslationX(0.0f);
@@ -338,8 +327,10 @@ public class LauncherStateTransitionAnimation {
toView.post(new StartAnimRunnable(animation, toView));
mCurrentAnimation = animation;
} else if (animType == PULLUP) {
- // We are animating the content view alpha, so ensure we have a layer for it
- layerViews.addView(contentView);
+ if (!FeatureFlags.LAUNCHER3_PHYSICS) {
+ // We are animating the content view alpha, so ensure we have a layer for it.
+ layerViews.addView(contentView);
+ }
animation.addListener(new AnimatorListenerAdapter() {
@Override
@@ -525,8 +516,7 @@ public class LauncherStateTransitionAnimation {
playCommonTransitionAnimations(toWorkspaceState,
animated, initialized, animation, layerViews);
if (!animated || !initialized) {
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
- fromWorkspaceState == Workspace.State.NORMAL_HIDDEN) {
+ if (fromWorkspaceState == Workspace.State.NORMAL_HIDDEN) {
mAllAppsController.finishPullDown();
}
fromView.setVisibility(View.GONE);
diff --git a/src/com/android/launcher3/SettingsActivity.java b/src/com/android/launcher3/SettingsActivity.java
index d5d5eab761..90463725ff 100644
--- a/src/com/android/launcher3/SettingsActivity.java
+++ b/src/com/android/launcher3/SettingsActivity.java
@@ -26,18 +26,15 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
-import android.database.ContentObserver;
import android.os.Bundle;
-import android.os.Handler;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
import android.provider.Settings;
-import android.provider.Settings.System;
-import android.view.View;
import com.android.launcher3.graphics.IconShapeOverride;
import com.android.launcher3.notification.NotificationListener;
+import com.android.launcher3.util.SettingsObserver;
import com.android.launcher3.views.ButtonPreference;
/**
@@ -46,8 +43,8 @@ import com.android.launcher3.views.ButtonPreference;
public class SettingsActivity extends Activity {
private static final String ICON_BADGING_PREFERENCE_KEY = "pref_icon_badging";
- // TODO: use Settings.Secure.NOTIFICATION_BADGING
- private static final String NOTIFICATION_BADGING = "notification_badging";
+ /** Hidden field Settings.Secure.NOTIFICATION_BADGING */
+ public static final String NOTIFICATION_BADGING = "notification_badging";
/** Hidden field Settings.Secure.ENABLED_NOTIFICATION_LISTENERS */
private static final String NOTIFICATION_ENABLED_LISTENERS = "enabled_notification_listeners";
@@ -89,12 +86,9 @@ public class SettingsActivity extends Activity {
// Register a content observer to listen for system setting changes while
// this UI is active.
- resolver.registerContentObserver(
- Settings.System.getUriFor(System.ACCELEROMETER_ROTATION),
- false, mRotationLockObserver);
+ mRotationLockObserver.register(Settings.System.ACCELEROMETER_ROTATION);
// Initialize the UI once
- mRotationLockObserver.onChange(true);
rotationPref.setDefaultValue(Utilities.getAllowRotationDefaultValue(getActivity()));
}
@@ -108,13 +102,7 @@ public class SettingsActivity extends Activity {
// Listen to system notification badge settings while this UI is active.
mIconBadgingObserver = new IconBadgingObserver(
iconBadgingPref, resolver, getFragmentManager());
- resolver.registerContentObserver(
- Settings.Secure.getUriFor(NOTIFICATION_BADGING),
- false, mIconBadgingObserver);
- resolver.registerContentObserver(
- Settings.Secure.getUriFor(NOTIFICATION_ENABLED_LISTENERS),
- false, mIconBadgingObserver);
- mIconBadgingObserver.onChange(true);
+ mIconBadgingObserver.register(NOTIFICATION_BADGING, NOTIFICATION_ENABLED_LISTENERS);
}
Preference iconShapeOverride = findPreference(IconShapeOverride.KEY_PREFERENCE);
@@ -130,11 +118,11 @@ public class SettingsActivity extends Activity {
@Override
public void onDestroy() {
if (mRotationLockObserver != null) {
- getActivity().getContentResolver().unregisterContentObserver(mRotationLockObserver);
+ mRotationLockObserver.unregister();
mRotationLockObserver = null;
}
if (mIconBadgingObserver != null) {
- getActivity().getContentResolver().unregisterContentObserver(mIconBadgingObserver);
+ mIconBadgingObserver.unregister();
mIconBadgingObserver = null;
}
super.onDestroy();
@@ -145,22 +133,18 @@ public class SettingsActivity extends Activity {
* Content observer which listens for system auto-rotate setting changes, and enables/disables
* the launcher rotation setting accordingly.
*/
- private static class SystemDisplayRotationLockObserver extends ContentObserver {
+ private static class SystemDisplayRotationLockObserver extends SettingsObserver.System {
private final Preference mRotationPref;
- private final ContentResolver mResolver;
public SystemDisplayRotationLockObserver(
Preference rotationPref, ContentResolver resolver) {
- super(new Handler());
+ super(resolver);
mRotationPref = rotationPref;
- mResolver = resolver;
}
@Override
- public void onChange(boolean selfChange) {
- boolean enabled = Settings.System.getInt(mResolver,
- Settings.System.ACCELEROMETER_ROTATION, 1) == 1;
+ public void onSettingChanged(boolean enabled) {
mRotationPref.setEnabled(enabled);
mRotationPref.setSummary(enabled
? R.string.allow_rotation_desc : R.string.allow_rotation_blocked_desc);
@@ -171,8 +155,8 @@ public class SettingsActivity extends Activity {
* Content observer which listens for system badging setting changes,
* and updates the launcher badging setting subtext accordingly.
*/
- private static class IconBadgingObserver extends ContentObserver
- implements View.OnClickListener {
+ private static class IconBadgingObserver extends SettingsObserver.Secure
+ implements Preference.OnPreferenceClickListener {
private final ButtonPreference mBadgingPref;
private final ContentResolver mResolver;
@@ -180,15 +164,14 @@ public class SettingsActivity extends Activity {
public IconBadgingObserver(ButtonPreference badgingPref, ContentResolver resolver,
FragmentManager fragmentManager) {
- super(new Handler());
+ super(resolver);
mBadgingPref = badgingPref;
mResolver = resolver;
mFragmentManager = fragmentManager;
}
@Override
- public void onChange(boolean selfChange) {
- boolean enabled = Settings.Secure.getInt(mResolver, NOTIFICATION_BADGING, 1) == 1;
+ public void onSettingChanged(boolean enabled) {
int summary = enabled ? R.string.icon_badging_desc_on : R.string.icon_badging_desc_off;
boolean serviceEnabled = true;
@@ -205,14 +188,16 @@ public class SettingsActivity extends Activity {
summary = R.string.title_missing_notification_access;
}
}
- mBadgingPref.setButtonOnClickListener(serviceEnabled ? null : this);
+ mBadgingPref.setWidgetFrameVisible(!serviceEnabled);
+ mBadgingPref.setOnPreferenceClickListener(serviceEnabled ? null : this);
mBadgingPref.setSummary(summary);
}
@Override
- public void onClick(View view) {
+ public boolean onPreferenceClick(Preference preference) {
new NotificationAccessConfirmation().show(mFragmentManager, "notification_access");
+ return true;
}
}
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index fd708c0fd5..a7e68ff148 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -101,7 +101,7 @@ public class ShortcutAndWidgetContainer extends ViewGroup {
mInvertIfRtl = invert;
}
- int getCellContentHeight() {
+ public int getCellContentHeight() {
return Math.min(getMeasuredHeight(),
mLauncher.getDeviceProfile().getCellHeight(mContainerType));
}
diff --git a/src/com/android/launcher3/UninstallDropTarget.java b/src/com/android/launcher3/UninstallDropTarget.java
index 45c14d6bba..e15cf9f50a 100644
--- a/src/com/android/launcher3/UninstallDropTarget.java
+++ b/src/com/android/launcher3/UninstallDropTarget.java
@@ -42,7 +42,7 @@ public class UninstallDropTarget extends ButtonDropTarget {
return supportsDrop(getContext(), info);
}
- public static boolean supportsDrop(Context context, Object info) {
+ public static boolean supportsDrop(Context context, ItemInfo info) {
UserManager userManager = (UserManager) context.getSystemService(Context.USER_SERVICE);
Bundle restrictions = userManager.getUserRestrictions();
if (restrictions.getBoolean(UserManager.DISALLOW_APPS_CONTROL, false)
@@ -56,21 +56,13 @@ public class UninstallDropTarget extends ButtonDropTarget {
/**
* @return the component name that should be uninstalled or null.
*/
- private static ComponentName getUninstallTarget(Context context, Object item) {
+ private static ComponentName getUninstallTarget(Context context, ItemInfo item) {
Intent intent = null;
UserHandle user = null;
- if (item instanceof AppInfo) {
- AppInfo info = (AppInfo) item;
- intent = info.intent;
- user = info.user;
- } else if (item instanceof ShortcutInfo) {
- ShortcutInfo info = (ShortcutInfo) item;
- if (info.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION) {
- // Do not use restore/target intent here as we cannot uninstall an app which is
- // being installed/restored.
- intent = info.intent;
- user = info.user;
- }
+ if (item != null &&
+ item.itemType == LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION) {
+ intent = item.getIntent();
+ user = item.user;
}
if (intent != null) {
LauncherActivityInfo info = LauncherAppsCompat.getInstance(context)
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index a2270d6c57..f8d64984e9 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -671,7 +671,8 @@ public class Workspace extends PagedView
newScreen.setSoundEffectsEnabled(false);
int paddingLeftRight = mLauncher.getDeviceProfile().cellLayoutPaddingLeftRightPx;
- newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, 0);
+ int paddingBottom = mLauncher.getDeviceProfile().cellLayoutBottomPaddingPx;
+ newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom);
mWorkspaceScreens.put(screenId, newScreen);
mScreenOrder.add(insertIndex, screenId);
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 32deaf2862..a105a73034 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -273,10 +273,8 @@ public class WorkspaceStateTransitionAnimation {
float finalBackgroundAlpha = (states.stateIsSpringLoaded || states.stateIsOverview) ?
1.0f : 0f;
float finalHotseatAlpha = (states.stateIsNormal || states.stateIsSpringLoaded ||
- (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && states.stateIsNormalHidden)) ? 1f : 0f;
- float finalOverviewPanelAlpha = states.stateIsOverview ? 1f : 0f;
- float finalQsbAlpha = (states.stateIsNormal ||
- (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && states.stateIsNormalHidden)) ? 1f : 0f;
+ states.stateIsNormalHidden) ? 1f : 0f;
+ float finalQsbAlpha = (states.stateIsNormal || states.stateIsNormalHidden) ? 1f : 0f;
float finalWorkspaceTranslationY = 0;
if (states.stateIsOverview || states.stateIsOverviewHidden) {
@@ -313,8 +311,7 @@ public class WorkspaceStateTransitionAnimation {
if (states.stateIsOverviewHidden) {
finalAlpha = 0f;
} else if(states.stateIsNormalHidden) {
- finalAlpha = (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
- i == mWorkspace.getNextPage()) ? 1 : 0;
+ finalAlpha = (i == mWorkspace.getNextPage()) ? 1 : 0;
} else if (states.stateIsNormal && mWorkspaceFadeInAdjacentScreens) {
finalAlpha = (i == toPage || i < customPageCount) ? 1f : 0f;
} else {
@@ -323,7 +320,7 @@ public class WorkspaceStateTransitionAnimation {
// If we are animating to/from the small state, then hide the side pages and fade the
// current page in
- if (!FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && !mWorkspace.isSwitchingState()) {
+ if (!FeatureFlags.NO_ALL_APPS_ICON && !mWorkspace.isSwitchingState()) {
if (states.workspaceToAllApps || states.allAppsToWorkspace) {
boolean isCurrentPage = (i == toPage);
if (states.allAppsToWorkspace && isCurrentPage) {
@@ -359,38 +356,47 @@ public class WorkspaceStateTransitionAnimation {
final ViewGroup overviewPanel = mLauncher.getOverviewPanel();
+ float finalOverviewPanelAlpha = states.stateIsOverview ? 1f : 0f;
if (animated) {
+ // This is true when transitioning between:
+ // - Overview <-> Workspace
+ // - Overview <-> Widget Tray
+ if (finalOverviewPanelAlpha != overviewPanel.getAlpha()) {
+ Animator overviewPanelAlpha = ObjectAnimator.ofFloat(
+ overviewPanel, View.ALPHA, finalOverviewPanelAlpha);
+ overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel,
+ accessibilityEnabled));
+ layerViews.addView(overviewPanel);
+
+ if (states.overviewToWorkspace) {
+ overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2));
+ } else if (states.workspaceToOverview) {
+ overviewPanelAlpha.setInterpolator(null);
+ }
+
+ overviewPanelAlpha.setDuration(duration);
+ mStateAnimator.play(overviewPanelAlpha);
+ }
+
Animator scale = LauncherAnimUtils.ofPropertyValuesHolder(mWorkspace,
new PropertyListBuilder().scale(mNewScale)
.translationY(finalWorkspaceTranslationY).build())
.setDuration(duration);
scale.setInterpolator(mZoomInInterpolator);
mStateAnimator.play(scale);
- Animator hotseatAlpha = mWorkspace.createHotseatAlphaAnimator(finalHotseatAlpha);
-
- Animator overviewPanelAlpha = ObjectAnimator.ofFloat(
- overviewPanel, View.ALPHA, finalOverviewPanelAlpha);
- overviewPanelAlpha.addListener(new AlphaUpdateListener(overviewPanel,
- accessibilityEnabled));
// For animation optimization, we may need to provide the Launcher transition
// with a set of views on which to force build and manage layers in certain scenarios.
- layerViews.addView(overviewPanel);
layerViews.addView(mLauncher.getHotseat());
layerViews.addView(mWorkspace.getPageIndicator());
+ Animator hotseatAlpha = mWorkspace.createHotseatAlphaAnimator(finalHotseatAlpha);
if (states.workspaceToOverview) {
hotseatAlpha.setInterpolator(new DecelerateInterpolator(2));
- overviewPanelAlpha.setInterpolator(null);
} else if (states.overviewToWorkspace) {
hotseatAlpha.setInterpolator(null);
- overviewPanelAlpha.setInterpolator(new DecelerateInterpolator(2));
}
-
- overviewPanelAlpha.setDuration(duration);
hotseatAlpha.setDuration(duration);
-
- mStateAnimator.play(overviewPanelAlpha);
mStateAnimator.play(hotseatAlpha);
mStateAnimator.addListener(new AnimatorListenerAdapter() {
boolean canceled = false;
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 34335330be..a0ad07aeb1 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -173,7 +173,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
ArrayList itemList = new ArrayList<>();
itemList.add(info);
- mLauncher.bindItems(itemList, 0, itemList.size(), true);
+ mLauncher.bindItems(itemList, true);
} else if (item instanceof PendingAddItemInfo) {
PendingAddItemInfo info = (PendingAddItemInfo) item;
Workspace workspace = mLauncher.getWorkspace();
@@ -205,7 +205,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme
public void run() {
ArrayList itemList = new ArrayList<>();
itemList.add(item);
- mLauncher.bindItems(itemList, 0, itemList.size(), true);
+ mLauncher.bindItems(itemList, true);
announceConfirmation(R.string.item_moved);
}
});
diff --git a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
index b7c500fa6e..5b7353aa18 100644
--- a/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/ShortcutMenuAccessibilityDelegate.java
@@ -73,7 +73,7 @@ public class ShortcutMenuAccessibilityDelegate extends LauncherAccessibilityDele
screenId, coordinates[0], coordinates[1]);
ArrayList itemList = new ArrayList<>();
itemList.add(info);
- mLauncher.bindItems(itemList, 0, itemList.size(), true);
+ mLauncher.bindItems(itemList, true);
AbstractFloatingView.closeAllOpenViews(mLauncher);
announceConfirmation(R.string.item_added_to_workspace);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 0083d47f2a..97a87c16cb 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -102,18 +102,14 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
@Override
protected void updateBackground(
int paddingLeft, int paddingTop, int paddingRight, int paddingBottom) {
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
- if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
- getRevealView().setBackground(new InsetDrawable(mBaseDrawable,
- paddingLeft, paddingTop, paddingRight, paddingBottom));
- getContentView().setBackground(
- new InsetDrawable(new ColorDrawable(Color.TRANSPARENT),
- paddingLeft, paddingTop, paddingRight, paddingBottom));
- } else {
- getRevealView().setBackground(mBaseDrawable);
- }
+ if (mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ getRevealView().setBackground(new InsetDrawable(mBaseDrawable,
+ paddingLeft, paddingTop, paddingRight, paddingBottom));
+ getContentView().setBackground(
+ new InsetDrawable(new ColorDrawable(Color.TRANSPARENT),
+ paddingLeft, paddingTop, paddingRight, paddingBottom));
} else {
- super.updateBackground(paddingLeft, paddingTop, paddingRight, paddingBottom);
+ getRevealView().setBackground(mBaseDrawable);
}
}
@@ -132,18 +128,10 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
}
/**
- * Adds new apps to the list.
+ * Adds or updates existing apps in the list
*/
- public void addApps(List apps) {
- mApps.addApps(apps);
- mSearchUiManager.refreshSearchResult();
- }
-
- /**
- * Updates existing apps in the list
- */
- public void updateApps(List apps) {
- mApps.updateApps(apps);
+ public void addOrUpdateApps(List apps) {
+ mApps.addOrUpdateApps(apps);
mSearchUiManager.refreshSearchResult();
}
@@ -224,6 +212,8 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
mAppsRecyclerView.setLayoutManager(mLayoutManager);
mAppsRecyclerView.setAdapter(mAdapter);
mAppsRecyclerView.setHasFixedSize(true);
+ // No animations will occur when changes occur to the items in this RecyclerView.
+ mAppsRecyclerView.setItemAnimator(null);
if (FeatureFlags.LAUNCHER3_PHYSICS) {
mAppsRecyclerView.setSpringAnimationHandler(mSpringAnimationHandler);
}
@@ -238,11 +228,9 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
mAppsRecyclerView.preMeasureViews(mAdapter);
mAdapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
- getRevealView().setVisibility(View.VISIBLE);
- getContentView().setVisibility(View.VISIBLE);
- getContentView().setBackground(null);
- }
+ getRevealView().setVisibility(View.VISIBLE);
+ getContentView().setVisibility(View.VISIBLE);
+ getContentView().setBackground(null);
}
public SearchUiManager getSearchUiManager() {
@@ -260,32 +248,15 @@ public class AllAppsContainerView extends BaseContainerView implements DragSourc
// Update the number of items in the grid before we measure the view
grid.updateAppsViewNumCols();
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
- if (mNumAppsPerRow != grid.inv.numColumns ||
- mNumPredictedAppsPerRow != grid.inv.numColumns) {
- mNumAppsPerRow = grid.inv.numColumns;
- mNumPredictedAppsPerRow = grid.inv.numColumns;
-
- mAppsRecyclerView.setNumAppsPerRow(grid, mNumAppsPerRow);
- mAdapter.setNumAppsPerRow(mNumAppsPerRow);
- mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
- }
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
- return;
- }
-
- // --- remove START when {@code FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP} is enabled. ---
- if (mNumAppsPerRow != grid.allAppsNumCols ||
- mNumPredictedAppsPerRow != grid.allAppsNumPredictiveCols) {
- mNumAppsPerRow = grid.allAppsNumCols;
- mNumPredictedAppsPerRow = grid.allAppsNumPredictiveCols;
+ if (mNumAppsPerRow != grid.inv.numColumns ||
+ mNumPredictedAppsPerRow != grid.inv.numColumns) {
+ mNumAppsPerRow = grid.inv.numColumns;
+ mNumPredictedAppsPerRow = grid.inv.numColumns;
mAppsRecyclerView.setNumAppsPerRow(grid, mNumAppsPerRow);
mAdapter.setNumAppsPerRow(mNumAppsPerRow);
mApps.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
}
-
- // --- remove END when {@code FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP} is enabled. ---
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 331900cf15..494cd5ac5e 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -110,12 +110,6 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
}
}
- @Override
- public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent ev) {
- mPullDetector.onTouchEvent(ev);
- return super.onInterceptTouchEvent(rv, ev) || mOverScrollHelper.isInOverScroll();
- }
-
@Override
public boolean onTouchEvent(MotionEvent e) {
mPullDetector.onTouchEvent(e);
@@ -205,8 +199,6 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
@Override
public void onDraw(Canvas c) {
- c.translate(0, mContentTranslationY);
-
// Draw the background
if (mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) {
mEmptySearchBackground.draw(c);
@@ -215,6 +207,13 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
super.onDraw(c);
}
+ @Override
+ protected void dispatchDraw(Canvas canvas) {
+ canvas.translate(0, mContentTranslationY);
+ super.dispatchDraw(canvas);
+ canvas.translate(0, -mContentTranslationY);
+ }
+
public float getContentTranslationY() {
return mContentTranslationY;
}
@@ -282,7 +281,8 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
- boolean result = super.onInterceptTouchEvent(e);
+ mPullDetector.onTouchEvent(e);
+ boolean result = super.onInterceptTouchEvent(e) || mOverScrollHelper.isInOverScroll();
if (!result && e.getAction() == MotionEvent.ACTION_DOWN
&& mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) {
mEmptySearchBackground.setHotspot(e.getX(), e.getY());
@@ -339,6 +339,22 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
mFastScrollHelper.onSetAdapter((AllAppsGridAdapter) adapter);
}
+ @Override
+ protected float getBottomFadingEdgeStrength() {
+ // No bottom fading edge.
+ return 0;
+ }
+
+ @Override
+ protected boolean isPaddingOffsetRequired() {
+ return true;
+ }
+
+ @Override
+ protected int getTopPaddingOffset() {
+ return -getPaddingTop();
+ }
+
/**
* Updates the bounds for the scrollbar.
*/
@@ -541,11 +557,16 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
// and if one of the following criteria are met:
// - User scrolls down when they're already at the bottom.
// - User starts scrolling up, hits the top, and continues scrolling up.
+ boolean wasInOverScroll = mIsInOverScroll;
mIsInOverScroll = !mScrollbar.isDraggingThumb() &&
((!canScrollVertically(1) && displacement < 0) ||
(!canScrollVertically(-1) && isScrollingUp && mFirstScrollYOnScrollUp != 0));
- if (mIsInOverScroll) {
+ if (wasInOverScroll && !mIsInOverScroll) {
+ // Exit overscroll. This can happen when the user is in overscroll and then
+ // scrolls the opposite way.
+ reset(false /* shouldSpring */);
+ } else if (mIsInOverScroll) {
if (Float.compare(mFirstDisplacement, 0) == 0) {
// Because users can scroll before entering overscroll, we need to
// subtract the amount where the user was not in overscroll.
@@ -560,11 +581,15 @@ public class AllAppsRecyclerView extends BaseRecyclerView implements LogContaine
@Override
public void onDragEnd(float velocity, boolean fling) {
+ reset(mIsInOverScroll /* shouldSpring */);
+ }
+
+ private void reset(boolean shouldSpring) {
float y = getContentTranslationY();
if (Float.compare(y, 0) != 0) {
- if (FeatureFlags.LAUNCHER3_PHYSICS) {
+ if (FeatureFlags.LAUNCHER3_PHYSICS && shouldSpring) {
// We calculate our own velocity to give the springs the desired effect.
- velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY;
+ float velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY;
// We want to negate the velocity because we are moving to 0 from -1 due to the
// downward motion. (y-axis -1 is above 0).
mSpringAnimationHandler.animateToPositionWithVelocity(0, -1, -velocity);
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 6896b37d99..edfe0c15e9 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -283,7 +283,9 @@ public class AllAppsTransitionController implements TouchController, SwipeDetect
}
// Use a light system UI (dark icons) if all apps is behind at least half of the status bar.
- boolean forceChange = shift <= mStatusBarHeight / 2;
+ boolean forceChange = FeatureFlags.LAUNCHER3_GRADIENT_ALL_APPS ?
+ shift <= mShiftRange / 4 :
+ shift <= mStatusBarHeight / 2;
if (forceChange) {
mLauncher.getSystemUiController().updateUiState(
SystemUiController.UI_STATE_ALL_APPS, !mIsDarkTheme);
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 608e898ae8..5e7a5cac56 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -298,14 +298,75 @@ public class AlphabeticalAppsList {
updateAdapterItems();
}
+ private List processPredictedAppComponents(List components) {
+ if (mComponentToAppMap.isEmpty()) {
+ // Apps have not been bound yet.
+ return Collections.emptyList();
+ }
+
+ List predictedApps = new ArrayList<>();
+ for (ComponentKey ck : components) {
+ AppInfo info = mComponentToAppMap.get(ck);
+ if (info != null) {
+ predictedApps.add(info);
+ } else {
+ if (FeatureFlags.IS_DOGFOOD_BUILD) {
+ Log.e(TAG, "Predicted app not found: " + ck);
+ }
+ }
+ // Stop at the number of predicted apps
+ if (predictedApps.size() == mNumPredictedAppsPerRow) {
+ break;
+ }
+ }
+ return predictedApps;
+ }
+
/**
- * Sets the current set of predicted apps. Since this can be called before we get the full set
- * of applications, we should merge the results only in onAppsUpdated() which is idempotent.
+ * Sets the current set of predicted apps.
+ *
+ * This can be called before we get the full set of applications, we should merge the results
+ * only in onAppsUpdated() which is idempotent.
+ *
+ * If the number of predicted apps is the same as the previous list of predicted apps,
+ * we can optimize by swapping them in place.
*/
public void setPredictedApps(List apps) {
mPredictedAppComponents.clear();
mPredictedAppComponents.addAll(apps);
- onAppsUpdated();
+
+ List newPredictedApps = processPredictedAppComponents(apps);
+ // We only need to do work if any of the visible predicted apps have changed.
+ if (!newPredictedApps.equals(mPredictedApps)) {
+ if (newPredictedApps.size() == mPredictedApps.size()) {
+ swapInNewPredictedApps(newPredictedApps);
+ } else {
+ // We need to update the appIndex of all the items.
+ onAppsUpdated();
+ }
+ }
+ }
+
+ /**
+ * Swaps out the old predicted apps with the new predicted apps, in place. This optimization
+ * allows us to skip an entire relayout that would otherwise be called by notifyDataSetChanged.
+ *
+ * Note: This should only be called if the # of predicted apps is the same.
+ * This method assumes that predicted apps are the first items in the adapter.
+ */
+ private void swapInNewPredictedApps(List apps) {
+ mPredictedApps.clear();
+ mPredictedApps.addAll(apps);
+
+ int size = apps.size();
+ for (int i = 0; i < size; ++i) {
+ AppInfo info = apps.get(i);
+ AdapterItem appItem = AdapterItem.asPredictedApp(i, "", info, i);
+ appItem.rowAppIndex = i;
+ mAdapterItems.set(i, appItem);
+ mFilteredApps.set(i, info);
+ mAdapter.notifyItemChanged(i);
+ }
}
/**
@@ -313,20 +374,13 @@ public class AlphabeticalAppsList {
*/
public void setApps(List apps) {
mComponentToAppMap.clear();
- addApps(apps);
+ addOrUpdateApps(apps);
}
/**
- * Adds new apps to the list.
+ * Adds or updates existing apps in the list
*/
- public void addApps(List apps) {
- updateApps(apps);
- }
-
- /**
- * Updates existing apps in the list
- */
- public void updateApps(List apps) {
+ public void addOrUpdateApps(List apps) {
for (AppInfo app : apps) {
mComponentToAppMap.put(app.toComponentKey(), app);
}
@@ -432,20 +486,7 @@ public class AlphabeticalAppsList {
// Process the predicted app components
mPredictedApps.clear();
if (mPredictedAppComponents != null && !mPredictedAppComponents.isEmpty() && !hasFilter()) {
- for (ComponentKey ck : mPredictedAppComponents) {
- AppInfo info = mComponentToAppMap.get(ck);
- if (info != null) {
- mPredictedApps.add(info);
- } else {
- if (FeatureFlags.IS_DOGFOOD_BUILD) {
- Log.e(TAG, "Predicted app not found: " + ck);
- }
- }
- // Stop at the number of predicted apps
- if (mPredictedApps.size() == mNumPredictedAppsPerRow) {
- break;
- }
- }
+ mPredictedApps.addAll(processPredictedAppComponents(mPredictedAppComponents));
if (!mPredictedApps.isEmpty()) {
// Add a section for the predictions
diff --git a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
index 39e2088746..d504551712 100644
--- a/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
+++ b/src/com/android/launcher3/allapps/search/AppsSearchContainerLayout.java
@@ -108,8 +108,7 @@ public class AppsSearchContainerLayout extends FrameLayout
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP &&
- !mLauncher.getDeviceProfile().isVerticalBarLayout()) {
+ if (!mLauncher.getDeviceProfile().isVerticalBarLayout()) {
getLayoutParams().height = mLauncher.getDragLayer().getInsets().top + mMinHeight;
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
index cdbaf708dc..e9dead3997 100644
--- a/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
+++ b/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithm.java
@@ -71,10 +71,6 @@ public class DefaultAppSearchAlgorithm implements SearchAlgorithm {
return result;
}
- public static boolean matches(AppInfo info, String query) {
- return matches(info, query, StringMatcher.getInstance());
- }
-
public static boolean matches(AppInfo info, String query, StringMatcher matcher) {
int queryLength = query.length();
diff --git a/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java b/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java
index 6233fabb2b..fe5ff2a8c6 100644
--- a/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java
+++ b/src/com/android/launcher3/compat/WallpaperManagerCompatVOMR1.java
@@ -20,6 +20,7 @@ import android.app.WallpaperManager;
import android.content.Context;
import android.graphics.Color;
import android.os.Build;
+import android.os.Handler;
import android.support.annotation.Nullable;
import android.util.Log;
@@ -48,8 +49,7 @@ public class WallpaperManagerCompatVOMR1 extends WallpaperManagerCompat {
mOCLClass = Class.forName("android.app.WallpaperManager$OnColorsChangedListener");
mAddOCLMethod = WallpaperManager.class.getDeclaredMethod(
- "addOnColorsChangedListener", mOCLClass);
-
+ "addOnColorsChangedListener", mOCLClass, Handler.class);
mWCGetMethod = WallpaperManager.class.getDeclaredMethod("getWallpaperColors", int.class);
Class wallpaperColorsClass = mWCGetMethod.getReturnType();
mWCGetPrimaryColorMethod = wallpaperColorsClass.getDeclaredMethod("getPrimaryColor");
@@ -89,7 +89,7 @@ public class WallpaperManagerCompatVOMR1 extends WallpaperManagerCompat {
}
});
try {
- mAddOCLMethod.invoke(mWm, onChangeListener);
+ mAddOCLMethod.invoke(mWm, onChangeListener, null);
} catch (Exception e) {
Log.e(TAG, "Error calling wallpaper API", e);
}
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index 9e0a3b3b5c..456562e2b5 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -34,12 +34,11 @@ abstract class BaseFlags {
public static boolean LAUNCHER3_DISABLE_ICON_NORMALIZATION = false;
public static boolean LAUNCHER3_LEGACY_FOLDER_ICON = false;
public static boolean LAUNCHER3_DISABLE_PINCH_TO_OVERVIEW = false;
- public static boolean LAUNCHER3_ALL_APPS_PULL_UP = true;
public static boolean LAUNCHER3_NEW_FOLDER_ANIMATION = true;
// When enabled allows to use any point on the fast scrollbar to start dragging.
public static final boolean LAUNCHER3_DIRECT_SCROLL = true;
// When enabled while all-apps open, the soft input will be set to adjust resize .
- public static final boolean LAUNCHER3_UPDATE_SOFT_INPUT_MODE = true;
+ public static final boolean LAUNCHER3_UPDATE_SOFT_INPUT_MODE = false;
// When enabled the promise icon is visible in all apps while installation an app.
public static final boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false;
// When enabled uses the AllAppsRadialGradientAndScrimDrawable for all apps
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index be5f01adbe..ee6a0e0b8c 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -243,7 +243,7 @@ public class DragLayer extends InsettableFrameLayout {
return true;
}
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP && mAllAppsController.onControllerInterceptTouchEvent(ev)) {
+ if (mAllAppsController.onControllerInterceptTouchEvent(ev)) {
mActiveController = mAllAppsController;
return true;
}
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index b6e38bb15e..e81e2a3863 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -218,6 +218,12 @@ public class DragView extends View {
Rect bounds = new Rect(0, 0, w, h);
bounds.inset(blurMargin, blurMargin);
+ // Badge is applied after icon normalization so the bounds for badge should not
+ // be scaled down due to icon normalization.
+ Rect badgeBounds = new Rect(bounds);
+ mBadge = getBadge(info, appState, outObj[0]);
+ mBadge.setBounds(badgeBounds);
+
Utilities.scaleRectAboutCenter(bounds,
IconNormalizer.getInstance(mLauncher).getScale(dr, null, null, null));
AdaptiveIconDrawable adaptiveIcon = (AdaptiveIconDrawable) dr;
@@ -234,9 +240,6 @@ public class DragView extends View {
mTranslateY = new SpringFloatValue(DragView.this,
h * AdaptiveIconDrawable.getExtraInsetFraction());
- mBadge = getBadge(info, appState, outObj[0]);
- mBadge.setBounds(bounds);
-
bounds.inset(
(int) (-bounds.width() * AdaptiveIconDrawable.getExtraInsetFraction()),
(int) (-bounds.height() * AdaptiveIconDrawable.getExtraInsetFraction())
diff --git a/src/com/android/launcher3/graphics/GradientView.java b/src/com/android/launcher3/graphics/GradientView.java
index 678396df1f..5455b43ec6 100644
--- a/src/com/android/launcher3/graphics/GradientView.java
+++ b/src/com/android/launcher3/graphics/GradientView.java
@@ -27,6 +27,7 @@ import android.graphics.RectF;
import android.graphics.Shader;
import android.support.v4.graphics.ColorUtils;
import android.util.AttributeSet;
+import android.util.DisplayMetrics;
import android.view.View;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Interpolator;
@@ -46,7 +47,6 @@ public class GradientView extends View implements WallpaperColorInfo.OnChangeLis
private static final int DEFAULT_COLOR = Color.WHITE;
private static final int ALPHA_MASK_HEIGHT_DP = 500;
private static final int ALPHA_MASK_WIDTH_DP = 2;
- private static final int ALPHA_COLORS = 0xBF;
private static final boolean DEBUG = false;
private final Bitmap mAlphaGradientMask;
@@ -62,7 +62,7 @@ public class GradientView extends View implements WallpaperColorInfo.OnChangeLis
private final Paint mPaintNoScrim = new Paint();
private float mProgress;
private final int mMaskHeight, mMaskWidth;
- private final Context mAppContext;
+ private final int mAlphaColors;
private final Paint mDebugPaint = DEBUG ? new Paint() : null;
private final Interpolator mAccelerator = new AccelerateInterpolator();
private final float mAlphaStart;
@@ -71,15 +71,14 @@ public class GradientView extends View implements WallpaperColorInfo.OnChangeLis
public GradientView(Context context, AttributeSet attrs) {
super(context, attrs);
- this.mAppContext = context.getApplicationContext();
- this.mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP,
- mAppContext.getResources().getDisplayMetrics());
- this.mMaskWidth = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP,
- mAppContext.getResources().getDisplayMetrics());
+ DisplayMetrics dm = getResources().getDisplayMetrics();
+ this.mMaskHeight = Utilities.pxFromDp(ALPHA_MASK_HEIGHT_DP, dm);
+ this.mMaskWidth = Utilities.pxFromDp(ALPHA_MASK_WIDTH_DP, dm);
Launcher launcher = Launcher.getLauncher(context);
this.mAlphaStart = launcher.getDeviceProfile().isVerticalBarLayout() ? 0 : 100;
this.mScrimColor = Themes.getAttrColor(context, R.attr.allAppsScrimColor);
this.mWallpaperColorInfo = WallpaperColorInfo.getInstance(launcher);
+ mAlphaColors = getResources().getInteger(R.integer.extracted_color_gradient_alpha);
updateColors();
mAlphaGradientMask = createDitheredAlphaMask();
}
@@ -104,9 +103,9 @@ public class GradientView extends View implements WallpaperColorInfo.OnChangeLis
private void updateColors() {
this.mColor1 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getMainColor(),
- ALPHA_COLORS);
+ mAlphaColors);
this.mColor2 = ColorUtils.setAlphaComponent(mWallpaperColorInfo.getSecondaryColor(),
- ALPHA_COLORS);
+ mAlphaColors);
if (mWidth + mHeight > 0) {
createRadialShader();
}
diff --git a/src/com/android/launcher3/graphics/IconNormalizer.java b/src/com/android/launcher3/graphics/IconNormalizer.java
index 34d0b727c1..8ed62bcdcc 100644
--- a/src/com/android/launcher3/graphics/IconNormalizer.java
+++ b/src/com/android/launcher3/graphics/IconNormalizer.java
@@ -32,10 +32,8 @@ import android.graphics.drawable.Drawable;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
-
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.Utilities;
-
import java.io.File;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
@@ -84,12 +82,12 @@ public class IconNormalizer {
private final Rect mBounds;
private final Matrix mMatrix;
- private Paint mPaintIcon;
- private Canvas mCanvasARGB;
+ private final Paint mPaintIcon;
+ private final Canvas mCanvasARGB;
- private File mDir;
+ private final File mDir;
private int mFileId;
- private Random mRandom;
+ private final Random mRandom;
private IconNormalizer(Context context) {
// Use twice the icon size as maximum size to avoid scaling down twice.
@@ -122,7 +120,6 @@ public class IconNormalizer {
mPaintMaskShapeOutline.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
mMatrix = new Matrix();
- int[] mPixels = new int[mMaxSize * mMaxSize];
mAdaptiveIconScale = SCALE_NOT_INITIALIZED;
mDir = context.getExternalFilesDir(null);
@@ -174,7 +171,8 @@ public class IconNormalizer {
boolean isTrans = isTransparentBitmap(mBitmapARGB);
if (DEBUG) {
- final File afterFile = new File(mDir, "isShape" + mFileId + "_after_" + isTrans + ".png");
+ final File afterFile = new File(mDir,
+ "isShape" + mFileId + "_after_" + isTrans + ".png");
try {
mBitmapARGB.compress(Bitmap.CompressFormat.PNG, 100,
new FileOutputStream(afterFile));
@@ -210,7 +208,9 @@ public class IconNormalizer {
float percentageDiffPixels = ((float) sum) / (mBounds.width() * mBounds.height());
boolean transparentImage = percentageDiffPixels < PIXEL_DIFF_PERCENTAGE_THRESHOLD;
if (DEBUG) {
- Log.d(TAG, "Total # pixel that is different (id="+ mFileId + "):" + percentageDiffPixels + "="+ sum + "/" + mBounds.width() * mBounds.height());
+ Log.d(TAG,
+ "Total # pixel that is different (id=" + mFileId + "):" + percentageDiffPixels
+ + "=" + sum + "/" + mBounds.width() * mBounds.height());
}
return transparentImage;
}
diff --git a/src/com/android/launcher3/logging/FileLog.java b/src/com/android/launcher3/logging/FileLog.java
index 4c83e9ac22..f7f8ef18f6 100644
--- a/src/com/android/launcher3/logging/FileLog.java
+++ b/src/com/android/launcher3/logging/FileLog.java
@@ -29,6 +29,8 @@ import java.util.concurrent.TimeUnit;
*/
public final class FileLog {
+ protected static final boolean ENABLED =
+ FeatureFlags.IS_DOGFOOD_BUILD || Utilities.IS_DEBUG_DEVICE;
private static final String FILE_NAME_PREFIX = "log-";
private static final DateFormat DATE_FORMAT =
DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
@@ -39,7 +41,7 @@ public final class FileLog {
private static File sLogsDirectory = null;
public static void setDir(File logsDir) {
- if (FeatureFlags.IS_DOGFOOD_BUILD || Utilities.IS_DEBUG_DEVICE) {
+ if (ENABLED) {
synchronized (DATE_FORMAT) {
// If the target directory changes, stop any active thread.
if (sHandler != null && !logsDir.equals(sLogsDirectory)) {
@@ -76,7 +78,7 @@ public final class FileLog {
}
public static void print(String tag, String msg, Exception e) {
- if (!FeatureFlags.IS_DOGFOOD_BUILD) {
+ if (!ENABLED) {
return;
}
String out = String.format("%s %s %s", DATE_FORMAT.format(new Date()), tag, msg);
@@ -102,7 +104,7 @@ public final class FileLog {
* @param out if not null, all the persisted logs are copied to the writer.
*/
public static void flushAll(PrintWriter out) throws InterruptedException {
- if (!FeatureFlags.IS_DOGFOOD_BUILD) {
+ if (!ENABLED) {
return;
}
CountDownLatch latch = new CountDownLatch(1);
@@ -135,7 +137,7 @@ public final class FileLog {
@Override
public boolean handleMessage(Message msg) {
- if (sLogsDirectory == null || !FeatureFlags.IS_DOGFOOD_BUILD) {
+ if (sLogsDirectory == null || !ENABLED) {
return true;
}
switch (msg.what) {
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 68012c4ba1..42926fa3ea 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -158,7 +158,7 @@ public class AddWorkspaceItemsTask extends BaseModelUpdateTask {
}
}
callbacks.bindAppsAdded(addedWorkspaceScreensFinal,
- addNotAnimated, addAnimated, null);
+ addNotAnimated, addAnimated);
}
});
}
diff --git a/src/com/android/launcher3/model/BaseModelUpdateTask.java b/src/com/android/launcher3/model/BaseModelUpdateTask.java
index 9b4510fcae..d5b5aa7cf3 100644
--- a/src/com/android/launcher3/model/BaseModelUpdateTask.java
+++ b/src/com/android/launcher3/model/BaseModelUpdateTask.java
@@ -26,6 +26,7 @@ import com.android.launcher3.LauncherModel.CallbackTask;
import com.android.launcher3.LauncherModel.Callbacks;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.MultiHashMap;
import java.util.ArrayList;
@@ -94,19 +95,12 @@ public abstract class BaseModelUpdateTask implements ModelUpdateTask {
public void bindUpdatedShortcuts(
- ArrayList updatedShortcuts, UserHandle user) {
- bindUpdatedShortcuts(updatedShortcuts, new ArrayList(), user);
- }
-
- public void bindUpdatedShortcuts(
- final ArrayList updatedShortcuts,
- final ArrayList removedShortcuts,
- final UserHandle user) {
- if (!updatedShortcuts.isEmpty() || !removedShortcuts.isEmpty()) {
+ final ArrayList updatedShortcuts, final UserHandle user) {
+ if (!updatedShortcuts.isEmpty()) {
scheduleCallbackTask(new CallbackTask() {
@Override
public void execute(Callbacks callbacks) {
- callbacks.bindShortcutsChanged(updatedShortcuts, removedShortcuts, user);
+ callbacks.bindShortcutsChanged(updatedShortcuts, user);
}
});
}
@@ -132,4 +126,16 @@ public abstract class BaseModelUpdateTask implements ModelUpdateTask {
}
});
}
+
+ public void deleteAndBindComponentsRemoved(final ItemInfoMatcher matcher) {
+ getModelWriter().deleteItemsFromDatabase(matcher);
+
+ // Call the components-removed callback
+ scheduleCallbackTask(new CallbackTask() {
+ @Override
+ public void execute(Callbacks callbacks) {
+ callbacks.bindWorkspaceComponentsRemoved(matcher);
+ }
+ });
+ }
}
diff --git a/src/com/android/launcher3/model/CacheDataUpdatedTask.java b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
index 8597e10486..7a27741c33 100644
--- a/src/com/android/launcher3/model/CacheDataUpdatedTask.java
+++ b/src/com/android/launcher3/model/CacheDataUpdatedTask.java
@@ -77,7 +77,7 @@ public class CacheDataUpdatedTask extends BaseModelUpdateTask {
scheduleCallbackTask(new CallbackTask() {
@Override
public void execute(Callbacks callbacks) {
- callbacks.bindAppsUpdated(updatedApps);
+ callbacks.bindAppsAddedOrUpdated(updatedApps);
}
});
}
diff --git a/src/com/android/launcher3/model/LoaderResults.java b/src/com/android/launcher3/model/LoaderResults.java
index 0df8b6fee2..b7a6b68e83 100644
--- a/src/com/android/launcher3/model/LoaderResults.java
+++ b/src/com/android/launcher3/model/LoaderResults.java
@@ -122,7 +122,7 @@ public class LoaderResults {
filterCurrentWorkspaceItems(currentScreenId, workspaceItems, currentWorkspaceItems,
otherWorkspaceItems);
- filterCurrentAppWidgets(currentScreenId, appWidgets, currentAppWidgets,
+ filterCurrentWorkspaceItems(currentScreenId, appWidgets, currentAppWidgets,
otherAppWidgets);
sortWorkspaceItemsSpatially(currentWorkspaceItems);
sortWorkspaceItemsSpatially(otherWorkspaceItems);
@@ -208,12 +208,12 @@ 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,
- ArrayList allWorkspaceItems,
- ArrayList currentScreenItems,
- ArrayList otherScreenItems) {
+ private void filterCurrentWorkspaceItems(long currentScreenId,
+ ArrayList allWorkspaceItems,
+ ArrayList currentScreenItems,
+ ArrayList otherScreenItems) {
// Purge any null ItemInfos
- Iterator iter = allWorkspaceItems.iterator();
+ Iterator iter = allWorkspaceItems.iterator();
while (iter.hasNext()) {
ItemInfo i = iter.next();
if (i == null) {
@@ -224,14 +224,14 @@ public class LoaderResults {
// Order the set of items by their containers first, this allows use to walk through the
// list sequentially, build up a list of containers that are in the specified screen,
// as well as all items in those containers.
- Set itemsOnScreen = new HashSet();
+ Set itemsOnScreen = new HashSet<>();
Collections.sort(allWorkspaceItems, new Comparator() {
@Override
public int compare(ItemInfo lhs, ItemInfo rhs) {
return Utilities.longCompare(lhs.container, rhs.container);
}
});
- for (ItemInfo info : allWorkspaceItems) {
+ for (T info : allWorkspaceItems) {
if (info.container == LauncherSettings.Favorites.CONTAINER_DESKTOP) {
if (info.screenId == currentScreenId) {
currentScreenItems.add(info);
@@ -253,23 +253,6 @@ public class LoaderResults {
}
}
- /** Filters the set of widgets which are on the specified screen. */
- private void filterCurrentAppWidgets(long currentScreenId,
- ArrayList appWidgets,
- ArrayList currentScreenWidgets,
- ArrayList otherScreenWidgets) {
-
- for (LauncherAppWidgetInfo widget : appWidgets) {
- if (widget == null) continue;
- if (widget.container == LauncherSettings.Favorites.CONTAINER_DESKTOP &&
- widget.screenId == currentScreenId) {
- currentScreenWidgets.add(widget);
- } else {
- otherScreenWidgets.add(widget);
- }
- }
- }
-
/** Sorts the set of items by hotseat, workspace (spatially from top to bottom, left to
* right) */
private void sortWorkspaceItemsSpatially(ArrayList workspaceItems) {
@@ -322,7 +305,7 @@ public class LoaderResults {
public void run() {
Callbacks callbacks = mCallbacks.get();
if (callbacks != null) {
- callbacks.bindItems(workspaceItems, start, start+chunkSize, false);
+ callbacks.bindItems(workspaceItems.subList(start, start+chunkSize), false);
}
}
};
@@ -332,12 +315,12 @@ public class LoaderResults {
// Bind the widgets, one at a time
N = appWidgets.size();
for (int i = 0; i < N; i++) {
- final LauncherAppWidgetInfo widget = appWidgets.get(i);
+ final ItemInfo widget = appWidgets.get(i);
final Runnable r = new Runnable() {
public void run() {
Callbacks callbacks = mCallbacks.get();
if (callbacks != null) {
- callbacks.bindAppWidget(widget);
+ callbacks.bindItems(Collections.singletonList(widget), false);
}
}
};
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 1b2f8d63fa..6c78d5bfca 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -43,6 +43,7 @@ import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.util.LongArrayMap;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import java.util.ArrayList;
@@ -147,55 +148,32 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
break;
}
- ArrayList added = null;
- ArrayList modified = null;
- final ArrayList removedApps = new ArrayList<>();
+ final ArrayList addedOrModified = new ArrayList<>();
+ addedOrModified.addAll(appsList.added);
+ appsList.added.clear();
+ addedOrModified.addAll(appsList.modified);
+ appsList.modified.clear();
- if (appsList.added.size() > 0) {
- added = new ArrayList<>(appsList.added);
- appsList.added.clear();
- }
- if (appsList.modified.size() > 0) {
- modified = new ArrayList<>(appsList.modified);
- appsList.modified.clear();
- }
- if (appsList.removed.size() > 0) {
- removedApps.addAll(appsList.removed);
- appsList.removed.clear();
- }
+ final ArrayList removedApps = new ArrayList<>(appsList.removed);
+ appsList.removed.clear();
final ArrayMap addedOrUpdatedApps = new ArrayMap<>();
-
- if (added != null) {
- final ArrayList addedApps = added;
+ if (!addedOrModified.isEmpty()) {
scheduleCallbackTask(new CallbackTask() {
@Override
public void execute(Callbacks callbacks) {
- callbacks.bindAppsAdded(null, null, null, addedApps);
+ callbacks.bindAppsAddedOrUpdated(addedOrModified);
}
});
- for (AppInfo ai : added) {
+ for (AppInfo ai : addedOrModified) {
addedOrUpdatedApps.put(ai.componentName, ai);
}
}
- if (modified != null) {
- final ArrayList modifiedFinal = modified;
- for (AppInfo ai : modified) {
- addedOrUpdatedApps.put(ai.componentName, ai);
- }
- scheduleCallbackTask(new CallbackTask() {
- @Override
- public void execute(Callbacks callbacks) {
- callbacks.bindAppsUpdated(modifiedFinal);
- }
- });
- }
-
// Update shortcut infos
if (mOp == OP_ADD || flagOp != FlagOp.NO_OP) {
final ArrayList updatedShortcuts = new ArrayList<>();
- final ArrayList removedShortcuts = new ArrayList<>();
+ final LongArrayMap removedShortcuts = new LongArrayMap<>();
final ArrayList widgets = new ArrayList<>();
synchronized (dataModel) {
@@ -236,7 +214,7 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
}
if ((intent == null) || (appInfo == null)) {
- removedShortcuts.add(si);
+ removedShortcuts.put(si.id, true);
continue;
}
si.intent = intent;
@@ -290,9 +268,9 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
}
}
- bindUpdatedShortcuts(updatedShortcuts, removedShortcuts, mUser);
+ bindUpdatedShortcuts(updatedShortcuts, mUser);
if (!removedShortcuts.isEmpty()) {
- getModelWriter().deleteItemsFromDatabase(removedShortcuts);
+ deleteAndBindComponentsRemoved(ItemInfoMatcher.ofItemIds(removedShortcuts, false));
}
if (!widgets.isEmpty()) {
@@ -329,22 +307,12 @@ public class PackageUpdatedTask extends BaseModelUpdateTask {
}
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
- getModelWriter().deleteItemsFromDatabase(
- ItemInfoMatcher.ofPackages(removedPackages, mUser));
- getModelWriter().deleteItemsFromDatabase(
- ItemInfoMatcher.ofComponents(removedComponents, mUser));
+ ItemInfoMatcher removeMatch = ItemInfoMatcher.ofPackages(removedPackages, mUser)
+ .or(ItemInfoMatcher.ofComponents(removedComponents, mUser));
+ deleteAndBindComponentsRemoved(removeMatch);
// Remove any queued items from the install queue
InstallShortcutReceiver.removeFromInstallQueue(context, removedPackages, mUser);
-
- // Call the components-removed callback
- scheduleCallbackTask(new CallbackTask() {
- @Override
- public void execute(Callbacks callbacks) {
- callbacks.bindWorkspaceComponentsRemoved(
- removedPackages, removedComponents, mUser);
- }
- });
}
if (!removedApps.isEmpty()) {
diff --git a/src/com/android/launcher3/model/ShortcutsChangedTask.java b/src/com/android/launcher3/model/ShortcutsChangedTask.java
index 17cc238d42..c1f33a6b2c 100644
--- a/src/com/android/launcher3/model/ShortcutsChangedTask.java
+++ b/src/com/android/launcher3/model/ShortcutsChangedTask.java
@@ -26,9 +26,12 @@ import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.graphics.LauncherIcons;
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
+import com.android.launcher3.shortcuts.ShortcutKey;
+import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.MultiHashMap;
import java.util.ArrayList;
+import java.util.HashSet;
import java.util.List;
/**
@@ -56,33 +59,35 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask {
deepShortcutManager.onShortcutsChanged(mShortcuts);
// Find ShortcutInfo's that have changed on the workspace.
- final ArrayList removedShortcutInfos = new ArrayList<>();
- MultiHashMap idsToWorkspaceShortcutInfos = new MultiHashMap<>();
+ HashSet removedKeys = new HashSet<>();
+ MultiHashMap keyToShortcutInfo = new MultiHashMap<>();
+ HashSet allIds = new HashSet<>();
+
for (ItemInfo itemInfo : dataModel.itemsIdMap) {
if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT) {
ShortcutInfo si = (ShortcutInfo) itemInfo;
- if (si.getIntent().getPackage().equals(mPackageName)
- && si.user.equals(mUser)) {
- idsToWorkspaceShortcutInfos.addToList(si.getDeepShortcutId(), si);
+ if (si.getIntent().getPackage().equals(mPackageName) && si.user.equals(mUser)) {
+ keyToShortcutInfo.addToList(ShortcutKey.fromItemInfo(si), si);
+ allIds.add(si.getDeepShortcutId());
}
}
}
final ArrayList updatedShortcutInfos = new ArrayList<>();
- if (!idsToWorkspaceShortcutInfos.isEmpty()) {
+ if (!keyToShortcutInfo.isEmpty()) {
// Update the workspace to reflect the changes to updated shortcuts residing on it.
List shortcuts = deepShortcutManager.queryForFullDetails(
- mPackageName, new ArrayList<>(idsToWorkspaceShortcutInfos.keySet()), mUser);
+ mPackageName, new ArrayList<>(allIds), mUser);
for (ShortcutInfoCompat fullDetails : shortcuts) {
- List shortcutInfos = idsToWorkspaceShortcutInfos
- .remove(fullDetails.getId());
+ ShortcutKey key = ShortcutKey.fromInfo(fullDetails);
+ List shortcutInfos = keyToShortcutInfo.remove(key);
if (!fullDetails.isPinned()) {
// The shortcut was previously pinned but is no longer, so remove it from
// the workspace and our pinned shortcut counts.
// Note that we put this check here, after querying for full details,
// because there's a possible race condition between pinning and
// receiving this callback.
- removedShortcutInfos.addAll(shortcutInfos);
+ removedKeys.add(key);
continue;
}
for (final ShortcutInfo shortcutInfo : shortcutInfos) {
@@ -94,16 +99,14 @@ public class ShortcutsChangedTask extends BaseModelUpdateTask {
}
}
- // If there are still entries in idsToWorkspaceShortcutInfos, that means that
+ // If there are still entries in keyToShortcutInfo, that means that
// the corresponding shortcuts weren't passed in onShortcutsChanged(). This
// means they were cleared, so we remove and unpin them now.
- for (String id : idsToWorkspaceShortcutInfos.keySet()) {
- removedShortcutInfos.addAll(idsToWorkspaceShortcutInfos.get(id));
- }
+ removedKeys.addAll(keyToShortcutInfo.keySet());
- bindUpdatedShortcuts(updatedShortcutInfos, removedShortcutInfos, mUser);
- if (!removedShortcutInfos.isEmpty()) {
- getModelWriter().deleteItemsFromDatabase(removedShortcutInfos);
+ bindUpdatedShortcuts(updatedShortcutInfos, mUser);
+ if (!keyToShortcutInfo.isEmpty()) {
+ deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(removedKeys));
}
if (mUpdateIdMap) {
diff --git a/src/com/android/launcher3/model/UserLockStateChangedTask.java b/src/com/android/launcher3/model/UserLockStateChangedTask.java
index 802771f048..8170f9a67f 100644
--- a/src/com/android/launcher3/model/UserLockStateChangedTask.java
+++ b/src/com/android/launcher3/model/UserLockStateChangedTask.java
@@ -29,9 +29,11 @@ import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.ShortcutInfoCompat;
import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.util.ComponentKey;
+import com.android.launcher3.util.ItemInfoMatcher;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
@@ -70,17 +72,19 @@ public class UserLockStateChangedTask extends BaseModelUpdateTask {
// Update the workspace to reflect the changes to updated shortcuts residing on it.
ArrayList updatedShortcutInfos = new ArrayList<>();
- ArrayList deletedShortcutInfos = new ArrayList<>();
+ HashSet removedKeys = new HashSet<>();
+
for (ItemInfo itemInfo : dataModel.itemsIdMap) {
if (itemInfo.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
&& mUser.equals(itemInfo.user)) {
ShortcutInfo si = (ShortcutInfo) itemInfo;
if (isUserUnlocked) {
- ShortcutInfoCompat shortcut = pinnedShortcuts.get(ShortcutKey.fromItemInfo(si));
+ ShortcutKey key = ShortcutKey.fromItemInfo(si);
+ ShortcutInfoCompat shortcut = pinnedShortcuts.get(key);
// We couldn't verify the shortcut during loader. If its no longer available
// (probably due to clear data), delete the workspace item as well
if (shortcut == null) {
- deletedShortcutInfos.add(si);
+ removedKeys.add(key);
continue;
}
si.isDisabled &= ~ShortcutInfo.FLAG_DISABLED_LOCKED_USER;
@@ -93,9 +97,9 @@ public class UserLockStateChangedTask extends BaseModelUpdateTask {
updatedShortcutInfos.add(si);
}
}
- bindUpdatedShortcuts(updatedShortcutInfos, deletedShortcutInfos, mUser);
- if (!deletedShortcutInfos.isEmpty()) {
- getModelWriter().deleteItemsFromDatabase(deletedShortcutInfos);
+ bindUpdatedShortcuts(updatedShortcutInfos, mUser);
+ if (!removedKeys.isEmpty()) {
+ deleteAndBindComponentsRemoved(ItemInfoMatcher.ofShortcutKeys(removedKeys));
}
// Remove shortcut id map for that user
diff --git a/src/com/android/launcher3/notification/NotificationListener.java b/src/com/android/launcher3/notification/NotificationListener.java
index 73d89aa189..6a7098915a 100644
--- a/src/com/android/launcher3/notification/NotificationListener.java
+++ b/src/com/android/launcher3/notification/NotificationListener.java
@@ -30,15 +30,20 @@ import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Log;
import android.util.Pair;
+
import com.android.launcher3.LauncherModel;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.SettingsObserver;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Set;
+import static com.android.launcher3.SettingsActivity.NOTIFICATION_BADGING;
+
/**
* A {@link NotificationListenerService} that sends updates to its
* {@link NotificationsChangedListener} when notifications are posted or canceled,
@@ -57,12 +62,14 @@ public class NotificationListener extends NotificationListenerService {
private static NotificationListener sNotificationListenerInstance = null;
private static NotificationsChangedListener sNotificationsChangedListener;
private static boolean sIsConnected;
+ private static boolean sIsCreated;
private final Handler mWorkerHandler;
private final Handler mUiHandler;
-
private final Ranking mTempRanking = new Ranking();
+ private SettingsObserver mNotificationBadgingObserver;
+
private final Handler.Callback mWorkerCallback = new Handler.Callback() {
@Override
public boolean handleMessage(Message message) {
@@ -77,7 +84,7 @@ public class NotificationListener extends NotificationListenerService {
List activeNotifications;
if (sIsConnected) {
try {
- activeNotifications = filterNotifications(getActiveNotifications());
+ activeNotifications = filterNotifications(getActiveNotifications());
} catch (SecurityException ex) {
Log.e(TAG, "SecurityException: failed to fetch notifications");
activeNotifications = new ArrayList();
@@ -130,6 +137,28 @@ public class NotificationListener extends NotificationListenerService {
sNotificationListenerInstance = this;
}
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ sIsCreated = true;
+ mNotificationBadgingObserver = new SettingsObserver.Secure(getContentResolver()) {
+ @Override
+ public void onSettingChanged(boolean isNotificationBadgingEnabled) {
+ if (!isNotificationBadgingEnabled) {
+ requestUnbind();
+ }
+ }
+ };
+ mNotificationBadgingObserver.register(NOTIFICATION_BADGING);
+ }
+
+ @Override
+ public void onDestroy() {
+ super.onDestroy();
+ sIsCreated = false;
+ mNotificationBadgingObserver.unregister();
+ }
+
public static @Nullable NotificationListener getInstanceIfConnected() {
return sIsConnected ? sNotificationListenerInstance : null;
}
@@ -143,6 +172,11 @@ public class NotificationListener extends NotificationListenerService {
NotificationListener notificationListener = getInstanceIfConnected();
if (notificationListener != null) {
notificationListener.onNotificationFullRefresh();
+ } else if (!sIsCreated && sNotificationsChangedListener != null) {
+ // User turned off badging globally, so we unbound this service;
+ // tell the listener that there are no notifications to remove dots.
+ sNotificationsChangedListener.onNotificationFullRefresh(
+ Collections.emptyList());
}
}
@@ -205,7 +239,7 @@ public class NotificationListener extends NotificationListenerService {
.getActiveNotifications(NotificationKeyData.extractKeysOnly(keys)
.toArray(new String[keys.size()]));
return notifications == null
- ? Collections.emptyList() : Arrays.asList(notifications);
+ ? Collections.emptyList() : Arrays.asList(notifications);
}
/**
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index 42de284665..18787b6a2a 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -18,6 +18,7 @@ package com.android.launcher3.util;
import android.content.ComponentName;
import android.os.UserHandle;
+import android.util.SparseLongArray;
import com.android.launcher3.FolderInfo;
import com.android.launcher3.ItemInfo;
@@ -66,6 +67,32 @@ public abstract class ItemInfoMatcher {
return filtered;
}
+ /**
+ * Returns a new matcher with returns true if either this or {@param matcher} returns true.
+ */
+ public ItemInfoMatcher or(final ItemInfoMatcher matcher) {
+ final ItemInfoMatcher that = this;
+ return new ItemInfoMatcher() {
+ @Override
+ public boolean matches(ItemInfo info, ComponentName cn) {
+ return that.matches(info, cn) || matcher.matches(info, cn);
+ }
+ };
+ }
+
+ /**
+ * Returns a new matcher with returns true if both this and {@param matcher} returns true.
+ */
+ public ItemInfoMatcher and(final ItemInfoMatcher matcher) {
+ final ItemInfoMatcher that = this;
+ return new ItemInfoMatcher() {
+ @Override
+ public boolean matches(ItemInfo info, ComponentName cn) {
+ return that.matches(info, cn) && matcher.matches(info, cn);
+ }
+ };
+ }
+
public static ItemInfoMatcher ofUser(final UserHandle user) {
return new ItemInfoMatcher() {
@Override
@@ -104,4 +131,14 @@ public abstract class ItemInfoMatcher {
}
};
}
+
+ public static ItemInfoMatcher ofItemIds(
+ final LongArrayMap ids, final Boolean matchDefault) {
+ return new ItemInfoMatcher() {
+ @Override
+ public boolean matches(ItemInfo info, ComponentName cn) {
+ return ids.get(info.id, matchDefault);
+ }
+ };
+ }
}
diff --git a/src/com/android/launcher3/util/RunnableWithId.java b/src/com/android/launcher3/util/RunnableWithId.java
new file mode 100644
index 0000000000..030eb09ff3
--- /dev/null
+++ b/src/com/android/launcher3/util/RunnableWithId.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2017 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.util;
+
+/**
+ * A runnable with an id associated which is used for equality check.
+ */
+public abstract class RunnableWithId implements Runnable {
+
+ public static final int RUNNABLE_ID_BIND_APPS = 1;
+ public static final int RUNNABLE_ID_BIND_WIDGETS = 2;
+
+ public final int id;
+
+ public RunnableWithId(int id) {
+ this.id = id;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj instanceof RunnableWithId && ((RunnableWithId) obj).id == id;
+ }
+}
diff --git a/src/com/android/launcher3/util/SettingsObserver.java b/src/com/android/launcher3/util/SettingsObserver.java
new file mode 100644
index 0000000000..6baa24293e
--- /dev/null
+++ b/src/com/android/launcher3/util/SettingsObserver.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2017 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.util;
+
+import android.content.ContentResolver;
+import android.database.ContentObserver;
+import android.os.Handler;
+import android.provider.Settings;
+
+public interface SettingsObserver {
+
+ /**
+ * Registers the content observer to call {@link #onSettingChanged(boolean)} when any of the
+ * passed settings change. The value passed to onSettingChanged() is based on the key setting.
+ */
+ void register(String keySetting, String ... dependentSettings);
+ void unregister();
+ void onSettingChanged(boolean keySettingEnabled);
+
+
+ abstract class Secure extends ContentObserver implements SettingsObserver {
+ private ContentResolver mResolver;
+ private String mKeySetting;
+
+ public Secure(ContentResolver resolver) {
+ super(new Handler());
+ mResolver = resolver;
+ }
+
+ @Override
+ public void register(String keySetting, String ... dependentSettings) {
+ mKeySetting = keySetting;
+ mResolver.registerContentObserver(
+ Settings.Secure.getUriFor(mKeySetting), false, this);
+ for (String setting : dependentSettings) {
+ mResolver.registerContentObserver(
+ Settings.Secure.getUriFor(setting), false, this);
+ }
+ onChange(true);
+ }
+
+ @Override
+ public void unregister() {
+ mResolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ onSettingChanged(Settings.Secure.getInt(mResolver, mKeySetting, 1) == 1);
+ }
+ }
+
+ abstract class System extends ContentObserver implements SettingsObserver {
+ private ContentResolver mResolver;
+ private String mKeySetting;
+
+ public System(ContentResolver resolver) {
+ super(new Handler());
+ mResolver = resolver;
+ }
+
+ @Override
+ public void register(String keySetting, String ... dependentSettings) {
+ mKeySetting = keySetting;
+ mResolver.registerContentObserver(
+ Settings.System.getUriFor(mKeySetting), false, this);
+ for (String setting : dependentSettings) {
+ mResolver.registerContentObserver(
+ Settings.System.getUriFor(setting), false, this);
+ }
+ onChange(true);
+ }
+
+ @Override
+ public void unregister() {
+ mResolver.unregisterContentObserver(this);
+ }
+
+ @Override
+ public void onChange(boolean selfChange) {
+ super.onChange(selfChange);
+ onSettingChanged(Settings.System.getInt(mResolver, mKeySetting, 1) == 1);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/util/SystemUiController.java b/src/com/android/launcher3/util/SystemUiController.java
index 6b5b095c78..d7a2625e94 100644
--- a/src/com/android/launcher3/util/SystemUiController.java
+++ b/src/com/android/launcher3/util/SystemUiController.java
@@ -30,6 +30,7 @@ public class SystemUiController {
public static final int UI_STATE_BASE_WINDOW = 0;
public static final int UI_STATE_ALL_APPS = 1;
public static final int UI_STATE_WIDGET_BOTTOM_SHEET = 2;
+ public static final int UI_STATE_ROOT_VIEW = 3;
public static final int FLAG_LIGHT_NAV = 1 << 0;
public static final int FLAG_DARK_NAV = 1 << 1;
@@ -37,7 +38,7 @@ public class SystemUiController {
public static final int FLAG_DARK_STATUS = 1 << 3;
private final Window mWindow;
- private final int[] mStates = new int[3];
+ private final int[] mStates = new int[4];
public SystemUiController(Window window) {
mWindow = window;
diff --git a/src/com/android/launcher3/util/ViewOnDrawExecutor.java b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
index 4cb6ca8314..e5c1dd1b43 100644
--- a/src/com/android/launcher3/util/ViewOnDrawExecutor.java
+++ b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
@@ -16,11 +16,13 @@
package com.android.launcher3.util;
+import android.os.Process;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewTreeObserver.OnDrawListener;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherModel;
import java.util.ArrayList;
import java.util.concurrent.Executor;
@@ -37,6 +39,7 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable,
private Launcher mLauncher;
private View mAttachedView;
private boolean mCompleted;
+ private boolean mIsExecuting;
private boolean mLoadAnimationCompleted;
private boolean mFirstDrawCompleted;
@@ -62,6 +65,7 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable,
@Override
public void execute(Runnable command) {
mTasks.add(command);
+ LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_BACKGROUND);
}
@Override
@@ -78,6 +82,13 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable,
mAttachedView.post(this);
}
+ /**
+ * Returns whether the executor is still queuing tasks and hasn't yet executed them.
+ */
+ public boolean canQueue() {
+ return !mIsExecuting && !mCompleted;
+ }
+
public void onLoadAnimationCompleted() {
mLoadAnimationCompleted = true;
if (mAttachedView != null) {
@@ -89,6 +100,7 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable,
public void run() {
// Post the pending tasks after both onDraw and onLoadAnimationCompleted have been called.
if (mLoadAnimationCompleted && mFirstDrawCompleted && !mCompleted) {
+ mIsExecuting = true;
for (final Runnable r : mTasks) {
mExecutor.execute(r);
}
@@ -99,6 +111,7 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable,
public void markCompleted() {
mTasks.clear();
mCompleted = true;
+ mIsExecuting = false;
if (mAttachedView != null) {
mAttachedView.getViewTreeObserver().removeOnDrawListener(this);
mAttachedView.removeOnAttachStateChangeListener(this);
@@ -106,5 +119,6 @@ public class ViewOnDrawExecutor implements Executor, OnDrawListener, Runnable,
if (mLauncher != null) {
mLauncher.clearPendingExecutor(this);
}
+ LauncherModel.setWorkerPriority(Process.THREAD_PRIORITY_DEFAULT);
}
}
diff --git a/src/com/android/launcher3/views/ButtonPreference.java b/src/com/android/launcher3/views/ButtonPreference.java
index 4697e25e44..fdcf2ca5ba 100644
--- a/src/com/android/launcher3/views/ButtonPreference.java
+++ b/src/com/android/launcher3/views/ButtonPreference.java
@@ -28,7 +28,7 @@ import android.view.ViewGroup;
*/
public class ButtonPreference extends Preference {
- private View.OnClickListener mClickListener;
+ private boolean mWidgetFrameVisible = false;
public ButtonPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
@@ -46,9 +46,9 @@ public class ButtonPreference extends Preference {
super(context);
}
- public void setButtonOnClickListener(View.OnClickListener clickListener) {
- if (mClickListener != clickListener) {
- mClickListener = clickListener;
+ public void setWidgetFrameVisible(boolean isVisible) {
+ if (mWidgetFrameVisible != isVisible) {
+ mWidgetFrameVisible = isVisible;
notifyChanged();
}
}
@@ -59,12 +59,7 @@ public class ButtonPreference extends Preference {
ViewGroup widgetFrame = view.findViewById(android.R.id.widget_frame);
if (widgetFrame != null) {
- View button = widgetFrame.getChildAt(0);
- if (button != null) {
- button.setOnClickListener(mClickListener);
- }
- widgetFrame.setVisibility(
- (mClickListener == null || button == null) ? View.GONE : View.VISIBLE);
+ widgetFrame.setVisibility(mWidgetFrameVisible ? View.VISIBLE : View.GONE);
}
}
}
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 0b4bf628e9..01101ac74c 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -88,7 +88,8 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
mScrollInterpolator = new SwipeDetector.ScrollInterpolator();
mInsets = new Rect();
mSwipeDetector = new SwipeDetector(context, this, SwipeDetector.VERTICAL);
- mGradientBackground = (GradientView) mLauncher.findViewById(R.id.gradient_bg);
+ mGradientBackground = (GradientView) mLauncher.getLayoutInflater().inflate(
+ R.layout.gradient_bg, mLauncher.getDragLayer(), false);
}
@Override
@@ -106,6 +107,8 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
onWidgetsBound();
+ mLauncher.getDragLayer().addView(mGradientBackground);
+ mGradientBackground.setVisibility(VISIBLE);
mLauncher.getDragLayer().addView(this);
measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED);
setTranslationY(mTranslationYClosed);
@@ -212,11 +215,8 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- mIsOpen = false;
mSwipeDetector.finishedScrolling();
- ((ViewGroup) getParent()).removeView(WidgetsBottomSheet.this);
- mLauncher.getSystemUiController().updateUiState(
- SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
+ onCloseComplete();
}
});
mOpenCloseAnimator.setInterpolator(mSwipeDetector.isIdleState()
@@ -224,12 +224,18 @@ public class WidgetsBottomSheet extends AbstractFloatingView implements Insettab
mOpenCloseAnimator.start();
} else {
setTranslationY(mTranslationYClosed);
- mLauncher.getSystemUiController().updateUiState(
- SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
- mIsOpen = false;
+ onCloseComplete();
}
}
+ private void onCloseComplete() {
+ mIsOpen = false;
+ mLauncher.getDragLayer().removeView(mGradientBackground);
+ mLauncher.getDragLayer().removeView(WidgetsBottomSheet.this);
+ mLauncher.getSystemUiController().updateUiState(
+ SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
+ }
+
@Override
protected boolean isOfType(@FloatingViewType int type) {
return (type & TYPE_WIDGETS_BOTTOM_SHEET) != 0;
diff --git a/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java b/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java
deleted file mode 100644
index 230d623e90..0000000000
--- a/tests/src/com/android/launcher3/InvariantDeviceProfileTest.java
+++ /dev/null
@@ -1,119 +0,0 @@
-/*
- * Copyright (C) 2015 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;
-
-import android.content.res.Resources;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-import android.util.Log;
-
-import java.util.ArrayList;
-
-/**
- * Tests the {@link DeviceProfile} and {@link InvariantDeviceProfile}.
- */
-@SmallTest
-public class InvariantDeviceProfileTest extends AndroidTestCase {
-
- private static final String TAG = "DeviceProfileTest";
- private static final boolean DEBUG = false;
-
- private InvariantDeviceProfile mInvariantProfile;
- private ArrayList mPredefinedDeviceProfiles;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mInvariantProfile = new InvariantDeviceProfile(getContext());
- mPredefinedDeviceProfiles = mInvariantProfile.getPredefinedDeviceProfiles(getContext());
- }
-
- @Override
- protected void tearDown() throws Exception {
- // Nothing to tear down as this class only tests static methods.
- }
-
- public void testFindClosestDeviceProfile2() {
- for (InvariantDeviceProfile idf: mPredefinedDeviceProfiles) {
- ArrayList predefinedProfilesCopy =
- new ArrayList<>(mPredefinedDeviceProfiles);
- ArrayList closestProfiles =
- mInvariantProfile.findClosestDeviceProfiles(
- idf.minWidthDps, idf.minHeightDps, predefinedProfilesCopy
- );
- assertTrue(closestProfiles.get(0).equals(idf));
- }
- }
-
- /**
- * Used to print out how the invDistWeightedInterpolate works between device profiles to
- * tweak the two constants that control how the interpolation curve is shaped.
- */
- public void testInvInterpolation() {
-
- InvariantDeviceProfile p1 = mPredefinedDeviceProfiles.get(7); // e.g., Large Phone
- InvariantDeviceProfile p2 = mPredefinedDeviceProfiles.get(8); // e.g., Nexus 7
-
- ArrayList pts = createInterpolatedPoints(
- new PointF(p1.minWidthDps, p1.minHeightDps),
- new PointF(p2.minWidthDps, p2.minHeightDps),
- 20f);
-
- for (int i = 0; i < pts.size(); i++) {
- ArrayList closestProfiles =
- mInvariantProfile.findClosestDeviceProfiles(
- pts.get(i).x, pts.get(i).y, mPredefinedDeviceProfiles);
- InvariantDeviceProfile result =
- mInvariantProfile.invDistWeightedInterpolate(
- pts.get(i).x, pts.get(i).y, closestProfiles);
- if (DEBUG) {
- Log.d(TAG, String.format("width x height = (%f, %f)] iconSize = %f",
- pts.get(i).x, pts.get(i).y, result.iconSize));
- }
- }
- }
-
- private ArrayList createInterpolatedPoints(PointF a, PointF b, float numPts) {
- ArrayList result = new ArrayList();
- result.add(a);
- for (float i = 1; i < numPts; i = i + 1.0f) {
- result.add(new PointF((b.x * i + a.x * (numPts - i)) / numPts,
- (b.y * i + a.y * (numPts - i)) / numPts));
- }
- result.add(b);
- return result;
- }
-
- /**
- * Ensures that system calls (e.g., WindowManager, DisplayMetrics) that require contexts are
- * properly working to generate minimum width and height of the display.
- */
- public void test_hammerhead() {
- if (!android.os.Build.DEVICE.equals("hammerhead")) {
- return;
- }
- assertEquals(4, mInvariantProfile.numRows);
- assertEquals(4, mInvariantProfile.numColumns);
- assertEquals(5, mInvariantProfile.numHotseatIcons);
- }
-
- // Add more tests for other devices, however, running them once on a single device is enough
- // for verifying that for a platform version, the WindowManager and DisplayMetrics is
- // working as intended.
-}
diff --git a/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java b/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
index 26ec69b1c7..846a163700 100644
--- a/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
+++ b/tests/src/com/android/launcher3/allapps/search/DefaultAppSearchAlgorithmTest.java
@@ -16,85 +16,78 @@
package com.android.launcher3.allapps.search;
import android.content.ComponentName;
-import android.test.InstrumentationTestCase;
+import android.support.test.runner.AndroidJUnit4;
import com.android.launcher3.AppInfo;
import com.android.launcher3.Utilities;
-import java.util.ArrayList;
-import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
/**
* Unit tests for {@link DefaultAppSearchAlgorithm}
*/
-public class DefaultAppSearchAlgorithmTest extends InstrumentationTestCase {
-
- private List mAppsList;
- private DefaultAppSearchAlgorithm mAlgorithm;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- mAppsList = new ArrayList<>();
- getInstrumentation().runOnMainSync(new Runnable() {
- @Override
- public void run() {
- mAlgorithm = new DefaultAppSearchAlgorithm(mAppsList);
- }
- });
- }
+@RunWith(AndroidJUnit4.class)
+public class DefaultAppSearchAlgorithmTest {
+ private static final DefaultAppSearchAlgorithm.StringMatcher MATCHER =
+ DefaultAppSearchAlgorithm.StringMatcher.getInstance();
+ @Test
public void testMatches() {
- assertTrue(mAlgorithm.matches(getInfo("white cow"), "cow"));
- assertTrue(mAlgorithm.matches(getInfo("whiteCow"), "cow"));
- assertTrue(mAlgorithm.matches(getInfo("whiteCOW"), "cow"));
- assertTrue(mAlgorithm.matches(getInfo("whitecowCOW"), "cow"));
- assertTrue(mAlgorithm.matches(getInfo("white2cow"), "cow"));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("white cow"), "cow", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("whiteCow"), "cow", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("whiteCOW"), "cow", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("whitecowCOW"), "cow", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("white2cow"), "cow", MATCHER));
- assertFalse(mAlgorithm.matches(getInfo("whitecow"), "cow"));
- assertFalse(mAlgorithm.matches(getInfo("whitEcow"), "cow"));
+ assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("whitecow"), "cow", MATCHER));
+ assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("whitEcow"), "cow", MATCHER));
- assertTrue(mAlgorithm.matches(getInfo("whitecowCow"), "cow"));
- assertTrue(mAlgorithm.matches(getInfo("whitecow cow"), "cow"));
- assertFalse(mAlgorithm.matches(getInfo("whitecowcow"), "cow"));
- assertFalse(mAlgorithm.matches(getInfo("whit ecowcow"), "cow"));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("whitecowCow"), "cow", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("whitecow cow"), "cow", MATCHER));
+ assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("whitecowcow"), "cow", MATCHER));
+ assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("whit ecowcow"), "cow", MATCHER));
- assertTrue(mAlgorithm.matches(getInfo("cats&dogs"), "dog"));
- assertTrue(mAlgorithm.matches(getInfo("cats&Dogs"), "dog"));
- assertTrue(mAlgorithm.matches(getInfo("cats&Dogs"), "&"));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("cats&dogs"), "dog", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("cats&Dogs"), "dog", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("cats&Dogs"), "&", MATCHER));
- assertTrue(mAlgorithm.matches(getInfo("2+43"), "43"));
- assertFalse(mAlgorithm.matches(getInfo("2+43"), "3"));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("2+43"), "43", MATCHER));
+ assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("2+43"), "3", MATCHER));
- assertTrue(mAlgorithm.matches(getInfo("Q"), "q"));
- assertTrue(mAlgorithm.matches(getInfo(" Q"), "q"));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("Q"), "q", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo(" Q"), "q", MATCHER));
// match lower case words
- assertTrue(mAlgorithm.matches(getInfo("elephant"), "e"));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("elephant"), "e", MATCHER));
- assertTrue(mAlgorithm.matches(getInfo("电子邮件"), "电"));
- assertTrue(mAlgorithm.matches(getInfo("电子邮件"), "电子"));
- assertFalse(mAlgorithm.matches(getInfo("电子邮件"), "子"));
- assertFalse(mAlgorithm.matches(getInfo("电子邮件"), "邮件"));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("电子邮件"), "电", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("电子邮件"), "电子", MATCHER));
+ assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("电子邮件"), "子", MATCHER));
+ assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("电子邮件"), "邮件", MATCHER));
- assertFalse(mAlgorithm.matches(getInfo("Bot"), "ba"));
- assertFalse(mAlgorithm.matches(getInfo("bot"), "ba"));
+ assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("Bot"), "ba", MATCHER));
+ assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("bot"), "ba", MATCHER));
}
+ @Test
public void testMatchesVN() {
if (!Utilities.ATLEAST_NOUGAT) {
return;
}
- assertTrue(mAlgorithm.matches(getInfo("다운로드"), "다"));
- assertTrue(mAlgorithm.matches(getInfo("드라이브"), "드"));
- assertTrue(mAlgorithm.matches(getInfo("다운로드 드라이브"), "ㄷ"));
- assertTrue(mAlgorithm.matches(getInfo("운로 드라이브"), "ㄷ"));
- assertTrue(mAlgorithm.matches(getInfo("abc"), "åbç"));
- assertTrue(mAlgorithm.matches(getInfo("Alpha"), "ål"));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("다운로드"), "다", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("드라이브"), "드", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("다운로드 드라이브"), "ㄷ", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("운로 드라이브"), "ㄷ", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("abc"), "åbç", MATCHER));
+ assertTrue(DefaultAppSearchAlgorithm.matches(getInfo("Alpha"), "ål", MATCHER));
- assertFalse(mAlgorithm.matches(getInfo("다운로드 드라이브"), "ㄷㄷ"));
- assertFalse(mAlgorithm.matches(getInfo("로드라이브"), "ㄷ"));
- assertFalse(mAlgorithm.matches(getInfo("abc"), "åç"));
+ assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("다운로드 드라이브"), "ㄷㄷ", MATCHER));
+ assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("로드라이브"), "ㄷ", MATCHER));
+ assertFalse(DefaultAppSearchAlgorithm.matches(getInfo("abc"), "åç", MATCHER));
}
private AppInfo getInfo(String title) {
diff --git a/tests/src/com/android/launcher3/logging/FileLogTest.java b/tests/src/com/android/launcher3/logging/FileLogTest.java
index c24cc3fb77..7048c2868c 100644
--- a/tests/src/com/android/launcher3/logging/FileLogTest.java
+++ b/tests/src/com/android/launcher3/logging/FileLogTest.java
@@ -37,6 +37,9 @@ public class FileLogTest extends AndroidTestCase {
}
public void testPrintLog() throws Exception {
+ if (!FileLog.ENABLED) {
+ return;
+ }
FileLog.print("Testing", "hoolalala");
StringWriter writer = new StringWriter();
FileLog.flushAll(new PrintWriter(writer));
@@ -54,6 +57,9 @@ public class FileLogTest extends AndroidTestCase {
}
public void testOldFileTruncated() throws Exception {
+ if (!FileLog.ENABLED) {
+ return;
+ }
FileLog.print("Testing", "hoolalala");
StringWriter writer = new StringWriter();
FileLog.flushAll(new PrintWriter(writer));
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
index 4c80902f00..82f34e43de 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
+++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.java
@@ -20,9 +20,9 @@ import com.android.launcher3.util.Provider;
import org.mockito.ArgumentCaptor;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
+import static org.mockito.Matchers.isNull;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -131,7 +131,7 @@ public class AddWorkspaceItemsTaskTest extends BaseModelUpdateTaskTestCase {
// only info2 should be added because info was already added to the workspace
// in setupWorkspaceWithHoles()
verify(callbacks).bindAppsAdded(any(ArrayList.class), notAnimated.capture(),
- animated.capture(), any(ArrayList.class));
+ animated.capture());
assertTrue(notAnimated.getValue().isEmpty());
assertEquals(1, animated.getValue().size());
diff --git a/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
similarity index 80%
rename from tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
rename to tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 47b43f530e..1be33d2f86 100644
--- a/tests/src/com/android/launcher3/ui/LauncherInstrumentationTestCase.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -15,29 +15,26 @@
*/
package com.android.launcher3.ui;
+import android.app.Instrumentation;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
+import android.content.pm.LauncherActivityInfo;
import android.graphics.Point;
-import android.os.ParcelFileDescriptor;
import android.os.Process;
import android.os.RemoteException;
import android.os.SystemClock;
+import android.support.test.InstrumentationRegistry;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.BySelector;
import android.support.test.uiautomator.Direction;
import android.support.test.uiautomator.UiDevice;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
-import android.test.InstrumentationTestCase;
import android.view.MotionEvent;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
@@ -45,25 +42,26 @@ import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.testcomponent.AppWidgetNoConfig;
import com.android.launcher3.testcomponent.AppWidgetWithConfig;
import com.android.launcher3.util.ManagedProfileHeuristic;
-import java.io.BufferedReader;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import java.util.ArrayList;
+import org.junit.Before;
+
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+
/**
* Base class for all instrumentation tests providing various utility methods.
*/
-public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
+public abstract class AbstractLauncherUiTest {
public static final long DEFAULT_ACTIVITY_TIMEOUT = TimeUnit.SECONDS.toMillis(10);
public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5;
@@ -71,16 +69,15 @@ public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
public static final long DEFAULT_UI_TIMEOUT = 3000;
public static final long DEFAULT_WORKER_TIMEOUT_SECS = 5;
+ protected MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
protected UiDevice mDevice;
protected Context mTargetContext;
protected String mTargetPackage;
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
+ @Before
+ public void setUp() throws Exception {
mDevice = UiDevice.getInstance(getInstrumentation());
- mTargetContext = getInstrumentation().getTargetContext();
+ mTargetContext = InstrumentationRegistry.getTargetContext();
mTargetPackage = mTargetContext.getPackageName();
}
@@ -97,57 +94,16 @@ public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
}
}
- /**
- * Starts the launcher activity in the target package and returns the Launcher instance.
- */
- protected Launcher startLauncher() {
- return (Launcher) getInstrumentation().startActivitySync(getHomeIntent());
- }
-
- protected Intent getHomeIntent() {
- return new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME)
- .setPackage(mTargetPackage)
- .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- }
-
- /**
- * Grants the launcher permission to bind widgets.
- */
- protected void grantWidgetPermission() throws IOException {
- // Check bind widget permission
- if (mTargetContext.getPackageManager().checkPermission(
- mTargetPackage, android.Manifest.permission.BIND_APPWIDGET)
- != PackageManager.PERMISSION_GRANTED) {
- runShellCommand("appwidget grantbind --package " + mTargetPackage);
- }
- }
-
- /**
- * Sets the target launcher as default launcher.
- */
- protected void setDefaultLauncher() throws IOException {
- ActivityInfo launcher = mTargetContext.getPackageManager()
- .queryIntentActivities(getHomeIntent(), 0).get(0).activityInfo;
- runShellCommand("cmd package set-home-activity " +
- new ComponentName(launcher.packageName, launcher.name).flattenToString());
- }
-
- protected void runShellCommand(String command) throws IOException {
- ParcelFileDescriptor pfd = getInstrumentation().getUiAutomation()
- .executeShellCommand(command);
-
- // Read the input stream fully.
- FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
- while (fis.read() != -1);
- fis.close();
+ protected Instrumentation getInstrumentation() {
+ return InstrumentationRegistry.getInstrumentation();
}
/**
* Opens all apps and returns the recycler view
*/
protected UiObject2 openAllApps() {
- if (FeatureFlags.LAUNCHER3_ALL_APPS_PULL_UP) {
+ mDevice.waitForIdle();
+ if (FeatureFlags.NO_ALL_APPS_ICON) {
// clicking on the page indicator brings up all apps tray on non tablets.
findViewById(R.id.page_indicator).click();
} else {
@@ -262,7 +218,7 @@ public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
protected void resetLoaderState() {
try {
- runTestOnUiThread(new Runnable() {
+ mMainThreadExecutor.execute(new Runnable() {
@Override
public void run() {
ManagedProfileHeuristic.markExistingUsersForNoFolderCreation(mTargetContext);
@@ -279,7 +235,7 @@ public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
*/
protected T getOnUiThread(final Callable callback) {
try {
- return new MainThreadExecutor().submit(callback).get();
+ return mMainThreadExecutor.submit(callback).get();
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -315,6 +271,10 @@ public class LauncherInstrumentationTestCase extends InstrumentationTestCase {
return By.res(mTargetPackage, name);
}
+ protected LauncherActivityInfo getSettingsApp() {
+ return LauncherAppsCompat.getInstance(mTargetContext)
+ .getActivityList("com.android.settings", Process.myUserHandle()).get(0);
+ }
/**
* Broadcast receiver which blocks until the result is received.
diff --git a/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java b/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
index 0ced7cf33a..46343a3894 100644
--- a/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
+++ b/tests/src/com/android/launcher3/ui/AllAppsAppLaunchTest.java
@@ -1,52 +1,55 @@
package com.android.launcher3.ui;
import android.content.pm.LauncherActivityInfo;
-import android.os.Process;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.LargeTest;
-import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.LauncherActivityRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
/**
* Test for verifying apps is launched from all-apps
*/
@LargeTest
-public class AllAppsAppLaunchTest extends LauncherInstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AllAppsAppLaunchTest extends AbstractLauncherUiTest {
- private LauncherActivityInfo mSettingsApp;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
- .getActivityList("com.android.settings", Process.myUserHandle()).get(0);
- }
+ @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+ @Test
public void testAppLauncher_portrait() throws Exception {
lockRotation(true);
performTest();
}
+ @Test
public void testAppLauncher_landscape() throws Exception {
lockRotation(false);
performTest();
}
private void performTest() throws Exception {
- startLauncher();
+ mActivityMonitor.startLauncher();
+
+ LauncherActivityInfo settingsApp = getSettingsApp();
// Open all apps and wait for load complete
final UiObject2 appsContainer = openAllApps();
assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
// Open settings app and verify app launched
- scrollAndFind(appsContainer, By.text(mSettingsApp.getLabel().toString())).click();
+ scrollAndFind(appsContainer, By.text(settingsApp.getLabel().toString())).click();
assertTrue(mDevice.wait(Until.hasObject(By.pkg(
- mSettingsApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
+ settingsApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
}
}
diff --git a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
index 9361750873..00f30ada9d 100644
--- a/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/AllAppsIconToHomeTest.java
@@ -1,58 +1,62 @@
package com.android.launcher3.ui;
import android.content.pm.LauncherActivityInfo;
-import android.os.Process;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.LargeTest;
-import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.LauncherActivityRule;
+import com.android.launcher3.util.rule.ShellCommandRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
/**
* Test for dragging an icon from all-apps to homescreen.
*/
@LargeTest
-public class AllAppsIconToHomeTest extends LauncherInstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AllAppsIconToHomeTest extends AbstractLauncherUiTest {
- private LauncherActivityInfo mSettingsApp;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- setDefaultLauncher();
-
- mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
- .getActivityList("com.android.settings", Process.myUserHandle()).get(0);
- }
+ @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+ @Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
+ @Test
public void testDragIcon_portrait() throws Throwable {
lockRotation(true);
performTest();
}
+ @Test
public void testDragIcon_landscape() throws Throwable {
lockRotation(false);
performTest();
}
private void performTest() throws Throwable {
+ LauncherActivityInfo settingsApp = getSettingsApp();
+
clearHomescreen();
- startLauncher();
+ mActivityMonitor.startLauncher();
// Open all apps and wait for load complete.
final UiObject2 appsContainer = openAllApps();
assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
// Drag icon to homescreen.
- UiObject2 icon = scrollAndFind(appsContainer, By.text(mSettingsApp.getLabel().toString()));
+ UiObject2 icon = scrollAndFind(appsContainer, By.text(settingsApp.getLabel().toString()));
dragToWorkspace(icon, true);
// Verify that the icon works on homescreen.
- mDevice.findObject(By.text(mSettingsApp.getLabel().toString())).click();
+ mDevice.findObject(By.text(settingsApp.getLabel().toString())).click();
assertTrue(mDevice.wait(Until.hasObject(By.pkg(
- mSettingsApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
+ settingsApp.getComponentName().getPackageName()).depth(0)), DEFAULT_UI_TIMEOUT));
}
}
diff --git a/tests/src/com/android/launcher3/ui/RotationPreferenceTest.java b/tests/src/com/android/launcher3/ui/RotationPreferenceTest.java
deleted file mode 100644
index e84ad047f1..0000000000
--- a/tests/src/com/android/launcher3/ui/RotationPreferenceTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-package com.android.launcher3.ui;
-
-import android.content.SharedPreferences;
-import android.graphics.Rect;
-import android.support.test.uiautomator.UiDevice;
-import android.support.test.uiautomator.UiObject;
-import android.support.test.uiautomator.UiSelector;
-import android.test.suitebuilder.annotation.MediumTest;
-
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-
-/**
- * Test for auto rotate preference.
- */
-@MediumTest
-public class RotationPreferenceTest extends LauncherInstrumentationTestCase {
-
- private SharedPreferences mPrefs;
- private boolean mOriginalRotationValue;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
-
- mDevice = UiDevice.getInstance(getInstrumentation());
- mTargetContext = getInstrumentation().getTargetContext();
- mTargetPackage = mTargetContext.getPackageName();
- mPrefs = Utilities.getPrefs(mTargetContext);
- mOriginalRotationValue = mPrefs.getBoolean(Utilities.ALLOW_ROTATION_PREFERENCE_KEY, false);
- }
-
- @Override
- protected void tearDown() throws Exception {
- setRotationEnabled(mOriginalRotationValue);
- super.tearDown();
- }
-
- public void testRotation_disabled() throws Exception {
- if (mTargetContext.getResources().getBoolean(R.bool.allow_rotation)) {
- // This is a tablet. The test is only valid to mobile devices.
- return;
- }
-
- setRotationEnabled(false);
- mDevice.setOrientationRight();
- startLauncher();
-
- Rect hotseat = getHotseatBounds();
- assertTrue(hotseat.width() > hotseat.height());
- }
-
- public void testRotation_enabled() throws Exception {
- if (mTargetContext.getResources().getBoolean(R.bool.allow_rotation)) {
- // This is a tablet. The test is only valid to mobile devices.
- return;
- }
-
- setRotationEnabled(true);
- mDevice.setOrientationRight();
- startLauncher();
-
- Rect hotseat = getHotseatBounds();
- assertTrue(hotseat.width() < hotseat.height());
- }
-
- private void setRotationEnabled(boolean enabled) {
- mPrefs.edit().putBoolean(Utilities.ALLOW_ROTATION_PREFERENCE_KEY, enabled).commit();
- }
-
- private Rect getHotseatBounds() throws Exception {
- UiObject hotseat = mDevice.findObject(
- new UiSelector().resourceId(mTargetPackage + ":id/hotseat"));
- hotseat.waitForExists(6000);
- return hotseat.getVisibleBounds();
- }
-}
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
index 3a0b6132c6..a40ad7fadc 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsLaunchTest.java
@@ -2,54 +2,58 @@ package com.android.launcher3.ui;
import android.content.pm.LauncherActivityInfo;
import android.graphics.Point;
-import android.os.Process;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.LargeTest;
import android.view.MotionEvent;
import com.android.launcher3.R;
-import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.LauncherActivityRule;
+import com.android.launcher3.util.rule.ShellCommandRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
/**
* Test for verifying that shortcuts are shown and can be launched after long pressing an app
*/
@LargeTest
-public class ShortcutsLaunchTest extends LauncherInstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class ShortcutsLaunchTest extends AbstractLauncherUiTest {
- private LauncherActivityInfo mSettingsApp;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- setDefaultLauncher();
-
- mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
- .getActivityList("com.android.settings", Process.myUserHandle()).get(0);
- }
+ @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+ @Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
+ @Test
public void testAppLauncher_portrait() throws Exception {
lockRotation(true);
performTest();
}
+ @Test
public void testAppLauncher_landscape() throws Exception {
lockRotation(false);
performTest();
}
private void performTest() throws Exception {
- startLauncher();
+ mActivityMonitor.startLauncher();
+ LauncherActivityInfo settingsApp = getSettingsApp();
// Open all apps and wait for load complete
final UiObject2 appsContainer = openAllApps();
assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
// Find settings app and verify shortcuts appear when long pressed
- UiObject2 icon = scrollAndFind(appsContainer, By.text(mSettingsApp.getLabel().toString()));
+ UiObject2 icon = scrollAndFind(appsContainer, By.text(settingsApp.getLabel().toString()));
// Press icon center until shortcuts appear
Point iconCenter = icon.getVisibleCenter();
sendPointer(MotionEvent.ACTION_DOWN, iconCenter);
@@ -63,7 +67,7 @@ public class ShortcutsLaunchTest extends LauncherInstrumentationTestCase {
.findObject(getSelectorForId(R.id.bubble_text));
shortcut.click();
assertTrue(mDevice.wait(Until.hasObject(By.pkg(
- mSettingsApp.getComponentName().getPackageName())
+ settingsApp.getComponentName().getPackageName())
.text(shortcut.getText())), DEFAULT_UI_TIMEOUT));
}
}
diff --git a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
index 5d86d1ec68..434311dd6f 100644
--- a/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
+++ b/tests/src/com/android/launcher3/ui/ShortcutsToHomeTest.java
@@ -2,40 +2,43 @@ package com.android.launcher3.ui;
import android.content.pm.LauncherActivityInfo;
import android.graphics.Point;
-import android.os.Process;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.LargeTest;
import android.view.MotionEvent;
import com.android.launcher3.R;
-import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.LauncherActivityRule;
+import com.android.launcher3.util.rule.ShellCommandRule;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
/**
* Test for dragging a deep shortcut to the home screen.
*/
@LargeTest
-public class ShortcutsToHomeTest extends LauncherInstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class ShortcutsToHomeTest extends AbstractLauncherUiTest {
- private LauncherActivityInfo mSettingsApp;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- setDefaultLauncher();
-
- mSettingsApp = LauncherAppsCompat.getInstance(mTargetContext)
- .getActivityList("com.android.settings", Process.myUserHandle()).get(0);
- }
+ @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+ @Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
+ @Test
public void testDragIcon_portrait() throws Throwable {
lockRotation(true);
performTest();
}
+ @Test
public void testDragIcon_landscape() throws Throwable {
lockRotation(false);
performTest();
@@ -43,14 +46,16 @@ public class ShortcutsToHomeTest extends LauncherInstrumentationTestCase {
private void performTest() throws Throwable {
clearHomescreen();
- startLauncher();
+ mActivityMonitor.startLauncher();
+
+ LauncherActivityInfo settingsApp = getSettingsApp();
// Open all apps and wait for load complete.
final UiObject2 appsContainer = openAllApps();
assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
// Find the app and long press it to show shortcuts.
- UiObject2 icon = scrollAndFind(appsContainer, By.text(mSettingsApp.getLabel().toString()));
+ UiObject2 icon = scrollAndFind(appsContainer, By.text(settingsApp.getLabel().toString()));
// Press icon center until shortcuts appear
Point iconCenter = icon.getVisibleCenter();
sendPointer(MotionEvent.ACTION_DOWN, iconCenter);
@@ -69,7 +74,7 @@ public class ShortcutsToHomeTest extends LauncherInstrumentationTestCase {
// (the app opens and has the same text as the shortcut).
mDevice.findObject(By.text(shortcutName)).click();
assertTrue(mDevice.wait(Until.hasObject(By.pkg(
- mSettingsApp.getComponentName().getPackageName())
+ settingsApp.getComponentName().getPackageName())
.text(shortcutName)), DEFAULT_UI_TIMEOUT));
}
}
diff --git a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
index 0b4e34f94c..a5c2e69af7 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddConfigWidgetTest.java
@@ -15,75 +15,75 @@
*/
package com.android.launcher3.ui.widget;
-import android.app.Activity;
-import android.app.Application;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
-import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
-import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.Workspace;
import com.android.launcher3.testcomponent.WidgetConfigActivity;
-import com.android.launcher3.ui.LauncherInstrumentationTestCase;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.Condition;
-import com.android.launcher3.util.SimpleActivityMonitor;
import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.LauncherActivityRule;
+import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.WidgetCell;
-import java.util.concurrent.Callable;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
/**
* Test to verify widget configuration is properly shown.
*/
@LargeTest
-public class AddConfigWidgetTest extends LauncherInstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AddConfigWidgetTest extends AbstractLauncherUiTest {
+
+ @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+ @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
private LauncherAppWidgetProviderInfo mWidgetInfo;
- private SimpleActivityMonitor mActivityMonitor;
- private MainThreadExecutor mMainThreadExecutor;
private AppWidgetManager mAppWidgetManager;
private int mWidgetId;
@Override
- protected void setUp() throws Exception {
+ @Before
+ public void setUp() throws Exception {
super.setUp();
mWidgetInfo = findWidgetProvider(true /* hasConfigureScreen */);
- mActivityMonitor = new SimpleActivityMonitor();
- ((Application) getInstrumentation().getTargetContext().getApplicationContext())
- .registerActivityLifecycleCallbacks(mActivityMonitor);
- mMainThreadExecutor = new MainThreadExecutor();
mAppWidgetManager = AppWidgetManager.getInstance(mTargetContext);
-
- grantWidgetPermission();
- }
-
- @Override
- protected void tearDown() throws Exception {
- ((Application) getInstrumentation().getTargetContext().getApplicationContext())
- .unregisterActivityLifecycleCallbacks(mActivityMonitor);
- super.tearDown();
}
+ @Test
public void testWidgetConfig() throws Throwable {
runTest(false, true);
}
+ @Test
public void testWidgetConfig_rotate() throws Throwable {
runTest(true, true);
}
+ @Test
public void testConfigCancelled() throws Throwable {
runTest(false, false);
}
+ @Test
public void testConfigCancelled_rotate() throws Throwable {
runTest(true, false);
}
@@ -96,7 +96,7 @@ public class AddConfigWidgetTest extends LauncherInstrumentationTestCase {
lockRotation(true);
clearHomescreen();
- startLauncher();
+ mActivityMonitor.startLauncher();
// Open widget tray and wait for load complete.
final UiObject2 widgetContainer = openWidgetsTray();
@@ -146,11 +146,11 @@ public class AddConfigWidgetTest extends LauncherInstrumentationTestCase {
* Condition for searching widget id
*/
private class WidgetSearchCondition extends Condition
- implements Callable, Workspace.ItemOperator {
+ implements Workspace.ItemOperator {
@Override
public boolean isTrue() throws Throwable {
- return mMainThreadExecutor.submit(this).get();
+ return mMainThreadExecutor.submit(mActivityMonitor.itemExists(this)).get();
}
@Override
@@ -159,21 +159,6 @@ public class AddConfigWidgetTest extends LauncherInstrumentationTestCase {
((LauncherAppWidgetInfo) info).providerName.equals(mWidgetInfo.provider) &&
((LauncherAppWidgetInfo) info).appWidgetId == mWidgetId;
}
-
- @Override
- public Boolean call() throws Exception {
- // Find the resumed launcher
- Launcher launcher = null;
- for (Activity a : mActivityMonitor.resumed) {
- if (a instanceof Launcher) {
- launcher = (Launcher) a;
- }
- }
- if (launcher == null) {
- return false;
- }
- return launcher.getWorkspace().getFirstMatch(this) != null;
- }
}
/**
diff --git a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
index 3c92c578d5..19f7db72bf 100644
--- a/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/AddWidgetTest.java
@@ -15,42 +15,46 @@
*/
package com.android.launcher3.ui.widget;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
-import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.Workspace.ItemOperator;
-import com.android.launcher3.ui.LauncherInstrumentationTestCase;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.Condition;
import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.LauncherActivityRule;
+import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.WidgetCell;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+
/**
* Test to add widget from widget tray
*/
@LargeTest
-public class AddWidgetTest extends LauncherInstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class AddWidgetTest extends AbstractLauncherUiTest {
- private LauncherAppWidgetProviderInfo widgetInfo;
-
- @Override
- protected void setUp() throws Exception {
- super.setUp();
- grantWidgetPermission();
-
- widgetInfo = findWidgetProvider(false /* hasConfigureScreen */);
- }
+ @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+ @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
+ @Test
public void testDragIcon_portrait() throws Throwable {
lockRotation(true);
performTest();
}
+ @Test
public void testDragIcon_landscape() throws Throwable {
lockRotation(false);
performTest();
@@ -58,7 +62,10 @@ public class AddWidgetTest extends LauncherInstrumentationTestCase {
private void performTest() throws Throwable {
clearHomescreen();
- Launcher launcher = startLauncher();
+ mActivityMonitor.startLauncher();
+
+ final LauncherAppWidgetProviderInfo widgetInfo =
+ findWidgetProvider(false /* hasConfigureScreen */);
// Open widget tray and wait for load complete.
final UiObject2 widgetContainer = openWidgetsTray();
@@ -69,12 +76,12 @@ public class AddWidgetTest extends LauncherInstrumentationTestCase {
.hasDescendant(By.text(widgetInfo.getLabel(mTargetContext.getPackageManager()))));
dragToWorkspace(widget, false);
- assertNotNull(launcher.getWorkspace().getFirstMatch(new ItemOperator() {
+ assertTrue(mActivityMonitor.itemExists(new ItemOperator() {
@Override
public boolean evaluate(ItemInfo info, View view) {
return info instanceof LauncherAppWidgetInfo &&
((LauncherAppWidgetInfo) info).providerName.equals(widgetInfo.provider);
}
- }));
+ }).call());
}
}
diff --git a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
index 221fed1fc5..d4d517a22c 100644
--- a/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/BindWidgetTest.java
@@ -24,10 +24,10 @@ import android.content.pm.PackageInstaller.SessionParams;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.UiSelector;
-import android.test.suitebuilder.annotation.LargeTest;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetHost;
import com.android.launcher3.LauncherAppWidgetHostView;
import com.android.launcher3.LauncherAppWidgetInfo;
@@ -38,23 +38,40 @@ import com.android.launcher3.PendingAppWidgetHostView;
import com.android.launcher3.Workspace;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.PackageInstallerCompat;
-import com.android.launcher3.ui.LauncherInstrumentationTestCase;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.ContentWriter;
import com.android.launcher3.util.LooperExecutor;
+import com.android.launcher3.util.rule.LauncherActivityRule;
+import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.WidgetHostViewLoader;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
/**
* Tests for bind widget flow.
*
* Note running these tests will clear the workspace on the device.
*/
@LargeTest
-public class BindWidgetTest extends LauncherInstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class BindWidgetTest extends AbstractLauncherUiTest {
+
+ @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+ @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
private ContentResolver mResolver;
private AppWidgetManagerCompat mWidgetManager;
@@ -65,21 +82,20 @@ public class BindWidgetTest extends LauncherInstrumentationTestCase {
private int mSessionId = -1;
@Override
- protected void setUp() throws Exception {
+ @Before
+ public void setUp() throws Exception {
super.setUp();
mResolver = mTargetContext.getContentResolver();
mWidgetManager = AppWidgetManagerCompat.getInstance(mTargetContext);
- grantWidgetPermission();
// Clear all existing data
LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CREATE_EMPTY_DB);
LauncherSettings.Settings.call(mResolver, LauncherSettings.Settings.METHOD_CLEAR_EMPTY_DB_FLAG);
}
- @Override
- protected void tearDown() throws Exception {
- super.tearDown();
+ @After
+ public void tearDown() throws Exception {
if (mCursor != null) {
mCursor.close();
}
@@ -89,6 +105,7 @@ public class BindWidgetTest extends LauncherInstrumentationTestCase {
}
}
+ @Test
public void testBindNormalWidget_withConfig() {
LauncherAppWidgetProviderInfo info = findWidgetProvider(true);
LauncherAppWidgetInfo item = createWidgetInfo(info, true);
@@ -96,6 +113,7 @@ public class BindWidgetTest extends LauncherInstrumentationTestCase {
setupAndVerifyContents(item, LauncherAppWidgetHostView.class, info.label);
}
+ @Test
public void testBindNormalWidget_withoutConfig() {
LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
LauncherAppWidgetInfo item = createWidgetInfo(info, true);
@@ -103,6 +121,7 @@ public class BindWidgetTest extends LauncherInstrumentationTestCase {
setupAndVerifyContents(item, LauncherAppWidgetHostView.class, info.label);
}
+ @Test
public void testUnboundWidget_removed() throws Exception {
LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
LauncherAppWidgetInfo item = createWidgetInfo(info, false);
@@ -121,6 +140,7 @@ public class BindWidgetTest extends LauncherInstrumentationTestCase {
assertFalse(mDevice.findObject(new UiSelector().description(info.label)).exists());
}
+ @Test
public void testPendingWidget_autoRestored() {
// A non-restored widget with no config screen gets restored automatically.
LauncherAppWidgetProviderInfo info = findWidgetProvider(false);
@@ -132,6 +152,7 @@ public class BindWidgetTest extends LauncherInstrumentationTestCase {
setupAndVerifyContents(item, LauncherAppWidgetHostView.class, info.label);
}
+ @Test
public void testPendingWidget_withConfigScreen() throws Exception {
// A non-restored widget with config screen get bound and shows a 'Click to setup' UI.
LauncherAppWidgetProviderInfo info = findWidgetProvider(true);
@@ -154,6 +175,7 @@ public class BindWidgetTest extends LauncherInstrumentationTestCase {
LauncherSettings.Favorites.APPWIDGET_ID))));
}
+ @Test
public void testPendingWidget_notRestored_removed() throws Exception {
LauncherAppWidgetInfo item = getInvalidWidgetInfo();
item.restoreStatus = LauncherAppWidgetInfo.FLAG_ID_NOT_VALID
@@ -170,6 +192,7 @@ public class BindWidgetTest extends LauncherInstrumentationTestCase {
assertEquals(0, mCursor.getCount());
}
+ @Test
public void testPendingWidget_notRestored_brokenInstall() throws Exception {
// A widget which is was being installed once, even if its not being
// installed at the moment is not removed.
@@ -192,6 +215,7 @@ public class BindWidgetTest extends LauncherInstrumentationTestCase {
& LauncherAppWidgetInfo.FLAG_ID_NOT_VALID);
}
+ @Test
public void testPendingWidget_notRestored_activeInstall() throws Exception {
// A widget which is being installed is not removed
LauncherAppWidgetInfo item = getInvalidWidgetInfo();
@@ -250,7 +274,7 @@ public class BindWidgetTest extends LauncherInstrumentationTestCase {
resetLoaderState();
// Launch the home activity
- startLauncher();
+ mActivityMonitor.startLauncher();
// Verify UI
UiSelector selector = new UiSelector().packageName(mTargetContext.getPackageName())
.className(widgetClass);
diff --git a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
index b798dfa88d..4b9d83f8ae 100644
--- a/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
+++ b/tests/src/com/android/launcher3/ui/widget/RequestPinItemTest.java
@@ -15,23 +15,20 @@
*/
package com.android.launcher3.ui.widget;
-import android.app.Activity;
-import android.app.Application;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.graphics.Color;
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
import android.support.test.uiautomator.By;
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
-import android.test.suitebuilder.annotation.LargeTest;
import android.view.View;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
@@ -40,50 +37,48 @@ import com.android.launcher3.shortcuts.ShortcutKey;
import com.android.launcher3.testcomponent.AppWidgetNoConfig;
import com.android.launcher3.testcomponent.AppWidgetWithConfig;
import com.android.launcher3.testcomponent.RequestPinItemActivity;
-import com.android.launcher3.ui.LauncherInstrumentationTestCase;
+import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.Condition;
-import com.android.launcher3.util.SimpleActivityMonitor;
import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.LauncherActivityRule;
+import com.android.launcher3.util.rule.ShellCommandRule;
import com.android.launcher3.widget.WidgetCell;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
import java.util.UUID;
-import java.util.concurrent.Callable;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertTrue;
/**
* Test to verify pin item request flow.
*/
@LargeTest
-public class RequestPinItemTest extends LauncherInstrumentationTestCase {
+@RunWith(AndroidJUnit4.class)
+public class RequestPinItemTest extends AbstractLauncherUiTest {
- private SimpleActivityMonitor mActivityMonitor;
- private MainThreadExecutor mMainThreadExecutor;
+ @Rule public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+ @Rule public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grandWidgetBind();
+ @Rule public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
private String mCallbackAction;
private String mShortcutId;
private int mAppWidgetId;
@Override
- protected void setUp() throws Exception {
+ @Before
+ public void setUp() throws Exception {
super.setUp();
- grantWidgetPermission();
- setDefaultLauncher();
-
- mActivityMonitor = new SimpleActivityMonitor();
- ((Application) getInstrumentation().getTargetContext().getApplicationContext())
- .registerActivityLifecycleCallbacks(mActivityMonitor);
- mMainThreadExecutor = new MainThreadExecutor();
-
mCallbackAction = UUID.randomUUID().toString();
mShortcutId = UUID.randomUUID().toString();
}
- @Override
- protected void tearDown() throws Exception {
- ((Application) getInstrumentation().getTargetContext().getApplicationContext())
- .unregisterActivityLifecycleCallbacks(mActivityMonitor);
- super.tearDown();
- }
-
+ @Test
public void testPinWidgetNoConfig() throws Throwable {
runTest("pinWidgetNoConfig", true, new ItemOperator() {
@Override
@@ -96,6 +91,7 @@ public class RequestPinItemTest extends LauncherInstrumentationTestCase {
});
}
+ @Test
public void testPinWidgetNoConfig_customPreview() throws Throwable {
// Command to set custom preview
Intent command = RequestPinItemActivity.getCommandIntent(
@@ -113,6 +109,7 @@ public class RequestPinItemTest extends LauncherInstrumentationTestCase {
}, command);
}
+ @Test
public void testPinWidgetWithConfig() throws Throwable {
runTest("pinWidgetWithConfig", true, new ItemOperator() {
@Override
@@ -125,6 +122,7 @@ public class RequestPinItemTest extends LauncherInstrumentationTestCase {
});
}
+ @Test
public void testPinShortcut() throws Throwable {
// Command to set the shortcut id
Intent command = RequestPinItemActivity.getCommandIntent(
@@ -149,7 +147,7 @@ public class RequestPinItemTest extends LauncherInstrumentationTestCase {
lockRotation(true);
clearHomescreen();
- startLauncher();
+ mActivityMonitor.startLauncher();
// Open all apps and wait for load complete
final UiObject2 appsContainer = openAllApps();
@@ -191,14 +189,14 @@ public class RequestPinItemTest extends LauncherInstrumentationTestCase {
}
// Go back to home
- mTargetContext.startActivity(getHomeIntent());
+ mActivityMonitor.returnToHome();
assertTrue(Wait.atMost(new ItemSearchCondition(itemMatcher), DEFAULT_ACTIVITY_TIMEOUT));
}
/**
* Condition for for an item
*/
- private class ItemSearchCondition extends Condition implements Callable {
+ private class ItemSearchCondition extends Condition {
private final ItemOperator mOp;
@@ -208,22 +206,7 @@ public class RequestPinItemTest extends LauncherInstrumentationTestCase {
@Override
public boolean isTrue() throws Throwable {
- return mMainThreadExecutor.submit(this).get();
- }
-
- @Override
- public Boolean call() throws Exception {
- // Find the resumed launcher
- Launcher launcher = null;
- for (Activity a : mActivityMonitor.resumed) {
- if (a instanceof Launcher) {
- launcher = (Launcher) a;
- }
- }
- if (launcher == null) {
- return false;
- }
- return launcher.getWorkspace().getFirstMatch(mOp) != null;
+ return mMainThreadExecutor.submit(mActivityMonitor.itemExists(mOp)).get();
}
}
}
diff --git a/tests/src/com/android/launcher3/util/SimpleActivityMonitor.java b/tests/src/com/android/launcher3/util/SimpleActivityMonitor.java
deleted file mode 100644
index 6154ab6c58..0000000000
--- a/tests/src/com/android/launcher3/util/SimpleActivityMonitor.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright (C) 2017 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.util;
-
-import android.app.Activity;
-import android.app.Application.*;
-import android.os.Bundle;
-
-import java.util.ArrayList;
-
-/**
- * Simple monitor to keep a list of active activities.
- */
-public class SimpleActivityMonitor implements ActivityLifecycleCallbacks {
-
- public final ArrayList created = new ArrayList<>();
- public final ArrayList started = new ArrayList<>();
- public final ArrayList resumed = new ArrayList<>();
-
- @Override
- public void onActivityCreated(Activity activity, Bundle bundle) {
- created.add(activity);
- }
-
- @Override
- public void onActivityStarted(Activity activity) {
- started.add(activity);
- }
-
- @Override
- public void onActivityResumed(Activity activity) {
- resumed.add(activity);
- }
-
- @Override
- public void onActivityPaused(Activity activity) {
- resumed.remove(activity);
- }
-
- @Override
- public void onActivityStopped(Activity activity) {
- started.remove(activity);
- }
-
- @Override
- public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { }
-
- @Override
- public void onActivityDestroyed(Activity activity) {
- created.remove(activity);
- }
-}
diff --git a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
new file mode 100644
index 0000000000..edd152a2c7
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2017 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.util.rule;
+
+import android.app.Activity;
+import android.app.Application;
+import android.app.Application.ActivityLifecycleCallbacks;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.test.InstrumentationRegistry;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.Workspace.ItemOperator;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.util.concurrent.Callable;
+
+/**
+ * Test rule to get the current Launcher activity.
+ */
+public class LauncherActivityRule implements TestRule {
+
+ private Launcher mActivity;
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new MyStatement(base);
+ }
+
+ public Launcher getActivity() {
+ return mActivity;
+ }
+
+ public Callable itemExists(final ItemOperator op) {
+ return new Callable() {
+
+ @Override
+ public Boolean call() throws Exception {
+ Launcher launcher = getActivity();
+ if (launcher == null) {
+ return false;
+ }
+ return launcher.getWorkspace().getFirstMatch(op) != null;
+ }
+ };
+ }
+
+ /**
+ * Starts the launcher activity in the target package.
+ */
+ public void startLauncher() {
+ InstrumentationRegistry.getInstrumentation().startActivitySync(getHomeIntent());
+ }
+
+ public void returnToHome() {
+ InstrumentationRegistry.getTargetContext().startActivity(getHomeIntent());
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ public static Intent getHomeIntent() {
+ return new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setPackage(InstrumentationRegistry.getTargetContext().getPackageName())
+ .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ }
+
+ private class MyStatement extends Statement implements ActivityLifecycleCallbacks {
+
+ private final Statement mBase;
+
+ public MyStatement(Statement base) {
+ mBase = base;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ Application app = (Application)
+ InstrumentationRegistry.getTargetContext().getApplicationContext();
+ app.registerActivityLifecycleCallbacks(this);
+ try {
+ mBase.evaluate();
+ } finally {
+ app.unregisterActivityLifecycleCallbacks(this);
+ }
+ }
+
+ @Override
+ public void onActivityCreated(Activity activity, Bundle bundle) {
+ if (activity instanceof Launcher) {
+ mActivity = (Launcher) activity;
+ }
+ }
+
+ @Override
+ public void onActivityStarted(Activity activity) { }
+
+ @Override
+ public void onActivityResumed(Activity activity) { }
+
+ @Override
+ public void onActivityPaused(Activity activity) { }
+
+ @Override
+ public void onActivityStopped(Activity activity) { }
+
+ @Override
+ public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { }
+
+ @Override
+ public void onActivityDestroyed(Activity activity) {
+ if (activity == mActivity) {
+ mActivity = null;
+ }
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
new file mode 100644
index 0000000000..dba2d71003
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/ShellCommandRule.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2017 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.util.rule;
+
+import android.content.ComponentName;
+import android.content.pm.ActivityInfo;
+import android.os.ParcelFileDescriptor;
+import android.support.test.InstrumentationRegistry;
+
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+/**
+ * Test rule which executes a shell command at the start of the test.
+ */
+public class ShellCommandRule implements TestRule {
+
+ private final String mCmd;
+
+ public ShellCommandRule(String cmd) {
+ mCmd = cmd;
+ }
+
+ @Override
+ public Statement apply(Statement base, Description description) {
+ return new MyStatement(base, mCmd);
+ }
+
+ public static void runShellCommand(String command) throws IOException {
+ ParcelFileDescriptor pfd = InstrumentationRegistry.getInstrumentation().getUiAutomation()
+ .executeShellCommand(command);
+
+ // Read the input stream fully.
+ FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
+ while (fis.read() != -1);
+ fis.close();
+ }
+
+ private static class MyStatement extends Statement {
+ private final Statement mBase;
+ private final String mCmd;
+
+ public MyStatement(Statement base, String cmd) {
+ mBase = base;
+ mCmd = cmd;
+ }
+
+ @Override
+ public void evaluate() throws Throwable {
+ runShellCommand(mCmd);
+ mBase.evaluate();
+ }
+ }
+
+ /**
+ * Grants the launcher permission to bind widgets.
+ */
+ public static ShellCommandRule grandWidgetBind() {
+ return new ShellCommandRule("appwidget grantbind --package "
+ + InstrumentationRegistry.getTargetContext().getPackageName());
+ }
+
+ /**
+ * Sets the target launcher as default launcher.
+ */
+ public static ShellCommandRule setDefaultLauncher() {
+ ActivityInfo launcher = InstrumentationRegistry.getTargetContext().getPackageManager()
+ .queryIntentActivities(LauncherActivityRule.getHomeIntent(), 0).get(0)
+ .activityInfo;
+ return new ShellCommandRule("cmd package set-home-activity " +
+ new ComponentName(launcher.packageName, launcher.name).flattenToString());
+ }
+}