Merge "Import translations. DO NOT MERGE ANYWHERE" into main
diff --git a/Android.bp b/Android.bp
index 223e2c2..73d0fce 100644
--- a/Android.bp
+++ b/Android.bp
@@ -387,6 +387,7 @@
"//frameworks/libs/systemui:view_capture",
"//frameworks/libs/systemui:animationlib",
"//frameworks/libs/systemui:contextualeducationlib",
+ "//frameworks/libs/systemui:msdl",
"SystemUI-statsd",
"launcher-testing-shared",
"androidx.lifecycle_lifecycle-common-java8",
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index ee7e975..878aa6e 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -519,4 +519,11 @@
namespace: "launcher"
description: "Enable MSDL feedback for Launcher interactions"
bug: "377496684"
+}
+
+flag {
+ name: "taskbar_recents_layout_transition"
+ namespace: "launcher"
+ description: "Enable Taskbar LayoutTransition for Recent Apps"
+ bug: "343521765"
}
\ No newline at end of file
diff --git a/aconfig/launcher_overview.aconfig b/aconfig/launcher_overview.aconfig
index 4335f76..93d8d54 100644
--- a/aconfig/launcher_overview.aconfig
+++ b/aconfig/launcher_overview.aconfig
@@ -54,4 +54,11 @@
namespace: "launcher_overview"
description: "Makes the desktop windowing task carousel detaches from fullscreen task carousel during quickswitch."
bug: "353947917"
+}
+
+flag {
+ name: "enable_desktop_exploded_view"
+ namespace: "launcher_overview"
+ description: "Enables the non-overlapping layout for desktop windows in Overview mode."
+ bug: "378011776"
}
\ No newline at end of file
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index f868baa..de550d1 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -52,8 +52,8 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Přejeďte prstem z úplného pravého nebo levého okraje obrazovky"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Přejeďte prstem z pravého nebo levého okraje doprostřed obrazovky a zdvihněte prst"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili jste se, jak se vrátit zpět přejetím prstem zprava. Teď se naučíte přepínat mezi aplikacemi."</string>
- <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Dokončili jste gesto pro přechod zpět. Teď se naučíte přepínat aplikace."</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Dokončili jste gesto pro přechod zpět"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Provedli jste gesto pro přechod zpět. Teď se naučíte přepínat aplikace."</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Provedli jste gesto pro přechod zpět"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Dejte pozor, abyste prstem nepřejížděli moc blízko ke spodnímu okraji obrazovky"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Citlivost gesta pro přechod zpět můžete změnit v Nastavení"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"Přejetím prstem se vrátíte zpět"</string>
@@ -64,8 +64,8 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Přejeďte prstem nahoru z dolního okraje obrazovky"</string>
<string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Před zdvihnutím prstu nedělejte pauzu"</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Přejeďte prstem přímo nahoru"</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Dokončili jste gesto pro přechod na plochu. Teď se naučíte vrátit se zpět."</string>
- <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Dokončili jste gesto pro přechod na plochu"</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Provedli jste gesto pro přechod na plochu. Teď se naučíte vrátit se zpět."</string>
+ <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Provedli jste gesto pro přechod na plochu"</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Přechod na plochu přejetím prstem"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Přejeďte prstem ze spodní části obrazovky nahoru. Tímto gestem se vždy dostanete na plochu."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Přejeďte dvěma prsty z dolního okraje obrazovky nahoru. Tímto gestem se vždy dostanete na plochu."</string>
@@ -76,7 +76,7 @@
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Zkuste podržet okno delší dobu, než ho uvolníte"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Přejeďte prstem přímo nahoru a pak udělejte pauzu"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili jste se používat gesta. Vypnout je můžete v Nastavení."</string>
- <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Dokončili jste gesto pro přepínání aplikací"</string>
+ <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Provedli jste gesto pro přepínání aplikací"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Přepínání aplikací přejetím prstem"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Přejeďte nahoru z dolního okraje obrazovky, podržte obrazovku a uvolněte."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Přepínání mezi aplikacemi: Přejeďte dvěma prsty nahoru z dolního okraje obrazovky, podržte obrazovku a uvolněte."</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 07ab18b..b022172 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -52,8 +52,8 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Stryg fra kanten yderst til højre eller venstre"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Stryg fra højre eller venstre kant mod midten af skærmen, og løft fingeren"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Du har lært, hvordan du stryger fra højre for at gå tilbage. Nu skal du se, hvordan du skifter app."</string>
- <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Du har fuldført bevægelsen for Gå tilbage. Som det næste kan du se, hvordan du skifter app."</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Du har fuldført bevægelsen for Gå tilbage"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Du har udført bevægelsen for Gå tilbage. Som det næste kan du se, hvordan du skifter app."</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Du har udført bevægelsen for Gå tilbage"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Undgå at stryge for tæt på bunden af skærmen"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Juster følsomheden for bevægelsen Gå tilbage i Indstillinger"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"Stryg for at gå tilbage"</string>
@@ -64,8 +64,8 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"Stryg opad fra bunden af skærmen"</string>
<string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"Undlad at holde fingeren stille, indtil du løfter fingeren"</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"Stryg lige opad"</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Du har fuldført bevægelsen for Gå til startskærmen. Som det næste kan du se, hvordan du går tilbage."</string>
- <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Du har fuldført bevægelsen for Gå til startskærmen"</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"Du har udført bevægelsen for Gå til startskærmen. Som det næste kan du se, hvordan du går tilbage."</string>
+ <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"Du har udført bevægelsen for Gå til startskærmen"</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"Stryg for at gå til startskærmen"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"Stryg opad fra bunden af skærmen. Denne bevægelse åbner altid startskærmen."</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"Stryg opad med 2 fingre fra bunden af skærmen. Denne bevægelse åbner altid startskærmen."</string>
@@ -76,7 +76,7 @@
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Prøv at holde fingeren nede på vinduet i længere tid, inden du løfter den"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Stryg lige opad, og hold derefter fingeren stille"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Du har lært, hvordan du bruger bevægelser. Du kan aktivere bevægelser i Indstillinger."</string>
- <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Du har fuldført bevægelsen for at skifte mellem apps"</string>
+ <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Du har udført bevægelsen for at skifte mellem apps"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Stryg for at skifte app"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Skift mellem apps ved at stryge opad fra bunden af skærmen, holde fingeren stille og løfte den."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Skift mellem apps ved at stryge opad fra bunden af skærmen med 2 fingre, holde dem nede og slippe."</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 49d1664..0f374ba 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -52,8 +52,8 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"स्क्रिनको सबैभन्दा दायाँ किनारा वा सबैभन्दा बायाँ किनाराबाट स्वाइप गर्नुहोस्"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"स्क्रिनको दायाँ वा बायाँ किनाराबाट मध्य भागसम्म स्वाइप गर्नुहोस् अनि औँला उठाउनुहोस्"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"तपाईंले स्क्रिनको दायाँ किनाराबाट स्वाइप गरेर अघिल्लो स्क्रिनमा फर्कने तरिका सिक्नुभयो। अब एउटा एपबाट अर्को एपमा जाने तरिका सिक्नुहोस्।"</string>
- <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"तपाईंले \'पछाडि जानुहोस्\' नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो। अब एउटा एपबाट अर्को एपमा जाने तरिका सिक्नुहोस्।"</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"तपाईंले \"पछाडि जानुहोस्\" नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"तपाईंले जेस्चर प्रयोग गरी पछाडि जाने तरिका सिक्नुभएको छ। अब एउटा एपबाट अर्को एपमा जाने तरिका सिक्नुहोस्।"</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"तपाईंले जेस्चर प्रयोग गरी पछाडि जाने तरिका सिक्नुभएको छ"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"स्क्रिनको फेदको धेरै नजिकसम्म स्वाइप नगर्नुहोस्"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"\'पछाडि\' नामक इसाराको संवेदनशीलता बदल्न सेटिङमा जानुहोस्"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"पछाडि जान स्वाइप गर्नुहोस्"</string>
@@ -64,7 +64,7 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्"</string>
<string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"औँला उठाउनुअघि नरोकिनुहोस्"</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"सीधै माथितिर स्वाइप गर्नुहोस्"</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"तपाईंले \"होम स्क्रिनमा जानुहोस्\" नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो। अब पछाडि जाने तरिका सिक्नुहोस्।"</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"तपाईंले जेस्चर प्रयोग गरी होम स्क्रिनमा जाने तरिका सिक्नुभएको छ। अब पछाडि जाने तरिका सिक्नुहोस्।"</string>
<string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"तपाईंले \"होम स्क्रिनमा जानुहोस्\" नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो"</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"होम स्क्रिनमा जान स्वाइप गर्नुहोस्"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"स्क्रिनको फेदबाट माथितिर स्वाइप गर्नुहोस्। यो इसारा प्रयोग गर्दा सधैँ होम स्क्रिन खुल्छ।"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 99b53d9..30e73e6 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -52,8 +52,8 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ปัดจากขอบด้านขวาสุดหรือซ้ายสุด"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ตรวจสอบว่าปัดจากขอบด้านขวาหรือซ้ายไปตรงกลางหน้าจอ แล้วยกนิ้วขึ้น"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"คุณรู้วิธีปัดจากด้านขวาเพื่อย้อนกลับแล้ว ต่อไปดูวิธีสลับแอป"</string>
- <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับเสร็จแล้ว ต่อไปดูวิธีสลับแอป"</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับเสร็จแล้ว"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับสำเร็จแล้ว ต่อไปดูวิธีสลับแอป"</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับสำเร็จแล้ว"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ไม่ปัดใกล้กับด้านล่างของหน้าจอมากเกินไป"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"เปลี่ยนความไวของท่าทางสัมผัสเพื่อย้อนกลับได้ที่การตั้งค่า"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"ปัดเพื่อย้อนกลับ"</string>
@@ -64,8 +64,8 @@
<string name="home_gesture_feedback_swipe_too_far_from_edge" msgid="4816365433160895458">"ปัดขึ้นจากขอบด้านล่างของหน้าจอ"</string>
<string name="home_gesture_feedback_overview_detected" msgid="5177627157303895077">"ไม่ต้องหยุดชั่วคราวก่อนยกนิ้วขึ้น"</string>
<string name="home_gesture_feedback_wrong_swipe_direction" msgid="8328465201424027148">"ปัดขึ้นในแนวตรง"</string>
- <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกเสร็จแล้ว ต่อไปดูวิธีย้อนกลับ"</string>
- <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกเสร็จแล้ว"</string>
+ <string name="home_gesture_feedback_complete_with_follow_up" msgid="8766981412895888417">"คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกสำเร็จแล้ว ต่อไปดูวิธีย้อนกลับ"</string>
+ <string name="home_gesture_feedback_complete_without_follow_up" msgid="2978063221383413443">"คุณทำท่าทางสัมผัสเพื่อไปที่หน้าแรกสำเร็จแล้ว"</string>
<string name="home_gesture_intro_title" msgid="836590312858441830">"ปัดเพื่อไปที่หน้าแรก"</string>
<string name="home_gesture_intro_subtitle" msgid="2632238748497975326">"ปัดขึ้นจากด้านล่างของหน้าจอ ท่าทางสัมผัสนี้จะนำคุณไปที่หน้าจอหลักเสมอ"</string>
<string name="home_gesture_spoken_intro_subtitle" msgid="1030987707382031750">"ใช้ 2 นิ้วปัดขึ้นจากด้านล่างของหน้าจอ ท่าทางสัมผัสนี้จะนำคุณไปที่หน้าจอหลักเสมอ"</string>
@@ -76,7 +76,7 @@
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"ลองแตะหน้าต่างค้างไว้นานขึ้นก่อนปล่อยนิ้ว"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"ปัดขึ้นในแนวตรง แล้วหยุดชั่วคราว"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"คุณรู้วิธีใช้ท่าทางสัมผัสแล้ว หากต้องการปิดท่าทางสัมผัส ให้ไปที่การตั้งค่า"</string>
- <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"คุณทำท่าทางสัมผัสเพื่อสลับแอปเสร็จแล้ว"</string>
+ <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"คุณทำท่าทางสัมผัสเพื่อสลับแอปสำเร็จแล้ว"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"ปัดเพื่อสลับแอป"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"หากต้องการสลับระหว่างแอปต่างๆ ให้ปัดขึ้นจากด้านล่างของหน้าจอ ค้างไว้ แล้วปล่อย"</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"หากต้องการสลับระหว่างแอป ให้ใช้ 2 นิ้วปัดขึ้นจากด้านล่างของหน้าจอค้างไว้แล้วปล่อย"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 3a32551..7eeacde 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -53,7 +53,7 @@
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Hãy vuốt từ mép phải hoặc mép trái tới giữa màn hình rồi nhấc ngón tay ra"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Bạn đã học được cách vuốt từ mép phải để quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng."</string>
<string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Bạn đã thực hiện xong cử chỉ quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng."</string>
- <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Bạn đã thực hiện xong cử chỉ quay lại"</string>
+ <string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Bạn đã hoàn tất cử chỉ quay lại"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Hãy nhớ không được vuốt quá gần phần dưới cùng của màn hình"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Để thay đổi độ nhạy của cử chỉ quay lại, hãy vào mục Cài đặt"</string>
<string name="back_gesture_intro_title" msgid="19551256430224428">"Vuốt để quay lại"</string>
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index bd2c7cc..dc0f899 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -55,6 +55,7 @@
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.picker.WidgetsFullSheet;
import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
+import com.android.systemui.animation.back.FlingOnBackAnimationCallback;
import java.util.ArrayList;
import java.util.HashSet;
@@ -374,12 +375,12 @@
/**
* Animation callback for different predictive back animation states for the widget picker.
*/
- private class BackAnimationCallback implements OnBackAnimationCallback {
+ private class BackAnimationCallback extends FlingOnBackAnimationCallback {
@Nullable
OnBackAnimationCallback mActiveOnBackAnimationCallback;
@Override
- public void onBackStarted(@NonNull BackEvent backEvent) {
+ public void onBackStartedCompat(@NonNull BackEvent backEvent) {
if (mActiveOnBackAnimationCallback != null) {
mActiveOnBackAnimationCallback.onBackCancelled();
}
@@ -390,7 +391,7 @@
}
@Override
- public void onBackInvoked() {
+ public void onBackInvokedCompat() {
if (mActiveOnBackAnimationCallback == null) {
return;
}
@@ -399,7 +400,7 @@
}
@Override
- public void onBackProgressed(@NonNull BackEvent backEvent) {
+ public void onBackProgressedCompat(@NonNull BackEvent backEvent) {
if (mActiveOnBackAnimationCallback == null) {
return;
}
@@ -407,7 +408,7 @@
}
@Override
- public void onBackCancelled() {
+ public void onBackCancelledCompat() {
if (mActiveOnBackAnimationCallback == null) {
return;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 09dbeb6..b1cb2c6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -372,6 +372,11 @@
* mTaskbarInAppDisplayProgress.value);
mControllers.navbarButtonsViewController
.getOnTaskbarBackgroundNavButtonColorOverride().updateValue(progress);
+
+ if (isBubbleBarEnabled()) {
+ mControllers.bubbleControllers.ifPresent(
+ c -> c.bubbleStashController.setInAppDisplayOverrideProgress(progress));
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 7273fac..eb47bb0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -192,7 +192,9 @@
public void onDestroy() {
- mRegionSamplingHelper.stopAndDestroy();
+ if (mRegionSamplingHelper != null) {
+ mRegionSamplingHelper.stopAndDestroy();
+ }
mRegionSamplingHelper = null;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
index 8a86402..b7f5575 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
@@ -108,8 +108,10 @@
/** Clean up animations. */
public void onDestroy() {
startIconUndimming();
- mControllers.navbarButtonsViewController.setHomeButtonAccessibilityDelegate(null);
- mControllers.navbarButtonsViewController.setBackButtonAccessibilityDelegate(null);
+ if (mControllers != null) {
+ mControllers.navbarButtonsViewController.setHomeButtonAccessibilityDelegate(null);
+ mControllers.navbarButtonsViewController.setBackButtonAccessibilityDelegate(null);
+ }
}
private void startIconUndimming() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 3e2c4b9..e0814d3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -528,9 +528,10 @@
* <p>
* Updates the value locally in Launcher and in WMShell.
*/
- public void updateBubbleBarLocation(BubbleBarLocation location) {
+ public void updateBubbleBarLocation(BubbleBarLocation location,
+ @BubbleBarLocation.UpdateSource int source) {
updateBubbleBarLocationInternal(location);
- mSystemUiProxy.setBubbleBarLocation(location);
+ mSystemUiProxy.setBubbleBarLocation(location, source);
}
private void updateBubbleBarLocationInternal(BubbleBarLocation location) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index c0a76a8..350f56f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -407,11 +407,13 @@
return true;
}
if (action == R.id.action_move_left) {
- mController.updateBubbleBarLocation(BubbleBarLocation.LEFT);
+ mController.updateBubbleBarLocation(BubbleBarLocation.LEFT,
+ BubbleBarLocation.UpdateSource.A11Y_ACTION_BAR);
return true;
}
if (action == R.id.action_move_right) {
- mController.updateBubbleBarLocation(BubbleBarLocation.RIGHT);
+ mController.updateBubbleBarLocation(BubbleBarLocation.RIGHT,
+ BubbleBarLocation.UpdateSource.A11Y_ACTION_BAR);
return true;
}
return false;
@@ -1567,6 +1569,7 @@
void dismissBubbleBar();
/** Requests the controller to update bubble bar location to the given value */
- void updateBubbleBarLocation(BubbleBarLocation location);
+ void updateBubbleBarLocation(BubbleBarLocation location,
+ @BubbleBarLocation.UpdateSource int source);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 96fadf7..776a98e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -217,8 +217,9 @@
}
@Override
- public void updateBubbleBarLocation(BubbleBarLocation location) {
- mBubbleBarController.updateBubbleBarLocation(location);
+ public void updateBubbleBarLocation(BubbleBarLocation location,
+ @BubbleBarLocation.UpdateSource int source) {
+ mBubbleBarController.updateBubbleBarLocation(location, source);
}
});
@@ -242,8 +243,9 @@
}
@Override
- public void updateBubbleBarLocation(BubbleBarLocation location) {
- mBubbleBarController.updateBubbleBarLocation(location);
+ public void updateBubbleBarLocation(BubbleBarLocation location,
+ @BubbleBarLocation.UpdateSource int source) {
+ mBubbleBarController.updateBubbleBarLocation(location, source);
}
};
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index 42bd197..fd4cf0e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -161,7 +161,8 @@
@Override
void onDragEnd() {
- mBubbleBarController.updateBubbleBarLocation(mReleasedLocation);
+ mBubbleBarController.updateBubbleBarLocation(mReleasedLocation,
+ BubbleBarLocation.UpdateSource.DRAG_BUBBLE);
mBubbleBarViewController.onBubbleDragEnd();
mBubblePinController.setListener(null);
}
@@ -226,7 +227,8 @@
@Override
void onDragEnd() {
// Make sure to update location as the first thing. Pivot update causes a relayout
- mBubbleBarController.updateBubbleBarLocation(mReleasedLocation);
+ mBubbleBarController.updateBubbleBarLocation(mReleasedLocation,
+ BubbleBarLocation.UpdateSource.DRAG_BAR);
bubbleBarView.setIsDragging(false);
// Restoring the initial pivot for the bubble bar view
bubbleBarView.setRelativePivot(initialRelativePivot.x, initialRelativePivot.y);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index 0ea4222..c74fa9b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -224,12 +224,14 @@
}
if (action == R.id.action_move_left) {
if (mController != null) {
- mController.updateBubbleBarLocation(BubbleBarLocation.LEFT);
+ mController.updateBubbleBarLocation(BubbleBarLocation.LEFT,
+ BubbleBarLocation.UpdateSource.A11Y_ACTION_BUBBLE);
}
}
if (action == R.id.action_move_right) {
if (mController != null) {
- mController.updateBubbleBarLocation(BubbleBarLocation.RIGHT);
+ mController.updateBubbleBarLocation(BubbleBarLocation.RIGHT,
+ BubbleBarLocation.UpdateSource.A11Y_ACTION_BUBBLE);
}
}
return false;
@@ -483,6 +485,7 @@
void collapse();
/** Request bubble bar location to be updated to the given location */
- void updateBubbleBarLocation(BubbleBarLocation location);
+ void updateBubbleBarLocation(BubbleBarLocation location,
+ @BubbleBarLocation.UpdateSource int source);
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
index 831faa1..d9589bb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
@@ -176,12 +176,18 @@
bubbleBarTranslationYForTaskbar
}
- /** Translation Y to align the bubble bar with the hotseat. */
+ /** Translation Y to align the bubble bar with the taskbar. */
val bubbleBarTranslationYForTaskbar: Float
- /** Return translation Y to align the bubble bar with the taskbar. */
+ /** Return translation Y to align the bubble bar with the hotseat. */
val bubbleBarTranslationYForHotseat: Float
+ /**
+ * Show bubble bar is if it were in-app while launcher state is still on home. Set as a progress
+ * value between 0 and 1: 0 - use home layout, 1 - use in-app layout.
+ */
+ var inAppDisplayOverrideProgress: Float
+
/** Dumps the state of BubbleStashController. */
fun dump(pw: PrintWriter) {
pw.println("Bubble stash controller state:")
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
index c117ad4..9a68335 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashController.kt
@@ -22,6 +22,8 @@
import android.graphics.Rect
import android.view.MotionEvent
import android.view.View
+import com.android.app.animation.Interpolators
+import com.android.launcher3.Utilities
import com.android.launcher3.anim.AnimatedFloat
import com.android.launcher3.taskbar.TaskbarInsetsController
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
@@ -97,6 +99,34 @@
return -hotseatVerticalCenter + bubbleBarHeight / 2
}
+ override val bubbleBarTranslationY: Float
+ get() =
+ if (inAppDisplayOverrideProgress > 0f && launcherState == BubbleLauncherState.HOME) {
+ Utilities.mapToRange(
+ inAppDisplayOverrideProgress,
+ /* fromMin = */ 0f,
+ /* fromMax = */ 1f,
+ bubbleBarTranslationYForHotseat,
+ bubbleBarTranslationYForTaskbar,
+ Interpolators.LINEAR,
+ )
+ } else {
+ super.bubbleBarTranslationY
+ }
+
+ override var inAppDisplayOverrideProgress: Float = 0f
+ set(value) {
+ if (field == value) return
+ field = value
+ if (launcherState == BubbleLauncherState.HOME) {
+ bubbleBarViewController.bubbleBarTranslationY.updateValue(bubbleBarTranslationY)
+ if (value == 0f || value == 1f) {
+ // Update insets only when we reach the end values
+ taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+ }
+ }
+ }
+
override fun init(
taskbarInsetsController: TaskbarInsetsController,
bubbleBarViewController: BubbleBarViewController,
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
index fbeecaa..71303f8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/TransientBubbleStashController.kt
@@ -126,6 +126,9 @@
override val bubbleBarTranslationYForTaskbar: Float =
-taskbarHotseatDimensionsProvider.getTaskbarBottomSpace().toFloat()
+ /** Not supported in transient mode */
+ override var inAppDisplayOverrideProgress: Float = 0f
+
/** Check if we have handle view controller */
override val hasHandleView: Boolean
get() = bubbleStashedHandleViewController != null
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index fe68ebc..34d9a68 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -190,6 +190,7 @@
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.RecentsViewContainer;
import com.android.quickstep.views.TaskView;
+import com.android.systemui.animation.back.FlingOnBackAnimationCallback;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.unfold.RemoteUnfoldSharedComponent;
@@ -900,12 +901,12 @@
protected void registerBackDispatcher() {
getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
OnBackInvokedDispatcher.PRIORITY_DEFAULT,
- new OnBackAnimationCallback() {
+ new FlingOnBackAnimationCallback() {
@Nullable OnBackAnimationCallback mActiveOnBackAnimationCallback;
@Override
- public void onBackStarted(@NonNull BackEvent backEvent) {
+ public void onBackStartedCompat(@NonNull BackEvent backEvent) {
if (mActiveOnBackAnimationCallback != null) {
mActiveOnBackAnimationCallback.onBackCancelled();
}
@@ -915,7 +916,7 @@
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
@Override
- public void onBackInvoked() {
+ public void onBackInvokedCompat() {
// Recreate mActiveOnBackAnimationCallback if necessary to avoid NPE
// because:
// 1. b/260636433: In 3-button-navigation mode, onBackStarted() is not
@@ -931,7 +932,7 @@
}
@Override
- public void onBackProgressed(@NonNull BackEvent backEvent) {
+ public void onBackProgressedCompat(@NonNull BackEvent backEvent) {
if (!FeatureFlags.IS_STUDIO_BUILD
&& mActiveOnBackAnimationCallback == null) {
return;
@@ -940,7 +941,7 @@
}
@Override
- public void onBackCancelled() {
+ public void onBackCancelledCompat() {
if (!FeatureFlags.IS_STUDIO_BUILD
&& mActiveOnBackAnimationCallback == null) {
return;
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index c618422..6c4c74c 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -886,10 +886,12 @@
/**
* Tells SysUI to update the bubble bar location to the new location.
* @param location new location for the bubble bar
+ * @param source what triggered the location update
*/
- public void setBubbleBarLocation(BubbleBarLocation location) {
+ public void setBubbleBarLocation(BubbleBarLocation location,
+ @BubbleBarLocation.UpdateSource int source) {
try {
- mBubbles.setBubbleBarLocation(location);
+ mBubbles.setBubbleBarLocation(location, source);
} catch (RemoteException e) {
Log.w(TAG, "Failed call setBubbleBarLocation");
}
diff --git a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
index db02f55..f719bed 100644
--- a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
+++ b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
@@ -217,6 +217,11 @@
animation.addListener(
AnimatorListeners.forEndCallback(
Runnable {
+ // The workspace might stay at a transparent state when the animation is
+ // cancelled, and the alpha will not be recovered (this doesn't apply to scales
+ // somehow). Resetting the alpha for the workspace here.
+ workspace.alpha = 1.0F
+
workspace.setLayerType(View.LAYER_TYPE_NONE, null)
hotseat.setLayerType(View.LAYER_TYPE_NONE, null)
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 9a8041b..839c42e 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -3607,7 +3607,8 @@
* @param dismissingForSplitSelection task dismiss animation is used for entering split
* selection state from app icon
*/
- public void createTaskDismissAnimation(PendingAnimation anim, TaskView dismissedTaskView,
+ public void createTaskDismissAnimation(PendingAnimation anim,
+ @Nullable TaskView dismissedTaskView,
boolean animateTaskView, boolean shouldRemoveTask, long duration,
boolean dismissingForSplitSelection) {
if (mPendingAnimation != null) {
@@ -3622,7 +3623,8 @@
boolean showAsGrid = showAsGrid();
int taskCount = getTaskViewCount();
int dismissedIndex = indexOfChild(dismissedTaskView);
- int dismissedTaskViewId = dismissedTaskView.getTaskViewId();
+ int dismissedTaskViewId =
+ dismissedTaskView != null ? dismissedTaskView.getTaskViewId() : INVALID_TASK_ID;
// Grid specific properties.
boolean isFocusedTaskDismissed = false;
@@ -3637,10 +3639,18 @@
int scrollDiffPerPage = 0;
// Non-grid specific properties.
boolean needsCurveUpdates = false;
+ boolean areAllDesktopTasksDismissed = false;
if (showAsGrid) {
- dismissedTaskWidth = dismissedTaskView.getLayoutParams().width + mPageSpacing;
- isFocusedTaskDismissed = dismissedTaskViewId == mFocusedTaskViewId;
+ if (dismissedTaskView != null) {
+ dismissedTaskWidth = dismissedTaskView.getLayoutParams().width + mPageSpacing;
+ }
+ isFocusedTaskDismissed = dismissedTaskViewId != INVALID_TASK_ID
+ && dismissedTaskViewId == mFocusedTaskViewId;
+ if (dismissingForSplitSelection && getTaskViewAt(
+ mCurrentPage) instanceof DesktopTaskView) {
+ areAllDesktopTasksDismissed = true;
+ }
if (isFocusedTaskDismissed) {
if (isSplitSelectionActive()) {
isStagingFocusedTask = true;
@@ -3812,19 +3822,23 @@
SplitAnimationTimings splitTimings =
AnimUtils.getDeviceOverviewToSplitTimings(mContainer.getDeviceProfile().isTablet);
- int distanceFromDismissedTask = 0;
+ int distanceFromDismissedTask = 1;
+ int stagingTranslation = 0;
+ if (isStagingFocusedTask || areAllDesktopTasksDismissed) {
+ int nextSnappedPage = isStagingFocusedTask
+ ? indexOfChild(mUtils.getFirstSmallTaskView(getTaskViews()))
+ : mUtils.getDesktopTaskViewCount(getTaskViews());
+ stagingTranslation = getPagedOrientationHandler().getPrimaryScroll(this)
+ - getScrollForPage(nextSnappedPage);
+ }
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
if (child == dismissedTaskView) {
- if (animateTaskView) {
- if (dismissingForSplitSelection) {
- createInitialSplitSelectAnimation(anim);
- } else {
- addDismissedTaskAnimations(dismissedTaskView, duration, anim);
- }
+ if (animateTaskView && !dismissingForSplitSelection) {
+ addDismissedTaskAnimations(dismissedTaskView, duration, anim);
}
} else if (!showAsGrid || (enableLargeDesktopWindowingTile()
- && dismissedTaskView.isLargeTile()
+ && dismissedTaskView != null && dismissedTaskView.isLargeTile()
&& nextFocusedTaskView == null && !dismissingForSplitSelection)) {
int offset = getOffsetToDismissedTask(scrollDiffPerPage, dismissedIndex, taskCount);
int scrollDiff = newScroll[i] - oldScroll[i] + offset;
@@ -3838,19 +3852,9 @@
needsCurveUpdates = true;
}
} else if (child instanceof TaskView taskView) {
- if (isFocusedTaskDismissed) {
- if (nextFocusedTaskView != null &&
- !isSameGridRow(taskView, nextFocusedTaskView)) {
- continue;
- }
- } else if (i < dismissedIndex || !isSameGridRow(taskView, dismissedTaskView)) {
- continue;
- }
-
// Animate task with index >= dismissed index and in the same row as the
// dismissed index or next focused index. Offset successive task dismissal
// durations for a staggered effect.
- distanceFromDismissedTask++;
int staggerColumn = isStagingFocusedTask
? (int) Math.ceil(distanceFromDismissedTask / 2f)
: distanceFromDismissedTask;
@@ -3877,16 +3881,15 @@
: dismissTranslationInterpolationEnd;
Interpolator dismissInterpolator = isStagingFocusedTask ? OVERSHOOT_0_75 : LINEAR;
+ float primaryTranslation = 0;
if (taskView == nextFocusedTaskView) {
// Enlarge the task to be focused next, and translate into focus position.
float scale = mTaskWidth / (float) mLastComputedGridTaskSize.width();
anim.setFloat(taskView, TaskView.DISMISS_SCALE, scale,
clampToProgress(LINEAR, animationStartProgress,
dismissTranslationInterpolationEnd));
- anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
- mIsRtl ? dismissedTaskWidth : -dismissedTaskWidth,
- clampToProgress(LINEAR, animationStartProgress,
- dismissTranslationInterpolationEnd));
+ primaryTranslation += mIsRtl ? dismissedTaskWidth : -dismissedTaskWidth;
+ animationEndProgress = dismissTranslationInterpolationEnd;
float secondaryTranslation = -mTaskGridVerticalDiff;
if (!nextFocusedTaskFromTop) {
secondaryTranslation -= mTopBottomRowHeightDiff;
@@ -3896,25 +3899,27 @@
dismissTranslationInterpolationEnd));
anim.add(taskView.getFocusTransitionScaleAndDimOutAnimator(),
clampToProgress(LINEAR, 0f, ANIMATION_DISMISS_PROGRESS_MIDPOINT));
- } else {
- float primaryTranslation =
+ } else if ((isFocusedTaskDismissed && nextFocusedTaskView != null && isSameGridRow(
+ taskView, nextFocusedTaskView))
+ || (!isFocusedTaskDismissed && i >= dismissedIndex && isSameGridRow(
+ taskView, dismissedTaskView))) {
+ primaryTranslation +=
nextFocusedTaskView != null ? nextFocusedTaskWidth : dismissedTaskWidth;
- if (isStagingFocusedTask) {
- // Moves less if focused task is not in scroll position.
- int focusedTaskScroll = getScrollForPage(dismissedIndex);
- int primaryScroll = getPagedOrientationHandler().getPrimaryScroll(this);
- int focusedTaskScrollDiff = primaryScroll - focusedTaskScroll;
- primaryTranslation +=
- mIsRtl ? focusedTaskScrollDiff : -focusedTaskScrollDiff;
- }
+ }
+ primaryTranslation += mIsRtl ? stagingTranslation : -stagingTranslation;
+ if (primaryTranslation != 0) {
anim.setFloat(taskView, taskView.getPrimaryDismissTranslationProperty(),
mIsRtl ? primaryTranslation : -primaryTranslation,
clampToProgress(dismissInterpolator, animationStartProgress,
animationEndProgress));
+ distanceFromDismissedTask++;
}
}
}
+ if (dismissingForSplitSelection) {
+ createInitialSplitSelectAnimation(anim);
+ }
if (needsCurveUpdates) {
anim.addOnFrameCallback(this::updateCurveProperties);
@@ -3923,7 +3928,7 @@
// Add a tiny bit of translation Z, so that it draws on top of other views. This is relevant
// (e.g.) when we dismiss a task by sliding it upward: if there is a row of icons above, we
// want the dragged task to stay above all other views.
- if (animateTaskView) {
+ if (animateTaskView && dismissedTaskView != null) {
dismissedTaskView.setTranslationZ(0.1f);
}
@@ -3935,7 +3940,8 @@
mPendingAnimation.addEndListener(new Consumer<>() {
@Override
public void accept(Boolean success) {
- if (mEnableDrawingLiveTile && dismissedTaskView.isRunningTask() && success) {
+ if (mEnableDrawingLiveTile && dismissedTaskView != null
+ && dismissedTaskView.isRunningTask() && success) {
finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
() -> onEnd(true));
} else {
@@ -3951,7 +3957,7 @@
if (success) {
mAnyTaskHasBeenDismissed = true;
- if (shouldRemoveTask) {
+ if (shouldRemoveTask && dismissedTaskView != null) {
if (dismissedTaskView.isRunningTask()) {
finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
() -> removeTaskInternal(dismissedTaskView));
@@ -5080,9 +5086,10 @@
if (enableLargeDesktopWindowingTile()) {
for (TaskView taskView : getTaskViews()) {
if (taskView instanceof DesktopTaskView) {
+ // Correcting the animation for split mode since we hide DW in split.
builder.addFloat(taskView.getSplitAlphaProperty(),
MULTI_PROPERTY_VALUE, 1f, 0f,
- deskTopFadeInterPolator);
+ clampToProgress(deskTopFadeInterPolator, 0f, 0.1f));
}
}
}
@@ -5140,7 +5147,15 @@
true /* dismissingForSplitSelection*/);
} else {
// Splitting from Home
- createInitialSplitSelectAnimation(builder);
+ TaskView currentPageTaskView = getTaskViewAt(mCurrentPage);
+ // When current page is a Desktop task it needs special handling to
+ // display correct animation in split mode
+ if (currentPageTaskView instanceof DesktopTaskView) {
+ createTaskDismissAnimation(builder, null, true, false, duration,
+ true /* dismissingForSplitSelection*/);
+ } else {
+ createInitialSplitSelectAnimation(builder);
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 28ecf96..0760618 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -636,24 +636,29 @@
override fun onInitializeAccessibilityNodeInfo(info: AccessibilityNodeInfo) {
super.onInitializeAccessibilityNodeInfo(info)
with(info) {
- addAction(
- AccessibilityAction(
- R.id.action_close,
- context.getText(R.string.accessibility_close),
+ // Only make actions available if the app icon menu is visible to the user.
+ // When modalness is >0, the user is in select mode and the icon menu is hidden.
+ if (modalness == 0f) {
+ addAction(
+ AccessibilityAction(
+ R.id.action_close,
+ context.getText(R.string.accessibility_close),
+ )
)
- )
- taskContainers.forEach {
- TraceHelper.allowIpcs("TV.a11yInfo") {
- TaskOverlayFactory.getEnabledShortcuts(this@TaskView, it).forEach { shortcut ->
- addAction(shortcut.createAccessibilityAction(context))
+ taskContainers.forEach {
+ TraceHelper.allowIpcs("TV.a11yInfo") {
+ TaskOverlayFactory.getEnabledShortcuts(this@TaskView, it).forEach { shortcut
+ ->
+ addAction(shortcut.createAccessibilityAction(context))
+ }
}
}
- }
- // Add DWB accessibility action at the end of the list
- taskContainers.forEach {
- it.digitalWellBeingToast?.getDWBAccessibilityAction()?.let(::addAction)
+ // Add DWB accessibility action at the end of the list
+ taskContainers.forEach {
+ it.digitalWellBeingToast?.getDWBAccessibilityAction()?.let(::addAction)
+ }
}
recentsView?.let {
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarScrimViewControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarScrimViewControllerTest.kt
index 436dfd3..4c94067 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarScrimViewControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarScrimViewControllerTest.kt
@@ -17,10 +17,14 @@
package com.android.launcher3.taskbar
import android.animation.AnimatorTestRule
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
import android.view.KeyEvent
import android.view.View.GONE
import android.view.View.VISIBLE
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.launcher3.taskbar.rules.TaskbarModeRule
import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.PINNED
import com.android.launcher3.taskbar.rules.TaskbarModeRule.Mode.TRANSIENT
@@ -34,6 +38,7 @@
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED
import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
+import com.android.wm.shell.Flags.FLAG_ENABLE_BUBBLE_BAR
import com.android.wm.shell.shared.bubbles.BubbleConstants.BUBBLE_EXPANDED_SCRIM_ALPHA
import com.google.common.truth.Truth.assertThat
import org.junit.Rule
@@ -43,7 +48,8 @@
@RunWith(LauncherMultivalentJUnit::class)
@EmulatedDevices(["pixelTablet2023"])
class TaskbarScrimViewControllerTest {
- @get:Rule(order = 0)
+ @get:Rule(order = 0) val setFlagsRule = SetFlagsRule()
+ @get:Rule(order = 1)
val context =
TaskbarWindowSandboxContext.create { builder ->
builder.bindSystemUiProxy(
@@ -55,9 +61,9 @@
}
)
}
- @get:Rule(order = 1) val taskbarModeRule = TaskbarModeRule(context)
- @get:Rule(order = 2) val animatorTestRule = AnimatorTestRule(this)
- @get:Rule(order = 3) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
+ @get:Rule(order = 2) val taskbarModeRule = TaskbarModeRule(context)
+ @get:Rule(order = 3) val animatorTestRule = AnimatorTestRule(this)
+ @get:Rule(order = 4) val taskbarUnitTestRule = TaskbarUnitTestRule(this, context)
@InjectController lateinit var scrimViewController: TaskbarScrimViewController
@@ -90,6 +96,7 @@
}
@Test
+ @DisableFlags(FLAG_ENABLE_BUBBLE_BAR)
@TaskbarMode(PINNED)
fun testOnTaskbarVisibilityChanged_pinnedTaskbarHiddenDuringScrim_hidesScrim() {
getInstrumentation().runOnMainSync {
@@ -106,6 +113,26 @@
}
@Test
+ @EnableFlags(FLAG_ENABLE_BUBBLE_BAR)
+ @TaskbarMode(PINNED)
+ fun testOnTaskbarVisibilityChanged_pinnedTaskbarOnHomeHiddenDuringScrim_hidesScrim() {
+ getInstrumentation().runOnMainSync {
+ scrimViewController.onTaskbarVisibilityChanged(VISIBLE)
+ taskbarUnitTestRule.activityContext.bubbleControllers!!
+ .bubbleStashController
+ .launcherState = BubbleStashController.BubbleLauncherState.HOME
+ scrimViewController.updateStateForSysuiFlags(SYSUI_STATE_BUBBLES_EXPANDED, true)
+ }
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(BUBBLE_EXPANDED_SCRIM_ALPHA)
+
+ getInstrumentation().runOnMainSync {
+ scrimViewController.onTaskbarVisibilityChanged(GONE)
+ animatorTestRule.advanceTimeBy(animationDuration)
+ }
+ assertThat(scrimViewController.scrimAlpha).isEqualTo(0)
+ }
+
+ @Test
@TaskbarMode(PINNED)
fun testOnTaskbarVisibilityChanged_notificationsOverPinnedTaskbarAndBubbles_noScrim() {
getInstrumentation().runOnMainSync {
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
index 00b42bc..e3d41e7 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentBubbleStashControllerTest.kt
@@ -38,6 +38,7 @@
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
import org.mockito.kotlin.clearInvocations
+import org.mockito.kotlin.never
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@@ -228,6 +229,90 @@
.isEqualTo(TASK_BAR_TRANSLATION_Y)
}
+ @Test
+ fun inAppDisplayOverrideProgress_onHome_updatesTranslationFromHomeToInApp() {
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
+ persistentTaskBarStashController.launcherState = BubbleLauncherState.HOME
+
+ assertThat(persistentTaskBarStashController.bubbleBarTranslationY)
+ .isEqualTo(HOTSEAT_TRANSLATION_Y)
+
+ persistentTaskBarStashController.inAppDisplayOverrideProgress = 0.5f
+
+ val middleBetweenHotseatAndTaskbar = (HOTSEAT_TRANSLATION_Y + TASK_BAR_TRANSLATION_Y) / 2f
+ assertThat(persistentTaskBarStashController.bubbleBarTranslationY)
+ .isWithin(0.1f)
+ .of(middleBetweenHotseatAndTaskbar)
+
+ persistentTaskBarStashController.inAppDisplayOverrideProgress = 1f
+
+ assertThat(persistentTaskBarStashController.bubbleBarTranslationY)
+ .isEqualTo(TASK_BAR_TRANSLATION_Y)
+ }
+
+ @Test
+ fun inAppDisplayOverrideProgress_onHome_updatesInsetsWhenProgressReachesOne() {
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
+ persistentTaskBarStashController.launcherState = BubbleLauncherState.HOME
+ // Reset invocations to track only changes from in-app display override
+ clearInvocations(taskbarInsetsController)
+
+ // Insets are not updated for values between 0 and 1
+ persistentTaskBarStashController.inAppDisplayOverrideProgress = 0.5f
+ verify(taskbarInsetsController, never()).onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+
+ // Update insets when progress reaches 1
+ persistentTaskBarStashController.inAppDisplayOverrideProgress = 1f
+ verify(taskbarInsetsController).onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+ }
+
+ @Test
+ fun inAppDisplayOverrideProgress_onHome_updatesInsetsWhenProgressReachesZero() {
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
+ persistentTaskBarStashController.launcherState = BubbleLauncherState.HOME
+ persistentTaskBarStashController.inAppDisplayOverrideProgress = 1f
+ // Reset invocations to track only changes from in-app display override
+ clearInvocations(taskbarInsetsController)
+
+ // Insets are not updated for values between 0 and 1
+ persistentTaskBarStashController.inAppDisplayOverrideProgress = 0.5f
+ verify(taskbarInsetsController, never()).onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+
+ // Update insets when progress reaches 0
+ persistentTaskBarStashController.inAppDisplayOverrideProgress = 0f
+ verify(taskbarInsetsController).onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+ }
+
+ @Test
+ fun inAppDisplayProgressUpdate_inApp_noTranslationUpdate() {
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
+ persistentTaskBarStashController.launcherState = BubbleLauncherState.IN_APP
+
+ assertThat(persistentTaskBarStashController.bubbleBarTranslationY)
+ .isEqualTo(TASK_BAR_TRANSLATION_Y)
+
+ persistentTaskBarStashController.inAppDisplayOverrideProgress = 0.5f
+
+ assertThat(persistentTaskBarStashController.bubbleBarTranslationY)
+ .isEqualTo(TASK_BAR_TRANSLATION_Y)
+ }
+
+ @Test
+ fun inAppDisplayOverrideProgress_inApp_noInsetsUpdate() {
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
+ persistentTaskBarStashController.launcherState = BubbleLauncherState.IN_APP
+
+ // Reset invocations to track only changes from in-app display override
+ clearInvocations(taskbarInsetsController)
+
+ persistentTaskBarStashController.inAppDisplayOverrideProgress = 0.5f
+ persistentTaskBarStashController.inAppDisplayOverrideProgress = 1f
+ persistentTaskBarStashController.inAppDisplayOverrideProgress = 0f
+
+ // Never triggers an update to insets
+ verify(taskbarInsetsController, never()).onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+ }
+
private fun advanceTimeBy(advanceMs: Long) {
// Advance animator for on-device tests
getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(advanceMs) }
diff --git a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
similarity index 73%
rename from quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
rename to quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
index e981570..5b46dc8 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplDigitalWellBeingToastTest.java
+++ b/quickstep/tests/src/com/android/quickstep/DigitalWellBeingToastTest.java
@@ -15,7 +15,9 @@
*/
package com.android.quickstep;
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
+import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.launcher3.util.TestUtil.resolveSystemAppInfo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -25,10 +27,13 @@
import android.app.usage.UsageStatsManager;
import android.content.Intent;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.uioverrides.QuickstepLauncher;
+import com.android.launcher3.util.BaseLauncherActivityTest;
import com.android.quickstep.views.DigitalWellBeingToast;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskContainer;
@@ -41,30 +46,31 @@
@LargeTest
@RunWith(AndroidJUnit4.class)
-public class TaplDigitalWellBeingToastTest extends AbstractQuickStepTest {
- private static final String CALCULATOR_PACKAGE =
- resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR);
+public class DigitalWellBeingToastTest extends BaseLauncherActivityTest<QuickstepLauncher> {
+
+ public final String calculatorPackage =
+ resolveSystemAppInfo(Intent.CATEGORY_APP_CALCULATOR).packageName;
@Test
- public void testToast() throws Exception {
- startAppFast(CALCULATOR_PACKAGE);
+ public void testToast() {
+ startAppFast(calculatorPackage);
final UsageStatsManager usageStatsManager =
- mTargetContext.getSystemService(UsageStatsManager.class);
+ targetContext().getSystemService(UsageStatsManager.class);
final int observerId = 0;
try {
- final String[] packages = new String[]{CALCULATOR_PACKAGE};
+ final String[] packages = new String[]{calculatorPackage};
// Set time limit for app.
runWithShellPermission(() ->
usageStatsManager.registerAppUsageLimitObserver(observerId, packages,
Duration.ofSeconds(600), Duration.ofSeconds(300),
- PendingIntent.getActivity(mTargetContext, -1, new Intent()
- .setPackage(mTargetContext.getPackageName()),
+ PendingIntent.getActivity(targetContext(), -1, new Intent()
+ .setPackage(targetContext().getPackageName()),
PendingIntent.FLAG_MUTABLE)));
- mLauncher.goHome();
+ loadLauncherSync();
final DigitalWellBeingToast toast = getToast();
waitForLauncherCondition("Toast is not visible", launcher -> toast.getHasLimit());
@@ -74,7 +80,7 @@
runWithShellPermission(
() -> usageStatsManager.unregisterAppUsageLimitObserver(observerId));
- mLauncher.goHome();
+ goToState(LauncherState.NORMAL);
assertFalse("Toast is visible", getToast().getHasLimit());
} finally {
runWithShellPermission(
@@ -83,12 +89,12 @@
}
private DigitalWellBeingToast getToast() {
- mLauncher.getWorkspace().switchToOverview();
+ goToState(LauncherState.OVERVIEW);
final TaskView task = getOnceNotNull("No latest task", launcher -> getLatestTask(launcher));
return getFromLauncher(launcher -> {
TaskContainer taskContainer = task.getTaskContainers().get(0);
- assertTrue("Latest task is not Calculator", CALCULATOR_PACKAGE.equals(
+ assertTrue("Latest task is not Calculator", calculatorPackage.equals(
taskContainer.getTask().getTopComponent().getPackageName()));
return taskContainer.getDigitalWellBeingToast();
});
@@ -105,6 +111,5 @@
} finally {
getInstrumentation().getUiAutomation().dropShellPermissionIdentity();
}
-
}
}
diff --git a/res/drawable/bg_widgets_header_states_two_pane.xml b/res/drawable/bg_widgets_header_states_two_pane.xml
index 5f4b8c6..1ec41a9 100644
--- a/res/drawable/bg_widgets_header_states_two_pane.xml
+++ b/res/drawable/bg_widgets_header_states_two_pane.xml
@@ -14,18 +14,16 @@
limitations under the License.
-->
<selector xmlns:android="http://schemas.android.com/apk/res/android">
-
- <item android:state_expanded="true">
- <shape android:shape="rectangle">
- <solid android:color="?attr/widgetPickerHeaderBackgroundColor" />
- <corners android:radius="@dimen/widget_list_top_bottom_corner_radius" />
- </shape>
+ <item android:state_expanded="true" android:state_focused="false">
+ <ripple android:color="@color/accent_ripple_color">
+ <item android:drawable="@drawable/bg_widgets_header_two_pane_expanded_unfocused" />
+ </ripple>
</item>
-
- <item android:state_expanded="false">
- <shape android:shape="rectangle">
- <solid android:color="@android:color/transparent" />
- <corners android:radius="@dimen/widget_list_top_bottom_corner_radius" />
- </shape>
+ <item android:state_expanded="false" android:state_focused="false">
+ <ripple android:color="@color/accent_ripple_color">
+ <item android:drawable="@drawable/bg_widgets_header_two_pane_unexpanded_unfocused" />
+ </ripple>
</item>
+ <item android:drawable="@drawable/bg_widgets_header_two_pane_expanded_focused" android:state_expanded="true" android:state_focused="true" />
+ <item android:drawable="@drawable/bg_widgets_header_two_pane_unexpanded_focused" android:state_expanded="false" android:state_focused="true" />
</selector>
diff --git a/res/drawable/bg_widgets_header_two_pane.xml b/res/drawable/bg_widgets_header_two_pane.xml
index ca3feef..e237002 100644
--- a/res/drawable/bg_widgets_header_two_pane.xml
+++ b/res/drawable/bg_widgets_header_two_pane.xml
@@ -14,13 +14,10 @@
limitations under the License.
-->
<inset xmlns:android="http://schemas.android.com/apk/res/android"
- android:insetTop="@dimen/widget_list_entry_spacing" >
- <ripple
- android:color="@color/accent_ripple_color"
- android:paddingTop="@dimen/widget_list_header_view_vertical_padding"
- android:paddingBottom="@dimen/widget_list_header_view_vertical_padding" >
- <item android:id="@android:id/mask"
- android:drawable="@drawable/bg_widgets_header_states_two_pane" />
+ android:insetTop="@dimen/widget_list_entry_spacing">
+ <layer-list
+ android:paddingBottom="@dimen/widget_list_header_view_vertical_padding"
+ android:paddingTop="@dimen/widget_list_header_view_vertical_padding">
<item android:drawable="@drawable/bg_widgets_header_states_two_pane" />
- </ripple>
-</inset>
+ </layer-list>
+</inset>
\ No newline at end of file
diff --git a/res/drawable/bg_widgets_header_two_pane_expanded_focused.xml b/res/drawable/bg_widgets_header_two_pane_expanded_focused.xml
new file mode 100644
index 0000000..0ee3d14
--- /dev/null
+++ b/res/drawable/bg_widgets_header_two_pane_expanded_focused.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Draw the focus ring -->
+ <item>
+ <shape>
+ <corners android:radius="@dimen/widget_focus_ring_corner_radius" />
+ <stroke
+ android:width="@dimen/widget_header_focus_ring_width"
+ android:color="?attr/widgetPickerTabBackgroundSelected" />
+ </shape>
+ </item>
+
+ <!-- Draw the background with padding to make it spaced within the focus ring. -->
+ <item
+ android:bottom="@dimen/widget_header_background_border"
+ android:end="@dimen/widget_header_background_border"
+ android:start="@dimen/widget_header_background_border"
+ android:top="@dimen/widget_header_background_border">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/widget_list_top_bottom_corner_radius" />
+ <solid android:color="?attr/widgetPickerHeaderBackgroundColor" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/bg_widgets_header_two_pane_expanded_unfocused.xml b/res/drawable/bg_widgets_header_two_pane_expanded_unfocused.xml
new file mode 100644
index 0000000..9028ebe
--- /dev/null
+++ b/res/drawable/bg_widgets_header_two_pane_expanded_unfocused.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android"
+ android:paddingBottom="@dimen/widget_list_header_view_vertical_padding"
+ android:paddingTop="@dimen/widget_list_header_view_vertical_padding">
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/widget_list_top_bottom_corner_radius" />
+ <solid android:color="?attr/widgetPickerHeaderBackgroundColor" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/bg_widgets_header_two_pane_unexpanded_focused.xml b/res/drawable/bg_widgets_header_two_pane_unexpanded_focused.xml
new file mode 100644
index 0000000..12dc907
--- /dev/null
+++ b/res/drawable/bg_widgets_header_two_pane_unexpanded_focused.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <!-- Draw the focus ring and a transparent background -->
+ <item>
+ <shape>
+ <corners android:radius="@dimen/widget_focus_ring_corner_radius" />
+ <solid android:color="@android:color/transparent" />
+ <stroke
+ android:width="@dimen/widget_header_focus_ring_width"
+ android:color="?attr/widgetPickerTabBackgroundSelected" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/drawable/bg_widgets_header_two_pane_unexpanded_unfocused.xml b/res/drawable/bg_widgets_header_two_pane_unexpanded_unfocused.xml
new file mode 100644
index 0000000..ba26f9f
--- /dev/null
+++ b/res/drawable/bg_widgets_header_two_pane_unexpanded_unfocused.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
+ <item>
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/widget_list_top_bottom_corner_radius" />
+ <solid android:color="@android:color/transparent" />
+ </shape>
+ </item>
+</layer-list>
\ No newline at end of file
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index f24707f..77d789f 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -215,6 +215,8 @@
<attr name="minDeviceHeightPx" format="float"/>
<attr name="numRowsNew" format="integer"/>
<attr name="dbFile" />
+ <attr name="defaultLayoutId"/>
+ <attr name="demoModeLayoutId"/>
</declare-styleable>
<declare-styleable name="GridDisplayOption">
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index d1dde3f..c69778a 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -228,6 +228,10 @@
<!-- Bottom margin for the search and recommended widgets container with work profile -->
<dimen name="search_and_recommended_widgets_container_small_bottom_margin">10dp</dimen>
+ <dimen name="widget_header_focus_ring_width">3dp</dimen>
+ <dimen name="widget_focus_ring_corner_radius">28dp</dimen>
+ <dimen name="widget_header_background_border">5dp</dimen>
+
<dimen name="widget_list_top_bottom_corner_radius">28dp</dimen>
<dimen name="widget_list_content_corner_radius">4dp</dimen>
<!-- Button that expands the widget apps list in the widget picker. -->
diff --git a/src/com/android/launcher3/InvariantDeviceProfile.java b/src/com/android/launcher3/InvariantDeviceProfile.java
index 090fe51..04e4b57 100644
--- a/src/com/android/launcher3/InvariantDeviceProfile.java
+++ b/src/com/android/launcher3/InvariantDeviceProfile.java
@@ -345,6 +345,11 @@
}
private String initGrid(Context context, String gridName) {
+ if (!Flags.oneGridSpecs() && (isFixedLandscapeMode || FIXED_LANDSCAPE_MODE.get(context))) {
+ LauncherPrefs.get(context).put(FIXED_LANDSCAPE_MODE, false);
+ isFixedLandscapeMode = false;
+ }
+
Info displayInfo = DisplayController.INSTANCE.get(context).getInfo();
List<DisplayOption> allOptions = getPredefinedDeviceProfiles(
@@ -539,8 +544,8 @@
}
/**
- * Updates the mounted mode, this triggers a new IDP, reloads the database and triggers a grid
- * migration.
+ * Updates the fixed landscape mode, this triggers a new IDP, reloads the database and triggers
+ * a grid migration.
*/
public void setFixedLandscape(Context context, boolean isFixedLandscape) {
this.isFixedLandscapeMode = isFixedLandscape;
@@ -580,8 +585,7 @@
private static boolean firstGridFilter(GridOption gridOption, int deviceType,
boolean allowDisabledGrid, boolean isFixedLandscapeMode) {
return (gridOption.isEnabled(deviceType) || allowDisabledGrid)
- && ((gridOption.mIsFixedLandscape == isFixedLandscapeMode)
- && gridOption.filterByFlag(deviceType));
+ && gridOption.filterByFlag(deviceType, isFixedLandscapeMode);
}
private static List<DisplayOption> getPredefinedDeviceProfiles(
@@ -755,9 +759,7 @@
return parseAllDefinedGridOptions(context, displayInfo)
.stream()
.filter(go -> go.isEnabled(deviceType))
- // if in fixedLandscape, then only show fixed landscape grids
- .filter(go -> go.mIsFixedLandscape == isFixedLandscapeMode)
- .filter(go -> go.filterByFlag(deviceType))
+ .filter(go -> go.filterByFlag(deviceType, isFixedLandscapeMode))
.collect(Collectors.toList());
}
@@ -1045,18 +1047,20 @@
NumRows numR = getRowCount(resourceHelper, context, displayInfo);
numRows = numR.mNumRowsNew;
dbFile = numR.mDbFile;
+ defaultLayoutId = numR.mDefaultLayoutId;
+ demoModeLayoutId = numR.mDemoModeLayoutId;
} else {
numRows = a.getInt(R.styleable.GridDisplayOption_numRows, 0);
dbFile = a.getString(R.styleable.GridDisplayOption_dbFile);
+ defaultLayoutId = a.getResourceId(
+ R.styleable.GridDisplayOption_defaultLayoutId, 0);
+ demoModeLayoutId = a.getResourceId(
+ R.styleable.GridDisplayOption_demoModeLayoutId, defaultLayoutId);
}
numColumns = a.getInt(R.styleable.GridDisplayOption_numColumns, 0);
numSearchContainerColumns = a.getInt(
R.styleable.GridDisplayOption_numSearchContainerColumns, numColumns);
- defaultLayoutId = a.getResourceId(
- R.styleable.GridDisplayOption_defaultLayoutId, 0);
- demoModeLayoutId = a.getResourceId(
- R.styleable.GridDisplayOption_demoModeLayoutId, defaultLayoutId);
allAppsStyle = a.getResourceId(R.styleable.GridDisplayOption_allAppsStyle,
R.style.AllAppsStyleDefault);
@@ -1203,15 +1207,19 @@
}
public boolean isNewGridOption() {
- Log.d("HHHH", "GRID = " + mIsFixedLandscape);
- return mRowCountSpecsId != INVALID_RESOURCE_HANDLE || mIsFixedLandscape;
+ return mRowCountSpecsId != INVALID_RESOURCE_HANDLE;
}
- public boolean filterByFlag(int deviceType) {
+ public boolean filterByFlag(int deviceType, boolean isFixedLandscape) {
if (deviceType == TYPE_TABLET) {
return Flags.oneGridRotationHandling() == mIsDualGrid;
}
- return Flags.oneGridSpecs() == isNewGridOption();
+
+ if (isFixedLandscape) {
+ return Flags.oneGridSpecs() && mIsFixedLandscape;
+ }
+
+ return ((Flags.oneGridSpecs() == isNewGridOption()) && !mIsFixedLandscape);
}
}
@@ -1220,6 +1228,9 @@
final float mMinDeviceWidthPx;
final float mMinDeviceHeightPx;
final String mDbFile;
+ final int mDefaultLayoutId;
+ final int mDemoModeLayoutId;
+
NumRows(Context context, AttributeSet attrs) {
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NumRows);
@@ -1228,6 +1239,10 @@
mMinDeviceWidthPx = a.getFloat(R.styleable.NumRows_minDeviceWidthPx, 0);
mMinDeviceHeightPx = a.getFloat(R.styleable.NumRows_minDeviceHeightPx, 0);
mDbFile = a.getString(R.styleable.NumRows_dbFile);
+ mDefaultLayoutId = a.getResourceId(
+ R.styleable.NumRows_defaultLayoutId, 0);
+ mDemoModeLayoutId = a.getResourceId(
+ R.styleable.NumRows_demoModeLayoutId, mDefaultLayoutId);
a.recycle();
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index be2ba57..6145077 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -96,7 +96,6 @@
import static com.android.launcher3.popup.SystemShortcut.INSTALL;
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
-import static com.android.launcher3.states.RotationHelper.REQUEST_FIXED_LANDSCAPE;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
import static com.android.launcher3.testing.shared.TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -782,12 +781,9 @@
if (!com.android.launcher3.Flags.oneGridSpecs()) {
return;
}
- if (Objects.requireNonNull(mDeviceProfile.inv).isFixedLandscapeMode) {
- // Set rotation fixed
- getRotationHelper().setStateHandlerRequest(REQUEST_FIXED_LANDSCAPE);
- } else {
- getRotationHelper().setStateHandlerRequest(REQUEST_NONE);
- }
+ getRotationHelper().setFixedLandscape(
+ Objects.requireNonNull(mDeviceProfile.inv).isFixedLandscapeMode
+ );
}
public void onAssistantVisibilityChanged(float visibility) {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index bd604eb..8554de5 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -43,9 +43,9 @@
import androidx.annotation.FloatRange;
import androidx.annotation.Nullable;
-import com.android.app.animation.Interpolators;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
+import com.android.launcher3.Flags;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
@@ -55,14 +55,16 @@
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.AllAppsSwipeController;
+import com.android.launcher3.util.MSDLPlayerWrapper;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.ScrollableLayoutManager;
import com.android.launcher3.util.Themes;
-import com.android.launcher3.util.VibratorWrapper;
import com.android.launcher3.views.ScrimView;
+import com.google.android.msdl.data.model.MSDLToken;
+
/**
* Handles AllApps view transition.
* 1) Slides all apps view using direct manipulation
@@ -183,7 +185,7 @@
private MultiPropertyFactory<View> mAppsViewTranslationY;
private boolean mHasScaleEffect;
- private final VibratorWrapper mVibratorWrapper;
+ private final MSDLPlayerWrapper mMSDLPlayerWrapper;
public AllAppsTransitionController(Launcher l) {
mLauncher = l;
@@ -197,7 +199,7 @@
setShiftRange(dp.allAppsShiftRange);
mAllAppScale.value = 1;
mLauncher.addOnDeviceProfileChangeListener(this);
- mVibratorWrapper = VibratorWrapper.INSTANCE.get(mLauncher.getApplicationContext());
+ mMSDLPlayerWrapper = MSDLPlayerWrapper.INSTANCE.get(mLauncher.getApplicationContext());
}
public float getShiftRange() {
@@ -277,10 +279,9 @@
return;
}
- float deceleratedProgress = Interpolators.BACK_GESTURE.getInterpolation(backProgress);
float scaleProgress = ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE
+ (1 - ScrollableLayoutManager.PREDICTIVE_BACK_MIN_SCALE)
- * (1 - deceleratedProgress);
+ * (1 - backProgress);
mAllAppScale.updateValue(scaleProgress);
}
@@ -370,8 +371,16 @@
setAlphas(toState, config, builder);
// This controls both haptics for tapping on QSB and going to all apps.
if (ALL_APPS.equals(toState) && mLauncher.isInState(NORMAL)) {
- mLauncher.getAppsView().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
- HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ if (Flags.msdlFeedback()) {
+ if (config.isUserControlled()) {
+ mMSDLPlayerWrapper.playToken(MSDLToken.SWIPE_THRESHOLD_INDICATOR);
+ } else {
+ mMSDLPlayerWrapper.playToken(MSDLToken.TAP_HIGH_EMPHASIS);
+ }
+ } else {
+ mLauncher.getAppsView().performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ }
}
}
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index 0e20f75..fb486f7 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -24,6 +24,7 @@
import com.android.launcher3.pm.InstallSessionHelper;
import com.android.launcher3.util.ApiWrapper;
import com.android.launcher3.util.DaggerSingletonTracker;
+import com.android.launcher3.util.MSDLPlayerWrapper;
import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PluginManagerWrapper;
import com.android.launcher3.util.ScreenOnTracker;
@@ -56,6 +57,7 @@
PackageManagerHelper getPackageManagerHelper();
PluginManagerWrapper getPluginManagerWrapper();
VibratorWrapper getVibratorWrapper();
+ MSDLPlayerWrapper getMSDLPlayerWrapper();
/** Builder for LauncherBaseAppComponent. */
interface Builder {
diff --git a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
index 94c36c0..3000b25 100644
--- a/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
+++ b/src/com/android/launcher3/graphics/PreviewSurfaceRenderer.java
@@ -16,6 +16,8 @@
package com.android.launcher3.graphics;
+import static android.content.res.Configuration.UI_MODE_NIGHT_NO;
+import static android.content.res.Configuration.UI_MODE_NIGHT_YES;
import static android.view.Display.DEFAULT_DISPLAY;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
@@ -25,6 +27,7 @@
import android.app.WallpaperColors;
import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
+import android.content.res.Configuration;
import android.database.Cursor;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
@@ -84,6 +87,7 @@
private static final String KEY_COLORS = "wallpaper_colors";
private static final String KEY_COLOR_RESOURCE_IDS = "color_resource_ids";
private static final String KEY_COLOR_VALUES = "color_values";
+ private static final String KEY_DARK_MODE = "use_dark_mode";
private Context mContext;
private final IBinder mHostToken;
@@ -95,6 +99,7 @@
private final Display mDisplay;
private final WallpaperColors mWallpaperColors;
private SparseIntArray mPreviewColorOverride;
+ @Nullable private Boolean mDarkMode;
private final RunnableList mLifeCycleTracker;
private final SurfaceControlViewHost mSurfaceControlViewHost;
@@ -235,6 +240,8 @@
}
private void updateColorOverrides(Bundle bundle) {
+ mDarkMode =
+ bundle.containsKey(KEY_DARK_MODE) ? bundle.getBoolean(KEY_DARK_MODE) : null;
int[] ids = bundle.getIntArray(KEY_COLOR_RESOURCE_IDS);
int[] colors = bundle.getIntArray(KEY_COLOR_VALUES);
if (ids != null && colors != null) {
@@ -253,6 +260,18 @@
*/
private Context getPreviewContext() {
Context context = mContext.createDisplayContext(mDisplay);
+ if (mDarkMode != null) {
+ Configuration configuration = new Configuration(
+ context.getResources().getConfiguration());
+ if (mDarkMode) {
+ configuration.uiMode &= ~UI_MODE_NIGHT_NO;
+ configuration.uiMode |= UI_MODE_NIGHT_YES;
+ } else {
+ configuration.uiMode &= ~UI_MODE_NIGHT_YES;
+ configuration.uiMode |= UI_MODE_NIGHT_NO;
+ }
+ context = context.createConfigurationContext(configuration);
+ }
if (Flags.newCustomizationPickerUi()) {
if (mPreviewColorOverride != null) {
LocalColorExtractor.newInstance(context)
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 76f8dd3..5851f62 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -294,6 +294,9 @@
case NOTIFICATION_DOTS_PREFERENCE_KEY:
return BuildConfig.NOTIFICATION_DOTS_ENABLED;
case ALLOW_ROTATION_PREFERENCE_KEY:
+ if (Flags.oneGridSpecs()) {
+ return false;
+ }
if (info.isTablet(info.realBounds)) {
// Launcher supports rotation by default. No need to show this setting.
return false;
diff --git a/src/com/android/launcher3/states/RotationHelper.java b/src/com/android/launcher3/states/RotationHelper.java
index 1f397d1..7d7ccd3 100644
--- a/src/com/android/launcher3/states/RotationHelper.java
+++ b/src/com/android/launcher3/states/RotationHelper.java
@@ -63,7 +63,8 @@
public static final int REQUEST_NONE = 0;
public static final int REQUEST_ROTATE = 1;
public static final int REQUEST_LOCK = 2;
- public static final int REQUEST_FIXED_LANDSCAPE = 3;
+
+ private boolean mIsFixedLandscape = false;
@NonNull
private final BaseActivity mActivity;
@@ -165,6 +166,18 @@
notifyChange();
}
+ public boolean isFixedLandscape() {
+ return mIsFixedLandscape;
+ }
+
+ /**
+ * If fixedLandscape is true then the Launcher become landscape until set false..
+ */
+ public void setFixedLandscape(boolean fixedLandscape) {
+ mIsFixedLandscape = fixedLandscape;
+ notifyChange();
+ }
+
// Used by tests only.
public void forceAllowRotationForTesting(boolean allowRotation) {
if (mDestroyed) return;
@@ -197,9 +210,7 @@
}
final int activityFlags;
- if (mStateHandlerRequest == REQUEST_FIXED_LANDSCAPE) {
- activityFlags = SCREEN_ORIENTATION_USER_LANDSCAPE;
- } else if (mStateHandlerRequest != REQUEST_NONE) {
+ if (mStateHandlerRequest != REQUEST_NONE) {
activityFlags = mStateHandlerRequest == REQUEST_LOCK ?
SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
} else if (mCurrentTransitionRequest != REQUEST_NONE) {
@@ -207,6 +218,8 @@
SCREEN_ORIENTATION_LOCKED : SCREEN_ORIENTATION_UNSPECIFIED;
} else if (mCurrentStateRequest == REQUEST_LOCK) {
activityFlags = SCREEN_ORIENTATION_LOCKED;
+ } else if (mIsFixedLandscape) {
+ activityFlags = SCREEN_ORIENTATION_USER_LANDSCAPE;
} else if (mIgnoreAutoRotateSettings || mCurrentStateRequest == REQUEST_ROTATE
|| mHomeRotationEnabled || mForceAllowRotationForTesting) {
activityFlags = SCREEN_ORIENTATION_UNSPECIFIED;
diff --git a/src/com/android/launcher3/util/MSDLPlayerWrapper.java b/src/com/android/launcher3/util/MSDLPlayerWrapper.java
new file mode 100644
index 0000000..1e53ac1
--- /dev/null
+++ b/src/com/android/launcher3/util/MSDLPlayerWrapper.java
@@ -0,0 +1,61 @@
+/*
+ * 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.util;
+
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
+import android.content.Context;
+import android.os.Vibrator;
+
+import com.android.launcher3.dagger.ApplicationContext;
+import com.android.launcher3.dagger.LauncherAppSingleton;
+import com.android.launcher3.dagger.LauncherBaseAppComponent;
+
+import com.google.android.msdl.data.model.MSDLToken;
+import com.google.android.msdl.domain.InteractionProperties;
+import com.google.android.msdl.domain.MSDLPlayer;
+
+import javax.inject.Inject;
+
+/**
+ * Wrapper around {@link com.google.android.msdl.domain.MSDLPlayer} to perform MSDL feedback.
+ */
+@LauncherAppSingleton
+public class MSDLPlayerWrapper {
+
+ public static final DaggerSingletonObject<MSDLPlayerWrapper> INSTANCE =
+ new DaggerSingletonObject<>(LauncherBaseAppComponent::getMSDLPlayerWrapper);
+
+ /** Internal player */
+ private final MSDLPlayer mMSDLPlayer;
+
+ @Inject
+ public MSDLPlayerWrapper(@ApplicationContext Context context) {
+ Vibrator vibrator = context.getSystemService(Vibrator.class);
+ mMSDLPlayer = MSDLPlayer.Companion.createPlayer(vibrator, UI_HELPER_EXECUTOR, null);
+ }
+
+ /** Perform MSDL feedback for a token with interaction properties */
+ public void playToken(MSDLToken token, InteractionProperties properties) {
+ mMSDLPlayer.playToken(token, properties);
+ }
+
+ /** Perform MSDL feedback for a token without properties */
+ public void playToken(MSDLToken token) {
+ mMSDLPlayer.playToken(token, null);
+ }
+}
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index 85aad89..65d02d0 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -298,8 +298,7 @@
@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
public void onBackProgressed(BackEvent backEvent) {
final float progress = backEvent.getProgress();
- float deceleratedProgress = Interpolators.BACK_GESTURE.getInterpolation(progress);
- mSwipeToDismissProgress.updateValue(deceleratedProgress);
+ mSwipeToDismissProgress.updateValue(progress);
}
/**
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java b/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java
index ce682f1..eb25acf 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/TestUtil.java
@@ -29,7 +29,10 @@
import android.app.blob.BlobHandle;
import android.app.blob.BlobStoreManager;
import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
import android.content.pm.LauncherApps;
+import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.Point;
import android.os.AsyncTask;
@@ -231,6 +234,15 @@
.adoptShellPermissionIdentity(Manifest.permission.WRITE_SECURE_SETTINGS);
}
+ /**
+ * Returns the activity info corresponding to the system app for the provided category
+ */
+ public static ActivityInfo resolveSystemAppInfo(String category) {
+ return getInstrumentation().getTargetContext().getPackageManager().resolveActivity(
+ new Intent(Intent.ACTION_MAIN).addCategory(category),
+ PackageManager.MATCH_SYSTEM_ONLY).activityInfo;
+ }
+
/** Interface to indicate a runnable which can throw any exception. */
public interface UncheckedRunnable {
/** Method to run the task */
diff --git a/tests/src/com/android/launcher3/LauncherIntentTest.java b/tests/src/com/android/launcher3/LauncherIntentTest.java
index 3e16713..a3d9614 100644
--- a/tests/src/com/android/launcher3/LauncherIntentTest.java
+++ b/tests/src/com/android/launcher3/LauncherIntentTest.java
@@ -27,17 +27,23 @@
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
import com.android.launcher3.allapps.SearchRecyclerView;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.util.BaseLauncherActivityTest;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@LargeTest
@RunWith(AndroidJUnit4.class)
-public class LauncherIntentTest extends AbstractLauncherUiTest<Launcher> {
+public class LauncherIntentTest extends BaseLauncherActivityTest<Launcher> {
public final Intent allAppsIntent = new Intent(Intent.ACTION_ALL_APPS);
+ @Before
+ public void setUp() {
+ loadLauncherSync();
+ }
+
@Test
public void testAllAppsIntent() {
// Try executing ALL_APPS intent
@@ -45,7 +51,6 @@
// A-Z view with Main adapter should be loaded
assertOnMainAdapterAToZView();
-
// Try Moving to search view now
moveToSearchView();
// Try executing ALL_APPS intent
@@ -63,12 +68,14 @@
// Search view should be in focus
waitForLauncherCondition("Search view is not in focus.",
launcher -> launcher.getAppsView().getSearchView().hasFocus());
- mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_C, 0);
+
+ injectKeyEvent(KeyEvent.KEYCODE_C, true);
// Upon key press, search recycler view should be loaded
waitForLauncherCondition("Search view not active.",
launcher -> launcher.getAppsView().getActiveRecyclerView()
instanceof SearchRecyclerView);
- mLauncher.unpressKeyCode(KeyEvent.KEYCODE_C, 0);
+
+ injectKeyEvent(KeyEvent.KEYCODE_C, false);
}
// Checks if main adapter view is selected, search bar is out of focus and scroller is at start.
diff --git a/tests/src/com/android/launcher3/allapps/KeyboardFocusTest.java b/tests/src/com/android/launcher3/allapps/KeyboardFocusTest.java
new file mode 100644
index 0000000..1e21ee5
--- /dev/null
+++ b/tests/src/com/android/launcher3/allapps/KeyboardFocusTest.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2023 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.allapps;
+
+import android.view.KeyEvent;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.util.BaseLauncherActivityTest;
+import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.views.ActivityContext;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class KeyboardFocusTest extends BaseLauncherActivityTest<Launcher> {
+
+ @Test
+ public void testAllAppsFocusApp() {
+ loadLauncherSync();
+ goToState(LauncherState.ALL_APPS);
+ freezeAllApps();
+
+ injectKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, true);
+ injectKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, false);
+ waitForLauncherCondition("No focused child", launcher ->
+ launcher.getAppsView().getActiveRecyclerView().getApps().getFocusedChild()
+ != null);
+ }
+
+ @Test
+ public void testAllAppsExitSearchAndFocusApp() {
+ loadLauncherSync();
+ goToState(LauncherState.ALL_APPS);
+ freezeAllApps();
+
+ executeOnLauncher(launcher -> launcher.getAppsView().getSearchView().requestFocus());
+ waitForLauncherCondition("Search view does not have focus.",
+ launcher -> launcher.getAppsView().getSearchView().hasFocus());
+
+ injectKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, true);
+ injectKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, false);
+ waitForLauncherCondition("No focused child", launcher ->
+ launcher.getAppsView().getActiveRecyclerView().getApps().getFocusedChild()
+ != null);
+ }
+
+ @Test
+ @ScreenRecord //b/378167329
+ public void testAllAppsExitSearchAndFocusSearchResults() {
+ loadLauncherSync();
+ goToState(LauncherState.ALL_APPS);
+ freezeAllApps();
+
+ executeOnLauncher(launcher -> launcher.getAppsView().getSearchView().requestFocus());
+ waitForLauncherCondition("Search view does not have focus.",
+ launcher -> launcher.getAppsView().getSearchView().hasFocus());
+
+ injectKeyEvent(KeyEvent.KEYCODE_C, true);
+ waitForLauncherCondition("Search view not active.",
+ launcher -> launcher.getAppsView().getActiveRecyclerView()
+ instanceof SearchRecyclerView);
+ injectKeyEvent(KeyEvent.KEYCODE_C, false);
+
+ executeOnLauncher(launcher -> launcher.getAppsView().getSearchUiManager().getEditText()
+ .hideKeyboard(/* clearFocus= */ false));
+ waitForLauncherCondition("Keyboard still visible.",
+ ActivityContext::isSoftwareKeyboardHidden);
+
+ injectKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, true);
+ injectKeyEvent(KeyEvent.KEYCODE_DPAD_DOWN, false);
+ waitForLauncherCondition("No focused child", launcher ->
+ launcher.getAppsView().getActiveRecyclerView().getApps().getFocusedChild()
+ != null);
+ }
+}
diff --git a/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java b/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
deleted file mode 100644
index 4e627a9..0000000
--- a/tests/src/com/android/launcher3/allapps/TaplKeyboardFocusTest.java
+++ /dev/null
@@ -1,108 +0,0 @@
-/*
- * Copyright (C) 2023 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.allapps;
-
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.view.KeyEvent;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
-import com.android.launcher3.tapl.HomeAllApps;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
-import com.android.launcher3.util.rule.TestStabilityRule;
-import com.android.launcher3.views.ActivityContext;
-
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class TaplKeyboardFocusTest extends AbstractLauncherUiTest<Launcher> {
-
- @Test
- public void testAllAppsFocusApp() {
- final HomeAllApps allApps = mLauncher.goHome().switchToAllApps();
- assertTrue("Launcher internal state is not All Apps",
- isInState(() -> LauncherState.ALL_APPS));
- allApps.freeze();
- try {
- mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_DPAD_DOWN, 0);
- executeOnLauncher(launcher -> assertNotNull("No focused child.",
- launcher.getAppsView().getActiveRecyclerView().getApps().getFocusedChild()));
- } finally {
- allApps.unfreeze();
- }
- }
-
- @Test
- public void testAllAppsExitSearchAndFocusApp() {
- final HomeAllApps allApps = mLauncher.goHome().switchToAllApps();
- assertTrue("Launcher internal state is not All Apps",
- isInState(() -> LauncherState.ALL_APPS));
- allApps.freeze();
- try {
- executeOnLauncher(launcher -> launcher.getAppsView().getSearchView().requestFocus());
- waitForLauncherCondition("Search view does not have focus.",
- launcher -> launcher.getAppsView().getSearchView().hasFocus());
-
- mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_DPAD_DOWN, 0);
- executeOnLauncher(launcher -> assertNotNull("No focused child.",
- launcher.getAppsView().getActiveRecyclerView().getApps().getFocusedChild()));
- } finally {
- allApps.unfreeze();
- }
- }
-
- @Test
- public void testAllAppsExitSearchAndFocusSearchResults() {
- final HomeAllApps allApps = mLauncher.goHome().switchToAllApps();
- assertTrue("Launcher internal state is not All Apps",
- isInState(() -> LauncherState.ALL_APPS));
- allApps.freeze();
- try {
- executeOnLauncher(launcher -> launcher.getAppsView().getSearchView().requestFocus());
- waitForLauncherCondition("Search view does not have focus.",
- launcher -> launcher.getAppsView().getSearchView().hasFocus());
-
- mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_C, 0);
- waitForLauncherCondition("Search view not active.",
- launcher -> launcher.getAppsView().getActiveRecyclerView()
- instanceof SearchRecyclerView);
- mLauncher.unpressKeyCode(KeyEvent.KEYCODE_C, 0);
-
- executeOnLauncher(launcher -> launcher.getAppsView().getSearchUiManager().getEditText()
- .hideKeyboard(/* clearFocus= */ false));
- waitForLauncherCondition("Keyboard still visible.",
- ActivityContext::isSoftwareKeyboardHidden);
-
- mLauncher.pressAndHoldKeyCode(KeyEvent.KEYCODE_DPAD_DOWN, 0);
- mLauncher.unpressKeyCode(KeyEvent.KEYCODE_DPAD_DOWN, 0);
- waitForLauncherCondition("No focused child", launcher ->
- launcher.getAppsView().getActiveRecyclerView().getApps().getFocusedChild()
- != null);
- } finally {
- allApps.unfreeze();
- }
- }
-}
diff --git a/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
similarity index 73%
rename from tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
rename to tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
index 1500538..34b292c 100644
--- a/tests/src/com/android/launcher3/compat/TaplPromiseIconUiTest.java
+++ b/tests/src/com/android/launcher3/compat/PromiseIconUiTest.java
@@ -1,18 +1,19 @@
/*
* Copyright (C) 2019 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
+ * 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
+ * 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.
+ * 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.compat;
import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
@@ -27,32 +28,31 @@
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.text.TextUtils;
+import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.LargeTest;
-import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.tapl.AllApps;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
+import com.android.launcher3.util.BaseLauncherActivityTest;
import com.android.launcher3.util.LauncherBindableItemsContainer.ItemOperator;
import com.android.launcher3.util.TestUtil;
-import com.android.launcher3.util.rule.ViewCaptureRule;
import org.junit.After;
+import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import java.io.IOException;
+import java.util.Arrays;
import java.util.UUID;
-
/**
* Test to verify promise icon flow.
*/
@LargeTest
@RunWith(AndroidJUnit4.class)
-public class TaplPromiseIconUiTest extends AbstractLauncherUiTest<Launcher> {
+public class PromiseIconUiTest extends BaseLauncherActivityTest<Launcher> {
@Rule
public final CheckFlagsRule mCheckFlagsRule =
@@ -64,19 +64,17 @@
private int mSessionId = -1;
- @Override
+ @Before
public void setUp() throws Exception {
- super.setUp();
- mDevice.pressHome();
- waitForLauncherCondition("Launcher didn't start", launcher -> launcher != null);
- waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
+ loadLauncherSync();
+ goToState(LauncherState.NORMAL);
mSessionId = -1;
}
@After
public void tearDown() throws IOException {
if (mSessionId > -1) {
- mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);
+ targetContext().getPackageManager().getPackageInstaller().abandonSession(mSessionId);
}
TestUtil.uninstallDummyApp();
}
@@ -90,7 +88,7 @@
params.setAppLabel(label);
params.setAppIcon(icon);
params.setInstallReason(PackageManager.INSTALL_REASON_USER);
- return mTargetContext.getPackageManager().getPackageInstaller().createSession(params);
+ return targetContext().getPackageManager().getPackageInstaller().createSession(params);
}
@Test
@@ -108,7 +106,7 @@
launcher.getWorkspace().getFirstMatch(findPromiseApp) != null);
// Remove session
- mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);
+ targetContext().getPackageManager().getPackageInstaller().abandonSession(mSessionId);
mSessionId = -1;
// Verify promise icon is removed
@@ -117,7 +115,6 @@
}
@Test
- @ViewCaptureRule.MayProduceNoFrames
public void testPromiseIcon_notAddedFromIneligibleSession() throws Throwable {
final String appLabel = "Test Promise App " + UUID.randomUUID().toString();
final ItemOperator findPromiseApp = (info, view) ->
@@ -138,7 +135,8 @@
@RequiresFlagsEnabled(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
public void testPromiseIcon_addedArchivedApp() throws Throwable {
installDummyAppAndWaitForUIUpdate();
- assertThat(mDevice.executeShellCommand(String.format("pm archive %s", DUMMY_PACKAGE)))
+ assertThat(executeShellCommand(
+ String.format("pm archive %s", DUMMY_PACKAGE)))
.isEqualTo("Success\n");
// Create and add test session
@@ -148,28 +146,19 @@
// Verify promise icon is added to all apps view. The icon may not be added to the
// workspace even if there might be no icon present for archived app. But icon will
// always be in all apps view. In case an icon is not added, an exception would be thrown.
- final AllApps allApps = mLauncher.getWorkspace().switchToAllApps();
+ goToState(LauncherState.ALL_APPS);
// Wait for the promise icon to be added.
waitForLauncherCondition(
DUMMY_PACKAGE + " app was not found on all apps after being archived",
- launcher -> {
- try {
- allApps.getAppIcon(DUMMY_LABEL);
- } catch (Throwable t) {
- return false;
- }
- return true;
- });
-
- // Remove session
- mTargetContext.getPackageManager().getPackageInstaller().abandonSession(mSessionId);
- mSessionId = -1;
+ launcher -> Arrays.stream(launcher.getAppsView().getAppsStore().getApps())
+ .filter(info -> DUMMY_LABEL.equals(info.title.toString()))
+ .findAny()
+ .isPresent());
}
private void installDummyAppAndWaitForUIUpdate() throws IOException {
TestUtil.installDummyApp();
- mLauncher.waitForModelQueueCleared();
- mLauncher.waitForLauncherInitialized();
+ loadLauncherSync();
}
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 1fbdceb..a273648 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.TestUtil.resolveSystemAppInfo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -31,7 +32,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.graphics.Point;
@@ -627,13 +627,6 @@
launcherInstrumentation);
}
- public static ActivityInfo resolveSystemAppInfo(String category) {
- return getInstrumentation().getContext().getPackageManager().resolveActivity(
- new Intent(Intent.ACTION_MAIN).addCategory(category),
- PackageManager.MATCH_SYSTEM_ONLY).
- activityInfo;
- }
-
public static String resolveSystemApp(String category) {
return resolveSystemAppInfo(category).packageName;
diff --git a/tests/src/com/android/launcher3/util/BaseLauncherActivityTest.kt b/tests/src/com/android/launcher3/util/BaseLauncherActivityTest.kt
new file mode 100644
index 0000000..bacce40
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/BaseLauncherActivityTest.kt
@@ -0,0 +1,146 @@
+/*
+ * 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.util
+
+import android.content.Context
+import android.content.Intent
+import android.os.SystemClock
+import android.view.InputDevice
+import android.view.KeyCharacterMap
+import android.view.KeyEvent
+import android.view.MotionEvent
+import androidx.lifecycle.Lifecycle.State.RESUMED
+import androidx.test.core.app.ActivityScenario
+import androidx.test.core.app.ActivityScenario.ActivityAction
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.Launcher
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherState
+import com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST
+import com.android.launcher3.tapl.TestHelpers
+import com.android.launcher3.util.ModelTestExtensions.loadModelSync
+import com.android.launcher3.util.Wait.atMost
+import java.util.function.Function
+import java.util.function.Supplier
+import org.junit.After
+
+/**
+ * Base class for tests which use Launcher activity with some utility methods.
+ *
+ * This should instead be a rule, but is kept as a base class for easier migration from TAPL
+ */
+open class BaseLauncherActivityTest<LAUNCHER_TYPE : Launcher> {
+
+ private var currentScenario: ActivityScenario<LAUNCHER_TYPE>? = null
+
+ val scenario: ActivityScenario<LAUNCHER_TYPE>
+ get() =
+ currentScenario
+ ?: ActivityScenario.launch<LAUNCHER_TYPE>(
+ TestHelpers.getHomeIntentInPackage(targetContext()),
+ null,
+ )
+ .also { currentScenario = it }
+
+ @After
+ fun closeCurrentActivity() {
+ currentScenario?.close()
+ currentScenario = null
+ }
+
+ protected fun loadLauncherSync() {
+ LauncherAppState.getInstance(targetContext()).model.loadModelSync()
+ scenario.moveToState(RESUMED)
+ }
+
+ protected fun targetContext(): Context = getInstrumentation().targetContext
+
+ protected fun goToState(state: LauncherState) = executeOnLauncher {
+ it.stateManager.goToState(state, 0)
+ }
+
+ protected fun executeOnLauncher(f: ActivityAction<LAUNCHER_TYPE>) = scenario.onActivity(f)
+
+ protected fun <T> getFromLauncher(f: Function<in LAUNCHER_TYPE, out T?>): T? {
+ var result: T? = null
+ executeOnLauncher { result = f.apply(it) }
+ return result
+ }
+
+ protected fun isInState(state: Supplier<LauncherState>): Boolean =
+ getFromLauncher { it.stateManager.state == state.get() }!!
+
+ protected fun waitForState(message: String, state: Supplier<LauncherState>) =
+ waitForLauncherCondition(message) { it.stateManager.currentStableState === state.get() }
+
+ protected fun waitForLauncherCondition(
+ message: String,
+ condition: Function<LAUNCHER_TYPE, Boolean>,
+ ) = atMost(message, { getFromLauncher(condition)!! })
+
+ protected fun <T> getOnceNotNull(message: String, f: Function<LAUNCHER_TYPE, T?>): T? {
+ var output: T? = null
+ atMost(
+ message,
+ {
+ val fromLauncher = getFromLauncher<T>(f)
+ output = fromLauncher
+ fromLauncher != null
+ },
+ )
+ return output
+ }
+
+ protected fun getAllAppsScroll(launcher: LAUNCHER_TYPE) =
+ launcher.appsView.activeRecyclerView.computeVerticalScrollOffset()
+
+ @JvmOverloads
+ protected fun injectKeyEvent(keyCode: Int, actionDown: Boolean, metaState: Int = 0) {
+ val eventTime = SystemClock.uptimeMillis()
+ val event =
+ KeyEvent.obtain(
+ eventTime,
+ eventTime,
+ if (actionDown) KeyEvent.ACTION_DOWN else MotionEvent.ACTION_UP,
+ keyCode,
+ /* repeat= */ 0,
+ metaState,
+ KeyCharacterMap.VIRTUAL_KEYBOARD,
+ /* scancode= */ 0,
+ /* flags= */ 0,
+ InputDevice.SOURCE_KEYBOARD,
+ /* characters =*/ null,
+ )
+ executeOnLauncher { it.dispatchKeyEvent(event) }
+ event.recycle()
+ }
+
+ fun startAppFast(packageName: String) {
+ val intent = targetContext().packageManager.getLaunchIntentForPackage(packageName)!!
+ intent.addCategory(Intent.CATEGORY_LAUNCHER)
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+ targetContext().startActivity(intent)
+ UiDevice.getInstance(getInstrumentation()).waitForIdle()
+ }
+
+ fun freezeAllApps() = executeOnLauncher {
+ it.appsView.appsStore.enableDeferUpdates(DEFER_UPDATES_TEST)
+ }
+
+ fun executeShellCommand(cmd: String) =
+ UiDevice.getInstance(getInstrumentation()).executeShellCommand(cmd)
+}