Merge "Migrate PackageManagerHelper to MainThreadInitializedObject" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 6b07bb6..eced590 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -239,3 +239,10 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_fallback_overview_in_window"
+ namespace: "launcher"
+ description: "Enables fallback recents opening inside of a window instead of an activity."
+ bug: "292269949"
+}
diff --git a/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java b/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
index 0d0f700..556d29c 100644
--- a/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
+++ b/go/quickstep/src/com/android/launcher3/model/AppShareabilityManager.java
@@ -35,6 +35,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.launcher3.model.AppShareabilityDatabase.ShareabilityDao;
import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
import java.lang.annotation.Retention;
import java.util.ArrayList;
@@ -47,7 +48,7 @@
* Each app's status is retrieved from the Play Store's API. Statuses are cached in order
* to limit extraneous calls to that API (which can be time-consuming).
*/
-public class AppShareabilityManager {
+public class AppShareabilityManager implements SafeCloseable {
@Retention(SOURCE)
@IntDef({
ShareabilityStatus.UNKNOWN,
@@ -194,6 +195,11 @@
}
}
+ @Override
+ public void close() {
+ mDatabase.close();
+ }
+
/**
* Provides a testable instance of this class
* This instance allows database queries on the main thread
diff --git a/quickstep/res/layout/transient_taskbar.xml b/quickstep/res/layout/transient_taskbar.xml
index 3c6878a..7c55bf8 100644
--- a/quickstep/res/layout/transient_taskbar.xml
+++ b/quickstep/res/layout/transient_taskbar.xml
@@ -44,7 +44,7 @@
android:layout_height="@dimen/bubblebar_size_with_pointer"
android:layout_gravity="bottom|end"
android:layout_marginHorizontal="@dimen/transient_taskbar_bottom_margin"
- android:paddingTop="@dimen/bubblebar_pointer_size"
+ android:paddingTop="@dimen/bubblebar_pointer_visible_size"
android:paddingEnd="@dimen/taskbar_icon_spacing"
android:paddingStart="@dimen/taskbar_icon_spacing"
android:visibility="gone"
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 959d06c..500cc3d 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ሰካ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ነፃ ቅጽ"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ዴስክቶፕ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ምንም የቅርብ ጊዜ ንጥሎች የሉም"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"የመተግበሪያ አጠቃቀም ቅንብሮች"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ሁሉንም አጽዳ"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 2eaea0c..de2c8b1 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"تثبيت"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"شكل مجاني"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"الكمبيوتر المكتبي"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ما مِن عناصر تم استخدامها مؤخرًا"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"إعدادات استخدام التطبيق"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"محو الكل"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index eedcd45..a07ffc5 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Připnout"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Neomezený režim"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Počítač"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Žádné položky z nedávné doby"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavení využití aplikací"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vymazat vše"</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index 8050284..64c68e0 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index 8050284..64c68e0 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index 8050284..64c68e0 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pin"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"No recent items"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"App usage settings"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Clear all"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 958eecc..a3e5b7f 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"پین"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"رایانه"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"چیز جدیدی اینجا نیست"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"تنظیمات استفاده از برنامه"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"پاک کردن همه"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index fe629dd..006184b 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Kitűzés"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Szabad forma"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Asztali"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nincsenek mostanában használt elemek"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Alkalmazáshasználati beállítások"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Összes törlése"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index eec7e10..34a8b2b 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Sematkan"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Format bebas"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Tidak ada item yang baru dibuka"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Setelan penggunaan aplikasi"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hapus semua"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index e023124..d5f2488 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Festa"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Frjálst snið"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Tölva"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Engin nýleg atriði"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Notkunarstillingar forrits"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hreinsa allt"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index f66761f..c38243f 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Blocca su schermo"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forma libera"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nessun elemento recente"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Impostazioni di utilizzo delle app"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Cancella tutto"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index a424bcd..9d6b246 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"הצמדה"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"מצב חופשי"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"במחשב"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"אין פריטים אחרונים"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"הגדרות שימוש באפליקציה"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ניקוי הכול"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index b0b1190..69b3954 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"固定"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"フリーフォーム"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"パソコン"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"最近のアイテムはありません"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"アプリの使用状況の設定"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"すべてクリア"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index c7c6389..4df7f3a 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ಪಿನ್ ಮಾಡಿ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ಮುಕ್ತಸ್ವರೂಪ"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ಡೆಸ್ಕ್ಟಾಪ್"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ಯಾವುದೇ ಇತ್ತೀಚಿನ ಐಟಂಗಳಿಲ್ಲ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ಆ್ಯಪ್ ಬಳಕೆಯ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ಎಲ್ಲವನ್ನೂ ತೆರವುಗೊಳಿಸಿ"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index c8a031f..47c3670 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Prisegti"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Laisva forma"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Stalinis kompiuteris"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Nėra jokių naujausių elementų"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Programos naudojimo nustatymai"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Išvalyti viską"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 17380a0..90ceeff 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"പിൻ ചെയ്യുക"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ഫ്രീഫോം"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ഡെസ്ക്ടോപ്പ്"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"സമീപകാല ഇനങ്ങൾ ഒന്നുമില്ല"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ആപ്പ് ഉപയോഗ ക്രമീകരണം"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"എല്ലാം മായ്ക്കുക"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index fa09e2b..3fea03b 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"पिन करा"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"फ्रीफॉर्म"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"डेस्कटॉप"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"कोणतेही अलीकडील आयटम नाहीत"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"अॅप वापर सेटिंग्ज"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"सर्व साफ करा"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 6f9f38c..6ee48dc 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Fest"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Fritt format"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Skrivebord"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Ingen nylige elementer"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Innstillinger for appbruk"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Fjern alt"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 5c85461..15be242 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"ਪਿੰਨ ਕਰੋ"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"ਫ੍ਰੀਫਾਰਮ"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ਡੈਸਕਟਾਪ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"ਕੋਈ ਹਾਲੀਆ ਆਈਟਮ ਨਹੀਂ"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ਐਪ ਵਰਤੋਂ ਦੀਆਂ ਸੈਟਿੰਗਾਂ"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"ਸਭ ਕਲੀਅਰ ਕਰੋ"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 6f1d9e7..5369d1e 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Закрепить"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Произвольная форма"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Включить режим для ПК"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Здесь пока ничего нет."</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Настройки использования приложения"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Очистить все"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 48f7a9c..c01f2f0 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Pripnúť"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Voľný režim"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Počítač"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Žiadne nedávne položky"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Nastavenia využívania aplikácie"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Vymazať všetko"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 7b14045..69b4ba1 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"پن کریں"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"فری فارم"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"ڈیسک ٹاپ"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"کوئی حالیہ آئٹم نہیں"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"ایپ کے استعمال کی ترتیبات"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"سبھی کو صاف کریں"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index e543225..f548c19 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Qadash"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"Erkin shakl"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Desktop"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Yaqinda ishlatilgan ilovalar yo‘q"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Ilovadan foydalanish sozlamalari"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Hammasini tozalash"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 5723214..71c9227 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -21,8 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="recent_task_option_pin" msgid="7929860679018978258">"Phina"</string>
<string name="recent_task_option_freeform" msgid="48863056265284071">"I-Freeform"</string>
- <!-- no translation found for recent_task_option_desktop (8280879717125435668) -->
- <skip />
+ <string name="recent_task_option_desktop" msgid="8280879717125435668">"Ideskithophu"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Azikho izinto zakamuva"</string>
<string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Izilungiselelo zokusetshenziswa kohlelo lokusebenza"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Sula konke"</string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index dc28614..9ca8060 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -420,7 +420,12 @@
<dimen name="bubblebar_stashed_handle_width">55dp</dimen>
<dimen name="bubblebar_stashed_size">@dimen/transient_taskbar_stashed_height</dimen>
<dimen name="bubblebar_stashed_handle_height">@dimen/taskbar_stashed_handle_height</dimen>
- <dimen name="bubblebar_pointer_size">8dp</dimen>
+ <!-- this is a pointer height minus 1dp to ensure the pointer overlaps with the bubblebar
+ background appropriately when close to the rounded corner -->
+ <dimen name="bubblebar_pointer_visible_size">9dp</dimen>
+ <dimen name="bubblebar_pointer_width">12dp</dimen>
+ <dimen name="bubblebar_pointer_height">10dp</dimen>
+ <dimen name="bubblebar_pointer_radius">2dp</dimen>
<!-- Container size with pointer included: bubblebar_size + bubblebar_pointer_size -->
<dimen name="bubblebar_size_with_pointer">80dp</dimen>
<dimen name="bubblebar_elevation">1dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index fb14f9e..65a49bd 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -326,8 +326,12 @@
super.destroy();
mActive = false;
StatsLogCompatManager.LOGS_CONSUMER.remove(mAppEventProducer);
- if (mIsPrimaryInstance) {
- mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
+ if (mIsPrimaryInstance && mStatsManager != null) {
+ try {
+ mStatsManager.clearPullAtomCallback(SysUiStatsLog.LAUNCHER_LAYOUT_SNAPSHOT);
+ } catch (RuntimeException e) {
+ Log.e(TAG, "Failed to unregister snapshot logging callback with StatsManager", e);
+ }
}
destroyPredictors();
}
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index c345d6e..a7c9652 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -32,7 +32,6 @@
import android.os.Bundle;
import android.os.DeadObjectException;
import android.os.Handler;
-import android.os.Looper;
import android.os.Process;
import android.os.UserHandle;
import android.text.TextUtils;
@@ -48,9 +47,10 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.popup.RemoteActionShortcut;
import com.android.launcher3.popup.SystemShortcut;
-import com.android.launcher3.util.BgObjectWithLooper;
+import com.android.launcher3.util.Executors;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.launcher3.views.ActivityContext;
@@ -61,7 +61,7 @@
/**
* Data model for digital wellbeing status of apps.
*/
-public final class WellbeingModel extends BgObjectWithLooper {
+public final class WellbeingModel implements SafeCloseable {
private static final String TAG = "WellbeingModel";
private static final int[] RETRY_TIMES_MS = {5000, 15000, 30000};
private static final boolean DEBUG = false;
@@ -81,8 +81,12 @@
private final Context mContext;
private final String mWellbeingProviderPkg;
- private Handler mWorkerHandler;
- private ContentObserver mContentObserver;
+ private final Handler mWorkerHandler;
+ private final ContentObserver mContentObserver;
+ private final SimpleBroadcastReceiver mWellbeingAppChangeReceiver =
+ new SimpleBroadcastReceiver(t -> restartObserver());
+ private final SimpleBroadcastReceiver mAppAddRemoveReceiver =
+ new SimpleBroadcastReceiver(this::onAppPackageChanged);
private final Object mModelLock = new Object();
// Maps the action Id to the corresponding RemoteAction
@@ -94,16 +98,23 @@
private WellbeingModel(final Context context) {
mContext = context;
mWellbeingProviderPkg = mContext.getString(R.string.wellbeing_provider_pkg);
- initializeInBackground("WellbeingHandler");
+ mWorkerHandler = new Handler(TextUtils.isEmpty(mWellbeingProviderPkg)
+ ? Executors.UI_HELPER_EXECUTOR.getLooper()
+ : Executors.getPackageExecutor(mWellbeingProviderPkg).getLooper());
+
+ mContentObserver = new ContentObserver(mWorkerHandler) {
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ updateAllPackages();
+ }
+ };
+ mWorkerHandler.post(this::initializeInBackground);
}
- @Override
- protected void onInitialized(Looper looper) {
- mWorkerHandler = new Handler(looper);
- mContentObserver = newContentObserver(mWorkerHandler, this::onWellbeingUriChanged);
+ private void initializeInBackground() {
if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
mContext.registerReceiver(
- new SimpleBroadcastReceiver(t -> restartObserver()),
+ mWellbeingAppChangeReceiver,
getPackageFilter(mWellbeingProviderPkg,
Intent.ACTION_PACKAGE_ADDED, Intent.ACTION_PACKAGE_CHANGED,
Intent.ACTION_PACKAGE_REMOVED, Intent.ACTION_PACKAGE_DATA_CLEARED,
@@ -113,17 +124,21 @@
IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addDataScheme("package");
- mContext.registerReceiver(new SimpleBroadcastReceiver(this::onAppPackageChanged),
- filter, null, mWorkerHandler);
+ mContext.registerReceiver(mAppAddRemoveReceiver, filter, null, mWorkerHandler);
restartObserver();
}
}
- @WorkerThread
- private void onWellbeingUriChanged(Uri uri) {
- Preconditions.assertNonUiThread();
- updateAllPackages();
+ @Override
+ public void close() {
+ if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
+ mWorkerHandler.post(() -> {
+ mWellbeingAppChangeReceiver.unregisterReceiverSafely(mContext);
+ mAppAddRemoveReceiver.unregisterReceiverSafely(mContext);
+ mContext.getContentResolver().unregisterContentObserver(mContentObserver);
+ });
+ }
}
public void setInTest(boolean inTest) {
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 74376c8..5ac5761 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -37,6 +37,9 @@
import com.android.quickstep.views.DesktopAppSelectView;
import com.android.wm.shell.desktopmode.IDesktopTaskListener;
+import java.util.HashSet;
+import java.util.Set;
+
/**
* Controls the visibility of the workspace and the resumed / paused state when desktop mode
* is enabled.
@@ -48,6 +51,7 @@
private static final boolean IS_STASHING_ENABLED = SystemProperties.getBoolean(
"persist.wm.debug.desktop_stashing", false);
private final Launcher mLauncher;
+ private final Set<DesktopVisibilityListener> mDesktopVisibilityListeners = new HashSet<>();
private int mVisibleDesktopTasksCount;
private boolean mInOverviewState;
@@ -127,6 +131,16 @@
return mVisibleDesktopTasksCount;
}
+ /** Registers a listener for Desktop Mode visibility updates. */
+ public void registerDesktopVisibilityListener(DesktopVisibilityListener listener) {
+ mDesktopVisibilityListeners.add(listener);
+ }
+
+ /** Removes a previously registered Desktop Mode visibility listener. */
+ public void unregisterDesktopVisibilityListener(DesktopVisibilityListener listener) {
+ mDesktopVisibilityListeners.remove(listener);
+ }
+
/**
* Sets the number of desktop windows that are visible and updates launcher visibility based on
* it.
@@ -140,7 +154,12 @@
if (visibleTasksCount != mVisibleDesktopTasksCount) {
final boolean wasVisible = mVisibleDesktopTasksCount > 0;
final boolean isVisible = visibleTasksCount > 0;
+ final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisible();
mVisibleDesktopTasksCount = visibleTasksCount;
+ final boolean areDesktopTasksVisibleNow = areDesktopTasksVisible();
+ if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
+ notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
+ }
if (!enableDesktopWindowingWallpaperActivity() && wasVisible != isVisible) {
// TODO: b/333533253 - Remove after flag rollout
@@ -179,15 +198,22 @@
+ " currentValue=" + mInOverviewState);
}
if (overviewStateEnabled != mInOverviewState) {
+ final boolean wereDesktopTasksVisibleBefore = areDesktopTasksVisible();
mInOverviewState = overviewStateEnabled;
+ final boolean areDesktopTasksVisibleNow = areDesktopTasksVisible();
+ if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
+ notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
+ }
+
if (enableDesktopWindowingWallpaperActivity()) {
return;
}
// TODO: b/333533253 - Clean up after flag rollout
+
if (mInOverviewState) {
setLauncherViewsVisibility(View.VISIBLE);
markLauncherResumed();
- } else if (areDesktopTasksVisible() && !mGestureInProgress) {
+ } else if (areDesktopTasksVisibleNow && !mGestureInProgress) {
// Switching out of overview state and gesture finished.
// If desktop tasks are still visible, hide launcher again.
setLauncherViewsVisibility(View.INVISIBLE);
@@ -196,6 +222,15 @@
}
}
+ private void notifyDesktopVisibilityListeners(boolean areDesktopTasksVisible) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyDesktopVisibilityListeners: visible=" + areDesktopTasksVisible);
+ }
+ for (DesktopVisibilityListener listener : mDesktopVisibilityListeners) {
+ listener.onDesktopVisibilityChanged(areDesktopTasksVisible);
+ }
+ }
+
/**
* TODO: b/333533253 - Remove after flag rollout
*/
@@ -359,4 +394,14 @@
mSelectAppToast.hide();
mSelectAppToast = null;
}
+
+ /** A listener for when the user enters/exits Desktop Mode. */
+ public interface DesktopVisibilityListener {
+ /**
+ * Callback for when the user enters or exits Desktop Mode
+ *
+ * @param visible whether Desktop Mode is now visible
+ */
+ void onDesktopVisibilityChanged(boolean visible);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
new file mode 100644
index 0000000..f665e21
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration
+import android.util.Log
+import android.util.SparseArray
+import androidx.annotation.VisibleForTesting
+import androidx.core.util.valueIterator
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.quickstep.RecentsModel
+import kotlin.collections.filterNotNull
+
+/**
+ * Shows running apps when in Desktop Mode.
+ *
+ * Users can enter and exit Desktop Mode at run-time, meaning this class falls back to the default
+ * recent-apps behaviour when outside of Desktop Mode.
+ *
+ * This class should only be used if
+ * [com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps] is enabled.
+ */
+class DesktopTaskbarRunningAppsController(
+ private val recentsModel: RecentsModel,
+ private val desktopVisibilityController: DesktopVisibilityController?,
+) : TaskbarRecentAppsController() {
+
+ private var apps: Array<AppInfo>? = null
+ private var allRunningDesktopAppInfos: List<AppInfo>? = null
+ private var runningDesktopAppInfosExceptHotseatItems: List<ItemInfo>? = null
+
+ private val isInDesktopMode: Boolean
+ get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false
+
+ override fun onDestroy() {
+ super.onDestroy()
+ apps = null
+ }
+
+ @VisibleForTesting
+ public override fun setApps(apps: Array<AppInfo>?) {
+ this.apps = apps
+ }
+
+ override fun isEnabled() = true
+
+ @VisibleForTesting
+ public override fun updateHotseatItemInfos(hotseatItems: Array<ItemInfo>?): Array<ItemInfo>? {
+ val actualHotseatItems = hotseatItems ?: return super.updateHotseatItemInfos(null)
+ if (!isInDesktopMode) {
+ Log.d(TAG, "updateHotseatItemInfos: not in Desktop Mode")
+ return hotseatItems
+ }
+ val newHotseatItemInfos =
+ actualHotseatItems
+ // Ignore predicted apps - we show running apps instead
+ .filter { itemInfo -> !itemInfo.isPredictedItem }
+ .toMutableList()
+ val runningDesktopAppInfos =
+ runningDesktopAppInfosExceptHotseatItems ?: return newHotseatItemInfos.toTypedArray()
+ newHotseatItemInfos.addAll(runningDesktopAppInfos)
+ return newHotseatItemInfos.toTypedArray()
+ }
+
+ @VisibleForTesting
+ public override fun updateRunningApps(hotseatItems: SparseArray<ItemInfo>?) {
+ if (!isInDesktopMode) {
+ Log.d(TAG, "updateRunningApps: not in Desktop Mode")
+ mControllers.taskbarViewController.commitRunningAppsToUI()
+ return
+ }
+ val allRunningDesktopAppInfos = getRunningDesktopAppInfos()
+ this.allRunningDesktopAppInfos = allRunningDesktopAppInfos
+ runningDesktopAppInfosExceptHotseatItems =
+ hotseatItems?.let {
+ getRunningDesktopAppInfosExceptHotseatApps(allRunningDesktopAppInfos, it.toList())
+ }
+
+ mControllers.taskbarViewController.commitRunningAppsToUI()
+ }
+
+ private fun getRunningDesktopAppInfosExceptHotseatApps(
+ allRunningDesktopAppInfos: List<AppInfo>,
+ hotseatItems: List<ItemInfo>
+ ): List<ItemInfo> {
+ val hotseatPackages = hotseatItems.map { it.targetPackage }
+ return allRunningDesktopAppInfos
+ .filter { appInfo -> !hotseatPackages.contains(appInfo.targetPackage) }
+ .map { WorkspaceItemInfo(it) }
+ }
+
+ private fun getRunningDesktopAppInfos(): List<AppInfo> {
+ return getAppInfosFromRunningTasks(
+ recentsModel.runningTasks
+ .filter { taskInfo: RunningTaskInfo ->
+ taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
+ }
+ .toList()
+ )
+ }
+
+ // TODO(b/335398876) fetch app icons from Tasks instead of AppInfos
+ private fun getAppInfosFromRunningTasks(tasks: List<RunningTaskInfo>): List<AppInfo> {
+ // Early return if apps is empty, since we then have no AppInfo to compare to
+ if (apps == null) {
+ return emptyList()
+ }
+ val packageNames = tasks.map { it.realActivity?.packageName }.distinct().filterNotNull()
+ return packageNames
+ .map { packageName -> apps?.find { app -> packageName == app.targetPackage } }
+ .filterNotNull()
+ }
+
+ private fun <E> SparseArray<E>.toList(): List<E> {
+ return valueIterator().asSequence().toList()
+ }
+
+ companion object {
+ private const val TAG = "TabletDesktopTaskbarRunningAppsController"
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 49d4afe..679528b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -41,6 +41,8 @@
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
@@ -127,7 +129,9 @@
import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.util.ViewCache;
import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.NavHandle;
+import com.android.quickstep.RecentsModel;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
@@ -244,7 +248,7 @@
mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
- final boolean isDesktopMode = getPackageManager().hasSystemFeature(FEATURE_PC);
+ final boolean isPcMode = getPackageManager().hasSystemFeature(FEATURE_PC);
// If Bubble bar is present, TaskbarControllers depends on it so build it first.
Optional<BubbleControllers> bubbleControllersOptional = Optional.empty();
@@ -276,7 +280,7 @@
mControllers = new TaskbarControllers(this,
new TaskbarDragController(this),
buttonController,
- isDesktopMode
+ isPcMode
? new DesktopNavbarButtonsViewController(this, mNavigationBarPanelContext,
navButtonsView)
: new NavbarButtonsViewController(this, mNavigationBarPanelContext,
@@ -301,9 +305,7 @@
new VoiceInteractionWindowController(this),
new TaskbarTranslationController(this),
new TaskbarSpringOnStashController(this),
- isDesktopMode
- ? new DesktopTaskbarRecentAppsController(this)
- : TaskbarRecentAppsController.DEFAULT,
+ createTaskbarRecentAppsController(isPcMode),
new TaskbarEduTooltipController(this),
new KeyboardQuickSwitchController(),
new TaskbarPinningController(this),
@@ -312,6 +314,18 @@
mLauncherPrefs = LauncherPrefs.get(this);
}
+ private TaskbarRecentAppsController createTaskbarRecentAppsController(boolean isPcMode) {
+ if (isPcMode) return new DesktopTaskbarRecentAppsController(this);
+ // TODO(b/335401172): unify DesktopMode checks in Launcher
+ final boolean showRunningAppsInDesktopMode = enableDesktopWindowingMode()
+ && enableDesktopWindowingTaskbarRunningApps();
+ return showRunningAppsInDesktopMode
+ ? new DesktopTaskbarRunningAppsController(
+ RecentsModel.INSTANCE.get(this),
+ LauncherActivityInterface.INSTANCE.getDesktopVisibilityController())
+ : TaskbarRecentAppsController.DEFAULT;
+ }
+
/** Updates {@link DeviceProfile} instances for any Taskbar windows. */
public void updateDeviceProfile(DeviceProfile launcherDp) {
applyDeviceProfile(launcherDp);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 14d46d1..6c84f80 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
+
import android.util.SparseArray;
import android.view.View;
@@ -26,6 +29,7 @@
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
@@ -33,6 +37,7 @@
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.RecentsModel;
import java.io.PrintWriter;
@@ -62,6 +67,8 @@
// Used to defer any UI updates during the SUW unstash animation.
private boolean mDeferUpdatesForSUW;
private Runnable mDeferredUpdates;
+ private DesktopVisibilityController.DesktopVisibilityListener mDesktopVisibilityListener =
+ visible -> updateRunningApps();
public TaskbarModelCallbacks(
TaskbarActivityContext context, TaskbarView container) {
@@ -73,6 +80,15 @@
mControllers = controllers;
if (mControllers.taskbarRecentAppsController.isEnabled()) {
RecentsModel.INSTANCE.get(mContext).registerRunningTasksListener(this);
+
+ if (shouldShowRunningAppsInDesktopMode()) {
+ DesktopVisibilityController desktopVisibilityController =
+ LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+ if (desktopVisibilityController != null) {
+ desktopVisibilityController.registerDesktopVisibilityListener(
+ mDesktopVisibilityListener);
+ }
+ }
}
}
@@ -81,6 +97,20 @@
*/
public void unregisterListeners() {
RecentsModel.INSTANCE.get(mContext).unregisterRunningTasksListener();
+
+ if (shouldShowRunningAppsInDesktopMode()) {
+ DesktopVisibilityController desktopVisibilityController =
+ LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
+ if (desktopVisibilityController != null) {
+ desktopVisibilityController.unregisterDesktopVisibilityListener(
+ mDesktopVisibilityListener);
+ }
+ }
+ }
+
+ private boolean shouldShowRunningAppsInDesktopMode() {
+ // TODO(b/335401172): unify DesktopMode checks in Launcher
+ return enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps();
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index 9799349..ec47c4f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -22,13 +22,12 @@
import android.graphics.Paint
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
-import android.graphics.drawable.ShapeDrawable
import com.android.app.animation.Interpolators
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.Utilities.mapToRange
import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
-import com.android.wm.shell.common.TriangleShape
+import com.android.launcher3.popup.RoundedArrowDrawable
/** Drawable for the background of the bubble bar. */
class BubbleBarBackground(context: Context, private var backgroundHeight: Float) : Drawable() {
@@ -37,7 +36,10 @@
private val LIGHT_THEME_SHADOW_ALPHA = 25f
private val paint: Paint = Paint()
- private val pointerSize: Float
+ private val pointerWidth: Float
+ private val pointerHeight: Float
+ private val pointerTipRadius: Float
+ private val pointerVisibleHeight: Float
private val shadowAlpha: Float
private var shadowBlur = 0f
@@ -47,7 +49,7 @@
private set
private var showingArrow: Boolean = false
- private var arrowDrawable: ShapeDrawable
+ private var arrowDrawable: RoundedArrowDrawable
var width: Float = 0f
@@ -75,7 +77,10 @@
val res = context.resources
shadowBlur = res.getDimension(R.dimen.transient_taskbar_shadow_blur)
keyShadowDistance = res.getDimension(R.dimen.transient_taskbar_key_shadow_distance)
- pointerSize = res.getDimension(R.dimen.bubblebar_pointer_size)
+ pointerWidth = res.getDimension(R.dimen.bubblebar_pointer_width)
+ pointerHeight = res.getDimension(R.dimen.bubblebar_pointer_height)
+ pointerVisibleHeight = res.getDimension(R.dimen.bubblebar_pointer_visible_size)
+ pointerTipRadius = res.getDimension(R.dimen.bubblebar_pointer_radius)
shadowAlpha =
if (Utilities.isDarkTheme(context)) {
@@ -85,11 +90,14 @@
}
arrowDrawable =
- ShapeDrawable(TriangleShape.create(pointerSize, pointerSize, /* pointUp= */ true))
- arrowDrawable.setBounds(0, 0, pointerSize.toInt(), pointerSize.toInt())
- arrowDrawable.paint.flags = Paint.ANTI_ALIAS_FLAG
- arrowDrawable.paint.style = Paint.Style.FILL
- arrowDrawable.paint.color = context.getColor(R.color.taskbar_background)
+ RoundedArrowDrawable.createVerticalRoundedArrow(
+ pointerWidth,
+ pointerHeight,
+ pointerTipRadius,
+ /* isPointingUp= */ true,
+ context.getColor(R.color.taskbar_background)
+ )
+ arrowDrawable.setBounds(0, 0, pointerWidth.toInt(), pointerHeight.toInt())
}
fun showArrow(show: Boolean) {
@@ -114,7 +122,7 @@
keyShadowDistance,
setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
)
- arrowDrawable.paint.setShadowLayer(
+ arrowDrawable.setShadowLayer(
shadowBlur,
0f,
keyShadowDistance,
@@ -127,7 +135,7 @@
val right = if (anchorLeft) width else bounds.width().toFloat()
canvas.drawRoundRect(
left,
- pointerSize,
+ pointerVisibleHeight,
right,
bounds.height().toFloat(),
radius,
@@ -137,10 +145,8 @@
if (showingArrow) {
// Draw arrow.
- val transX = arrowPositionX - pointerSize / 2f
- // Shift arrow down by 1 pixel. Rounded rect has a 1 pixel border which will show up
- // between background and arrow otherwise.
- canvas.translate(transX, 1f)
+ val transX = arrowPositionX - pointerWidth / 2f
+ canvas.translate(transX, 0f)
arrowDrawable.draw(canvas)
}
@@ -157,7 +163,7 @@
override fun setAlpha(alpha: Int) {
paint.alpha = alpha
- arrowDrawable.paint.alpha = alpha
+ arrowDrawable.alpha = alpha
}
override fun getAlpha(): Int {
@@ -169,7 +175,7 @@
}
fun setArrowAlpha(alpha: Int) {
- arrowDrawable.paint.alpha = alpha
+ arrowDrawable.alpha = alpha
}
fun setHeight(newHeight: Float) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 1003c3f..110c30f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -177,7 +177,8 @@
R.dimen.bubblebar_expanded_icon_spacing);
mBubbleElevation = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_elevation);
mDragElevation = getResources().getDimensionPixelSize(R.dimen.bubblebar_drag_elevation);
- mPointerSize = getResources().getDimensionPixelSize(R.dimen.bubblebar_pointer_size);
+ mPointerSize = getResources()
+ .getDimensionPixelSize(R.dimen.bubblebar_pointer_visible_size);
setClipToPadding(false);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index a1a2898..0e62eaf 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -371,10 +371,9 @@
return;
}
- boolean isStashedOrGone =
- mBubbleStashController.isStashed() || mBarView.getVisibility() != VISIBLE;
- // don't animate the new bubble if we're auto expanding from stashed
- if (b instanceof BubbleBarBubble && isStashedOrGone && !isExpanding) {
+ boolean isInApp = mTaskbarStashController.isInApp();
+ // only animate the new bubble if we're in an app and not auto expanding
+ if (b instanceof BubbleBarBubble && isInApp && !isExpanding) {
mBubbleBarViewAnimator.animateBubbleInForStashed((BubbleBarBubble) b);
}
} else {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 9e1addf..8e4dde2 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -38,8 +38,6 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_OVERVIEW_GESTURE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_LEFT;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_QUICKSWITCH_RIGHT;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
@@ -1651,12 +1649,6 @@
int taskToLaunch = mRecentsView.getNextPage();
int runningTask = getLastAppearedTaskIndex();
boolean hasStartedNewTask = hasStartedNewTask();
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "taskToLaunch=" + taskToLaunch);
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "runningTask=" + runningTask);
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "hasStartedNewTask=" + hasStartedNewTask);
if (target == NEW_TASK && taskToLaunch == runningTask
&& !hasStartedNewTask) {
// We are about to launch the current running task, so use LAST_TASK
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index bf50d70..3380291 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -39,6 +39,7 @@
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.NavigationMode;
+import com.android.launcher3.util.SafeCloseable;
import com.android.quickstep.util.RecentsOrientedState;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
@@ -50,7 +51,7 @@
/**
* Helper class for transforming touch events
*/
-public class RotationTouchHelper implements DisplayInfoChangeListener {
+public class RotationTouchHelper implements DisplayInfoChangeListener, SafeCloseable {
public static final MainThreadInitializedObject<RotationTouchHelper> INSTANCE =
new MainThreadInitializedObject<>(RotationTouchHelper::new);
@@ -197,6 +198,11 @@
mOnDestroyActions.add(action);
}
+ @Override
+ public void close() {
+ destroy();
+ }
+
/**
* Cleans up all the registered listeners and receivers.
*/
diff --git a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
index f474796..29a57fc 100644
--- a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
@@ -24,22 +24,30 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
public class SimpleOrientationTouchTransformer implements
- DisplayController.DisplayInfoChangeListener {
+ DisplayController.DisplayInfoChangeListener, SafeCloseable {
public static final MainThreadInitializedObject<SimpleOrientationTouchTransformer> INSTANCE =
new MainThreadInitializedObject<>(SimpleOrientationTouchTransformer::new);
+ private final Context mContext;
private OrientationRectF mOrientationRectF;
public SimpleOrientationTouchTransformer(Context context) {
+ mContext = context;
DisplayController.INSTANCE.get(context).addChangeListener(this);
onDisplayInfoChanged(context, DisplayController.INSTANCE.get(context).getInfo(),
CHANGE_ALL);
}
@Override
+ public void close() {
+ DisplayController.INSTANCE.get(mContext).removeChangeListener(this);
+ }
+
+ @Override
public void onDisplayInfoChanged(Context context, DisplayController.Info info, int flags) {
if ((flags & (CHANGE_ROTATION | CHANGE_ACTIVE_SCREEN)) == 0) {
return;
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 30bb863..ab9840f 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -16,6 +16,7 @@
package com.android.quickstep;
import static android.app.ActivityManager.RECENT_IGNORE_UNAVAILABLE;
+import static android.content.pm.PackageManager.FEATURE_PC;
import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -23,6 +24,8 @@
import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENT_TASKS_MISSING;
import static com.android.quickstep.util.LogUtils.splitFailureMessage;
+import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -32,7 +35,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
import android.content.pm.ShortcutInfo;
import android.graphics.Point;
import android.graphics.Rect;
@@ -65,6 +67,7 @@
import com.android.internal.view.AppearanceRegion;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
import com.android.quickstep.util.ActiveGestureLog;
import com.android.quickstep.util.AssistUtils;
import com.android.quickstep.util.unfold.ProxyUnfoldTransitionProvider;
@@ -108,7 +111,7 @@
/**
* Holds the reference to SystemUI.
*/
-public class SystemUiProxy implements ISystemUiProxy, NavHandle {
+public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable {
private static final String TAG = SystemUiProxy.class.getSimpleName();
public static final MainThreadInitializedObject<SystemUiProxy> INSTANCE =
@@ -199,6 +202,9 @@
}
@Override
+ public void close() { }
+
+ @Override
public void onBackPressed() {
if (mSystemUiProxy != null) {
try {
@@ -1366,8 +1372,7 @@
* Gets the set of running tasks.
*/
public ArrayList<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
- if (mRecentTasks != null
- && mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_PC)) {
+ if (mRecentTasks != null && shouldEnableRunningTasksForDesktopMode()) {
try {
return new ArrayList<>(Arrays.asList(mRecentTasks.getRunningTasks(numTasks)));
} catch (RemoteException e) {
@@ -1377,6 +1382,12 @@
return new ArrayList<>();
}
+ private boolean shouldEnableRunningTasksForDesktopMode() {
+ // TODO(b/335401172): unify DesktopMode checks in Launcher
+ return (enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps())
+ || mContext.getPackageManager().hasSystemFeature(FEATURE_PC);
+ }
+
private boolean handleMessageAsync(Message msg) {
switch (msg.what) {
case MSG_SET_SHELF_HEIGHT:
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index dec8a12..9d899fc 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -59,6 +59,7 @@
public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
&& SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
+ private final Context mCtx;
private RecentsAnimationController mController;
private RecentsAnimationCallbacks mCallbacks;
private RecentsAnimationTargets mTargets;
@@ -66,7 +67,6 @@
private GestureState mLastGestureState;
private RemoteAnimationTarget[] mLastAppearedTaskTargets;
private Runnable mLiveTileCleanUpHandler;
- private Context mCtx;
private boolean mRecentsAnimationStartPending = false;
private boolean mShouldIgnoreMotionEvents = false;
@@ -329,7 +329,7 @@
options.setTransientLaunch();
}
options.setSourceInfo(ActivityOptions.SourceInfo.TYPE_RECENTS_ANIMATION, eventTime);
- mRecentsAnimationStartPending = SystemUiProxy.INSTANCE.getNoCreate()
+ mRecentsAnimationStartPending = SystemUiProxy.INSTANCE.get(mCtx)
.startRecentsActivity(intent, options, mCallbacks);
if (enableHandleDelayedGestureCallbacks()) {
ActiveGestureLog.INSTANCE.addLog(new ActiveGestureLog.CompoundString(
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index a2a6dde..3a6b804 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -34,6 +34,7 @@
import androidx.annotation.UiThread;
import com.android.launcher3.util.MainThreadInitializedObject;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitStageInfo;
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
@@ -57,7 +58,8 @@
* This class tracked the top-most task and some 'approximate' task history to allow faster
* system state estimation during touch interaction
*/
-public class TopTaskTracker extends ISplitScreenListener.Stub implements TaskStackChangeListener {
+public class TopTaskTracker extends ISplitScreenListener.Stub
+ implements TaskStackChangeListener, SafeCloseable {
public static MainThreadInitializedObject<TopTaskTracker> INSTANCE =
new MainThreadInitializedObject<>(TopTaskTracker::new);
@@ -67,12 +69,13 @@
// Ordered list with first item being the most recent task.
private final LinkedList<RunningTaskInfo> mOrderedTaskList = new LinkedList<>();
-
+ private final Context mContext;
private final SplitStageInfo mMainStagePosition = new SplitStageInfo();
private final SplitStageInfo mSideStagePosition = new SplitStageInfo();
private int mPinnedTaskId = INVALID_TASK_ID;
private TopTaskTracker(Context context) {
+ mContext = context;
mMainStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_MAIN;
mSideStagePosition.stageType = SplitConfigurationOptions.STAGE_TYPE_SIDE;
@@ -81,6 +84,12 @@
}
@Override
+ public void close() {
+ TaskStackChangeListeners.getInstance().unregisterTaskStackListener(this);
+ SystemUiProxy.INSTANCE.get(mContext).unregisterSplitScreenListener(this);
+ }
+
+ @Override
public void onTaskRemoved(int taskId) {
mOrderedTaskList.removeIf(rto -> rto.taskId == taskId);
}
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index a09e027..ed633df 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -347,7 +347,6 @@
event.getId() + "";
Log.d(TAG, name);
}
- LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
if (mSlice == null && mSliceItem != null) {
mSlice = LauncherAtom.Slice.newBuilder().setUri(
@@ -369,15 +368,10 @@
return;
}
- if (mItemInfo.container < 0 || appState == null) {
- // Write log on the model thread so that logs do not go out of order
- // (for eg: drop comes after drag)
- Executors.MODEL_EXECUTOR.execute(
- () -> write(event, applyOverwrites(mItemInfo.buildProto())));
- } else {
+ if (mItemInfo.container < 0 || !LauncherAppState.INSTANCE.executeIfCreated(app -> {
// Item is inside a collection, fetch collection info in a BG thread
// and then write to StatsLog.
- appState.getModel().enqueueModelUpdateTask(
+ app.getModel().enqueueModelUpdateTask(
new BaseModelUpdateTask() {
@Override
public void execute(@NonNull final LauncherAppState app,
@@ -388,6 +382,11 @@
write(event, applyOverwrites(mItemInfo.buildProto(collectionInfo)));
}
});
+ })) {
+ // Write log on the model thread so that logs do not go out of order
+ // (for eg: drop comes after drag)
+ Executors.MODEL_EXECUTOR.execute(
+ () -> write(event, applyOverwrites(mItemInfo.buildProto())));
}
}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index 2b4d280..a82031a 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -316,7 +316,7 @@
itemInfos.stream().map(ItemInfo::getComponentKey).toList();
// Use TopTaskTracker to find the currently running app (or apps)
- TopTaskTracker topTaskTracker = getTopTaskTracker(context);
+ TopTaskTracker topTaskTracker = getTopTaskTracker();
// getRunningSplitTasksIds() will return a pair of ids if we are currently running a
// split pair, or an empty array with zero length if we are running a single app.
@@ -489,7 +489,7 @@
* Gets the TopTaskTracker, which is a cached record of the top running Task.
*/
@VisibleForTesting
- public TopTaskTracker getTopTaskTracker(Context context) {
- return TopTaskTracker.INSTANCE.get(context);
+ public TopTaskTracker getTopTaskTracker() {
+ return TopTaskTracker.INSTANCE.get(mContext);
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index b6e6bf7..2396512 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -63,7 +63,7 @@
SplitSelectStateController controller) {
mLauncher = launcher;
mController = controller;
- mIconCache = LauncherAppState.getInstanceNoCreate().getIconCache();
+ mIconCache = LauncherAppState.getInstance(launcher).getIconCache();
mHalfDividerSize = mLauncher.getResources().getDimensionPixelSize(
R.dimen.multi_window_task_divider_size) / 2;
}
diff --git a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
index 89d8cc4..e80d2a6 100644
--- a/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
+++ b/quickstep/src/com/android/quickstep/util/TaskRemovedDuringLaunchListener.java
@@ -22,6 +22,8 @@
import static com.android.launcher3.BaseActivity.EVENT_RESUMED;
import static com.android.launcher3.BaseActivity.EVENT_STOPPED;
+import android.content.Context;
+
import androidx.annotation.NonNull;
import com.android.quickstep.RecentsModel;
@@ -45,6 +47,12 @@
private final Runnable mUnregisterCallback = this::unregister;
private final Runnable mResumeCallback = this::checkTaskLaunchFailed;
+ private final Context mContext;
+
+ public TaskRemovedDuringLaunchListener(Context context) {
+ mContext = context;
+ }
+
/**
* Registers a failure listener callback if it detects a scenario in which an app launch
* failed before the transition finished.
@@ -88,7 +96,7 @@
if (mLaunchedTaskId != INVALID_TASK_ID) {
final int launchedTaskId = mLaunchedTaskId;
final Runnable taskLaunchFailedCallback = mTaskLaunchFailedCallback;
- RecentsModel.INSTANCE.getNoCreate().isTaskRemoved(mLaunchedTaskId, (taskRemoved) -> {
+ RecentsModel.INSTANCE.get(mContext).isTaskRemoved(mLaunchedTaskId, (taskRemoved) -> {
if (taskRemoved) {
ActiveGestureLog.INSTANCE.addLog(
new ActiveGestureLog.CompoundString("Launch failed, task (id=")
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index 8fa5375..82ba30b 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -19,7 +19,7 @@
import static android.provider.Settings.ACTION_APP_USAGE_SETTINGS;
import static com.android.launcher3.Utilities.prefixTextWithIcon;
-import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
+import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
@@ -140,7 +140,7 @@
public void initialize(Task task) {
mAppUsageLimitTimeMs = mAppRemainingTimeMs = -1;
mTask = task;
- THREAD_POOL_EXECUTOR.execute(() -> {
+ ORDERED_BG_EXECUTOR.execute(() -> {
AppUsageLimit usageLimit = null;
try {
usageLimit = mLauncherApps.getAppUsageLimit(
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
index c124f03..1db04a8 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt
@@ -347,7 +347,7 @@
override fun updateArrowColor() {
mArrow.background =
- RoundedArrowDrawable(
+ RoundedArrowDrawable.createHorizontalRoundedArrow(
mArrowWidth.toFloat(),
mArrowHeight.toFloat(),
mArrowPointRadius.toFloat(),
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index ec57115..a033243 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -30,8 +30,6 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -93,6 +91,7 @@
import com.android.launcher3.util.CancellableTask;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.RunnableList;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
import com.android.launcher3.util.TraceHelper;
@@ -118,6 +117,8 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
+import kotlin.Unit;
+
import java.lang.annotation.Retention;
import java.util.Arrays;
import java.util.Collections;
@@ -126,8 +127,6 @@
import java.util.function.Consumer;
import java.util.stream.Stream;
-import kotlin.Unit;
-
/**
* A task in the Recents view.
*/
@@ -649,7 +648,6 @@
*/
public void bind(Task task, RecentsOrientedState orientedState) {
cancelPendingLoadTasks();
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "TaskView.bind: task=" + task);
mTask = task;
mTaskIdContainer[0] = mTask.key.id;
mTaskIdAttributeContainer[0] = new TaskIdAttributeContainer(task, mSnapshotView, mIconView,
@@ -863,11 +861,7 @@
*/
@Nullable
public RunnableList launchTaskAnimated() {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTaskAnimated: mTask=" + mTask);
if (mTask != null) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTaskAnimated: startActivityFromRecentsAsync");
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
ActivityOptionsWrapper opts = mContainer.getActivityLaunchOptions(this, null);
@@ -915,15 +909,12 @@
* Starts the task associated with this view without any animation
*/
public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "TaskView.launchTask: mTask=" + mTask);
if (mTask != null) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTask: startActivityFromRecentsAsync");
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
- final TaskRemovedDuringLaunchListener
- failureListener = new TaskRemovedDuringLaunchListener();
+ TaskRemovedDuringLaunchListener failureListener = new TaskRemovedDuringLaunchListener(
+ getContext().getApplicationContext());
if (isQuickswitch) {
// We only listen for failures to launch in quickswitch because the during this
// gesture launcher is in the background state, vs other launches which are in
@@ -950,12 +941,8 @@
// Indicate success once the system has indicated that the transition has started
ActivityOptions opts = ActivityOptions.makeCustomTaskAnimation(getContext(), 0, 0,
MAIN_EXECUTOR.getHandler(),
- elapsedRealTime -> {
- callback.accept(true);
- },
- elapsedRealTime -> {
- failureListener.onTransitionFinished();
- });
+ elapsedRealTime -> callback.accept(true),
+ elapsedRealTime -> failureListener.onTransitionFinished());
opts.setLaunchDisplayId(
getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
if (isQuickswitch) {
@@ -986,9 +973,6 @@
public RunnableList launchTasks() {
RecentsView recentsView = getRecentsView();
RemoteTargetHandle[] remoteTargetHandles = recentsView.mRemoteTargetHandles;
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTasks: isRunningTask=" + isRunningTask() + ", "
- + "remoteTargetHandles == null?" + (remoteTargetHandles == null));
if (isRunningTask() && remoteTargetHandles != null) {
if (!mIsClickableAsLiveTile) {
Log.e(TAG, "TaskView is not clickable as a live tile; returning to home.");
@@ -1015,8 +999,6 @@
if (targets == null) {
// If the recents animation is cancelled somehow between the parent if block and
// here, try to launch the task as a non live tile task.
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTasks: recents animation is cancelled");
RunnableList runnableList = launchTaskAnimated();
if (runnableList == null) {
Log.e(TAG, "Recents animation cancelled and cannot launch task as non-live tile"
@@ -1037,8 +1019,6 @@
@Override
public void onAnimationEnd(Animator animator) {
if (mTask != null && mTask.key.displayId != getRootViewDisplayId()) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "TaskView.launchTasks: onAnimationEnd");
launchTaskAnimated();
}
mIsClickableAsLiveTile = true;
@@ -1857,7 +1837,7 @@
/**
* We update and subsequently draw these in {@link #setFullscreenProgress(float)}.
*/
- public static class FullscreenDrawParams {
+ public static class FullscreenDrawParams implements SafeCloseable {
private float mCornerRadius;
private float mWindowCornerRadius;
@@ -1892,6 +1872,9 @@
Utilities.mapRange(fullscreenProgress, mCornerRadius, mWindowCornerRadius)
/ parentScale / taskViewScale;
}
+
+ @Override
+ public void close() { }
}
public class TaskIdAttributeContainer {
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
index 9fa4b79..72cfd92 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
@@ -44,7 +44,6 @@
import com.android.launcher3.util.window.CachedDisplayInfo;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.quickstep.FallbackActivityInterface;
-import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.SurfaceTransaction.MockProperties;
import org.hamcrest.Description;
@@ -160,7 +159,6 @@
void verifyNoTransforms() {
LauncherModelHelper helper = new LauncherModelHelper();
try {
- helper.sandboxContext.allow(SystemUiProxy.INSTANCE);
int rotation = mDisplaySize.x > mDisplaySize.y
? Surface.ROTATION_90 : Surface.ROTATION_0;
CachedDisplayInfo cdi = new CachedDisplayInfo(mDisplaySize, rotation);
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
new file mode 100644
index 0000000..93eefe2
--- /dev/null
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
+import android.content.ComponentName
+import android.content.Intent
+import android.os.Process
+import android.os.UserHandle
+import android.testing.AndroidTestingRunner
+import android.util.SparseArray
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.quickstep.RecentsModel
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.kotlin.whenever
+
+@RunWith(AndroidTestingRunner::class)
+class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
+
+ @get:Rule val mockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var mockRecentsModel: RecentsModel
+ @Mock private lateinit var mockDesktopVisibilityController: DesktopVisibilityController
+
+ private var nextTaskId: Int = 500
+
+ private lateinit var taskbarRunningAppsController: DesktopTaskbarRunningAppsController
+ private lateinit var userHandle: UserHandle
+
+ @Before
+ fun setUp() {
+ super.setup()
+ userHandle = Process.myUserHandle()
+ taskbarRunningAppsController =
+ DesktopTaskbarRunningAppsController(mockRecentsModel, mockDesktopVisibilityController)
+ taskbarRunningAppsController.init(taskbarControllers)
+ taskbarRunningAppsController.setApps(
+ ALL_APP_PACKAGES.map { createTestAppInfo(packageName = it) }.toTypedArray()
+ )
+ }
+
+ @Test
+ fun updateHotseatItemInfos_null_returnsNull() {
+ assertThat(taskbarRunningAppsController.updateHotseatItemInfos(/* hotseatItems= */ null))
+ .isNull()
+ }
+
+ @Test
+ fun updateHotseatItemInfos_notInDesktopMode_returnsExistingHotseatItems() {
+ setInDesktopMode(false)
+ val hotseatItems =
+ createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+ .toTypedArray()
+
+ assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems))
+ .isEqualTo(hotseatItems)
+ }
+
+ @Test
+ fun updateHotseatItemInfos_notInDesktopMode_runningApps_returnsExistingHotseatItems() {
+ setInDesktopMode(false)
+ val hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2)
+ val hotseatItems = createHotseatItemsFromPackageNames(hotseatPackages)
+ val runningTasks =
+ createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+ whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+ taskbarRunningAppsController.updateRunningApps(createSparseArray(hotseatItems))
+
+ val newHotseatItems =
+ taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+ assertThat(newHotseatItems?.map { it.targetPackage }).isEqualTo(hotseatPackages)
+ }
+
+ @Test
+ fun updateHotseatItemInfos_noRunningApps_returnsExistingHotseatItems() {
+ setInDesktopMode(true)
+ val hotseatItems: Array<ItemInfo> =
+ createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+ .toTypedArray()
+
+ assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems))
+ .isEqualTo(hotseatItems)
+ }
+
+ @Test
+ fun updateHotseatItemInfos_returnsExistingHotseatItemsAndRunningApps() {
+ setInDesktopMode(true)
+ val hotseatItems =
+ createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+ val runningTasks =
+ createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+ whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+ taskbarRunningAppsController.updateRunningApps(createSparseArray(hotseatItems))
+
+ val newHotseatItems =
+ taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+ val expectedPackages =
+ listOf(
+ HOTSEAT_PACKAGE_1,
+ HOTSEAT_PACKAGE_2,
+ RUNNING_APP_PACKAGE_1,
+ RUNNING_APP_PACKAGE_2,
+ )
+ assertThat(newHotseatItems?.map { it.targetPackage }).isEqualTo(expectedPackages)
+ }
+
+ @Test
+ fun updateHotseatItemInfos_runningAppIsHotseatItem_returnsDistinctItems() {
+ setInDesktopMode(true)
+ val hotseatItems =
+ createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
+ val runningTasks =
+ createDesktopTasksFromPackageNames(
+ listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
+ )
+ whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+ taskbarRunningAppsController.updateRunningApps(createSparseArray(hotseatItems))
+
+ val newHotseatItems =
+ taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+
+ val expectedPackages =
+ listOf(
+ HOTSEAT_PACKAGE_1,
+ HOTSEAT_PACKAGE_2,
+ RUNNING_APP_PACKAGE_1,
+ RUNNING_APP_PACKAGE_2,
+ )
+ assertThat(newHotseatItems?.map { it.targetPackage }).isEqualTo(expectedPackages)
+ }
+
+ private fun createHotseatItemsFromPackageNames(packageNames: List<String>): List<ItemInfo> {
+ return packageNames.map { createTestAppInfo(packageName = it) }
+ }
+
+ private fun createDesktopTasksFromPackageNames(
+ packageNames: List<String>
+ ): ArrayList<RunningTaskInfo> {
+ return ArrayList(packageNames.map { createDesktopTaskInfo(packageName = it) })
+ }
+
+ private fun createDesktopTaskInfo(packageName: String): RunningTaskInfo {
+ return RunningTaskInfo().apply {
+ taskId = nextTaskId++
+ configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM
+ realActivity = ComponentName(packageName, "TestActivity")
+ }
+ }
+
+ private fun createTestAppInfo(
+ packageName: String = "testPackageName",
+ className: String = "testClassName"
+ ) = AppInfo(ComponentName(packageName, className), className /* title */, userHandle, Intent())
+
+ private fun setInDesktopMode(inDesktopMode: Boolean) {
+ whenever(mockDesktopVisibilityController.areDesktopTasksVisible()).thenReturn(inDesktopMode)
+ }
+
+ private fun createSparseArray(itemInfos: List<ItemInfo>): SparseArray<ItemInfo> {
+ val sparseArray = SparseArray<ItemInfo>()
+ itemInfos.forEachIndexed { index, itemInfo -> sparseArray[index] = itemInfo }
+ return sparseArray
+ }
+
+ private companion object {
+ const val HOTSEAT_PACKAGE_1 = "hotseat1"
+ const val HOTSEAT_PACKAGE_2 = "hotseat2"
+ const val RUNNING_APP_PACKAGE_1 = "running1"
+ const val RUNNING_APP_PACKAGE_2 = "running2"
+ const val RUNNING_APP_PACKAGE_3 = "running3"
+ val ALL_APP_PACKAGES =
+ listOf(
+ HOTSEAT_PACKAGE_1,
+ HOTSEAT_PACKAGE_2,
+ RUNNING_APP_PACKAGE_1,
+ RUNNING_APP_PACKAGE_2,
+ RUNNING_APP_PACKAGE_3,
+ )
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java
index fc757b4..ca5fb70 100644
--- a/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/AbstractTaplTestsTaskbar.java
@@ -55,7 +55,7 @@
"com.android.launcher3.testcomponent.BaseTestingActivity");
mLauncherLayout = TestUtil.setLauncherDefaultLayout(mTargetContext, layoutBuilder);
AbstractLauncherUiTest.initialize(this);
- startAppFast(CALCULATOR_APP_PACKAGE);
+ startAppFastInFullscreen(CALCULATOR_APP_PACKAGE);
mLauncher.enableBlockTimeout(true);
mLauncher.showTaskbarIfHidden();
}
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 5b16c0f..2858929 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -22,7 +22,6 @@
import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
import static com.android.launcher3.tapl.TestHelpers.getHomeIntentInPackage;
import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
-import static com.android.launcher3.testing.shared.TestProtocol.UPDATE_OVERVIEW_TARGETS_RUNNING_LATE;
import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_ACTIVITY_TIMEOUT;
import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_BROADCAST_TIMEOUT_SECS;
import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT;
@@ -43,7 +42,6 @@
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.RemoteException;
-import android.util.Log;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -116,8 +114,6 @@
mDevice.setOrientationNatural();
mLauncher = AbstractLauncherUiTest.createLauncherInstrumentation();
mLauncher.enableDebugTracing();
- // b/143488140
- //mLauncher.enableCheckEventsForSuccessfulGestures();
if (TestHelpers.isInLauncherProcess()) {
Utilities.enableRunningInTestHarnessForTests();
@@ -133,13 +129,6 @@
getLauncherCommand(mOtherLauncherActivity));
updateHandler.mChangeCounter
.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS);
- Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
- "AFTER AWAIT: mObserver home intent package name="
- + updateHandler.mObserver.getHomeIntent()
- .getComponent().getPackageName());
- Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
- "AFTER AWAIT: mOtherLauncherActivity package name="
- + mOtherLauncherActivity.packageName);
try {
base.evaluate();
} finally {
@@ -147,7 +136,6 @@
TestCommandReceiver.callCommand(TestCommandReceiver.DISABLE_TEST_LAUNCHER);
UiDevice.getInstance(getInstrumentation()).executeShellCommand(
getLauncherCommand(getLauncherInMyProcess()));
- // b/143488140
pressHomeAndWaitForOverviewClose();
}
}
@@ -191,8 +179,6 @@
}
}
- // b/143488140
- //@NavigationModeSwitch
@Test
public void goToOverviewFromHome() {
mDevice.pressHome();
@@ -261,10 +247,7 @@
DEFAULT_UI_TIMEOUT, mLauncher);
}
- // b/143488140
- //@NavigationModeSwitch
@Test
- @ScreenRecordRule.ScreenRecord // b/321775748
public void testOverview() throws IOException {
startAppFast(getAppPackageName());
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
@@ -348,25 +331,12 @@
mRads = new RecentsAnimationDeviceState(ctx);
mObserver = new OverviewComponentObserver(ctx, mRads);
mChangeCounter = new CountDownLatch(1);
- Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
- "OverviewUpdateHandler(Constructor): mObserver home intent package name="
- + mObserver.getHomeIntent().getComponent().getPackageName());
- Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
- "OverviewUpdateHandler(Constructor): mOtherLauncherActivity package name="
- + mOtherLauncherActivity.packageName);
if (mObserver.getHomeIntent().getComponent()
.getPackageName().equals(mOtherLauncherActivity.packageName)) {
// Home already same
mChangeCounter.countDown();
} else {
- mObserver.setOverviewChangeListener(b -> {
- Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
- "OverviewChangeListener(Callback): isHomeAndOverviewSame=" + b);
- Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
- "OverviewChangeListener(Callback): mObserver home intent package name="
- + mObserver.getHomeIntent().getComponent().getPackageName());
- mChangeCounter.countDown();
- });
+ mObserver.setOverviewChangeListener(b -> mChangeCounter.countDown());
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
index 0c143b4..857a4e3 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -29,6 +29,7 @@
import androidx.test.filters.LargeTest;
import com.android.launcher3.tapl.LauncherInstrumentation;
+import com.android.launcher3.util.rule.ScreenRecordRule;
import org.junit.After;
import org.junit.Test;
@@ -91,6 +92,7 @@
}
@Test
+ @ScreenRecordRule.ScreenRecord // b/334946529
public void testPrivateSpaceContainerIsPresent() {
assumeTrue(mPrivateProfileSetupSuccessful);
// Scroll to the bottom of All Apps
diff --git a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
index e4caa26..1886ce6 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplStartLauncherViaGestureTests.java
@@ -35,7 +35,6 @@
@Before
public void setUp() throws Exception {
super.setUp();
- // b/143488140
mLauncher.goHome();
// Start an activity where the gestures start.
startTestActivity(2);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
index f0683f9..ec245ee 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTaskbar.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep;
+import static androidx.test.InstrumentationRegistry.getTargetContext;
+
import static com.android.launcher3.util.TestConstants.AppNames.TEST_APP_NAME;
import static com.android.quickstep.TaplTestsTaskbar.TaskbarMode.PERSISTENT;
import static com.android.quickstep.TaplTestsTaskbar.TaskbarMode.TRANSIENT;
@@ -53,7 +55,7 @@
@Override
public void setUp() throws Exception {
- mTaskbarWasInTransientMode = isTaskbarInTransientMode(mTargetContext);
+ mTaskbarWasInTransientMode = isTaskbarInTransientMode(getTargetContext());
setTaskbarMode(mLauncher, isTaskbarTestModeTransient());
super.setUp();
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
index 374722e..1556aa5 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -30,6 +30,7 @@
import com.android.launcher3.tapl.LauncherInstrumentation.TrackpadGestureType;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import org.junit.After;
@@ -84,6 +85,7 @@
@Test
@PortraitLandscape
@NavigationModeSwitch
+ @ScreenRecordRule.ScreenRecord // b/335674307
public void switchToOverview() throws Exception {
assumeTrue(mLauncher.isTablet());
diff --git a/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt b/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt
index adaf7ff..ece67af 100644
--- a/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/util/AppPairsControllerTest.kt
@@ -43,6 +43,7 @@
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
import org.mockito.kotlin.never
import org.mockito.kotlin.spy
@@ -100,8 +101,7 @@
// Stub methods on appPairsController so that they return mocks
spyAppPairsController = spy(appPairsController)
whenever(mockAppPairIcon.context).thenReturn(mockTaskbarActivityContext)
- whenever(spyAppPairsController.getTopTaskTracker(mockTaskbarActivityContext))
- .thenReturn(mockTopTaskTracker)
+ doReturn(mockTopTaskTracker).whenever(spyAppPairsController).topTaskTracker
whenever(mockTopTaskTracker.getCachedTopTask(any())).thenReturn(mockCachedTaskInfo)
whenever(mockTask1.getKey()).thenReturn(mockTaskKey1)
whenever(mockTask2.getKey()).thenReturn(mockTaskKey2)
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index d4c18f0..6946ed5 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -124,7 +124,7 @@
<string name="allow_rotation_title" msgid="7222049633713050106">"Дазволіць паварот галоўнага экрана"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"Пры павароце тэлефона"</string>
<string name="notification_dots_title" msgid="9062440428204120317">"Значкі апавяшчэнняў"</string>
- <string name="notification_dots_desc_on" msgid="1679848116452218908">"Укл."</string>
+ <string name="notification_dots_desc_on" msgid="1679848116452218908">"Уключана"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Выкл."</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Патрабуецца доступ да апавяшчэнняў"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Каб паказваліся значкі апавяшчэнняў, уключыце апавяшчэнні праграм для <xliff:g id="NAME">%1$s</xliff:g>"</string>
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 98cb84e..f405b93 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -59,6 +59,7 @@
import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.Partner;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.WindowManagerProxy;
@@ -75,7 +76,7 @@
import java.util.Objects;
import java.util.stream.Collectors;
-public class InvariantDeviceProfile {
+public class InvariantDeviceProfile implements SafeCloseable {
public static final String TAG = "IDP";
// We do not need any synchronization for this variable as its only written on UI thread.
@@ -229,9 +230,8 @@
if (!newGridName.equals(gridName)) {
LauncherPrefs.get(context).put(GRID_NAME, newGridName);
}
- LockedUserState.get(context).runOnUserUnlocked(() -> {
- new DeviceGridState(this).writeToPrefs(context);
- });
+ LockedUserState.get(context).runOnUserUnlocked(() ->
+ new DeviceGridState(this).writeToPrefs(context));
DisplayController.INSTANCE.get(context).setPriorityListener(
(displayContext, info, flags) -> {
@@ -295,6 +295,11 @@
initGrid(context, myInfo, result, deviceType);
}
+ @Override
+ public void close() {
+ DisplayController.INSTANCE.executeIfCreated(dc -> dc.setPriorityListener(null));
+ }
+
/**
* Reinitialize the current grid after a restore, where some grids might now be disabled.
*/
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 50a597d..d2633e0 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -78,14 +78,10 @@
private final RunnableList mOnTerminateCallback = new RunnableList();
- public static LauncherAppState getInstance(final Context context) {
+ public static LauncherAppState getInstance(Context context) {
return INSTANCE.get(context);
}
- public static LauncherAppState getInstanceNoCreate() {
- return INSTANCE.getNoCreate();
- }
-
public Context getContext() {
return mContext;
}
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index 80a8cea..b503739 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -30,6 +30,7 @@
import com.android.launcher3.states.RotationHelper
import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.MainThreadInitializedObject
+import com.android.launcher3.util.SafeCloseable
import com.android.launcher3.util.Themes
/**
@@ -37,7 +38,7 @@
*
* TODO(b/262721340): Replace all direct SharedPreference refs with LauncherPrefs / Item methods.
*/
-class LauncherPrefs(private val encryptedContext: Context) {
+class LauncherPrefs(private val encryptedContext: Context) : SafeCloseable {
private val deviceProtectedStorageContext =
encryptedContext.createDeviceProtectedStorageContext()
@@ -242,6 +243,8 @@
}
}
+ override fun close() {}
+
companion object {
@VisibleForTesting const val BOOT_AWARE_PREFS_KEY = "boot_aware_prefs"
diff --git a/src/com/android/launcher3/LauncherProvider.java b/src/com/android/launcher3/LauncherProvider.java
index 4e0ba62..6e2d357 100644
--- a/src/com/android/launcher3/LauncherProvider.java
+++ b/src/com/android/launcher3/LauncherProvider.java
@@ -48,11 +48,11 @@
*/
@Override
public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
- LauncherAppState appState = LauncherAppState.getInstanceNoCreate();
- if (appState == null || !appState.getModel().isModelLoaded()) {
- return;
- }
- appState.getModel().dumpState("", fd, writer, args);
+ LauncherAppState.INSTANCE.executeIfCreated(appState -> {
+ if (appState.getModel().isModelLoaded()) {
+ appState.getModel().dumpState("", fd, writer, args);
+ }
+ });
}
@Override
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 564daf1..1b0ad04 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -294,7 +294,9 @@
private void onScaleProgressChanged() {
final float scaleProgress = mAllAppScale.value;
SCALE_PROPERTY.set(mLauncher.getAppsView(), scaleProgress);
- mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
+ if (!mLauncher.getAppsView().isSearching() || !mLauncher.getDeviceProfile().isTablet) {
+ mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
+ }
AllAppsRecyclerView rv = mLauncher.getAppsView().getActiveRecyclerView();
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 0e4b48e..50d2b43 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -66,7 +66,6 @@
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -88,14 +87,11 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
-import com.android.launcher3.pm.InstallSessionHelper;
-import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.IntArray;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
-import com.android.launcher3.util.PluginManagerWrapper;
import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.views.ActivityContext;
@@ -104,7 +100,6 @@
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.LauncherWidgetHolder;
import com.android.launcher3.widget.LocalColorExtractor;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
import com.android.launcher3.widget.util.WidgetSizes;
import java.util.ArrayList;
@@ -136,13 +131,10 @@
new ConcurrentLinkedQueue<>();
public PreviewContext(Context base, InvariantDeviceProfile idp) {
- super(base, UserCache.INSTANCE, InstallSessionHelper.INSTANCE, LauncherPrefs.INSTANCE,
- LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
- CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE,
- WindowManagerProxy.INSTANCE, DisplayController.INSTANCE);
+ super(base);
mIdp = idp;
- mObjectMap.put(InvariantDeviceProfile.INSTANCE, idp);
- mObjectMap.put(LauncherAppState.INSTANCE,
+ putObject(InvariantDeviceProfile.INSTANCE, idp);
+ putObject(LauncherAppState.INSTANCE,
new LauncherAppState(this, null /* iconCacheFileName */));
}
@@ -419,7 +411,7 @@
private void inflateAndAddWidgets(LauncherAppWidgetInfo info, WidgetsModel widgetsModel) {
WidgetItem widgetItem = widgetsModel.getWidgetProviderInfoByProviderName(
- info.providerName, info.user);
+ info.providerName, info.user, mContext);
if (widgetItem == null) {
return;
}
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index 90aba2a..551c2d8 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -45,7 +45,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings.Favorites;
-import com.android.launcher3.Utilities;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -55,6 +54,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.PersistedItemArray;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import java.util.HashSet;
@@ -65,7 +65,7 @@
/**
* Class to maintain a queue of pending items to be added to the workspace.
*/
-public class ItemInstallQueue {
+public class ItemInstallQueue implements SafeCloseable {
private static final String LOG = "ItemInstallQueue";
@@ -99,6 +99,9 @@
mContext = context;
}
+ @Override
+ public void close() {}
+
@WorkerThread
private void ensureQueueLoaded() {
Preconditions.assertWorkerThread();
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 91ce5ea..5e0edb3 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -118,8 +118,8 @@
Map<PackageUserKey, List<WidgetItem>> packagesToWidgets = new HashMap<>();
mWidgetsList.forEach((packageItemInfo, widgetsAndShortcuts) -> {
List<WidgetItem> widgets = widgetsAndShortcuts.stream()
- .filter(item -> item.widgetInfo != null)
- .collect(toList());
+ .filter(item -> item.widgetInfo != null)
+ .collect(toList());
if (widgets.size() > 0) {
packagesToWidgets.put(
new PackageUserKey(packageItemInfo.packageName, packageItemInfo.user),
@@ -239,20 +239,45 @@
}
}
+ private PackageItemInfo createPackageItemInfo(
+ ComponentName providerName,
+ UserHandle user,
+ int category
+ ) {
+ if (category == NO_CATEGORY) {
+ return new PackageItemInfo(providerName.getPackageName(), user);
+ } else {
+ return new PackageItemInfo("" , category, user);
+ }
+ }
+
+ private IntSet getCategories(ComponentName providerName, Context context) {
+ IntSet categories = WidgetSections.getWidgetsToCategory(context).get(providerName);
+ if (categories != null) {
+ return categories;
+ }
+ categories = new IntSet();
+ categories.add(NO_CATEGORY);
+ return categories;
+ }
+
public WidgetItem getWidgetProviderInfoByProviderName(
- ComponentName providerName, UserHandle user) {
+ ComponentName providerName, UserHandle user, Context context) {
if (!WIDGETS_ENABLED) {
return null;
}
- List<WidgetItem> widgetsList = mWidgetsList.get(
- new PackageItemInfo(providerName.getPackageName(), user));
- if (widgetsList == null) {
- return null;
- }
+ IntSet categories = getCategories(providerName, context);
- for (WidgetItem item : widgetsList) {
- if (item.componentName.equals(providerName)) {
- return item;
+ // Checking if we have a provider in any of the categories.
+ for (Integer category: categories) {
+ PackageItemInfo key = createPackageItemInfo(providerName, user, category);
+ List<WidgetItem> widgets = mWidgetsList.get(key);
+ if (widgets != null) {
+ return widgets.stream().filter(
+ item -> item.componentName.equals(providerName)
+ )
+ .findFirst()
+ .orElse(null);
}
}
return null;
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 8c3efd7..72e85c7 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -427,12 +427,10 @@
@NonNull
protected LauncherAtom.ItemInfo.Builder getDefaultItemInfoBuilder() {
LauncherAtom.ItemInfo.Builder itemBuilder = LauncherAtom.ItemInfo.newBuilder();
- UserIconInfo info = getUserInfo();
- itemBuilder.setIsWork(info != null && info.isWork());
- itemBuilder.setUserType(getUserType(info));
- SettingsCache settingsCache = SettingsCache.INSTANCE.getNoCreate();
- boolean isKidsMode = settingsCache != null && settingsCache.getValue(NAV_BAR_KIDS_MODE, 0);
- itemBuilder.setIsKidsMode(isKidsMode);
+ SettingsCache.INSTANCE.executeIfCreated(cache ->
+ itemBuilder.setIsKidsMode(cache.getValue(NAV_BAR_KIDS_MODE, 0)));
+ UserCache.INSTANCE.executeIfCreated(cache ->
+ itemBuilder.setUserType(getUserType(cache.getUserInfo(user))));
itemBuilder.setRank(rank);
return itemBuilder;
}
@@ -526,15 +524,6 @@
this.title = title;
}
- private UserIconInfo getUserInfo() {
- UserCache userCache = UserCache.INSTANCE.getNoCreate();
- if (userCache == null) {
- return null;
- }
-
- return userCache.getUserInfo(user);
- }
-
private int getUserType(UserIconInfo info) {
if (info == null) {
return SysUiStatsLog.LAUNCHER_UICHANGED__USER_TYPE__TYPE_UNKNOWN;
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index e1d1868..e66f496 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -32,7 +32,6 @@
import com.android.launcher3.Flags;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.SessionCommitReceiver;
-import com.android.launcher3.Utilities;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.util.IntArray;
@@ -41,6 +40,7 @@
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
+import com.android.launcher3.util.SafeCloseable;
import java.util.ArrayList;
import java.util.HashMap;
@@ -52,7 +52,7 @@
* Utility class to tracking install sessions
*/
@SuppressWarnings("NewApi")
-public class InstallSessionHelper {
+public class InstallSessionHelper implements SafeCloseable {
@NonNull
private static final String LOG = "InstallSessionHelper";
@@ -89,6 +89,9 @@
mLauncherApps = context.getSystemService(LauncherApps.class);
}
+ @Override
+ public void close() { }
+
@WorkerThread
@NonNull
private IntSet getPromiseIconIds() {
diff --git a/src/com/android/launcher3/popup/RoundedArrowDrawable.java b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
index 436aa51..575052c 100644
--- a/src/com/android/launcher3/popup/RoundedArrowDrawable.java
+++ b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
@@ -84,11 +84,12 @@
* @param width of the arrow.
* @param height of the arrow.
* @param radius of the tip of the arrow.
- * @param isPointingLeft or not.
+ * @param isHorizontal or not.
+ * @param isLeftOrTop or not.
* @param color to draw the triangle.
*/
- public RoundedArrowDrawable(float width, float height, float radius, boolean isPointingLeft,
- int color) {
+ private RoundedArrowDrawable(float width, float height, float radius, boolean isHorizontal,
+ boolean isLeftOrTop, int color) {
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(color);
@@ -98,10 +99,47 @@
// Make the drawable with the triangle pointing down...
addDownPointingRoundedTriangleToPath(width, height, radius, mPath);
- // ... then rotate it to the side it needs to point.
- Matrix pathTransform = new Matrix();
- pathTransform.setRotate(isPointingLeft ? 90 : -90, width * 0.5f, height * 0.5f);
- mPath.transform(pathTransform);
+ if (isHorizontal || isLeftOrTop) {
+ // ... then rotate it to the side it needs to point.
+ Matrix pathTransform = new Matrix();
+ int rotationAngle;
+ if (isHorizontal) {
+ rotationAngle = isLeftOrTop ? 90 : -90;
+ } else {
+ // it could only be vertical arrow pointing up
+ rotationAngle = 180;
+ }
+ pathTransform.setRotate(rotationAngle, width * 0.5f, height * 0.5f);
+ mPath.transform(pathTransform);
+ }
+ }
+
+ /**
+ * factory method for an arrow that points to the left or right.
+ *
+ * @param width of the arrow.
+ * @param height of the arrow.
+ * @param radius of the tip of the arrow.
+ * @param isPointingLeft or not.
+ * @param color to draw the triangle.
+ */
+ public static RoundedArrowDrawable createHorizontalRoundedArrow(float width, float height,
+ float radius, boolean isPointingLeft, int color) {
+ return new RoundedArrowDrawable(width, height, radius, true, isPointingLeft, color);
+ }
+
+ /**
+ * factory method for an arrow that points to the left or right.
+ *
+ * @param width of the arrow.
+ * @param height of the arrow.
+ * @param radius of the tip of the arrow.
+ * @param isPointingUp or not.
+ * @param color to draw the triangle.
+ */
+ public static RoundedArrowDrawable createVerticalRoundedArrow(float width, float height,
+ float radius, boolean isPointingUp, int color) {
+ return new RoundedArrowDrawable(width, height, radius, false, isPointingUp, color);
}
@Override
@@ -129,6 +167,14 @@
mPaint.setColorFilter(colorFilter);
}
+ /**
+ * Set shadow layer to internal {@link Paint#setShadowLayer(float, float, float, int) paint}
+ * object
+ */
+ public void setShadowLayer(float shadowBlur, float dx, float dy, int shadowColor) {
+ mPaint.setShadowLayer(shadowBlur, dx, dy, shadowColor);
+ }
+
private static void addDownPointingRoundedTriangleToPath(float width, float height,
float radius, Path path) {
// Calculated for the arrow pointing down, will be flipped later if needed.
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index d5f1e18..a4ff29f 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -526,10 +526,7 @@
}
logFavoritesTable(controller.getDb(), "launcher db after remap widget ids", null, null);
- LauncherAppState app = LauncherAppState.getInstanceNoCreate();
- if (app != null) {
- app.getModel().forceReload();
- }
+ LauncherAppState.INSTANCE.executeIfCreated(app -> app.getModel().forceReload());
}
private static void logDatabaseWidgetInfo(ModelDbController controller) {
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index d5c9b9f..db2a6e0 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -94,13 +94,10 @@
protected Context mContext;
protected DeviceProfile mDeviceProfile;
- protected LauncherAppState mLauncherAppState;
public void init(Context context) {
mContext = context;
- mDeviceProfile = InvariantDeviceProfile.INSTANCE.
- get(context).getDeviceProfile(context);
- mLauncherAppState = LauncherAppState.getInstanceNoCreate();
+ mDeviceProfile = InvariantDeviceProfile.INSTANCE.get(context).getDeviceProfile(context);
if (sActivityLifecycleCallbacks == null) {
sActivityLifecycleCallbacks = new ActivityLifecycleCallbacksAdapter() {
@Override
diff --git a/src/com/android/launcher3/util/ActivityTracker.java b/src/com/android/launcher3/util/ActivityTracker.java
index 95a0511..b2d0d75 100644
--- a/src/com/android/launcher3/util/ActivityTracker.java
+++ b/src/com/android/launcher3/util/ActivityTracker.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.util;
-import static com.android.launcher3.testing.shared.TestProtocol.GET_FROM_RECENTS_FAILURE;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
-
import android.util.Log;
import androidx.annotation.Nullable;
@@ -46,9 +43,6 @@
public void onActivityDestroyed(T activity) {
if (mCurrentActivity.get() == activity) {
- testLogD(GET_FROM_RECENTS_FAILURE,
- String.format("ActivityTracker.onActivityDestroyed this=%s, activity=%s",
- this, activity));
mCurrentActivity.clear();
}
}
@@ -82,8 +76,6 @@
}
public boolean handleCreate(T activity) {
- testLogD(GET_FROM_RECENTS_FAILURE,
- String.format("ActivityTracker.handleCreate this=%s, activity=%s", this, activity));
mCurrentActivity = new WeakReference<>(activity);
return handleIntent(activity, false /* alreadyOnHome */);
}
diff --git a/src/com/android/launcher3/util/BgObjectWithLooper.java b/src/com/android/launcher3/util/BgObjectWithLooper.java
deleted file mode 100644
index adc3c7d..0000000
--- a/src/com/android/launcher3/util/BgObjectWithLooper.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (C) 2020 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.database.ContentObserver;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Looper;
-
-import androidx.annotation.WorkerThread;
-
-import java.util.function.Consumer;
-
-/**
- * Utility class to define an object which does most of it's processing on a
- * dedicated background thread.
- */
-public abstract class BgObjectWithLooper {
-
- /**
- * Start initialization of the object
- */
- public final void initializeInBackground(String threadName) {
- new Thread(this::runOnThread, threadName).start();
- }
-
- private void runOnThread() {
- Looper.prepare();
- onInitialized(Looper.myLooper());
- Looper.loop();
- }
-
- /**
- * Called on the background thread to handle initialization
- */
- @WorkerThread
- protected abstract void onInitialized(Looper looper);
-
- /**
- * Helper method to create a content provider
- */
- protected static ContentObserver newContentObserver(Handler handler, Consumer<Uri> command) {
- return new ContentObserver(handler) {
- @Override
- public void onChange(boolean selfChange, Uri uri) {
- command.accept(uri);
- }
- };
- }
-}
diff --git a/src/com/android/launcher3/util/DynamicResource.java b/src/com/android/launcher3/util/DynamicResource.java
index 1008ebb..fbdb5c2 100644
--- a/src/com/android/launcher3/util/DynamicResource.java
+++ b/src/com/android/launcher3/util/DynamicResource.java
@@ -33,7 +33,8 @@
*
* To allow customization for a particular resource, add them to dynamic_resources.xml
*/
-public class DynamicResource implements ResourceProvider, PluginListener<ResourceProvider> {
+public class DynamicResource implements
+ ResourceProvider, PluginListener<ResourceProvider>, SafeCloseable {
private static final MainThreadInitializedObject<DynamicResource> INSTANCE =
new MainThreadInitializedObject<>(DynamicResource::new);
@@ -48,6 +49,11 @@
}
@Override
+ public void close() {
+ PluginManagerWrapper.INSTANCE.get(mContext).removePluginListener(this);
+ }
+
+ @Override
public int getInt(@IntegerRes int resId) {
return mContext.getResources().getInteger(resId);
}
diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java
index b966d8e..1a0f9a0 100644
--- a/src/com/android/launcher3/util/MainThreadInitializedObject.java
+++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java
@@ -28,17 +28,15 @@
import com.android.launcher3.util.ResourceBasedOverride.Overrides;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
import java.util.concurrent.ExecutionException;
+import java.util.function.Consumer;
/**
* Utility class for defining singletons which are initiated on main thread.
*/
-public class MainThreadInitializedObject<T> {
+public class MainThreadInitializedObject<T extends SafeCloseable> {
private final ObjectProvider<T> mProvider;
private T mValue;
@@ -48,14 +46,14 @@
}
public T get(Context context) {
- if (context instanceof SandboxContext sc) {
+ Context app = context.getApplicationContext();
+ if (app instanceof SandboxApplication sc) {
return sc.getObject(this);
}
if (mValue == null) {
if (Looper.myLooper() == Looper.getMainLooper()) {
- mValue = TraceHelper.allowIpcs("main.thread.object",
- () -> mProvider.get(context.getApplicationContext()));
+ mValue = TraceHelper.allowIpcs("main.thread.object", () -> mProvider.get(app));
} else {
try {
return MAIN_EXECUTOR.submit(() -> get(context)).get();
@@ -67,8 +65,18 @@
return mValue;
}
- public T getNoCreate() {
- return mValue;
+ /**
+ * Executes the callback is the value is already created
+ * @return true if the callback was executed, false otherwise
+ */
+ public boolean executeIfCreated(Consumer<T> callback) {
+ T v = mValue;
+ if (v != null) {
+ callback.accept(v);
+ return true;
+ } else {
+ return false;
+ }
}
@VisibleForTesting
@@ -79,8 +87,8 @@
/**
* Initializes a provider based on resource overrides
*/
- public static <T extends ResourceBasedOverride> MainThreadInitializedObject<T> forOverride(
- Class<T> clazz, int resourceId) {
+ public static <T extends ResourceBasedOverride & SafeCloseable> MainThreadInitializedObject<T>
+ forOverride(Class<T> clazz, int resourceId) {
return new MainThreadInitializedObject<>(c -> Overrides.getObject(clazz, c, resourceId));
}
@@ -89,24 +97,36 @@
T get(Context context);
}
+ public interface SandboxApplication {
+
+ /**
+ * Find a cached object from mObjectMap if we have already created one. If not, generate
+ * an object using the provider.
+ */
+ <T extends SafeCloseable> T getObject(MainThreadInitializedObject<T> object);
+
+ @UiThread
+ default <T extends SafeCloseable> T createObject(MainThreadInitializedObject<T> object) {
+ return object.mProvider.get((Context) this);
+ }
+ }
+
/**
* Abstract Context which allows custom implementations for
* {@link MainThreadInitializedObject} providers
*/
- public static class SandboxContext extends ContextWrapper {
+ public static class SandboxContext extends ContextWrapper implements SandboxApplication {
private static final String TAG = "SandboxContext";
- protected final Set<MainThreadInitializedObject> mAllowedObjects;
- protected final Map<MainThreadInitializedObject, Object> mObjectMap = new HashMap<>();
- protected final ArrayList<Object> mOrderedObjects = new ArrayList<>();
+ private final Map<MainThreadInitializedObject, Object> mObjectMap = new HashMap<>();
+ private final ArrayList<SafeCloseable> mOrderedObjects = new ArrayList<>();
private final Object mDestroyLock = new Object();
private boolean mDestroyed = false;
- public SandboxContext(Context base, MainThreadInitializedObject... allowedObjects) {
+ public SandboxContext(Context base) {
super(base);
- mAllowedObjects = new HashSet<>(Arrays.asList(allowedObjects));
}
@Override
@@ -118,20 +138,14 @@
synchronized (mDestroyLock) {
// Destroy in reverse order
for (int i = mOrderedObjects.size() - 1; i >= 0; i--) {
- Object o = mOrderedObjects.get(i);
- if (o instanceof SafeCloseable) {
- ((SafeCloseable) o).close();
- }
+ mOrderedObjects.get(i).close();
}
mDestroyed = true;
}
}
- /**
- * Find a cached object from mObjectMap if we have already created one. If not, generate
- * an object using the provider.
- */
- protected <T> T getObject(MainThreadInitializedObject<T> object) {
+ @Override
+ public <T extends SafeCloseable> T getObject(MainThreadInitializedObject<T> object) {
synchronized (mDestroyLock) {
if (mDestroyed) {
Log.e(TAG, "Static object access with a destroyed context");
@@ -142,12 +156,6 @@
}
if (Looper.myLooper() == Looper.getMainLooper()) {
t = createObject(object);
- // Check if we've explicitly allowed the object or if it's a SafeCloseable,
- // it will get destroyed in onDestroy()
- if (!mAllowedObjects.contains(object) && !(t instanceof SafeCloseable)) {
- throw new IllegalStateException("Leaking unknown objects "
- + object + " " + object.mProvider + " " + t);
- }
mObjectMap.put(object, t);
mOrderedObjects.add(t);
return t;
@@ -161,17 +169,12 @@
}
}
- @UiThread
- protected <T> T createObject(MainThreadInitializedObject<T> object) {
- return object.mProvider.get(this);
- }
-
/**
* Put a value into mObjectMap, can be used to put mocked MainThreadInitializedObject
* instances into SandboxContext.
*/
- @VisibleForTesting
- public <T> void putObject(MainThreadInitializedObject<T> object, T value) {
+ public <T extends SafeCloseable> void putObject(
+ MainThreadInitializedObject<T> object, T value) {
mObjectMap.put(object, value);
}
}
diff --git a/src/com/android/launcher3/util/ScreenOnTracker.java b/src/com/android/launcher3/util/ScreenOnTracker.java
index 67530a6..e16e477 100644
--- a/src/com/android/launcher3/util/ScreenOnTracker.java
+++ b/src/com/android/launcher3/util/ScreenOnTracker.java
@@ -27,7 +27,7 @@
/**
* Utility class for tracking if the screen is currently on or off
*/
-public class ScreenOnTracker {
+public class ScreenOnTracker implements SafeCloseable {
public static final MainThreadInitializedObject<ScreenOnTracker> INSTANCE =
new MainThreadInitializedObject<>(ScreenOnTracker::new);
@@ -35,14 +35,21 @@
private final SimpleBroadcastReceiver mReceiver = new SimpleBroadcastReceiver(this::onReceive);
private final CopyOnWriteArrayList<ScreenOnListener> mListeners = new CopyOnWriteArrayList<>();
+ private final Context mContext;
private boolean mIsScreenOn;
private ScreenOnTracker(Context context) {
// Assume that the screen is on to begin with
+ mContext = context;
mIsScreenOn = true;
mReceiver.register(context, ACTION_SCREEN_ON, ACTION_SCREEN_OFF, ACTION_USER_PRESENT);
}
+ @Override
+ public void close() {
+ mReceiver.unregisterReceiverSafely(mContext);
+ }
+
private void onReceive(Intent intent) {
String action = intent.getAction();
if (ACTION_SCREEN_ON.equals(action)) {
diff --git a/src/com/android/launcher3/util/VibratorWrapper.java b/src/com/android/launcher3/util/VibratorWrapper.java
index cd60c1d..b2b4959 100644
--- a/src/com/android/launcher3/util/VibratorWrapper.java
+++ b/src/com/android/launcher3/util/VibratorWrapper.java
@@ -39,7 +39,7 @@
/**
* Wrapper around {@link Vibrator} to easily perform haptic feedback where necessary.
*/
-public class VibratorWrapper {
+public class VibratorWrapper implements SafeCloseable {
public static final MainThreadInitializedObject<VibratorWrapper> INSTANCE =
new MainThreadInitializedObject<>(VibratorWrapper::new);
@@ -77,6 +77,7 @@
private final Vibrator mVibrator;
private final boolean mHasVibrator;
+ private ContentObserver mHapticFeedbackObserver;
private boolean mIsHapticFeedbackEnabled;
private VibratorWrapper(Context context) {
@@ -86,14 +87,14 @@
if (mHasVibrator) {
final ContentResolver resolver = context.getContentResolver();
mIsHapticFeedbackEnabled = isHapticFeedbackEnabled(resolver);
- final ContentObserver observer = new ContentObserver(MAIN_EXECUTOR.getHandler()) {
+ mHapticFeedbackObserver = new ContentObserver(MAIN_EXECUTOR.getHandler()) {
@Override
public void onChange(boolean selfChange) {
mIsHapticFeedbackEnabled = isHapticFeedbackEnabled(resolver);
}
};
resolver.registerContentObserver(Settings.System.getUriFor(HAPTIC_FEEDBACK_ENABLED),
- false /* notifyForDescendants */, observer);
+ false /* notifyForDescendants */, mHapticFeedbackObserver);
} else {
mIsHapticFeedbackEnabled = false;
}
@@ -126,6 +127,13 @@
}
}
+ @Override
+ public void close() {
+ if (mHapticFeedbackObserver != null) {
+ mContext.getContentResolver().unregisterContentObserver(mHapticFeedbackObserver);
+ }
+ }
+
/**
* This is called when the user swipes to/from all apps. This is meant to be used in between
* long animation progresses so that it gives a dragging texture effect. For a better
diff --git a/src/com/android/launcher3/util/window/WindowManagerProxy.java b/src/com/android/launcher3/util/window/WindowManagerProxy.java
index 998191e..4b004f3 100644
--- a/src/com/android/launcher3/util/window/WindowManagerProxy.java
+++ b/src/com/android/launcher3/util/window/WindowManagerProxy.java
@@ -59,6 +59,7 @@
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.NavigationMode;
import com.android.launcher3.util.ResourceBasedOverride;
+import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.WindowBounds;
import java.util.ArrayList;
@@ -67,7 +68,7 @@
/**
* Utility class for mocking some window manager behaviours
*/
-public class WindowManagerProxy implements ResourceBasedOverride {
+public class WindowManagerProxy implements ResourceBasedOverride, SafeCloseable {
private static final String TAG = "WindowManagerProxy";
public static final int MIN_TABLET_WIDTH = 600;
@@ -305,12 +306,12 @@
navBarHeightPortrait = isTablet
? (mTaskbarDrawnInProcess
- ? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
+ ? 0 : context.getResources().getDimensionPixelSize(R.dimen.taskbar_size))
: getDimenByName(systemRes, NAVBAR_HEIGHT);
navBarHeightLandscape = isTablet
? (mTaskbarDrawnInProcess
- ? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
+ ? 0 : context.getResources().getDimensionPixelSize(R.dimen.taskbar_size))
: (isTabletOrGesture
? getDimenByName(systemRes, NAVBAR_HEIGHT_LANDSCAPE) : 0);
navbarWidthLandscape = isTabletOrGesture
@@ -474,6 +475,9 @@
NavigationMode.THREE_BUTTONS;
}
+ @Override
+ public void close() { }
+
/**
* @see DisplayCutout#getSafeInsets
*/
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 97aa67d..b14ec42 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -216,6 +216,7 @@
protected WidgetCell addItemCell(ViewGroup parent) {
WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext())
.inflate(R.layout.widget_cell, parent, false);
+ widget.setOnClickListener(this);
View previewContainer = widget.findViewById(R.id.widget_preview_container);
previewContainer.setOnClickListener(this);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index a7f7785..56352cc 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -160,6 +160,7 @@
WidgetCell widget = (WidgetCell) mLayoutInflater.inflate(
R.layout.widget_cell, tableRow, false);
// set up touch.
+ widget.setOnClickListener(mIconClickListener);
View preview = widget.findViewById(R.id.widget_preview_container);
preview.setOnClickListener(mIconClickListener);
preview.setOnLongClickListener(mIconLongClickListener);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
index a565780..03af0cb 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -123,6 +123,7 @@
private WidgetCell addItemCell(ViewGroup parent) {
WidgetCell widget = (WidgetCell) LayoutInflater.from(
getContext()).inflate(R.layout.widget_cell, parent, false);
+ widget.setOnClickListener(mWidgetCellOnClickListener);
View previewContainer = widget.findViewById(R.id.widget_preview_container);
previewContainer.setOnClickListener(mWidgetCellOnClickListener);
diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml
index 27dd2a9..a9b75ea 100644
--- a/tests/AndroidManifest-common.xml
+++ b/tests/AndroidManifest-common.xml
@@ -319,6 +319,15 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity-alias>
+ <activity-alias android:name="ActivityNoLabel"
+ android:label=""
+ android:exported="true"
+ android:targetActivity="com.android.launcher3.testcomponent.BaseTestingActivity">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity-alias>
<activity-alias android:name="MaxShortcutsActivity"
android:label="TestActivityMaxShortcuts"
android:exported="true"
diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index fea0330..108db6c 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -174,13 +174,11 @@
public static final String ICON_MISSING = "b/282963545";
public static final String OVERVIEW_OVER_HOME = "b/279059025";
public static final String UIOBJECT_STALE_ELEMENT = "b/319501259";
- public static final String GET_FROM_RECENTS_FAILURE = "b/321775748";
- public static final String SUCCESSFUL_GESTURE_MISMATCH_EVENTS = "b/324940434";
public static final String TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE = "b/326908466";
public static final String TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE = "b/326073471";
public static final String WIDGET_CONFIG_NULL_EXTRA_INTENT = "b/324419890";
public static final String ACTIVITY_NOT_RESUMED_AFTER_BACK = "b/322823209";
- public static final String UPDATE_OVERVIEW_TARGETS_RUNNING_LATE = "b/321775748";
+ public static final String OVERVIEW_SELECT_TOOLTIP_MISALIGNED = "b/332485341";
public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
index 0009a4e..002f496 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LauncherModelHelper.java
@@ -52,17 +52,11 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherModel.ModelUpdateTask;
-import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.model.ItemInstallQueue;
-import com.android.launcher3.pm.InstallSessionHelper;
-import com.android.launcher3.pm.UserCache;
import com.android.launcher3.testing.TestInformationProvider;
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
-import com.android.launcher3.util.window.WindowManagerProxy;
-import com.android.launcher3.widget.custom.CustomWidgetManager;
import java.io.ByteArrayOutputStream;
import java.io.File;
@@ -233,13 +227,7 @@
private final File mDbDir;
public SandboxModelContext() {
- super(ApplicationProvider.getApplicationContext(),
- UserCache.INSTANCE, InstallSessionHelper.INSTANCE, LauncherPrefs.INSTANCE,
- LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
- DisplayController.INSTANCE, CustomWidgetManager.INSTANCE,
- SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE,
- LockedUserState.INSTANCE, WallpaperColorHints.INSTANCE,
- ItemInstallQueue.INSTANCE, WindowManagerProxy.INSTANCE);
+ super(ApplicationProvider.getApplicationContext());
// System settings cache content provider. Ensure that they are statically initialized
Settings.Secure.getString(
@@ -254,18 +242,13 @@
}
@Override
- protected <T> T createObject(MainThreadInitializedObject<T> object) {
+ public <T extends SafeCloseable> T createObject(MainThreadInitializedObject<T> object) {
if (object == LauncherAppState.INSTANCE) {
return (T) new LauncherAppState(this, null /* iconCacheFileName */);
}
return super.createObject(object);
}
- public SandboxModelContext allow(MainThreadInitializedObject object) {
- mAllowedObjects.add(object);
- return this;
- }
-
@Override
public File getDatabasePath(String name) {
if (!mDbDir.exists()) {
diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index 577334b..aefc2db 100644
--- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -300,13 +300,7 @@
smallestScreenWidthDp = min(screenWidthDp, screenHeightDp)
}
val configurationContext = runningContext.createConfigurationContext(config)
- context =
- SandboxContext(
- configurationContext,
- DisplayController.INSTANCE,
- WindowManagerProxy.INSTANCE,
- LauncherPrefs.INSTANCE
- )
+ context = SandboxContext(configurationContext)
context.putObject(DisplayController.INSTANCE, displayController)
context.putObject(WindowManagerProxy.INSTANCE, windowManagerProxy)
context.putObject(LauncherPrefs.INSTANCE, launcherPrefs)
diff --git a/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
index 389d027..28a1325 100644
--- a/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
+++ b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
@@ -40,7 +40,6 @@
import com.android.launcher3.tapl.WidgetResizeFrame;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.ModelTestExtensions;
-import com.android.launcher3.util.rule.ScreenRecordRule;
import com.android.launcher3.util.rule.ShellCommandRule;
import org.junit.After;
@@ -238,7 +237,6 @@
}
@Test
- @ScreenRecordRule.ScreenRecord // b/330019521
public void simpleReorder() throws Exception {
runTestCaseMap(getTestMap("ReorderWidgets/simple_reorder_case"),
"push_reorder_case");
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 99e15ba..9c289d6 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -15,7 +15,10 @@
*/
package com.android.launcher3.ui;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
+import static android.view.Display.DEFAULT_DISPLAY;
import static androidx.test.InstrumentationRegistry.getInstrumentation;
@@ -26,6 +29,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import android.app.ActivityOptions;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
@@ -571,6 +575,21 @@
true /* newTask */);
}
+ /** alternative of startAppFast where app is guaranteed to launch in fullscreen mode */
+ public static void startAppFastInFullscreen(String packageName) {
+ ActivityOptions options = ActivityOptions.makeBasic();
+ options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN);
+ options.setLaunchDisplayId(DEFAULT_DISPLAY);
+ options.setLaunchActivityType(ACTIVITY_TYPE_STANDARD);
+
+ startIntent(
+ getInstrumentation().getContext().getPackageManager().getLaunchIntentForPackage(
+ packageName),
+ By.pkg(packageName).depth(0),
+ true /* newTask */,
+ options);
+ }
+
public static void startTestActivity(String activityName, String activityLabel) {
final String packageName = getAppPackageName();
final Intent intent = getInstrumentation().getContext().getPackageManager().
@@ -606,7 +625,8 @@
false /* newTask */);
}
- private static void startIntent(Intent intent, BySelector selector, boolean newTask) {
+ private static void startIntent(
+ Intent intent, BySelector selector, boolean newTask, ActivityOptions options) {
intent.addCategory(Intent.CATEGORY_LAUNCHER);
if (newTask) {
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
@@ -614,7 +634,12 @@
intent.addFlags(
Intent.FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);
}
- getInstrumentation().getTargetContext().startActivity(intent);
+
+ if (options != null) {
+ getInstrumentation().getTargetContext().startActivity(intent, options.toBundle());
+ } else {
+ getInstrumentation().getTargetContext().startActivity(intent);
+ }
assertTrue("App didn't start: " + selector,
TestHelpers.wait(Until.hasObject(selector), DEFAULT_UI_TIMEOUT));
@@ -625,6 +650,10 @@
DEFAULT_ACTIVITY_TIMEOUT, launcherInstrumentation);
}
+ private static void startIntent(Intent intent, BySelector selector, boolean newTask) {
+ startIntent(intent, selector, newTask, null);
+ }
+
public static ActivityInfo resolveSystemAppInfo(String category) {
return getInstrumentation().getContext().getPackageManager().resolveActivity(
new Intent(Intent.ACTION_MAIN).addCategory(category),
diff --git a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
index 706ab27..2e57ad5 100644
--- a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -45,6 +45,7 @@
import org.mockito.kotlin.any
import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.doNothing
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.eq
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
@@ -123,6 +124,7 @@
whenever(displayManager.getDisplay(any())).thenReturn(display)
// Mock resources
+ doReturn(context).whenever(context).applicationContext
whenever(resources.configuration).thenReturn(configuration)
whenever(context.resources).thenReturn(resources)
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index 3f96999..200f2ff 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -24,13 +24,11 @@
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_SHELL_DRAG_READY;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_STASHED_TASKBAR_SCALE;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemClock;
-import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -141,8 +139,6 @@
return new Taskbar(mLauncher);
} finally {
- Log.d(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "swipeUpToUnstashTaskbar: completed gesture");
mLauncher.getTestInfo(REQUEST_DISABLE_BLOCK_TIMEOUT);
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 0a52955..ba8121f 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -31,10 +31,8 @@
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_GET_SPLIT_SELECTION_ACTIVE;
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_NUM_ALL_APPS_COLUMNS;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import android.app.ActivityManager;
import android.app.Instrumentation;
@@ -2400,13 +2398,9 @@
}
if (mEventChecker != null) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "eventsCheck: mEventChecker exists");
mEventChecker = null;
if (mCheckEventsForSuccessfulGestures) {
final String message = eventChecker.verify(WAIT_TIME_MS, true);
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
- "mCheckEventsForSuccessfulGestures = true | eventsCheck: message="
- + message);
if (message != null) {
dumpDiagnostics(message);
checkForAnomaly();
diff --git a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
index 70d63bd..672c6e0 100644
--- a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
+++ b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
@@ -18,8 +18,6 @@
import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_MAIN;
import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_PILFER;
import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_TIS;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import android.os.SystemClock;
@@ -90,7 +88,6 @@
}
String verify(long waitForExpectedCountMs, boolean successfulGesture) {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "LogEventChecker.java - verify");
final ListMap<String> actualEvents = finishSync(waitForExpectedCountMs);
if (actualEvents == null) return "null event sequences because launcher likely died";
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index 99da5c3..6f420af 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -19,10 +19,8 @@
import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.DEFAULT;
import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT;
import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.SPLIT_TOP_OR_LEFT;
-import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
import android.graphics.Rect;
-import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -222,7 +220,6 @@
return new LaunchedAppState(mLauncher);
}
} else {
- Log.d(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "TaskView.launchTaskAnimated");
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
return new LaunchedAppState(mLauncher);
}