Merge "Create floatingMaskViewTest and make FloatingMaskView testable." into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 21b9863..a779641 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -316,3 +316,16 @@
description: "Archived apps will use new icon in app title"
bug: "350758155"
}
+
+flag {
+ name: "enable_multi_instance_menu_taskbar"
+ namespace: "launcher"
+ description: "Menu in Taskbar with options to launch and manage multiple instances of the same app"
+ bug: "355237285"
+}
+flag {
+ name: "navigate_to_child_preference"
+ namespace: "launcher"
+ description: "Settings screen supports navigating to child preference if the key is not on the screen"
+ bug: "293390881"
+}
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 73c8129..8c3b953 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oorvloei"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> vanaf <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> en nog <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index f9eed39..fd8b206 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ትርፍ ፍሰት"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ከ<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> እና <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> ተጨማሪ"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 7a0be9b..c53e427 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"القائمة الكاملة"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"\"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" من \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"\"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>\" و<xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> غيرها"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index d440400..e82cad2 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"অ’ভাৰফ্ল’"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>ৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> আৰু <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> টা"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index 9cdcc01..1da7f55 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kənara çıxma"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> və daha <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> yumrucuq"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index b6271a9..303f0d8 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index bb6c764..2be8e5c 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Меню з пашырэннем"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, крыніца: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> і яшчэ <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index d674dbc..b71d3cf 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Препълване"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> от <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> и още <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 3e974f5..59f9d7a 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ওভারফ্লো"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> থেকে <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> এবং আরও <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>টি"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 19268be..946c08c 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni meni"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index 6a6f131..6850656 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Desbordament"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> i <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> més"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index e134850..9fd843a 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbalovací nabídka"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikace <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> a ještě <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index e9cdbce..823c071 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overløb"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> mere"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 9e5cb12..c9b288c 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Weitere Optionen"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ aus <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> und <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> weitere"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index bbb1282..9f0480c 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Υπερχείλιση"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> από <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> και <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> ακόμα"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index b84f646..ae915ed 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> more"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 88cd0dd..3302a5a 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> more"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index b84f646..ae915ed 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> more"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index b84f646..ae915ed 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> more"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index 76dab0d..24a7919 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> more"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 58d540f..b8d50d0 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ampliada"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> y <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> más"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 2a956f0..ad9f731 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> y <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> más"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 0ecc0c0..da16bdc 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ületäide"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ja veel <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> mulli"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index e83ee28..bc8b285 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Luzapena"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> eta beste <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index bafc2d5..2d82376 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"سرریز"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> و <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> حبابک دیگر"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 5ac124a..fe54f09 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ylivuoto"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ja <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> muuta"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 9510494..8385f50 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bulle à développer"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> et <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> autres"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 60f8944..519fcc1 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dépassement"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> et <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> autre(s)"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index bf081d4..0f09368 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> e <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> máis"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index b20f771..1db3dcb 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ઓવરફ્લો"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>થી <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> અને વધુ <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index a645186..40bb511 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओवरफ़्लो"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> की <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> वाली सूचना"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> और <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> अन्य"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index c96381d..f8412a8 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dodatni izbornik"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 03235aa..3958bc5 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Túlcsordulás"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, forrás: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> és <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> további"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 3cb7990..d82c93e 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Լրացուցիչ ընտրացանկ"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>՝ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածից"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ու ևս <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> ամպիկ"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 015b09e..b35eade 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tambahan"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> dari <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> dan <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> lainnya"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index 883fe82..2794ddc 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Yfirflæði"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> frá <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> í viðbót"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index 59b195a..04b4489 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Extra"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> e altri <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 9f0ed14..2ac80e0 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"אפשרויות נוספות"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> מתוך <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ועוד <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 4f1a162..4ad992b 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"オーバーフロー"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>(<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>、他 <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> 件"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 1fb6077..4ade09e 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"გადავსება"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: <xliff:g id="APP_NAME">%2$s</xliff:g>-იდან"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> და <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> სხვა"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index d83e2d3..e10ad21 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Қосымша мәзір"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> ұсынатын <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> және тағы <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 5448433..33c0738 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ម៉ឺនុយបន្ថែម"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ពី <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> និង <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> នាក់ទៀត"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 74c7750..18ef7e1 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ಓವರ್ಫ್ಲೋ"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> ನಿಂದ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ಮತ್ತು ಇನ್ನೂ <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index c27b7f8..3b48d06 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"더보기"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> 외 <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>개"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index f0d2af8..413d135 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Кошумча меню"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> колдонмосунан <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> жана дагы <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index f54c712..c2418b6 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ລາຍການເພີ່ມເຕີມ"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ຈາກ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ແລະ ອີກ <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> ລາຍການ"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index 554745e..59bda55 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Perpildymas"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ iš „<xliff:g id="APP_NAME">%2$s</xliff:g>“"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"„<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>“ ir dar <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index a6a0dab..ede41c3 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Pārpilde"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> no lietotnes <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> un vēl <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 4859055..5787da3 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Проширено балонче"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> од <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> и уште <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 85b093d..61dcce0 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ഓവർഫ്ലോ"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> എന്നതും മറ്റ് <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> എണ്ണവും"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index fe2e4a4..22f4390 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Илүү хэсэг"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>-с ирсэн <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> болон бусад <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index b053a21..d7143a1 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओव्हरफ्लो"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> वरील <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> आणि आणखी <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index c0219e0..ce2367d 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Limpahan"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> daripada <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> dan <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> lagi"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 7c7ff82..357f2f8 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"မီနူးအပို"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> မှ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> နှင့် နောက်ထပ် <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> ခု"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 6aa755a..e075be9 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflyt"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> andre"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index d49fd2d..456c1c3 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओभरफ्लो"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> मा देखाइएका <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> र थप <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index ca44a69..b6321de 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overloop"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> en nog <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index bf0bdc8..b7d42ef 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ଓଭରଫ୍ଲୋ"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>ରୁ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ଏବଂ ଅଧିକ <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index fc60396..d83d744 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ਓਵਰਫ਼ਲੋ"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਤੋਂ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ਅਤੇ <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> ਹੋਰ"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index d88e28a..064ba19 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozwijany"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikacji <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> i jeszcze <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index e4d07bd..dc8bceb 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menu adicional"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da app <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> e mais <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> pessoas"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 4fec4f8..3a5ee73 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Balão flutuante"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> do app <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> e mais <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index c839602..46322ed 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Suplimentar"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de la <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> și încă <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index da49ad3..ec03374 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Дополнительное меню"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"\"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" из приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> и ещё <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 9cbe837..7f4754f 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"පිටාර යාම"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> සිට <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> හා තව <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>ක්"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 3eca787..42faef3 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbaľovacia ponuka"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikácie <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> a ešte <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 52faeb7..c824fc0 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oblaček z dodatnimi elementi"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> in še <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index cdb9cf9..cb793af 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tejkalimi"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"\"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" nga <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"\"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>\" dhe <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> të tjera"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 7456a36..c8819c8 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Преклопни"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> и још <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index f369dae..6cc637b 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Fler alternativ"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> från <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> och <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> till"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 3d8277b..aac394a 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kiputo cha vipengee vya ziada"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kutoka <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> na vingine <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 47d8055..a20d23c 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"கூடுதல் விருப்பங்களைக் காட்டும்"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> வழங்கும் <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> மற்றும் <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index a4e1cbf..c96412e 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ఓవర్ఫ్లో"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>, మరో <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 1bbb137..080e032 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"การดำเนินการเพิ่มเติม"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> จาก <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> และอีก <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> รายการ"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 978a5a3..194a81f 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> mula sa <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> at <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> pa"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 0cc5d7f..0c64537 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Taşma"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> uygulamasından <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ve <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> tane daha"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 9c706a8..9bb0064 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Додаткове повідомлення"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> з додатка <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> і ще <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index e125248..63fe0cb 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"اوورفلو"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> سے <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> اور <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> مزید"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 3f4f981..94a23c0 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kengaytirish"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> va yana <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> kishi"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 9bc526f..2fe1d14 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bong bóng bổ sung"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> từ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> và <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> bong bóng khác"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index 79ea299..e649e39 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢出式气泡框"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"来自“<xliff:g id="APP_NAME">%2$s</xliff:g>”的<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>以及另外 <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> 个"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index b9d8eb7..e554148 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"展開式"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> 的「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」通知"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>和其他 <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> 則通知"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 90140cb..e598332 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢位"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"「<xliff:g id="APP_NAME">%2$s</xliff:g>」的「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」通知"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>和另外 <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> 則通知"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 73be445..eb2e9b3 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -144,4 +144,10 @@
<string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ukugcwala kakhulu"</string>
<string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kusuka ku-<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
<string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> nokunye okungu-<xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
+ <!-- no translation found for bubble_bar_action_move_left (3306922475737714758) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_move_right (3455099638571411251) -->
+ <skip />
+ <!-- no translation found for bubble_bar_action_dismiss_all (3290722022983403060) -->
+ <skip />
</resources>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 98a2783..63412e9 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -348,4 +348,8 @@
<string name="bubble_bar_action_move_right">Move right</string>
<!-- Action in accessibility menu to dismiss all bubbles. [CHAR_LIMIT=30] -->
<string name="bubble_bar_action_dismiss_all">Dismiss all</string>
+ <!-- Accessibility announcement when the bubble bar expands. [CHAR LIMIT=NONE]-->
+ <string name="bubble_bar_accessibility_announce_expand">expand <xliff:g id="bubble_description" example="some title from Messages">%1$s</xliff:g></string>
+ <!-- Accessibility announcement when the bubble bar collapses. [CHAR LIMIT=NONE]-->
+ <string name="bubble_bar_accessibility_announce_collapse">collapse <xliff:g id="bubble_description" example="some title from Messages">%1$s</xliff:g></string>
</resources>
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index 0b18633..e925af6 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -28,7 +28,6 @@
import android.appwidget.AppWidgetProviderInfo;
import android.content.ClipData;
import android.content.ClipDescription;
-import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
@@ -48,11 +47,11 @@
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.PackageItemInfo;
-import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.widget.WidgetCell;
import com.android.launcher3.widget.model.WidgetsListBaseEntriesBuilder;
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.picker.WidgetsFullSheet;
+import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
import java.util.ArrayList;
import java.util.HashSet;
@@ -110,8 +109,8 @@
private WidgetsModel mModel;
private LauncherAppState mApp;
private WidgetPredictionsRequester mWidgetPredictionsRequester;
- private final PopupDataProvider mPopupDataProvider = new PopupDataProvider(i -> {
- });
+ private final WidgetPickerDataProvider mWidgetPickerDataProvider =
+ new WidgetPickerDataProvider();
private int mDesiredWidgetWidth;
private int mDesiredWidgetHeight;
@@ -215,8 +214,8 @@
@NonNull
@Override
- public PopupDataProvider getPopupDataProvider() {
- return mPopupDataProvider;
+ public WidgetPickerDataProvider getWidgetPickerDataProvider() {
+ return mWidgetPickerDataProvider;
}
@Override
@@ -293,8 +292,6 @@
private void refreshAndBindWidgets() {
MODEL_EXECUTOR.execute(() -> {
LauncherAppState app = LauncherAppState.getInstance(this);
- Context context = app.getContext();
-
mModel.update(app, null);
bindWidgets(mModel.getWidgetsByPackageItem());
// Open sheet once widgets are available, so that it doesn't interrupt the open
@@ -317,7 +314,8 @@
shouldShowDefaultWidgets() ? builder.build(widgets,
mDefaultWidgetsFilter) : List.of();
- MAIN_EXECUTOR.execute(() -> mPopupDataProvider.setAllWidgets(allWidgets, defaultWidgets));
+ MAIN_EXECUTOR.execute(
+ () -> mWidgetPickerDataProvider.setWidgets(allWidgets, defaultWidgets));
}
private void openWidgetsSheet() {
@@ -332,7 +330,7 @@
private void bindRecommendedWidgets(List<ItemInfo> recommendedWidgets) {
// Bind recommendations once picker has finished open animation.
MAIN_EXECUTOR.getHandler().postDelayed(
- () -> mPopupDataProvider.setRecommendedWidgets(recommendedWidgets),
+ () -> mWidgetPickerDataProvider.setWidgetRecommendations(recommendedWidgets),
mDeviceProfile.bottomSheetOpenDuration);
}
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index a16031d..92d9516 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -290,6 +290,9 @@
writer.println(prefix + "\tmPredictionsEnabled: " + mPredictionsEnabled);
writer.println(prefix + "\tmPredictionUiUpdatePaused: " + mPredictionUiUpdatePaused);
writer.println(prefix + "\tmNumPredictedAppsPerRow: " + mNumPredictedAppsPerRow);
- writer.println(prefix + "\tmPredictedApps: " + mPredictedApps);
+ writer.println(prefix + "\tmPredictedApps: " + mPredictedApps.size());
+ for (WorkspaceItemInfo info : mPredictedApps) {
+ writer.println(prefix + "\t\t" + info);
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
index de974ec..c50e82d 100644
--- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
+++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java
@@ -536,6 +536,9 @@
writer.println(prefix + "HotseatPredictionController");
writer.println(prefix + "\tFlags: " + getStateString(mPauseFlags));
writer.println(prefix + "\tmHotSeatItemsCount: " + mHotSeatItemsCount);
- writer.println(prefix + "\tmPredictedItems: " + mPredictedItems);
+ writer.println(prefix + "\tmPredictedItems: " + mPredictedItems.size());
+ for (ItemInfo info : mPredictedItems) {
+ writer.println(prefix + "\t\t" + info);
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
index 62cc0bb..6c7fe5b 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.java
@@ -19,10 +19,9 @@
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import android.os.Debug;
-import android.os.SystemProperties;
import android.util.Log;
import android.view.View;
@@ -145,7 +144,7 @@
notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
}
- if (!enableDesktopWindowingWallpaperActivity() && wasVisible != isVisible) {
+ if (!WALLPAPER_ACTIVITY.isEnabled(mLauncher) && wasVisible != isVisible) {
// TODO: b/333533253 - Remove after flag rollout
if (mVisibleDesktopTasksCount > 0) {
setLauncherViewsVisibility(View.INVISIBLE);
@@ -189,7 +188,7 @@
notifyDesktopVisibilityListeners(areDesktopTasksVisibleNow);
}
- if (enableDesktopWindowingWallpaperActivity()) {
+ if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) {
return;
}
// TODO: b/333533253 - Clean up after flag rollout
@@ -289,7 +288,7 @@
* TODO: b/333533253 - Remove after flag rollout
*/
private void setLauncherViewsVisibility(int visibility) {
- if (enableDesktopWindowingWallpaperActivity()) {
+ if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) {
return;
}
if (DEBUG) {
@@ -314,7 +313,7 @@
* TODO: b/333533253 - Remove after flag rollout
*/
private void markLauncherPaused() {
- if (enableDesktopWindowingWallpaperActivity()) {
+ if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) {
return;
}
if (DEBUG) {
@@ -331,7 +330,7 @@
* TODO: b/333533253 - Remove after flag rollout
*/
private void markLauncherResumed() {
- if (enableDesktopWindowingWallpaperActivity()) {
+ if (WALLPAPER_ACTIVITY.isEnabled(mLauncher)) {
return;
}
if (DEBUG) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 0add1c4..93a023d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -21,7 +21,7 @@
import static com.android.launcher3.taskbar.TaskbarLauncherStateController.FLAG_VISIBLE;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IGNORE_IN_APP;
import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
-import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import android.animation.Animator;
import android.animation.AnimatorSet;
@@ -214,7 +214,7 @@
DesktopVisibilityController desktopController =
LauncherActivityInterface.INSTANCE.getDesktopVisibilityController();
- if (!enableDesktopWindowingWallpaperActivity()
+ if (!WALLPAPER_ACTIVITY.isEnabled(mLauncher)
&& desktopController != null
&& desktopController.areDesktopTasksVisible()) {
// TODO: b/333533253 - Remove after flag rollout
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 3048243..088c3cc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -315,6 +315,7 @@
new TaskbarTranslationController(this),
new TaskbarSpringOnStashController(this),
new TaskbarRecentAppsController(
+ this,
RecentsModel.INSTANCE.get(this),
LauncherActivityInterface.INSTANCE::getDesktopVisibilityController),
TaskbarEduTooltipController.newInstance(this),
@@ -813,7 +814,7 @@
*/
public void setUIController(@NonNull TaskbarUIController uiController) {
mControllers.setUiController(uiController);
- if (mControllers.bubbleControllers.isEmpty()) {
+ if (BubbleBarController.isBubbleBarEnabled() && mControllers.bubbleControllers.isEmpty()) {
// if the bubble bar was visible in a previous configuration of taskbar and is being
// recreated now without bubbles, clean up any bubble bar adjustments from hotseat
bubbleBarVisibilityChanged(/* isVisible= */ false);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
index 5c08116..49fc0dd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar
+import android.content.Context
import androidx.annotation.VisibleForTesting
import com.android.launcher3.Flags.enableRecentsInTaskbar
import com.android.launcher3.model.data.ItemInfo
@@ -26,8 +27,8 @@
import com.android.quickstep.RecentsModel
import com.android.quickstep.util.DesktopTask
import com.android.quickstep.util.GroupTask
-import com.android.window.flags.Flags.enableDesktopWindowingMode
import com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps
+import com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE
import java.io.PrintWriter
/**
@@ -36,6 +37,7 @@
* - When in Desktop Mode: show the currently running (open) Tasks
*/
class TaskbarRecentAppsController(
+ context: Context,
private val recentsModel: RecentsModel,
// Pass a provider here instead of the actual DesktopVisibilityController instance since that
// instance might not be available when this constructor is called.
@@ -44,10 +46,13 @@
// TODO(b/335401172): unify DesktopMode checks in Launcher.
var canShowRunningApps =
- enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps()
+ DESKTOP_WINDOWING_MODE.isEnabled(context) && enableDesktopWindowingTaskbarRunningApps()
@VisibleForTesting
set(isEnabledFromTest) {
field = isEnabledFromTest
+ if (!field && !canShowRecentApps) {
+ recentsModel.unregisterRecentTasksChangedListener()
+ }
}
// TODO(b/343532825): Add a setting to disable Recents even when the flag is on.
@@ -55,6 +60,9 @@
@VisibleForTesting
set(isEnabledFromTest) {
field = isEnabledFromTest
+ if (!field && !canShowRunningApps) {
+ recentsModel.unregisterRecentTasksChangedListener()
+ }
}
// Initialized in init.
@@ -114,8 +122,10 @@
fun init(taskbarControllers: TaskbarControllers) {
controllers = taskbarControllers
- recentsModel.registerRecentTasksChangedListener(recentTasksChangedListener)
- reloadRecentTasksIfNeeded()
+ if (canShowRunningApps || canShowRecentApps) {
+ recentsModel.registerRecentTasksChangedListener(recentTasksChangedListener)
+ reloadRecentTasksIfNeeded()
+ }
}
fun onDestroy() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index fab7975..5d550ae 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -1228,6 +1228,7 @@
mWidthAnimator.reverse();
}
updateBubbleAccessibilityStates();
+ announceExpandedStateChange();
}
}
@@ -1344,6 +1345,26 @@
setContentDescription(contentDesc);
}
+ private void announceExpandedStateChange() {
+ final CharSequence selectedBubbleContentDesc;
+ if (mSelectedBubbleView != null) {
+ selectedBubbleContentDesc = mSelectedBubbleView.getContentDescription();
+ } else {
+ selectedBubbleContentDesc = getResources().getString(
+ R.string.bubble_bar_bubble_fallback_description);
+ }
+
+ final String msg;
+ if (mIsBarExpanded) {
+ msg = getResources().getString(R.string.bubble_bar_accessibility_announce_expand,
+ selectedBubbleContentDesc);
+ } else {
+ msg = getResources().getString(R.string.bubble_bar_accessibility_announce_collapse,
+ selectedBubbleContentDesc);
+ }
+ announceForAccessibility(msg);
+ }
+
private boolean isIconSizeOrPaddingUpdated(float newIconSize, float newBubbleBarPadding) {
return isIconSizeUpdated(newIconSize) || isPaddingUpdated(newBubbleBarPadding);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 74a673b..9270f68 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -73,6 +73,7 @@
private TaskbarInsetsController mTaskbarInsetsController;
private View.OnClickListener mBubbleClickListener;
private View.OnClickListener mBubbleBarClickListener;
+ private BubbleView.Controller mBubbleViewController;
// These are exposed to {@link BubbleStashController} to animate for stashing/un-stashing
private final MultiValueAlpha mBubbleBarAlpha;
@@ -153,6 +154,31 @@
mBubbleBarController.updateBubbleBarLocation(location);
}
});
+
+ mBubbleViewController = new BubbleView.Controller() {
+ @Override
+ public BubbleBarLocation getBubbleBarLocation() {
+ return BubbleBarViewController.this.getBubbleBarLocation();
+ }
+
+ @Override
+ public void dismiss(BubbleView bubble) {
+ if (bubble.getBubble() != null) {
+ notifySysUiBubbleDismissed(bubble.getBubble());
+ }
+ onBubbleDismissed(bubble);
+ }
+
+ @Override
+ public void collapse() {
+ collapseBubbleBar();
+ }
+
+ @Override
+ public void updateBubbleBarLocation(BubbleBarLocation location) {
+ mBubbleBarController.updateBubbleBarLocation(location);
+ }
+ };
}
private void onBubbleClicked(BubbleView bubbleView) {
@@ -165,8 +191,7 @@
final String currentlySelected = mBubbleBarController.getSelectedBubbleKey();
if (mBarView.isExpanded() && Objects.equals(bubble.getKey(), currentlySelected)) {
// Tapping the currently selected bubble while expanded collapses the view.
- setExpanded(false);
- mBubbleStashController.stashBubbleBar();
+ collapseBubbleBar();
} else {
mBubbleBarController.showAndSelectBubble(bubble);
}
@@ -196,6 +221,11 @@
}
}
+ private void collapseBubbleBar() {
+ setExpanded(false);
+ mBubbleStashController.stashBubbleBar();
+ }
+
/** Notifies that the stash state is changing. */
public void onStashStateChanging() {
if (isAnimatingNewBubble()) {
@@ -220,7 +250,7 @@
return mBubbleBarTranslationY;
}
- float getBubbleBarCollapsedHeight() {
+ public float getBubbleBarCollapsedHeight() {
return mBarView.getBubbleBarCollapsedHeight();
}
@@ -440,6 +470,7 @@
public void removeBubble(BubbleBarBubble b) {
if (b != null) {
mBarView.removeBubble(b.getView());
+ b.getView().setController(null);
} else {
Log.w(TAG, "removeBubble, bubble was null!");
}
@@ -450,6 +481,8 @@
BubbleBarBubble removedBubble, boolean isExpanding, boolean suppressAnimation) {
mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), removedBubble.getView());
addedBubble.getView().setOnClickListener(mBubbleClickListener);
+ addedBubble.getView().setController(mBubbleViewController);
+ removedBubble.getView().setController(null);
mBubbleDragController.setupBubbleView(addedBubble.getView());
if (!suppressAnimation) {
animateBubbleNotification(addedBubble, isExpanding, /* isUpdate= */ false);
@@ -464,6 +497,7 @@
mBarView.addBubble(b.getView());
b.getView().setOnClickListener(mBubbleClickListener);
mBubbleDragController.setupBubbleView(b.getView());
+ b.getView().setController(mBubbleViewController);
if (b instanceof BubbleBarOverflow) {
return;
@@ -580,8 +614,8 @@
mSystemUiProxy.stopBubbleDrag(location, mBarView.getRestingTopPositionOnScreen());
}
- /** Notifies {@link BubbleBarView} that the dragged bubble was dismissed. */
- public void onBubbleDragDismissed(BubbleView bubble) {
+ /** Handle given bubble being dismissed */
+ public void onBubbleDismissed(BubbleView bubble) {
mBubbleBarController.onBubbleDismissed(bubble);
mBarView.removeBubble(bubble);
}
@@ -624,10 +658,9 @@
}
/**
- * Called when given bubble was dismissed. Notifies SystemUI
- * @param bubble dismissed bubble item
+ * Notify SystemUI that the given bubble has been dismissed.
*/
- public void onDismissBubble(@NonNull BubbleBarItem bubble) {
+ public void notifySysUiBubbleDismissed(@NonNull BubbleBarItem bubble) {
mSystemUiProxy.dragBubbleToDismiss(bubble.getKey(), mTimeSource.currentTimeMillis());
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
index 6a63da8..5eebbd8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
@@ -143,7 +143,7 @@
if (mMagnetizedObject.getUnderlyingObject() instanceof BubbleView) {
BubbleView bubbleView = (BubbleView) mMagnetizedObject.getUnderlyingObject();
if (bubbleView.getBubble() != null) {
- mBubbleBarViewController.onDismissBubble(bubbleView.getBubble());
+ mBubbleBarViewController.notifySysUiBubbleDismissed(bubbleView.getBubble());
}
} else if (mMagnetizedObject.getUnderlyingObject() instanceof BubbleBarView) {
mBubbleBarViewController.onDismissAllBubbles();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index 8316b5b..656a266 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -153,7 +153,7 @@
@Override
protected void onDragDismiss() {
mBubblePinController.onDragEnd();
- mBubbleBarViewController.onBubbleDragDismissed(bubbleView);
+ mBubbleBarViewController.onBubbleDismissed(bubbleView);
mBubbleBarViewController.onBubbleDragEnd();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index acb6b4e..3bcaa16 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -23,11 +23,13 @@
import android.graphics.Outline;
import android.graphics.Path;
import android.graphics.Rect;
+import android.os.Bundle;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewOutlineProvider;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.ImageView;
import androidx.constraintlayout.widget.ConstraintLayout;
@@ -36,6 +38,7 @@
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.IconNormalizer;
import com.android.wm.shell.animation.Interpolators;
+import com.android.wm.shell.common.bubbles.BubbleBarLocation;
import com.android.wm.shell.common.bubbles.BubbleInfo;
// TODO: (b/276978250) This is will be similar to WMShell's BadgedImageView, it'd be nice to share.
@@ -73,6 +76,9 @@
private BubbleBarItem mBubble;
+ @Nullable
+ private Controller mController;
+
public BubbleView(Context context) {
this(context, null);
}
@@ -180,6 +186,58 @@
mDotRenderer.draw(canvas, mDrawParams);
}
+ @Override
+ public void onInitializeAccessibilityNodeInfoInternal(AccessibilityNodeInfo info) {
+ super.onInitializeAccessibilityNodeInfoInternal(info);
+ info.addAction(AccessibilityNodeInfo.ACTION_COLLAPSE);
+ if (mBubble instanceof BubbleBarBubble) {
+ info.addAction(AccessibilityNodeInfo.ACTION_DISMISS);
+ }
+ if (mController != null) {
+ if (mController.getBubbleBarLocation().isOnLeft(isLayoutRtl())) {
+ info.addAction(new AccessibilityNodeInfo.AccessibilityAction(R.id.action_move_right,
+ getResources().getString(R.string.bubble_bar_action_move_right)));
+ } else {
+ info.addAction(new AccessibilityNodeInfo.AccessibilityAction(R.id.action_move_left,
+ getResources().getString(R.string.bubble_bar_action_move_left)));
+ }
+ }
+ }
+
+ @Override
+ public boolean performAccessibilityActionInternal(int action, Bundle arguments) {
+ if (super.performAccessibilityActionInternal(action, arguments)) {
+ return true;
+ }
+ if (action == AccessibilityNodeInfo.ACTION_COLLAPSE) {
+ if (mController != null) {
+ mController.collapse();
+ }
+ return true;
+ }
+ if (action == AccessibilityNodeInfo.ACTION_DISMISS) {
+ if (mController != null) {
+ mController.dismiss(this);
+ }
+ return true;
+ }
+ if (action == R.id.action_move_left) {
+ if (mController != null) {
+ mController.updateBubbleBarLocation(BubbleBarLocation.LEFT);
+ }
+ }
+ if (action == R.id.action_move_right) {
+ if (mController != null) {
+ mController.updateBubbleBarLocation(BubbleBarLocation.RIGHT);
+ }
+ }
+ return false;
+ }
+
+ void setController(@Nullable Controller controller) {
+ mController = controller;
+ }
+
/** Sets the bubble being rendered in this view. */
public void setBubble(BubbleBarBubble bubble) {
mBubble = bubble;
@@ -337,4 +395,19 @@
String toString = mBubble != null ? mBubble.getKey() : "null";
return "BubbleView{" + toString + "}";
}
+
+ /** Interface for BubbleView to communicate with its controller */
+ public interface Controller {
+ /** Get current bubble bar {@link BubbleBarLocation} */
+ BubbleBarLocation getBubbleBarLocation();
+
+ /** This bubble should be dismissed */
+ void dismiss(BubbleView bubble);
+
+ /** Collapse the bubble bar */
+ void collapse();
+
+ /** Request bubble bar location to be updated to the given location */
+ void updateBubbleBarLocation(BubbleBarLocation location);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
new file mode 100644
index 0000000..e42b6d6
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleStashController.kt
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.bubbles.stashing
+
+import android.view.InsetsController
+import android.view.MotionEvent
+import android.view.View
+import com.android.launcher3.taskbar.TaskbarInsetsController
+import com.android.launcher3.taskbar.bubbles.BubbleBarView
+import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
+import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
+import com.android.wm.shell.common.bubbles.BubbleBarLocation
+import com.android.wm.shell.shared.animation.PhysicsAnimator
+import java.io.PrintWriter
+
+/** StashController that defines stashing behaviour for the taskbar modes. */
+interface BubbleStashController {
+
+ /**
+ * Abstraction on the task bar activity context to only provide the dimensions required for
+ * [BubbleBarView] translation Y computation.
+ */
+ interface TaskbarHotseatDimensionsProvider {
+
+ /** Provides taskbar bottom space in pixels. */
+ fun getTaskbarBottomSpace(): Int
+
+ /** Provides taskbar height in pixels. */
+ fun getTaskbarHeight(): Int
+
+ /** Provides hotseat bottom space in pixels. */
+ fun getHotseatBottomSpace(): Int
+
+ /** Provides hotseat height in pixels. */
+ fun getHotseatHeight(): Int
+ }
+
+ /** Execute passed action only after controllers are initiated. */
+ interface ControllersAfterInitAction {
+ /** Execute action after controllers are initiated. */
+ fun runAfterInit(action: () -> Unit)
+ }
+
+ /** Whether bubble bar is currently stashed */
+ val isStashed: Boolean
+
+ /** Whether launcher enters or exits the home page. */
+ var isBubblesShowingOnHome: Boolean
+
+ /** Whether launcher enters or exits the overview page. */
+ var isBubblesShowingOnOverview: Boolean
+
+ /** Updated when sysui locked state changes, when locked, bubble bar is not shown. */
+ var isSysuiLocked: Boolean
+
+ /** Whether there is a transient taskbar mode */
+ val isTransientTaskBar: Boolean
+
+ /** Whether stash control has a handle view */
+ val hasHandleView: Boolean
+
+ /** Initialize controller */
+ fun init(
+ taskbarInsetsController: TaskbarInsetsController,
+ bubbleBarViewController: BubbleBarViewController,
+ bubbleStashedHandleViewController: BubbleStashedHandleViewController?,
+ controllersAfterInitAction: ControllersAfterInitAction
+ )
+
+ /** Sets stashed and expanded state of the bubble bar */
+ fun updateStashedAndExpandedState(stash: Boolean = false, expand: Boolean = false)
+
+ /**
+ * Shows the bubble bar at [getBubbleBarTranslationY] position immediately without animation.
+ */
+ fun showBubbleBarImmediate()
+
+ /** Shows the bubble bar at [bubbleBarTranslationY] position immediately without animation. */
+ fun showBubbleBarImmediate(bubbleBarTranslationY: Float)
+
+ /** Stashes the bubble bar immediately without animation. */
+ fun stashBubbleBarImmediate()
+
+ /** Returns the touchable height of the bubble bar based on it's stashed state. */
+ fun getTouchableHeight(): Int
+
+ /** Whether bubble bar is currently visible */
+ fun isBubbleBarVisible(): Boolean
+
+ /**
+ * Updates the values of the internal animators after the new bubble animation was interrupted
+ *
+ * @param isStashed whether the current state should be stashed
+ * @param bubbleBarTranslationY the current bubble bar translation. this is only used if the
+ * bubble bar is showing to ensure that the stash animator runs smoothly.
+ */
+ fun onNewBubbleAnimationInterrupted(isStashed: Boolean, bubbleBarTranslationY: Float)
+
+ /** Checks whether the motion event is over the stash handle or bubble bar. */
+ fun isEventOverBubbleBarViews(ev: MotionEvent): Boolean
+
+ /** Set a bubble bar location */
+ fun setBubbleBarLocation(bubbleBarLocation: BubbleBarLocation)
+
+ /**
+ * Stashes the bubble bar (transform to the handle view), or just shrink width of the expanded
+ * bubble bar based on the controller implementation.
+ */
+ fun stashBubbleBar() {
+ updateStashedAndExpandedState(stash = true, expand = false)
+ }
+
+ /** Shows the bubble bar, and expands bubbles depending on [expandBubbles]. */
+ fun showBubbleBar(expandBubbles: Boolean) {
+ updateStashedAndExpandedState(stash = false, expandBubbles)
+ }
+
+ // TODO(b/354218264): Move to BubbleBarViewAnimator
+ /**
+ * The difference on the Y axis between the center of the handle and the center of the bubble
+ * bar.
+ */
+ fun getSlideInAnimationDistanceY(): Float
+
+ // TODO(b/354218264): Move to BubbleBarViewAnimator
+ /** The distance the handle moves as part of the new bubble animation. */
+ fun getStashedHandleTranslationForNewBubbleAnimation(): Float
+
+ // TODO(b/354218264): Move to BubbleBarViewAnimator
+ /** Returns the [PhysicsAnimator] for the stashed handle view. */
+ fun getStashedHandlePhysicsAnimator(): PhysicsAnimator<View>?
+
+ // TODO(b/354218264): Move to BubbleBarViewAnimator
+ /** Notifies taskbar that it should update its touchable region. */
+ fun updateTaskbarTouchRegion()
+
+ // TODO(b/354218264): Move to BubbleBarViewAnimator
+ /** Set the translation Y for the stashed handle. */
+ fun setHandleTranslationY(translationY: Float)
+
+ /**
+ * Returns bubble bar Y position according to [isBubblesShowingOnHome] and
+ * [isBubblesShowingOnOverview] values. Default implementation only analyse
+ * [isBubblesShowingOnHome] and return translationY to align with the hotseat vertical center.
+ * For Other cases align bubbles with the taskbar.
+ */
+ val bubbleBarTranslationY: Float
+ get() =
+ if (isBubblesShowingOnHome) {
+ bubbleBarTranslationYForHotseat
+ } else {
+ bubbleBarTranslationYForTaskbar
+ }
+
+ /** Translation Y to align the bubble bar with the hotseat. */
+ val bubbleBarTranslationYForTaskbar: Float
+
+ /** Return translation Y to align the bubble bar with the taskbar. */
+ val bubbleBarTranslationYForHotseat: Float
+
+ /** Dumps the state of BubbleStashController. */
+ fun dump(pw: PrintWriter) {
+ pw.println("Bubble stash controller state:")
+ pw.println(" isStashed: $isStashed")
+ pw.println(" isBubblesShowingOnOverview: $isBubblesShowingOnOverview")
+ pw.println(" isBubblesShowingOnHome: $isBubblesShowingOnHome")
+ pw.println(" isSysuiLocked: $isSysuiLocked")
+ }
+
+ companion object {
+ /** How long to stash/unstash. */
+ const val BAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE.toLong()
+
+ /** How long to translate Y coordinate of the BubbleBar. */
+ const val BAR_TRANSLATION_DURATION = 300L
+
+ /** The scale bubble bar animates to when being stashed. */
+ const val STASHED_BAR_SCALE = 0.5f
+
+ /** Creates new instance of [BubbleStashController] */
+ @JvmStatic
+ fun newInstance(
+ taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider
+ ): BubbleStashController {
+ return PersistentTaskbarStashController(taskbarHotseatDimensionsProvider)
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentTaskbarStashController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentTaskbarStashController.kt
new file mode 100644
index 0000000..4a05a5e
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentTaskbarStashController.kt
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.bubbles.stashing
+
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.AnimatorSet
+import android.view.MotionEvent
+import android.view.View
+import com.android.launcher3.anim.AnimatedFloat
+import com.android.launcher3.taskbar.TaskbarInsetsController
+import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
+import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_STASH_DURATION
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.Companion.BAR_TRANSLATION_DURATION
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.ControllersAfterInitAction
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider
+import com.android.launcher3.util.MultiPropertyFactory
+import com.android.wm.shell.common.bubbles.BubbleBarLocation
+import com.android.wm.shell.shared.animation.PhysicsAnimator
+
+class PersistentTaskbarStashController(
+ private val taskbarHotseatDimensionsProvider: TaskbarHotseatDimensionsProvider,
+) : BubbleStashController {
+
+ private lateinit var taskbarInsetsController: TaskbarInsetsController
+ private lateinit var bubbleBarViewController: BubbleBarViewController
+ private lateinit var bubbleBarTranslationYAnimator: AnimatedFloat
+ private lateinit var bubbleBarAlphaAnimator: MultiPropertyFactory<View>.MultiProperty
+ private lateinit var bubbleBarScaleAnimator: AnimatedFloat
+ private lateinit var controllersAfterInitAction: ControllersAfterInitAction
+
+ override var isBubblesShowingOnHome: Boolean = false
+ set(onHome) {
+ if (field == onHome) return
+ field = onHome
+ if (!bubbleBarViewController.hasBubbles()) {
+ // if there are no bubbles, there's nothing to show, so just return.
+ return
+ }
+ if (onHome) {
+ // When transition to home we should show collapse the bubble bar
+ updateStashedAndExpandedState(stash = false, expand = false)
+ }
+ animateBubbleBarY()
+ bubbleBarViewController.onBubbleBarConfigurationChanged(/* animate= */ true)
+ }
+
+ override var isBubblesShowingOnOverview: Boolean = false
+ set(onOverview) {
+ if (field == onOverview) return
+ field = onOverview
+ if (!onOverview) {
+ // When transition from overview we should show collapse the bubble bar
+ updateStashedAndExpandedState(stash = false, expand = false)
+ }
+ bubbleBarViewController.onBubbleBarConfigurationChanged(/* animate= */ true)
+ }
+
+ override var isSysuiLocked: Boolean = false
+ set(isLocked) {
+ if (field == isLocked) return
+ field = isLocked
+ if (!isLocked && bubbleBarViewController.hasBubbles()) {
+ animateAfterUnlock()
+ }
+ }
+
+ override var isTransientTaskBar: Boolean = false
+
+ /** When the bubble bar is shown for the persistent task bar, there is no handle view. */
+ override val hasHandleView: Boolean = false
+
+ /** For persistent task bar we never stash the bubble bar */
+ override val isStashed: Boolean = false
+
+ override val bubbleBarTranslationYForTaskbar: Float
+ get() {
+ val taskbarBottomMargin = taskbarHotseatDimensionsProvider.getTaskbarBottomSpace()
+ val bubbleBarHeight: Float = bubbleBarViewController.bubbleBarCollapsedHeight
+ val taskbarHeight = taskbarHotseatDimensionsProvider.getTaskbarHeight()
+ return -taskbarBottomMargin - (taskbarHeight - bubbleBarHeight) / 2f
+ }
+
+ override val bubbleBarTranslationYForHotseat: Float
+ get() {
+ val hotseatBottomSpace = taskbarHotseatDimensionsProvider.getHotseatBottomSpace()
+ val hotseatCellHeight = taskbarHotseatDimensionsProvider.getHotseatHeight()
+ val bubbleBarHeight: Float = bubbleBarViewController.bubbleBarCollapsedHeight
+ return -hotseatBottomSpace - (hotseatCellHeight - bubbleBarHeight) / 2
+ }
+
+ override fun init(
+ taskbarInsetsController: TaskbarInsetsController,
+ bubbleBarViewController: BubbleBarViewController,
+ bubbleStashedHandleViewController: BubbleStashedHandleViewController?,
+ controllersAfterInitAction: ControllersAfterInitAction
+ ) {
+ this.taskbarInsetsController = taskbarInsetsController
+ this.bubbleBarViewController = bubbleBarViewController
+ this.controllersAfterInitAction = controllersAfterInitAction
+ bubbleBarTranslationYAnimator = bubbleBarViewController.bubbleBarTranslationY
+ bubbleBarAlphaAnimator = bubbleBarViewController.bubbleBarAlpha.get(0)
+ bubbleBarScaleAnimator = bubbleBarViewController.bubbleBarScale
+ }
+
+ private fun animateAfterUnlock() {
+ val animatorSet = AnimatorSet()
+ if (isBubblesShowingOnHome || isBubblesShowingOnOverview) {
+ animatorSet.playTogether(
+ bubbleBarScaleAnimator.animateToValue(1f),
+ bubbleBarTranslationYAnimator.animateToValue(bubbleBarTranslationY),
+ bubbleBarAlphaAnimator.animateToValue(1f)
+ )
+ }
+ updateTouchRegionOnAnimationEnd(animatorSet)
+ animatorSet.setDuration(BAR_STASH_DURATION).start()
+ }
+
+ override fun updateStashedAndExpandedState(stash: Boolean, expand: Boolean) {
+ if (bubbleBarViewController.isHiddenForNoBubbles) {
+ // If there are no bubbles the bar is invisible, nothing to do here.
+ return
+ }
+ if (bubbleBarViewController.isExpanded != expand) {
+ bubbleBarViewController.isExpanded = expand
+ }
+ }
+
+ override fun showBubbleBarImmediate() = showBubbleBarImmediate(bubbleBarTranslationY)
+
+ override fun showBubbleBarImmediate(bubbleBarTranslationY: Float) {
+ bubbleBarTranslationYAnimator.updateValue(bubbleBarTranslationY)
+ bubbleBarAlphaAnimator.setValue(1f)
+ bubbleBarScaleAnimator.updateValue(1f)
+ }
+
+ override fun setBubbleBarLocation(bubbleBarLocation: BubbleBarLocation) {
+ // When the bubble bar is shown for the persistent task bar, there is no handle view, so no
+ // operation is performed.
+ }
+
+ override fun stashBubbleBarImmediate() {
+ // When the bubble bar is shown for the persistent task bar, there is no handle view, so no
+ // operation is performed.
+ }
+
+ /** If bubble bar is visible return bubble bar height, 0 otherwise */
+ override fun getTouchableHeight() =
+ if (isBubbleBarVisible()) {
+ bubbleBarViewController.bubbleBarCollapsedHeight.toInt()
+ } else {
+ 0
+ }
+
+ override fun isBubbleBarVisible(): Boolean = bubbleBarViewController.hasBubbles()
+
+ override fun onNewBubbleAnimationInterrupted(isStashed: Boolean, bubbleBarTranslationY: Float) {
+ showBubbleBarImmediate(bubbleBarTranslationY)
+ }
+
+ override fun isEventOverBubbleBarViews(ev: MotionEvent): Boolean =
+ bubbleBarViewController.isEventOverAnyItem(ev)
+
+ override fun getSlideInAnimationDistanceY(): Float {
+ // distance from the bottom of the screen and the bubble bar center.
+ return -bubbleBarViewController.bubbleBarCollapsedHeight / 2f
+ }
+
+ /** When the bubble bar is shown for the persistent task bar, there is no handle view. */
+ override fun getStashedHandleTranslationForNewBubbleAnimation(): Float = 0f
+
+ /** When the bubble bar is shown for the persistent task bar, there is no handle view. */
+ override fun getStashedHandlePhysicsAnimator(): PhysicsAnimator<View>? = null
+
+ override fun updateTaskbarTouchRegion() {
+ taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+ }
+
+ /**
+ * When the bubble bar is shown for the persistent task bar the bar does not stash, so no
+ * operation is performed
+ */
+ override fun setHandleTranslationY(translationY: Float) {
+ // no op since does not have a handle view
+ }
+
+ /** Animates bubble bar Y accordingly to the showing mode */
+ private fun animateBubbleBarY() {
+ val animator =
+ bubbleBarViewController.bubbleBarTranslationY.animateToValue(bubbleBarTranslationY)
+ updateTouchRegionOnAnimationEnd(animator)
+ animator.setDuration(BAR_TRANSLATION_DURATION)
+ animator.start()
+ }
+
+ private fun updateTouchRegionOnAnimationEnd(animator: Animator) {
+ animator.addListener(
+ object : AnimatorListenerAdapter() {
+
+ override fun onAnimationEnd(animation: Animator) {
+ controllersAfterInitAction.runAfterInit {
+ taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+ }
+ }
+ }
+ )
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index be6f690..bbc6b42 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -64,10 +64,10 @@
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.QUICK_SWITCH_FROM_HOME_FALLBACK;
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
-import static com.android.window.flags.Flags.enableDesktopWindowingMode;
-import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -201,6 +201,8 @@
import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver;
import com.android.systemui.unfold.updates.RotationChangeProvider;
+import kotlin.Unit;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -213,8 +215,6 @@
import java.util.function.Predicate;
import java.util.stream.Stream;
-import kotlin.Unit;
-
public class QuickstepLauncher extends Launcher implements RecentsViewContainer {
private static final boolean TRACE_LAYOUTS =
SystemProperties.getBoolean("persist.debug.trace_layouts", false);
@@ -256,6 +256,8 @@
private boolean mIsPredictiveBackToHomeInProgress;
+ private boolean mCanShowAllAppsEducationView;
+
public static QuickstepLauncher getLauncher(Context context) {
return fromContext(context);
}
@@ -276,7 +278,7 @@
// TODO(b/337863494): Explore use of the same OverviewComponentObserver across launcher
OverviewComponentObserver overviewComponentObserver = new OverviewComponentObserver(
asContext(), deviceState);
- if (enableDesktopWindowingMode()) {
+ if (DESKTOP_WINDOWING_MODE.isEnabled(this)) {
mDesktopRecentsTransitionController = new DesktopRecentsTransitionController(
getStateManager(), systemUiProxy, getIApplicationThread(),
getDepthController());
@@ -296,7 +298,7 @@
mTISBindHelper = new TISBindHelper(this, this::onTISConnected);
mDepthController = new DepthController(this);
- if (enableDesktopWindowingMode()) {
+ if (DESKTOP_WINDOWING_MODE.isEnabled(this)) {
mDesktopVisibilityController = new DesktopVisibilityController(this);
mDesktopVisibilityController.registerSystemUiListener();
mSplitSelectStateController.initSplitFromDesktopController(this,
@@ -513,7 +515,7 @@
} else if (item.containerId == Favorites.CONTAINER_HOTSEAT_PREDICTION) {
mHotseatPredictionController.setPredictedItems(item);
} else if (item.containerId == Favorites.CONTAINER_WIDGETS_PREDICTION) {
- getPopupDataProvider().setRecommendedWidgets(item.items);
+ getWidgetPickerDataProvider().setWidgetRecommendations(item.items);
}
}
@@ -1004,7 +1006,7 @@
@Override
public void setResumed() {
- if (!enableDesktopWindowingWallpaperActivity()
+ if (!WALLPAPER_ACTIVITY.isEnabled(this)
&& mDesktopVisibilityController != null
&& mDesktopVisibilityController.areDesktopTasksVisible()
&& !mDesktopVisibilityController.isRecentsGestureInProgress()) {
@@ -1494,4 +1496,12 @@
public boolean isRecentsViewVisible() {
return getStateManager().getState().isRecentsViewVisible;
}
+
+ public boolean isCanShowAllAppsEducationView() {
+ return mCanShowAllAppsEducationView;
+ }
+
+ public void setCanShowAllAppsEducationView(boolean canShowAllAppsEducationView) {
+ mCanShowAllAppsEducationView = canShowAllAppsEducationView;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index 3325009..5377983 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -39,7 +39,6 @@
import android.view.ViewConfiguration;
import com.android.internal.jank.Cuj;
-import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -88,13 +87,16 @@
// Normal to Hint animation has flag SKIP_OVERVIEW, so we update this scrim with this animator.
private ObjectAnimator mNormalToHintOverviewScrimAnimator;
+ private final QuickstepLauncher mLauncher;
+
/**
* @param cancelSplitRunnable Called when split placeholder view needs to be cancelled.
* Animation should be added to the provided AnimatorSet
*/
- public NoButtonNavbarToOverviewTouchController(Launcher l,
+ public NoButtonNavbarToOverviewTouchController(QuickstepLauncher l,
BiConsumer<AnimatorSet, Long> cancelSplitRunnable) {
super(l);
+ mLauncher = l;
mRecentsView = l.getOverviewPanel();
mMotionPauseDetector = new MotionPauseDetector(l);
mMotionPauseMinDisplacement = ViewConfiguration.get(l).getScaledTouchSlop();
@@ -104,7 +106,9 @@
@Override
protected boolean canInterceptTouch(MotionEvent ev) {
- if (!isTrackpadMotionEvent(ev) && DisplayController.getNavigationMode(mLauncher)
+ boolean isTrackpadEvent = isTrackpadMotionEvent(ev);
+ mLauncher.setCanShowAllAppsEducationView(!isTrackpadEvent);
+ if (!isTrackpadEvent && DisplayController.getNavigationMode(mLauncher)
== THREE_BUTTONS) {
return false;
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 20eaddc..5a03ae6 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -62,6 +62,7 @@
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET;
import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -148,10 +149,12 @@
import com.android.systemui.shared.system.SysUiStatsLog;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.window.flags.Flags;
import com.android.wm.shell.common.TransactionPool;
+import com.android.wm.shell.shared.desktopmode.DesktopModeFlags;
import com.android.wm.shell.startingsurface.SplashScreenExitAnimationUtils;
+import kotlin.Unit;
+
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
@@ -161,8 +164,6 @@
import java.util.OptionalInt;
import java.util.function.Consumer;
-import kotlin.Unit;
-
/**
* Handles the navigation gestures when Launcher is the default home activity.
*/
@@ -952,7 +953,7 @@
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
super.onRecentsAnimationStart(controller, targets);
- if (targets.hasDesktopTasks()) {
+ if (targets.hasDesktopTasks(mContext)) {
mRemoteTargetHandles = mTargetGluer.assignTargetsForDesktop(targets);
} else {
int untrimmedAppCount = mRemoteTargetHandles.length;
@@ -1272,9 +1273,9 @@
TaskView currentPageTaskView = mRecentsView != null
? mRecentsView.getCurrentPageTaskView() : null;
- if (Flags.enableDesktopWindowingMode()
- && !(Flags.enableDesktopWindowingWallpaperActivity()
- && Flags.enableDesktopWindowingQuickSwitch())) {
+ if (DESKTOP_WINDOWING_MODE.isEnabled(mContext)
+ && !(DesktopModeFlags.WALLPAPER_ACTIVITY.isEnabled(mContext)
+ && DesktopModeFlags.QUICK_SWITCH.isEnabled(mContext))) {
if ((nextPageTaskView instanceof DesktopTaskView
|| currentPageTaskView instanceof DesktopTaskView)
&& endTarget == NEW_TASK) {
@@ -1445,9 +1446,9 @@
setClampScrollOffset(false);
};
- if (Flags.enableDesktopWindowingMode()
- && !(Flags.enableDesktopWindowingWallpaperActivity()
- && Flags.enableDesktopWindowingQuickSwitch())) {
+ if (DESKTOP_WINDOWING_MODE.isEnabled(mContext)
+ && !(DesktopModeFlags.WALLPAPER_ACTIVITY.isEnabled(mContext)
+ && DesktopModeFlags.QUICK_SWITCH.isEnabled(mContext))) {
if (mRecentsView != null && (mRecentsView.getCurrentPageTaskView() != null
&& !(mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView))) {
ActiveGestureLog.INSTANCE.trackEvent(ActiveGestureErrorDetector.GestureEvent
@@ -2293,9 +2294,9 @@
mRecentsAnimationController, mRecentsAnimationTargets);
});
- if (Flags.enableDesktopWindowingMode()
- && !(Flags.enableDesktopWindowingWallpaperActivity()
- && Flags.enableDesktopWindowingQuickSwitch())) {
+ if (DESKTOP_WINDOWING_MODE.isEnabled(mContext)
+ && !(DesktopModeFlags.WALLPAPER_ACTIVITY.isEnabled(mContext)
+ && DesktopModeFlags.QUICK_SWITCH.isEnabled(mContext))) {
if (mRecentsView.getNextPageTaskView() instanceof DesktopTaskView
|| mRecentsView.getCurrentPageTaskView() instanceof DesktopTaskView) {
mRecentsViewScrollLinked = false;
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 4989831..95c86fa 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -20,13 +20,14 @@
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.util.SplitScreenUtils.convertShellSplitBoundsToLauncher;
-import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
import static com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM;
import android.app.ActivityManager;
import android.app.KeyguardManager;
import android.app.TaskInfo;
import android.content.ComponentName;
+import android.content.Context;
import android.os.Process;
import android.os.RemoteException;
import android.util.SparseBooleanArray;
@@ -58,6 +59,7 @@
private static final TaskLoadResult INVALID_RESULT = new TaskLoadResult(-1, false, 0);
+ private final Context mContext;
private final KeyguardManager mKeyguardManager;
private final LooperExecutor mMainThreadExecutor;
private final SystemUiProxy mSysUiProxy;
@@ -76,8 +78,10 @@
// Tasks are stored in order of least recently launched to most recently launched.
private ArrayList<ActivityManager.RunningTaskInfo> mRunningTasks;
- public RecentTasksList(LooperExecutor mainThreadExecutor, KeyguardManager keyguardManager,
- SystemUiProxy sysUiProxy, TopTaskTracker topTaskTracker) {
+ public RecentTasksList(Context context, LooperExecutor mainThreadExecutor,
+ KeyguardManager keyguardManager, SystemUiProxy sysUiProxy,
+ TopTaskTracker topTaskTracker) {
+ mContext = context;
mMainThreadExecutor = mainThreadExecutor;
mKeyguardManager = keyguardManager;
mChangeId = 1;
@@ -325,9 +329,9 @@
int numVisibleTasks = 0;
for (GroupedRecentTaskInfo rawTask : rawTasks) {
if (rawTask.getType() == TYPE_FREEFORM) {
- // TYPE_FREEFORM tasks is only created when enableDesktopWindowingMode() is true,
+ // TYPE_FREEFORM tasks is only created whenDESKTOP_WINDOWING_MODE.isEnabled is true,
// leftover TYPE_FREEFORM tasks created when flag was on should be ignored.
- if (enableDesktopWindowingMode()) {
+ if (DESKTOP_WINDOWING_MODE.isEnabled(mContext)) {
GroupTask desktopTask = createDesktopTask(rawTask);
if (desktopTask != null) {
allTasks.add(desktopTask);
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 18461a6..e84200d 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -27,7 +27,7 @@
import static com.android.quickstep.OverviewComponentObserver.startHomeIntentSafely;
import static com.android.quickstep.TaskUtils.taskIsATargetWithMode;
import static com.android.quickstep.TaskViewUtils.createRecentsWindowAnimator;
-import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -147,7 +147,7 @@
mActionsView = findViewById(R.id.overview_actions_view);
getRootView().getSysUiScrim().getSysUIProgress().updateValue(0);
mDragLayer.recreateControllers();
- if (enableDesktopWindowingMode()) {
+ if (DESKTOP_WINDOWING_MODE.isEnabled(this)) {
mDesktopRecentsTransitionController = new DesktopRecentsTransitionController(
getStateManager(), systemUiProxy, getIApplicationThread(),
null /* depthController */
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
index 82bb453..d104911 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationTargets.java
@@ -18,9 +18,10 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.view.RemoteAnimationTarget.MODE_CLOSING;
-import static com.android.window.flags.Flags.enableDesktopWindowingMode;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
import android.app.WindowConfiguration;
+import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.view.RemoteAnimationTarget;
@@ -54,8 +55,8 @@
*
* @return {@code true} if at least one target app is a desktop task
*/
- public boolean hasDesktopTasks() {
- if (!enableDesktopWindowingMode()) {
+ public boolean hasDesktopTasks(Context context) {
+ if (!DESKTOP_WINDOWING_MODE.isEnabled(context)) {
return false;
}
for (RemoteAnimationTarget target : apps) {
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index f2b6005..db03dac 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -90,7 +90,9 @@
private RecentsModel(Context context, IconProvider iconProvider) {
this(context,
- new RecentTasksList(MAIN_EXECUTOR,
+ new RecentTasksList(
+ context,
+ MAIN_EXECUTOR,
context.getSystemService(KeyguardManager.class),
SystemUiProxy.INSTANCE.get(context),
TopTaskTracker.INSTANCE.get(context)),
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 3f73959..f2db5af 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -23,8 +23,8 @@
import static com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENT_TASKS_MISSING;
import static com.android.quickstep.util.LogUtils.splitFailureMessage;
-import static com.android.window.flags.Flags.enableDesktopWindowingMode;
import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.DESKTOP_WINDOWING_MODE;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -1444,7 +1444,8 @@
private boolean shouldEnableRunningTasksForDesktopMode() {
// TODO(b/335401172): unify DesktopMode checks in Launcher
- return enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps();
+ return DESKTOP_WINDOWING_MODE.isEnabled(mContext)
+ && enableDesktopWindowingTaskbarRunningApps();
}
private boolean handleMessageAsync(Message msg) {
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index 186c453..f4d3695 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -27,6 +27,8 @@
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import androidx.annotation.VisibleForTesting;
+
import com.android.launcher3.Utilities;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.util.DisplayController;
@@ -48,7 +50,7 @@
private static final boolean DEBUG_NAV_HANDLE = Utilities.isPropertyEnabled(
NAV_HANDLE_LONG_PRESS);
- private final NavHandleLongPressHandler mNavHandleLongPressHandler;
+ private NavHandleLongPressHandler mNavHandleLongPressHandler;
private final float mNavHandleWidth;
private final float mScreenWidth;
@@ -265,4 +267,9 @@
protected String getDelegatorName() {
return "NavHandleLongPressInputConsumer";
}
+
+ @VisibleForTesting
+ void setNavHandleLongPressHandler(NavHandleLongPressHandler navHandleLongPressHandler) {
+ mNavHandleLongPressHandler = navHandleLongPressHandler;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/AnimUtils.java b/quickstep/src/com/android/quickstep/util/AnimUtils.java
index 8e3d44f..31aca03 100644
--- a/quickstep/src/com/android/quickstep/util/AnimUtils.java
+++ b/quickstep/src/com/android/quickstep/util/AnimUtils.java
@@ -17,18 +17,28 @@
package com.android.quickstep.util;
import static com.android.app.animation.Interpolators.clampToProgress;
+import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import android.animation.AnimatorSet;
+import android.annotation.NonNull;
import android.os.Bundle;
import android.os.IRemoteCallback;
import android.view.animation.Interpolator;
+import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.statemanager.BaseState;
+import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.util.RunnableList;
+import com.android.quickstep.views.RecentsViewContainer;
/**
* Utility class containing methods to help manage animations, interpolators, and timings.
*/
public class AnimUtils {
+ private static final int DURATION_DEFAULT_SPLIT_DISMISS = 350;
+
/**
* Fetches device-specific timings for the Overview > Split animation
* (splitscreen initiated from Overview).
@@ -59,6 +69,33 @@
}
/**
+ * Synchronizes the timing for the split dismiss animation to the current transition to
+ * NORMAL (launcher home/workspace)
+ */
+ public static void goToNormalStateWithSplitDismissal(@NonNull StateManager stateManager,
+ @NonNull RecentsViewContainer container,
+ @NonNull StatsLogManager.LauncherEvent exitReason,
+ @NonNull SplitAnimationController animationController) {
+ StateAnimationConfig config = new StateAnimationConfig();
+ BaseState startState = stateManager.getState();
+ long duration = startState.getTransitionDuration(container.asContext(),
+ false /*isToState*/);
+ if (duration == 0) {
+ // Case where we're in contextual on workspace (NORMAL), which by default has 0
+ // transition duration
+ duration = DURATION_DEFAULT_SPLIT_DISMISS;
+ }
+ config.duration = duration;
+ AnimatorSet stateAnim = stateManager.createAtomicAnimation(
+ startState, NORMAL, config);
+ AnimatorSet dismissAnim = animationController
+ .createPlaceholderDismissAnim(container, exitReason, duration);
+ stateAnim.play(dismissAnim);
+ stateManager.setCurrentAnimation(stateAnim, NORMAL);
+ stateAnim.start();
+ }
+
+ /**
* Returns a IRemoteCallback which completes the provided list as a result
*/
public static IRemoteCallback completeRunnableListCallback(RunnableList list) {
diff --git a/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt b/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
index d36dc7e..2dd727e 100644
--- a/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
+++ b/quickstep/src/com/android/quickstep/util/DeviceConfigHelper.kt
@@ -26,19 +26,21 @@
import androidx.annotation.WorkerThread
import com.android.launcher3.BuildConfig
import com.android.launcher3.util.Executors
+import java.util.concurrent.CopyOnWriteArrayList
/** Utility class to manage a set of device configurations */
class DeviceConfigHelper<ConfigType>(private val factory: (PropReader) -> ConfigType) {
var config: ConfigType
private set
+
private val allKeys: Set<String>
private val propertiesListener = OnPropertiesChangedListener { onDevicePropsChanges(it) }
private val sharedPrefChangeListener = OnSharedPreferenceChangeListener { _, _ ->
recreateConfig()
}
- private val changeListeners = mutableListOf<Runnable>()
+ private val changeListeners = CopyOnWriteArrayList<Runnable>()
init {
// Initialize the default config once.
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index cfe5b2c..70ef47c 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -106,7 +106,8 @@
return;
}
mShouldIncreaseCount = toState == HINT_STATE
- && launcher.getWorkspace().getNextPage() == Workspace.DEFAULT_PAGE;
+ && launcher.getWorkspace().getNextPage() == Workspace.DEFAULT_PAGE
+ && launcher.isCanShowAllAppsEducationView();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index e48a7c6..d20d0a5 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -26,7 +26,7 @@
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.LauncherState.SPRING_LOADED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
-import static com.android.window.flags.Flags.enableDesktopWindowingWallpaperActivity;
+import static com.android.wm.shell.shared.desktopmode.DesktopModeFlags.WALLPAPER_ACTIVITY;
import android.annotation.TargetApi;
import android.content.Context;
@@ -54,6 +54,7 @@
import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.RotationTouchHelper;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.util.AnimUtils;
import com.android.quickstep.util.SplitSelectStateController;
import com.android.systemui.shared.recents.model.Task;
@@ -91,10 +92,12 @@
protected void handleStartHome(boolean animated) {
StateManager stateManager = getStateManager();
animated &= stateManager.shouldAnimateStateChange();
- stateManager.goToState(NORMAL, animated);
- if (FeatureFlags.enableSplitContextually()) {
- mSplitSelectStateController.getSplitAnimationController()
- .playPlaceholderDismissAnim(mContainer, LAUNCHER_SPLIT_SELECTION_EXIT_HOME);
+ if (mSplitSelectStateController.isSplitSelectActive()) {
+ AnimUtils.goToNormalStateWithSplitDismissal(stateManager, mContainer,
+ LAUNCHER_SPLIT_SELECTION_EXIT_HOME,
+ mSplitSelectStateController.getSplitAnimationController());
+ } else {
+ stateManager.goToState(NORMAL, animated);
}
AbstractFloatingView.closeAllOpenViews(mContainer, animated);
}
@@ -265,7 +268,7 @@
super.onGestureAnimationStart(runningTasks, rotationTouchHelper);
DesktopVisibilityController desktopVisibilityController =
mContainer.getDesktopVisibilityController();
- if (!enableDesktopWindowingWallpaperActivity() && desktopVisibilityController != null) {
+ if (!WALLPAPER_ACTIVITY.isEnabled(mContext) && desktopVisibilityController != null) {
// TODO: b/333533253 - Remove after flag rollout
desktopVisibilityController.setRecentsGestureStart();
}
@@ -288,7 +291,7 @@
}
}
super.onGestureAnimationEnd();
- if (!enableDesktopWindowingWallpaperActivity() && desktopVisibilityController != null) {
+ if (!WALLPAPER_ACTIVITY.isEnabled(mContext) && desktopVisibilityController != null) {
// TODO: b/333533253 - Remove after flag rollout
desktopVisibilityController.setRecentsGestureEnd(endTarget);
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index a3d6359..d63ac56 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -5498,7 +5498,7 @@
}
RemoteTargetGluer gluer;
- if (recentsAnimationTargets.hasDesktopTasks()) {
+ if (recentsAnimationTargets.hasDesktopTasks(mContext)) {
gluer = new RemoteTargetGluer(getContext(), getSizeStrategy(), recentsAnimationTargets,
true /* forDesktop */);
mRemoteTargetHandles = gluer.assignTargetsForDesktop(recentsAnimationTargets);
diff --git a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
index 3d994e8..f6393e4 100644
--- a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
@@ -16,13 +16,11 @@
package com.android.quickstep.views;
-import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON;
import static com.android.settingslib.widget.theme.R.dimen.settingslib_preferred_minimum_touch_target;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
@@ -42,9 +40,8 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StateManager;
-import com.android.launcher3.states.StateAnimationConfig;
+import com.android.quickstep.util.AnimUtils;
import com.android.quickstep.util.SplitSelectStateController;
/**
@@ -57,7 +54,6 @@
public class SplitInstructionsView extends LinearLayout {
private static final int BOUNCE_DURATION = 250;
private static final float BOUNCE_HEIGHT = 20;
- private static final int DURATION_DEFAULT_SPLIT_DISMISS = 350;
private final RecentsViewContainer mContainer;
public boolean mIsCurrentlyAnimating = false;
@@ -165,25 +161,11 @@
private void exitSplitSelection() {
RecentsView recentsView = mContainer.getOverviewPanel();
SplitSelectStateController splitSelectController = recentsView.getSplitSelectController();
-
StateManager stateManager = recentsView.getStateManager();
- BaseState startState = stateManager.getState();
- long duration = startState.getTransitionDuration(mContainer.asContext(), false);
- if (duration == 0) {
- // Case where we're in contextual on workspace (NORMAL), which by default has 0
- // transition duration
- duration = DURATION_DEFAULT_SPLIT_DISMISS;
- }
- StateAnimationConfig config = new StateAnimationConfig();
- config.duration = duration;
- AnimatorSet stateAnim = stateManager.createAtomicAnimation(
- startState, NORMAL, config);
- AnimatorSet dismissAnim = splitSelectController.getSplitAnimationController()
- .createPlaceholderDismissAnim(mContainer,
- LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON, duration);
- stateAnim.play(dismissAnim);
- stateManager.setCurrentAnimation(stateAnim, NORMAL);
- stateAnim.start();
+
+ AnimUtils.goToNormalStateWithSplitDismissal(stateManager, mContainer,
+ LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON,
+ splitSelectController.getSplitAnimationController());
}
void ensureProperRotation() {
diff --git a/quickstep/tests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt
similarity index 79%
rename from quickstep/tests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt
rename to quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt
index a532762..0005df6 100644
--- a/quickstep/tests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/QuickstepModelDelegateTest.kt
@@ -1,3 +1,18 @@
+/*
+ * 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.model
import android.app.prediction.AppPredictor
@@ -19,7 +34,7 @@
import org.mockito.Mock
import org.mockito.Mockito.never
import org.mockito.Mockito.verify
-import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.MockitoAnnotations
/** Unit tests for [QuickstepModelDelegate]. */
@@ -57,25 +72,25 @@
underTest.onAppTargetEvent(mockedAppTargetEvent, CONTAINER_PREDICTION)
verify(allAppsPredictor).notifyAppTargetEvent(mockedAppTargetEvent)
- verifyZeroInteractions(hotseatPredictor)
- verifyZeroInteractions(widgetRecommendationPredictor)
+ verifyNoMoreInteractions(hotseatPredictor)
+ verifyNoMoreInteractions(widgetRecommendationPredictor)
}
@Test
fun onWidgetPrediction_notifyWidgetRecommendationPredictor() {
underTest.onAppTargetEvent(mockedAppTargetEvent, CONTAINER_WIDGETS_PREDICTION)
- verifyZeroInteractions(allAppsPredictor)
+ verifyNoMoreInteractions(allAppsPredictor)
verify(widgetRecommendationPredictor).notifyAppTargetEvent(mockedAppTargetEvent)
- verifyZeroInteractions(hotseatPredictor)
+ verifyNoMoreInteractions(hotseatPredictor)
}
@Test
fun onHotseatPrediction_notifyHotseatPredictor() {
underTest.onAppTargetEvent(mockedAppTargetEvent, CONTAINER_HOTSEAT_PREDICTION)
- verifyZeroInteractions(allAppsPredictor)
- verifyZeroInteractions(widgetRecommendationPredictor)
+ verifyNoMoreInteractions(allAppsPredictor)
+ verifyNoMoreInteractions(widgetRecommendationPredictor)
verify(hotseatPredictor).notifyAppTargetEvent(mockedAppTargetEvent)
}
@@ -83,8 +98,8 @@
fun onOtherClient_notifyHotseatPredictor() {
underTest.onAppTargetEvent(mockedAppTargetEvent, CONTAINER_WALLPAPERS)
- verifyZeroInteractions(allAppsPredictor)
- verifyZeroInteractions(widgetRecommendationPredictor)
+ verifyNoMoreInteractions(allAppsPredictor)
+ verifyNoMoreInteractions(widgetRecommendationPredictor)
verify(hotseatPredictor).notifyAppTargetEvent(mockedAppTargetEvent)
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentTaskbarStashControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentTaskbarStashControllerTest.kt
new file mode 100644
index 0000000..c46c08d
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/PersistentTaskbarStashControllerTest.kt
@@ -0,0 +1,256 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.bubbles.stashing
+
+import android.animation.AnimatorTestRule
+import android.content.Context
+import android.widget.FrameLayout
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.anim.AnimatedFloat
+import com.android.launcher3.taskbar.TaskbarInsetsController
+import com.android.launcher3.taskbar.bubbles.BubbleBarView
+import com.android.launcher3.taskbar.bubbles.BubbleBarViewController
+import com.android.launcher3.util.MultiValueAlpha
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.clearInvocations
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+/** Unit tests for [PersistentTaskbarStashController]. */
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class PersistentTaskbarStashControllerTest {
+
+ companion object {
+ const val BUBBLE_BAR_HEIGHT = 100f
+ const val HOTSEAT_TRANSLATION_Y = -45f
+ const val TASK_BAR_TRANSLATION_Y = -5f
+ }
+
+ @get:Rule val animatorTestRule: AnimatorTestRule = AnimatorTestRule(this)
+ @get:Rule val rule: MockitoRule = MockitoJUnit.rule()
+
+ private val context = ApplicationProvider.getApplicationContext<Context>()
+ private lateinit var bubbleBarView: BubbleBarView
+
+ @Mock lateinit var bubbleBarViewController: BubbleBarViewController
+ @Mock lateinit var taskbarInsetsController: TaskbarInsetsController
+
+ private lateinit var persistentTaskBarStashController: PersistentTaskbarStashController
+ private lateinit var translationY: AnimatedFloat
+ private lateinit var scale: AnimatedFloat
+ private lateinit var alpha: MultiValueAlpha
+
+ @Before
+ fun setUp() {
+ persistentTaskBarStashController =
+ PersistentTaskbarStashController(DefaultDimensionsProvider())
+ setUpBubbleBarView()
+ setUpBubbleBarController()
+ persistentTaskBarStashController.init(
+ taskbarInsetsController,
+ bubbleBarViewController,
+ null,
+ ImmediateAction()
+ )
+ }
+
+ @Test
+ fun setBubblesShowingOnHomeUpdatedToFalse_barPositionYUpdated_controllersNotified() {
+ // Given bubble bar is on home and has bubbles
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
+ persistentTaskBarStashController.isBubblesShowingOnHome = true
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+
+ // When switch out of the home screen
+ getInstrumentation().runOnMainSync {
+ persistentTaskBarStashController.isBubblesShowingOnHome = false
+ }
+
+ // Then translation Y is animating and the bubble bar controller is notified
+ assertThat(translationY.isAnimating).isTrue()
+ verify(bubbleBarViewController).onBubbleBarConfigurationChanged(/* animate= */ true)
+ // Wait until animation ends
+ advanceTimeBy(BubbleStashController.BAR_TRANSLATION_DURATION)
+ // Check translation Y is correct and the insets controller is notified
+ assertThat(bubbleBarView.translationY).isEqualTo(TASK_BAR_TRANSLATION_Y)
+ verify(taskbarInsetsController).onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+ }
+
+ @Test
+ fun setBubblesShowingOnHomeUpdatedToTrue_barPositionYUpdated_controllersNotified() {
+ // Given bubble bar has bubbles
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+
+ // When switch to home screen
+ getInstrumentation().runOnMainSync {
+ persistentTaskBarStashController.isBubblesShowingOnHome = true
+ }
+
+ // Then translation Y is animating and the bubble bar controller is notified
+ assertThat(translationY.isAnimating).isTrue()
+ verify(bubbleBarViewController).onBubbleBarConfigurationChanged(/* animate= */ true)
+ // Wait until animation ends
+ advanceTimeBy(BubbleStashController.BAR_TRANSLATION_DURATION)
+
+ // Check translation Y is correct and the insets controller is notified
+ assertThat(bubbleBarView.translationY).isEqualTo(HOTSEAT_TRANSLATION_Y)
+ verify(taskbarInsetsController).onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+ }
+
+ @Test
+ fun setBubblesShowingOnOverviewUpdatedToFalse_controllersNotified() {
+ // Given bubble bar is on overview
+ persistentTaskBarStashController.isBubblesShowingOnOverview = true
+ clearInvocations(bubbleBarViewController)
+
+ // When switch out of the overview screen
+ persistentTaskBarStashController.isBubblesShowingOnOverview = false
+
+ // Then bubble bar controller is notified
+ verify(bubbleBarViewController).onBubbleBarConfigurationChanged(/* animate= */ true)
+ }
+
+ @Test
+ fun setBubblesShowingOnOverviewUpdatedToTrue_controllersNotified() {
+ // When switch to the overview screen
+ persistentTaskBarStashController.isBubblesShowingOnOverview = true
+
+ // Then bubble bar controller is notified
+ verify(bubbleBarViewController).onBubbleBarConfigurationChanged(/* animate= */ true)
+ }
+
+ @Test
+ fun isSysuiLockedSwitchedToFalseForOverview_unlockAnimationIsShown() {
+ // Given screen is locked and bubble bar has bubbles
+ persistentTaskBarStashController.isSysuiLocked = true
+ persistentTaskBarStashController.isBubblesShowingOnOverview = true
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+
+ // When switch to the overview screen
+ getInstrumentation().runOnMainSync {
+ persistentTaskBarStashController.isSysuiLocked = false
+ }
+
+ // Then
+ assertThat(translationY.isAnimating).isTrue()
+ assertThat(scale.isAnimating).isTrue()
+ // Wait until animation ends
+ advanceTimeBy(BubbleStashController.BAR_STASH_DURATION)
+
+ // Then bubble bar is fully visible at the correct location
+ assertThat(bubbleBarView.scaleX).isEqualTo(1f)
+ assertThat(bubbleBarView.scaleY).isEqualTo(1f)
+ assertThat(bubbleBarView.translationY).isEqualTo(TASK_BAR_TRANSLATION_Y)
+ assertThat(bubbleBarView.alpha).isEqualTo(1f)
+ // Insets controller is notified
+ verify(taskbarInsetsController).onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
+ }
+
+ @Test
+ fun showBubbleBarImmediateToY() {
+ // Given bubble bar is fully transparent and scaled to 0 at 0 y position
+ val targetY = 341f
+ bubbleBarView.alpha = 0f
+ bubbleBarView.scaleX = 0f
+ bubbleBarView.scaleY = 0f
+ bubbleBarView.translationY = 0f
+
+ // When
+ persistentTaskBarStashController.showBubbleBarImmediate(targetY)
+
+ // Then all property values are updated
+ assertThat(bubbleBarView.translationY).isEqualTo(targetY)
+ assertThat(bubbleBarView.alpha).isEqualTo(1f)
+ assertThat(bubbleBarView.scaleX).isEqualTo(1f)
+ assertThat(bubbleBarView.scaleY).isEqualTo(1f)
+ }
+
+ @Test
+ fun isTransientTaskbar_false() {
+ assertThat(persistentTaskBarStashController.isTransientTaskBar).isFalse()
+ }
+
+ @Test
+ fun hasHandleView_false() {
+ assertThat(persistentTaskBarStashController.hasHandleView).isFalse()
+ }
+
+ @Test
+ fun isStashed_false() {
+ assertThat(persistentTaskBarStashController.isStashed).isFalse()
+ }
+
+ @Test
+ fun bubbleBarTranslationYForTaskbar() {
+ // Give bubble bar is on home
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(false)
+ persistentTaskBarStashController.isBubblesShowingOnHome = true
+
+ // Then bubbleBarTranslationY would be HOTSEAT_TRANSLATION_Y
+ assertThat(persistentTaskBarStashController.bubbleBarTranslationY)
+ .isEqualTo(HOTSEAT_TRANSLATION_Y)
+
+ // Give bubble bar is not on home
+ persistentTaskBarStashController.isBubblesShowingOnHome = false
+
+ // Then bubbleBarTranslationY would be TASK_BAR_TRANSLATION_Y
+ assertThat(persistentTaskBarStashController.bubbleBarTranslationY)
+ .isEqualTo(TASK_BAR_TRANSLATION_Y)
+ }
+
+ private fun advanceTimeBy(advanceMs: Long) {
+ // Advance animator for on-device tests
+ getInstrumentation().runOnMainSync { animatorTestRule.advanceTimeBy(advanceMs) }
+ }
+
+ private fun setUpBubbleBarView() {
+ getInstrumentation().runOnMainSync {
+ bubbleBarView = BubbleBarView(context)
+ bubbleBarView.layoutParams = FrameLayout.LayoutParams(0, 0)
+ }
+ }
+
+ private fun setUpBubbleBarController() {
+ translationY = AnimatedFloat(Runnable { bubbleBarView.translationY = translationY.value })
+ scale =
+ AnimatedFloat(
+ Runnable {
+ val scale: Float = scale.value
+ bubbleBarView.scaleX = scale
+ bubbleBarView.scaleY = scale
+ }
+ )
+ alpha = MultiValueAlpha(bubbleBarView, 1 /* num alpha channels */)
+
+ whenever(bubbleBarViewController.hasBubbles()).thenReturn(true)
+ whenever(bubbleBarViewController.bubbleBarTranslationY).thenReturn(translationY)
+ whenever(bubbleBarViewController.bubbleBarScale).thenReturn(scale)
+ whenever(bubbleBarViewController.bubbleBarAlpha).thenReturn(alpha)
+ whenever(bubbleBarViewController.bubbleBarCollapsedHeight).thenReturn(BUBBLE_BAR_HEIGHT)
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt
new file mode 100644
index 0000000..5dc9440
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/stashing/StashingTestUtils.kt
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.bubbles.stashing
+
+class ImmediateAction : BubbleStashController.ControllersAfterInitAction {
+ override fun runAfterInit(action: () -> Unit) = action.invoke()
+}
+
+class DefaultDimensionsProvider : BubbleStashController.TaskbarHotseatDimensionsProvider {
+ override fun getTaskbarBottomSpace(): Int = TASKBAR_BOTTOM_SPACE
+
+ override fun getTaskbarHeight(): Int = TASKBAR_HEIGHT
+
+ override fun getHotseatBottomSpace(): Int = HOTSEAT_BOTTOM_SPACE
+
+ override fun getHotseatHeight(): Int = HOTSEAT_HEIGHT
+
+ companion object {
+ const val TASKBAR_BOTTOM_SPACE = 0
+ const val TASKBAR_HEIGHT = 110
+ const val HOTSEAT_BOTTOM_SPACE = 20
+ const val HOTSEAT_HEIGHT = 150
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java
new file mode 100644
index 0000000..679a208
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumerTest.java
@@ -0,0 +1,298 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.inputconsumers;
+
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_HOVER_ENTER;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_UP;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.os.SystemClock;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import androidx.test.ext.junit.runners.AndroidJUnit4;
+import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
+
+import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
+import com.android.quickstep.GestureState;
+import com.android.quickstep.InputConsumer;
+import com.android.quickstep.NavHandle;
+import com.android.quickstep.RecentsAnimationDeviceState;
+import com.android.quickstep.TopTaskTracker;
+import com.android.systemui.shared.system.InputMonitorCompat;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class NavHandleLongPressInputConsumerTest {
+
+ private static final float TOUCH_SLOP = 10;
+ private static final float SQUARED_TOUCH_SLOP = 100;
+
+ private final AtomicBoolean mLongPressTriggered = new AtomicBoolean();
+ private NavHandleLongPressInputConsumer mUnderTest;
+ private float mScreenWidth;
+ @Mock InputConsumer mDelegate;
+ @Mock InputMonitorCompat mInputMonitor;
+ @Mock RecentsAnimationDeviceState mDeviceState;
+ @Mock NavHandle mNavHandle;
+ @Mock GestureState mGestureState;
+ @Mock NavHandleLongPressHandler mNavHandleLongPressHandler;
+ @Mock TopTaskTracker mTopTaskTracker;
+ @Mock TopTaskTracker.CachedTaskInfo mTaskInfo;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+ when(mTopTaskTracker.getCachedTopTask(anyBoolean())).thenReturn(mTaskInfo);
+ when(mDeviceState.getSquaredTouchSlop()).thenReturn(SQUARED_TOUCH_SLOP);
+ when(mDelegate.allowInterceptByParent()).thenReturn(true);
+ mLongPressTriggered.set(false);
+ when(mNavHandleLongPressHandler.getLongPressRunnable(any())).thenReturn(
+ () -> mLongPressTriggered.set(true));
+ SandboxContext context = new SandboxContext(getApplicationContext());
+ context.putObject(TopTaskTracker.INSTANCE, mTopTaskTracker);
+ mScreenWidth = DisplayController.INSTANCE.get(context).getInfo().currentSize.x;
+ mUnderTest = new NavHandleLongPressInputConsumer(context, mDelegate, mInputMonitor,
+ mDeviceState, mNavHandle, mGestureState);
+ mUnderTest.setNavHandleLongPressHandler(mNavHandleLongPressHandler);
+ }
+
+ @Test
+ public void testGetType() {
+ assertThat(mUnderTest.getType() & InputConsumer.TYPE_NAV_HANDLE_LONG_PRESS).isNotEqualTo(0);
+ }
+
+ @Test
+ public void testDelegateDisallowsTouchIntercept() {
+ when(mDelegate.allowInterceptByParent()).thenReturn(false);
+ mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
+
+ verify(mDelegate).onMotionEvent(any());
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
+ verify(mNavHandleLongPressHandler, never()).onTouchStarted(any());
+ verify(mNavHandleLongPressHandler, never()).onTouchFinished(any(), any());
+ }
+
+ @Test
+ public void testDelegateDisallowsTouchInterceptAfterTouchDown() {
+ mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
+
+ // Delegate should still get touches unless long press is triggered.
+ verify(mDelegate).onMotionEvent(any());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchStarted(any());
+ verify(mNavHandleLongPressHandler, never()).onTouchFinished(any(), any());
+
+ when(mDelegate.allowInterceptByParent()).thenReturn(false);
+ mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_MOVE));
+
+ // Delegate should still get motion events unless long press is triggered.
+ verify(mDelegate, times(2)).onMotionEvent(any());
+ // But our handler should be cancelled.
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
+ verify(mNavHandleLongPressHandler, times(1)).onTouchStarted(any());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchFinished(any(), any());
+ }
+
+ @Test
+ public void testLongPressTriggered() {
+ mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
+ SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE);
+ assertTrue(mLongPressTriggered.get());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchStarted(any());
+ verify(mNavHandleLongPressHandler, never()).onTouchFinished(any(), any());
+ }
+
+ @Test
+ public void testLongPressTriggeredWithSlightVerticalMovement() {
+ mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
+ mUnderTest.onMotionEvent(generateCenteredMotionEventWithYOffset(ACTION_MOVE,
+ -(TOUCH_SLOP - 1)));
+ SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE);
+ assertTrue(mLongPressTriggered.get());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchStarted(any());
+ verify(mNavHandleLongPressHandler, never()).onTouchFinished(any(), any());
+ }
+
+ @Test
+ public void testLongPressTriggeredWithSlightHorizontalMovement() {
+ mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
+ mUnderTest.onMotionEvent(generateMotionEvent(ACTION_MOVE,
+ mScreenWidth / 2f - (TOUCH_SLOP - 1), 0));
+ SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_ACTIVE);
+ assertTrue(mLongPressTriggered.get());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchStarted(any());
+ verify(mNavHandleLongPressHandler, never()).onTouchFinished(any(), any());
+ }
+
+ @Test
+ public void testLongPressAbortedByTouchUp() {
+ mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
+ SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
+ assertFalse(mLongPressTriggered.get());
+
+ mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_UP));
+ // Wait past the long press timeout, to be extra sure it wouldn't have triggered.
+ SystemClock.sleep(20);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
+ assertFalse(mLongPressTriggered.get());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchStarted(any());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchFinished(any(), any());
+ }
+
+ @Test
+ public void testLongPressAbortedByTouchCancel() {
+ mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
+ SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
+ assertFalse(mLongPressTriggered.get());
+
+ mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_CANCEL));
+ // Wait past the long press timeout, to be extra sure it wouldn't have triggered.
+ SystemClock.sleep(20);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
+ assertFalse(mLongPressTriggered.get());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchStarted(any());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchFinished(any(), any());
+ }
+
+ @Test
+ public void testLongPressAbortedByTouchSlopPassedVertically() {
+ mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
+ SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
+ assertFalse(mLongPressTriggered.get());
+
+ mUnderTest.onMotionEvent(generateCenteredMotionEventWithYOffset(ACTION_MOVE,
+ -(TOUCH_SLOP + 1)));
+ // Wait past the long press timeout, to be extra sure it wouldn't have triggered.
+ SystemClock.sleep(20);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
+ assertFalse(mLongPressTriggered.get());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchStarted(any());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchFinished(any(), any());
+ }
+
+ @Test
+ public void testLongPressAbortedByTouchSlopPassedHorizontally() {
+ mUnderTest.onMotionEvent(generateCenteredMotionEvent(ACTION_DOWN));
+ SystemClock.sleep(ViewConfiguration.getLongPressTimeout() - 10);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
+ assertFalse(mLongPressTriggered.get());
+
+ mUnderTest.onMotionEvent(generateMotionEvent(ACTION_MOVE,
+ mScreenWidth / 2f - (TOUCH_SLOP + 1), 0));
+ // Wait past the long press timeout, to be extra sure it wouldn't have triggered.
+ SystemClock.sleep(20);
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
+ assertFalse(mLongPressTriggered.get());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchStarted(any());
+ verify(mNavHandleLongPressHandler, times(1)).onTouchFinished(any(), any());
+ }
+
+ @Test
+ public void testTouchOutsideNavHandleIgnored() {
+ // Touch the far left side of the screen. (y=0 is top of navbar region, picked arbitrarily)
+ mUnderTest.onMotionEvent(generateMotionEvent(ACTION_DOWN, 0, 0));
+ SystemClock.sleep(ViewConfiguration.getLongPressTimeout());
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+
+ // Should be ignored because the x position was not centered in the navbar region.
+ assertThat(mUnderTest.mState).isEqualTo(DelegateInputConsumer.STATE_INACTIVE);
+ assertFalse(mLongPressTriggered.get());
+ verify(mNavHandleLongPressHandler, never()).onTouchStarted(any());
+ verify(mNavHandleLongPressHandler, never()).onTouchFinished(any(), any());
+ }
+
+ @Test
+ public void testHoverPassedToDelegate() {
+ // Regardless of whether the delegate wants us to intercept, we tell it about hover events.
+ when(mDelegate.allowInterceptByParent()).thenReturn(false);
+ mUnderTest.onHoverEvent(generateCenteredMotionEvent(ACTION_HOVER_ENTER));
+
+ verify(mDelegate).onHoverEvent(any());
+
+ when(mDelegate.allowInterceptByParent()).thenReturn(true);
+ mUnderTest.onHoverEvent(generateCenteredMotionEvent(ACTION_HOVER_ENTER));
+
+ verify(mDelegate, times(2)).onHoverEvent(any());
+ }
+
+ /** Generate a motion event centered horizontally in the screen. */
+ private MotionEvent generateCenteredMotionEvent(int motionAction) {
+ return generateCenteredMotionEventWithYOffset(motionAction, 0);
+ }
+
+ /** Generate a motion event centered horizontally in the screen, with y offset. */
+ private MotionEvent generateCenteredMotionEventWithYOffset(int motionAction, float y) {
+ return generateMotionEvent(motionAction, mScreenWidth / 2f, y);
+ }
+
+ private static MotionEvent generateMotionEvent(int motionAction, float x, float y) {
+ return MotionEvent.obtain(0, 0, motionAction, x, y, 0);
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
index 070eeaf..ea2e484 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/logging/SettingsChangeLoggerTest.kt
@@ -20,9 +20,18 @@
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.THEMED_ICONS
import com.android.launcher3.LauncherPrefs.Companion.backedUpItem
import com.android.launcher3.logging.InstanceId
import com.android.launcher3.logging.StatsLogManager
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ADD_NEW_APPS_TO_HOME_SCREEN_ENABLED
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALL_APPS_SUGGESTIONS_ENABLED
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_ROTATION_DISABLED
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_ROTATION_ENABLED
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NOTIFICATION_DOT_ENABLED
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_THEMED_ICON_DISABLED
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Before
@@ -52,18 +61,24 @@
@Captor private lateinit var mEventCaptor: ArgumentCaptor<StatsLogManager.EventEnum>
+ private var mDefaultThemedIcons = false
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
whenever(mStatsLogManager.logger()).doReturn(mMockLogger)
whenever(mStatsLogManager.logger().withInstanceId(any())).doReturn(mMockLogger)
+ mDefaultThemedIcons = LauncherPrefs.get(mContext).get(THEMED_ICONS)
+ // To match the default value of THEMED_ICONS
+ LauncherPrefs.get(mContext).put(THEMED_ICONS, false)
mSystemUnderTest = SettingsChangeLogger(mContext, mStatsLogManager)
}
@After
fun tearDown() {
+ LauncherPrefs.get(mContext).put(THEMED_ICONS, mDefaultThemedIcons)
mSystemUnderTest.close()
}
@@ -87,7 +102,8 @@
assertThat(capturedEvents.isNotEmpty()).isTrue()
verifyDefaultEvent(capturedEvents)
// pref_allowRotation false
- assertThat(capturedEvents.any { it.id == 616 }).isTrue()
+ assertThat(capturedEvents.any { it.id == LAUNCHER_HOME_SCREEN_ROTATION_DISABLED.id })
+ .isTrue()
}
@Test
@@ -108,24 +124,22 @@
val capturedEvents = mEventCaptor.allValues
assertThat(capturedEvents.isNotEmpty()).isTrue()
verifyDefaultEvent(capturedEvents)
- // pref_allowRotation true
- assertThat(capturedEvents.any { it.id == 615 }).isTrue()
+ assertThat(capturedEvents.any { it.id == LAUNCHER_HOME_SCREEN_ROTATION_ENABLED.id })
+ .isTrue()
}
private fun verifyDefaultEvent(capturedEvents: MutableList<StatsLogManager.EventEnum>) {
- // LAUNCHER_NOTIFICATION_DOT_ENABLED
- assertThat(capturedEvents.any { it.id == 611 }).isTrue()
- // LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON
- assertThat(capturedEvents.any { it.id == 625 }).isTrue()
- // LAUNCHER_THEMED_ICON_DISABLED
- assertThat(capturedEvents.any { it.id == 837 }).isTrue()
- // pref_add_icon_to_home true
- assertThat(capturedEvents.any { it.id == 613 }).isTrue()
- // pref_overview_action_suggestions true
- assertThat(capturedEvents.any { it.id == 619 }).isTrue()
- // pref_smartspace_home_screen true
- assertThat(capturedEvents.any { it.id == 621 }).isTrue()
- // pref_enable_minus_one true
+ assertThat(capturedEvents.any { it.id == LAUNCHER_NOTIFICATION_DOT_ENABLED.id }).isTrue()
+ assertThat(capturedEvents.any { it.id == LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON.id })
+ .isTrue()
+ assertThat(capturedEvents.any { it.id == LAUNCHER_THEMED_ICON_DISABLED.id }).isTrue()
+ assertThat(capturedEvents.any { it.id == LAUNCHER_ADD_NEW_APPS_TO_HOME_SCREEN_ENABLED.id })
+ .isTrue()
+ assertThat(capturedEvents.any { it.id == LAUNCHER_ALL_APPS_SUGGESTIONS_ENABLED.id })
+ .isTrue()
+ assertThat(capturedEvents.any { it.id == LAUNCHER_HOME_SCREEN_SUGGESTIONS_ENABLED.id })
+ .isTrue()
+ // LAUNCHER_GOOGLE_APP_SWIPE_LEFT_ENABLED
assertThat(capturedEvents.any { it.id == 617 }).isTrue()
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TestExtensions.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TestExtensions.kt
new file mode 100644
index 0000000..6c526a4
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TestExtensions.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import com.android.launcher3.BuildConfig
+import com.android.launcher3.util.SafeCloseable
+import com.android.quickstep.DeviceConfigWrapper.Companion.configHelper
+import com.android.quickstep.util.DeviceConfigHelper.Companion.prefs
+import java.util.concurrent.CountDownLatch
+import java.util.function.BooleanSupplier
+import org.junit.Assert
+import org.junit.Assume
+
+/** Helper methods for testing */
+object TestExtensions {
+
+ @JvmStatic
+ fun overrideNavConfigFlag(
+ key: String,
+ value: Boolean,
+ targetValue: BooleanSupplier
+ ): AutoCloseable {
+ Assume.assumeTrue(BuildConfig.IS_DEBUG_DEVICE)
+ if (targetValue.asBoolean == value) {
+ return AutoCloseable {}
+ }
+
+ navConfigEditWatcher().let {
+ prefs.edit().putBoolean(key, value).commit()
+ it.close()
+ }
+ Assert.assertEquals(value, targetValue.asBoolean)
+
+ val watcher = navConfigEditWatcher()
+ return AutoCloseable {
+ prefs.edit().remove(key).commit()
+ watcher.close()
+ }
+ }
+
+ private fun navConfigEditWatcher(): SafeCloseable {
+ val wait = CountDownLatch(1)
+ val listener = Runnable { wait.countDown() }
+ configHelper.addChangeListener(listener)
+
+ return SafeCloseable {
+ wait.await()
+ configHelper.removeChangeListener(listener)
+ }
+ }
+}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
index 27e761a..c0ff189 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
@@ -18,9 +18,11 @@
import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.content.ComponentName
+import android.content.Context
import android.content.Intent
import android.os.Process
import android.os.UserHandle
+import android.platform.test.rule.TestWatcher
import android.testing.AndroidTestingRunner
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION
@@ -39,12 +41,14 @@
import org.junit.Before
import org.junit.Rule
import org.junit.Test
+import org.junit.runner.Description
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.Mock
import org.mockito.junit.MockitoJUnit
import org.mockito.kotlin.any
import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.never
import org.mockito.kotlin.times
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
@@ -53,32 +57,60 @@
class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() {
@get:Rule val mockitoRule = MockitoJUnit.rule()
+ @get:Rule
+ val disableControllerForCertainTestsWatcher =
+ object : TestWatcher() {
+ override fun starting(description: Description) {
+ // Update canShowRunningAndRecentAppsAtInit before setUp() is called for each test.
+ canShowRunningAndRecentAppsAtInit =
+ description.methodName !in
+ listOf(
+ "canShowRunningAndRecentAppsAtInitIsFalse_getTasksNeverCalled",
+ )
+ }
+ }
@Mock private lateinit var mockIconCache: TaskIconCache
@Mock private lateinit var mockRecentsModel: RecentsModel
+ @Mock private lateinit var mockContext: Context
@Mock private lateinit var mockDesktopVisibilityController: DesktopVisibilityController
private var taskListChangeId: Int = 1
private lateinit var recentAppsController: TaskbarRecentAppsController
- private lateinit var recentTasksChangedListener: RecentTasksChangedListener
private lateinit var userHandle: UserHandle
+ private var canShowRunningAndRecentAppsAtInit = true
+ private var recentTasksChangedListener: RecentTasksChangedListener? = null
+
@Before
fun setUp() {
super.setup()
userHandle = Process.myUserHandle()
whenever(mockRecentsModel.iconCache).thenReturn(mockIconCache)
+ whenever(mockRecentsModel.unregisterRecentTasksChangedListener()).then {
+ recentTasksChangedListener = null
+ it
+ }
recentAppsController =
- TaskbarRecentAppsController(mockRecentsModel) { mockDesktopVisibilityController }
+ TaskbarRecentAppsController(mockContext, mockRecentsModel) {
+ mockDesktopVisibilityController
+ }
+ recentAppsController.canShowRunningApps = canShowRunningAndRecentAppsAtInit
+ recentAppsController.canShowRecentApps = canShowRunningAndRecentAppsAtInit
recentAppsController.init(taskbarControllers)
- recentAppsController.canShowRunningApps = true
- recentAppsController.canShowRecentApps = true
- val listenerCaptor = ArgumentCaptor.forClass(RecentTasksChangedListener::class.java)
- verify(mockRecentsModel).registerRecentTasksChangedListener(listenerCaptor.capture())
- recentTasksChangedListener = listenerCaptor.value
+ recentTasksChangedListener =
+ if (canShowRunningAndRecentAppsAtInit) {
+ val listenerCaptor = ArgumentCaptor.forClass(RecentTasksChangedListener::class.java)
+ verify(mockRecentsModel)
+ .registerRecentTasksChangedListener(listenerCaptor.capture())
+ listenerCaptor.value
+ } else {
+ verify(mockRecentsModel, never()).registerRecentTasksChangedListener(any())
+ null
+ }
// Make sure updateHotseatItemInfos() is called after commitRunningAppsToUI()
whenever(taskbarViewController.commitRunningAppsToUI()).then {
@@ -88,6 +120,32 @@
}
}
+ // See the TestWatcher rule at the top which sets canShowRunningAndRecentAppsAtInit = false.
+ @Test
+ fun canShowRunningAndRecentAppsAtInitIsFalse_getTasksNeverCalled() {
+ prepareHotseatAndRunningAndRecentApps(
+ hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2),
+ runningTasks = listOf(createTask(1, RUNNING_APP_PACKAGE_1)),
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ )
+ verify(mockRecentsModel, never()).getTasks(any<Consumer<List<GroupTask>>>())
+ }
+
+ @Test
+ fun canShowRunningAndRecentAppsIsFalseAfterInit_getTasksOnlyCalledInInit() {
+ // getTasks() should have been called once from init().
+ verify(mockRecentsModel, times(1)).getTasks(any<Consumer<List<GroupTask>>>())
+ recentAppsController.canShowRunningApps = false
+ recentAppsController.canShowRecentApps = false
+ prepareHotseatAndRunningAndRecentApps(
+ hotseatPackages = listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2),
+ runningTasks = listOf(createTask(1, RUNNING_APP_PACKAGE_1)),
+ recentTaskPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
+ )
+ // Verify that getTasks() was not called again after the init().
+ verify(mockRecentsModel, times(1)).getTasks(any<Consumer<List<GroupTask>>>())
+ }
+
@Test
fun updateHotseatItemInfos_cantShowRunning_inDesktopMode_returnsAllHotseatItems() {
recentAppsController.canShowRunningApps = false
@@ -518,7 +576,7 @@
)
setInDesktopMode(true)
- recentTasksChangedListener.onRecentTasksChanged()
+ recentTasksChangedListener!!.onRecentTasksChanged()
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
assertThat(shownPackages).containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
}
@@ -535,7 +593,7 @@
recentTaskPackages = recentTaskPackages
)
setInDesktopMode(false)
- recentTasksChangedListener.onRecentTasksChanged()
+ recentTasksChangedListener!!.onRecentTasksChanged()
val shownPackages = recentAppsController.shownTasks.flatMap { it.packageNames }
// Don't expect RECENT_PACKAGE_3 because it is currently running.
val expectedPackages = listOf(RECENT_PACKAGE_1, RECENT_PACKAGE_2)
@@ -705,7 +763,7 @@
}
.whenever(mockRecentsModel)
.getTasks(any<Consumer<List<GroupTask>>>())
- recentTasksChangedListener.onRecentTasksChanged()
+ recentTasksChangedListener?.onRecentTasksChanged()
}
private fun createHotseatItemsFromPackageNames(packageNames: List<String>): List<ItemInfo> {
diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
index d049fbc..c213dbb 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
+++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
@@ -29,6 +29,7 @@
import android.app.ActivityManager;
import android.app.KeyguardManager;
+import android.content.Context;
import androidx.test.filters.SmallTest;
@@ -54,7 +55,9 @@
public class RecentTasksListTest {
@Mock
- private SystemUiProxy mockSystemUiProxy;
+ private Context mContext;
+ @Mock
+ private SystemUiProxy mSystemUiProxy;
@Mock
private TopTaskTracker mTopTaskTracker;
@@ -66,14 +69,14 @@
MockitoAnnotations.initMocks(this);
LooperExecutor mockMainThreadExecutor = mock(LooperExecutor.class);
KeyguardManager mockKeyguardManager = mock(KeyguardManager.class);
- mRecentTasksList = new RecentTasksList(mockMainThreadExecutor, mockKeyguardManager,
- mockSystemUiProxy, mTopTaskTracker);
+ mRecentTasksList = new RecentTasksList(mContext, mockMainThreadExecutor,
+ mockKeyguardManager, mSystemUiProxy, mTopTaskTracker);
}
@Test
public void onRecentTasksChanged_doesNotFetchTasks() throws Exception {
mRecentTasksList.onRecentTasksChanged();
- verify(mockSystemUiProxy, times(0))
+ verify(mSystemUiProxy, times(0))
.getRecentTasks(anyInt(), anyInt());
}
@@ -81,7 +84,7 @@
public void loadTasksInBackground_onlyKeys_noValidTaskDescription() throws Exception {
GroupedRecentTaskInfo recentTaskInfos = GroupedRecentTaskInfo.forSplitTasks(
new ActivityManager.RecentTaskInfo(), new ActivityManager.RecentTaskInfo(), null);
- when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
+ when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
.thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1,
@@ -94,7 +97,7 @@
@Test
public void loadTasksInBackground_GetRecentTasksException() throws Exception {
- when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
+ when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
.thenThrow(new SystemUiProxy.GetRecentTasksException("task load failed"));
RecentTasksList.TaskLoadResult taskList = mRecentTasksList.loadTasksInBackground(
@@ -113,7 +116,7 @@
task2.taskDescription = new ActivityManager.TaskDescription();
GroupedRecentTaskInfo recentTaskInfos = GroupedRecentTaskInfo.forSplitTasks(task1, task2,
null);
- when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
+ when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
.thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(Integer.MAX_VALUE, -1,
@@ -132,7 +135,7 @@
createRecentTaskInfo(5 /* taskId */)};
GroupedRecentTaskInfo recentTaskInfos = GroupedRecentTaskInfo.forFreeformTasks(
tasks, Collections.emptySet() /* minimizedTaskIds */);
- when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
+ when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
.thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(
@@ -158,7 +161,7 @@
Arrays.stream(new Integer[]{1, 4, 5}).collect(Collectors.toSet());
GroupedRecentTaskInfo recentTaskInfos =
GroupedRecentTaskInfo.forFreeformTasks(tasks, minimizedTaskIds);
- when(mockSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
+ when(mSystemUiProxy.getRecentTasks(anyInt(), anyInt()))
.thenReturn(new ArrayList<>(Collections.singletonList(recentTaskInfos)));
List<GroupTask> taskList = mRecentTasksList.loadTasksInBackground(
diff --git a/res/drawable/rounded_action_button.xml b/res/drawable/rounded_action_button.xml
index ddd3042..ebfa996 100644
--- a/res/drawable/rounded_action_button.xml
+++ b/res/drawable/rounded_action_button.xml
@@ -22,8 +22,5 @@
<stroke
android:width="1dp"
android:color="?attr/materialColorSurfaceContainerLow" />
- <padding
- android:left="@dimen/rounded_button_padding"
- android:right="@dimen/rounded_button_padding" />
</shape>
diff --git a/res/layout/work_apps_edu.xml b/res/layout/work_apps_edu.xml
index c581ae3..a45d585 100644
--- a/res/layout/work_apps_edu.xml
+++ b/res/layout/work_apps_edu.xml
@@ -44,8 +44,7 @@
<FrameLayout
android:layout_width="@dimen/rounded_button_width"
android:layout_height="@dimen/rounded_button_width"
- android:background="@drawable/rounded_action_button"
- android:padding="@dimen/rounded_button_padding">
+ android:background="@drawable/rounded_action_button">
<ImageButton
android:id="@+id/action_btn"
android:layout_width="@dimen/x_icon_size"
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 1a8f8e2..0ef1f47 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Apppaar is nie beskikbaar nie"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Raak en hou om \'n legstuk te skuif."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dubbeltik en hou om \'n legstuk te skuif of gebruik gepasmaakte handelinge."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breed by %2$d hoog"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-legstuk"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 80447c5..63cace9 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"የመተግበሪያ ጥምረት አይገኝም"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ምግብርን ለማንቀሳቀስ ይንኩ እና ይያዙ።"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ምግብርን ለማንቀሳቀስ ወይም ብጁ እርምጃዎችን ለመጠቀም ሁለቴ መታ ያድርጉ እና ይያዙ።"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ስፋት በ%2$d ከፍታ"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"የ<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ምግብር"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 4eee121..d62400e 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"ميزة \"استخدام تطبيقين في الوقت نفسه\" غير متوفّرة"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"انقر مع الاستمرار لنقل أداة."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"انقر مرتين مع تثبيت إصبعك لنقل أداة أو استخدام الإجراءات المخصّصة."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"العرض %1$d الطول %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"أداة <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 52ec7ea..a3c0bc0 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"এপ্ পেয়াৰ কৰাৰ সুবিধাটো উপলব্ধ নহয়"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ৱিজেট স্থানান্তৰ কৰিবলৈ টিপি ধৰি ৰাখক।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"কোনো ৱিজেট স্থানান্তৰ কৰিবলৈ দুবাৰ টিপি ধৰি ৰাখক অথবা কাষ্টম কাৰ্য ব্যৱহাৰ কৰক।"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d বহল x %2$d ওখ"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ৱিজেট"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 6c1cc46..cfdcbe0 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Tətbiq cütü əlçatan deyil"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidceti daşımaq üçün toxunub saxlayın."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Vidceti daşımaq üçün iki dəfə toxunub saxlayın və ya fərdi əməliyyatlardan istifadə edin."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%2$d hündürlük %1$d enində"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidceti"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 24328cf..322a613 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Par aplikacija nije dostupan"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite radi pomeranja vidžeta."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite da biste pomerali vidžet ili koristite prilagođene radnje."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"širina od %1$d i visina od %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidžet"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index ebbb378..6f423aa 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Спалучэнне праграм недаступнае"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Націсніце і ўтрымлівайце віджэт для перамяшчэння."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Дакраніцеся двойчы і ўтрымлівайце, каб перамясціць віджэт або выкарыстоўваць спецыяльныя дзеянні."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Шырына: %1$d, вышыня: %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Віджэт \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index d5d948e..2230012 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Двойката приложения не е налице"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Докоснете и задръжте за преместване на приспособление"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Докоснете двукратно и задръжте за преместване на приспособление или използвайте персонал. действия."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Ширина %1$d и височина %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> приспособление"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index cf75fb58..09ebf2f 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"অ্যাপ পেয়ার উপলভ্য নেই"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"কোনও উইজেট সরাতে সেটি টাচ করে ধরে রাখুন।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"একটি উইজেট সরাতে বা কাস্টম অ্যাকশন ব্যবহার করতে ডবল ট্যাপ করে ধরে রাখুন।"</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"আরও বিকল্প"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"সব উইজেট দেখুন"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%2$d উচ্চতা অনুযায়ী %1$d প্রস্থ"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>টি উইজেট"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 1758c39..e6dffb2 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Par aplikacija nije dostupan"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite da pomjerite vidžet."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite da pomjerite vidžet ili da koristite prilagođene radnje."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Širina %1$d, visina %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index bf578f5..014e481 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"La parella d\'aplicacions no està disponible"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Fes doble toc i mantén premut per moure un widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Fes doble toc i mantén premut per moure un widget o per utilitzar accions personalitzades."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d d\'amplada per %2$d d\'alçada"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget de <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 9a8fc6f..456b4da 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Dvojice aplikací není k dispozici"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Widget přesunete klepnutím a podržením."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvojitým klepnutím a podržením přesunete widget, případně použijte vlastní akce."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"šířka %1$d, výška %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 208c2ef..b202828 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Appsammenknytning er ikke tilgængelig"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Hold en widget nede for at flytte den."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tryk to gange, og hold en widget nede for at flytte den eller bruge tilpassede handlinger."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d i bredden og %2$d i højden"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widgetten <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 380030b..3e984cd 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"App-Paar nicht verfügbar"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Zum Verschieben des Widgets gedrückt halten"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Doppeltippen und halten, um ein Widget zu bewegen oder benutzerdefinierte Aktionen zu nutzen."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breit und %2$d hoch"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index e86ebae..cda7670 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Το ζεύγος εφαρμογών δεν είναι διαθέσιμο"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Πατήστε παρατετ. για μετακίνηση γραφ. στοιχείου."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Πατήστε δύο φορές παρατεταμένα για μετακίνηση γραφικού στοιχείου ή χρήση προσαρμοσμένων ενεργειών."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Πλάτος %1$d επί ύψος %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Γραφικό στοιχείο <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 50c5976..80957b2 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"App pair isn\'t available"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 08ff6e7..311b4b9 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"App pair isn\'t available"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap and hold to move a widget or use custom actions."</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"More options"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Show all widgets"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 50c5976..80957b2 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"App pair isn\'t available"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 50c5976..80957b2 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"App pair isn\'t available"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch and hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index fa6d1f1..047a67f 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"App pair isn\'t available"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Touch & hold to move a widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Double-tap & hold to move a widget or use custom actions."</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"More options"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Show all widgets"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d wide by %2$d high"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 5879129..dc3e779 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"La vinculación de apps no está disponible"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén presionado para mover un widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Presiona dos veces y mantén presionado para mover un widget o usar acciones personalizadas."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de ancho por %2$d de alto"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 8d384ac..0f716dc 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"La aplicación emparejada no está disponible"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén pulsado un widget para moverlo"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toca dos veces y mantén pulsado un widget para moverlo o usar acciones personalizadas."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de ancho por %2$d de alto"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget de <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 44448a6..e7e9c98 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Rakendusepaar ei ole saadaval"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidina teisaldamiseks puudutage ja hoidke all."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Vidina teisaldamiseks või kohandatud toimingute kasutamiseks topeltpuudutage ja hoidke all."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d lai ja %2$d kõrge"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 6fc4cf4..9868cca 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Aplikazio parea ez dago erabilgarri"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Eduki sakatuta widget bat mugitzeko."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Sakatu birritan eta eduki sakatuta widget bat mugitzeko edo ekintza pertsonalizatuak erabiltzeko."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d zabal eta %2$d luze"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index fffce13..19689d3 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"جفت برنامه دردسترس نیست"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"برای جابهجا کردن ابزارک، لمس کنید و نگه دارید."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"برای جابهجا کردن ابزارک یا استفاده از کنشهای سفارشی، دو تکضرب بزنید و نگه دارید."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d عرض در %2$d طول"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 310053e..6bb0faf 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Sovelluspari ei ole saatavilla"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Kosketa pitkään, niin voit siirtää widgetiä."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Kaksoisnapauta ja paina pitkään, niin voit siirtää widgetiä tai käyttää muokattuja toimintoja."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Leveys: %1$d, korkeus: %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 11b2c01..6bf5d63 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"La Paire d\'applis n\'est pas offerte"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Maintenez le doigt sur un widget pour le déplacer."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Touchez 2x un widget et maintenez le doigt dessus pour le déplacer ou utiliser des actions personnalisées."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largeur sur %2$d de hauteur"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index b4c5ec6..c128343 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"La paire d\'applications n\'est pas disponible"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Appuyez de manière prolongée sur un widget pour le déplacer."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Appuyez deux fois et maintenez la pression pour déplacer widget ou utiliser actions personnalisées."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largeur et %2$d de hauteur"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index ac72802..e68d0e5 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Non está dispoñible o emparellamento de aplicacións"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Mantén premido un widget para movelo."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toca dúas veces un widget e manteno premido para movelo ou utiliza accións personalizadas."</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"Máis opcións"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Mostrar todos os widgets"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largo por %2$d de alto"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 74747d0..c5e00ef 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"ઍપની જોડી ઉપલબ્ધ નથી"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"વિજેટ ખસેડવા ટચ કરીને થોડી વાર દબાવી રાખો."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"વિજેટ ખસેડવા બે વાર ટૅપ કરીને દબાવી રાખો અથવા કસ્ટમ ક્રિયાઓનો ઉપયોગ કરો."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d પહોળાઈ X %2$d ઊંચાઈ"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> વિજેટ"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 6071935..79fcc3f 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"साथ में इस्तेमाल किए जा सकने वाले ऐप्लिकेशन की सुविधा उपलब्ध नहीं है"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"किसी विजेट को एक से दूसरी जगह ले जाने के लिए, उसे दबाकर रखें."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"किसी विजेट को एक से दूसरी जगह ले जाने के लिए, उस पर दो बार टैप करके दबाकर रखें या पसंद के मुताबिक कार्रवाइयां इस्तेमाल करें."</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"ज़्यादा विकल्प"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"सभी विजेट दिखाएं"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d चौड़ाई गुणा %2$d ऊंचाई"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index cf7a91a..6c86d88 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Par aplikacija nije dostupan"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Dodirnite i zadržite da biste premjestili widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvaput dodirnite i zadržite pritisak da biste premjestili widget ili upotrijebite prilagođene radnje"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d širine i %2$d visine"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index f306110..2378a52 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Az alkalmazáspár nem áll rendelkezésre"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Tartsa lenyomva a modult az áthelyezéshez."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Modul áthelyezéséhez koppintson duplán, tartsa nyomva az ujját, vagy használjon egyéni műveleteket."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d széles és %2$d magas"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 2d345f2..67cc1d5 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Հավելվածների զույգը հասանելի չէ"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Հպեք և պահեք՝ վիջեթ տեղափոխելու համար։"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Կրկնակի հպեք և պահեք՝ վիջեթ տեղափոխելու համար, կամ օգտվեք հատուկ գործողություններից։"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Լայնությունը՝ %1$d, բարձրությունը՝ %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> վիջեթ"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 9ced9f4..f112064 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Pasangan aplikasi tidak tersedia"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Sentuh lama untuk memindahkan widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ketuk dua kali & tahan untuk memindahkan widget atau gunakan tindakan khusus."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"lebar %1$d x tinggi %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 2ab7817..558af15 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Forritapar er ekki í boði"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Haltu fingri á græju til að færa hana."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ýttu tvisvar og haltu fingri á græju til að færa hana eða notaðu sérsniðnar aðgerðir."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d á breidd og %2$d á hæð"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Græjan <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index a59de6c..fb05034 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"La coppia di app non è disponibile"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Tocca e tieni premuto per spostare un widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tocca due volte e tieni premuto per spostare un widget o per usare le azioni personalizzate."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d di larghezza per %2$d di altezza"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 89a0c8a..09a876a 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"צמד האפליקציות לא זמין"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"להעברת ווידג\'ט למקום אחר לוחצים עליו לחיצה ארוכה."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"כדי להעביר ווידג\'ט למקום אחר או להשתמש בפעולות מותאמות אישית, יש ללחוץ פעמיים ולא להרפות."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"רוחב %1$d על גובה %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"ווידג\'ט <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index b48c7be..e0aa65f 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"アプリのペア設定は利用できません"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"長押ししてウィジェットを移動させます。"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ウィジェットをダブルタップして長押ししながら移動するか、カスタム操作を使用してください。"</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"その他のオプション"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"すべてのウィジェットを表示"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$dx%2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"幅 %1$d、高さ %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ウィジェット"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 76b8b5d..369aa22 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"აპთა წყვილი მიუწვდომელია"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"შეხებით აირჩიეთ და გეჭიროთ ვიჯეტის გადასაადგილებლად."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ორმაგი შეხებით აირჩიეთ და გეჭიროთ ვიჯეტის გადასაადგილებლად ან მორგებული მოქმედებების გამოსაყენებლად."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"სიგრძე: %1$d, სიგანე: %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ვიჯეტი"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 95d4420..8d4efa7 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Қолданбаларды жұптау функциясы қолжетімді емес."</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетті жылжыту үшін басып тұрыңыз."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетті жылжыту үшін екі рет түртіңіз де, ұстап тұрыңыз немесе арнаулы әрекеттерді пайдаланыңыз."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Ені: %1$d, биіктігі: %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджеті"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 5c71276..caa92bd 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"មិនអាចប្រើគូកម្មវិធីបានទេ"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ចុចឱ្យជាប់ដើម្បីផ្លាស់ទីធាតុក្រាហ្វិក។"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ចុចពីរដង រួចសង្កត់ឱ្យជាប់ ដើម្បីផ្លាស់ទីធាតុក្រាហ្វិក ឬប្រើសកម្មភាពតាមបំណង។"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"ទទឺង %1$d គុណនឹងកម្ពស់ %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"ធាតុក្រាហ្វិក <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 931ca30..04daaac 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"ಆ್ಯಪ್ ಜೋಡಿ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ವಿಜೆಟ್ ಸರಿಸಲು ಸ್ಪರ್ಶಿಸಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ವಿಜೆಟ್ ಸರಿಸಲು ಅಥವಾ ಕಸ್ಟಮ್ ಕ್ರಿಯೆಗಳನ್ನು ಬಳಸಲು ಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ ಮತ್ತು ಹಿಡಿದುಕೊಳ್ಳಿ."</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"ಇನ್ನಷ್ಟು ಆಯ್ಕೆಗಳು"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"ಎಲ್ಲಾ ವಿಜೆಟ್ ತೋರಿಸಿ"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ಅಗಲ ಮತ್ತು %2$d ಎತ್ತರ"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ವಿಜೆಟ್"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 9f64cfb..152745a 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"앱 페어링을 사용할 수 없습니다."</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"길게 터치하여 위젯을 이동하세요."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"두 번 탭한 다음 길게 터치하여 위젯을 이동하거나 맞춤 작업을 사용하세요."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"너비 %1$d, 높이 %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"위젯 <xliff:g id="WIDGET_NAME">%1$s</xliff:g>개"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 3e67c36..6a9b4df 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Эки колдонмону бир маалда пайдаланууга болбойт"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетти кое бербей басып туруп жылдырыңыз."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетти жылдыруу үчүн эки жолу таптап, кармап туруңуз же ыңгайлаштырылган аракеттерди колдонуңуз."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Туурасы: %1$d, бийиктиги: %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджети"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index e0cd3ee..9572f3d 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"ການຈັບຄູ່ແອັບບໍ່ມີໃຫ້"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ແຕະຄ້າງໄວ້ເພື່ອຍ້າຍວິດເຈັດ."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ແຕະສອງເທື່ອຄ້າງໄວ້ເພື່ອຍ້າຍວິດເຈັດ ຫຼື ໃຊ້ຄຳສັ່ງກຳນົດເອງ."</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"ຕົວເລືອກເພີ່ມເຕີມ"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"ສະແດງວິດເຈັດທັງໝົດ"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"ກວ້າງ %1$d ຄູນສູງ %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"ວິດເຈັດ <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 9846525..6cd8872 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Programų pora nepasiekiama"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Dukart pal. ir palaik., kad perkeltumėte valdiklį."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dukart palieskite ir palaikykite, kad perkeltumėte valdiklį ar naudotumėte tinkintus veiksmus."</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"Daugiau parinkčių"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Rodyti visus valdiklius"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d plotis ir %2$d aukštis"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> valdiklis"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 49f7ffe..6fd8345 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Lietotņu pāris nav pieejams"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Lai pārvietotu logrīku, pieskarieties un turiet."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Lai pārvietotu logrīku, uz tā veiciet dubultskārienu un turiet. Varat arī veikt pielāgotas darbības."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d plats un %2$d augsts"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Logrīks <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 2bfa089..5440af6 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Парот апликации не е достапен"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Допрете и задржете за да преместите виџет."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Допрете двапати и задржете за да преместите виџет или користете приспособени дејства."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d широк на %2$d висок"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index a2babd5..8a860bf 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"ആപ്പ് ജോടി ലഭ്യമല്ല"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"വിജറ്റ് നീക്കാൻ സ്പർശിച്ച് പിടിക്കുക."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"വിജറ്റ് നീക്കാൻ ഡബിൾ ടാപ്പ് ചെയ്യൂ, ഹോൾഡ് ചെയ്യൂ അല്ലെങ്കിൽ ഇഷ്ടാനുസൃത പ്രവർത്തനങ്ങൾ ഉപയോഗിക്കൂ."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d വീതിയും %2$d ഉയരവും"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> വിജറ്റ്"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 93a1c9c..e85a33c 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Апп хослуулалт боломжгүй байна"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Виджетийг зөөх бол хүрээд, удаан дарна уу."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Виджетийг зөөх эсвэл захиалгат үйлдлийг ашиглахын тулд хоёр товшоод, удаан дарна уу."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d өргөн %2$d өндөр"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> жижиг хэрэгсэл"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index c084fab..2f78245 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"ॲपची जोडी उपलब्ध नाही"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"विजेट हलवण्यासाठी स्पर्श करा आणि धरून ठेवा."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"विजेट हलवण्यासाठी किंवा कस्टम कृती वापरण्यासाठी दोनदा टॅप करा आणि धरून ठेवा."</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"आणखी पर्याय"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"सर्व विजेट दाखवा"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d रूंद बाय %2$d उंच"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 72d92e2..d2fd7a8 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Gandingan apl tidak tersedia"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Sentuh & tahan untuk menggerakkan widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ketik dua kali & tahan untuk menggerakkan widget atau menggunakan tindakan tersuai."</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"Lagi pilihan"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Tunjukkan semua widget"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Lebar %1$d kali tinggi %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 194ece7..a6b8500 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"အက်ပ်တွဲချိတ်ခြင်းကို မရနိုင်ပါ"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ဝိဂျက်ကို ရွှေ့ရန် တို့ပြီး ဖိထားပါ။"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ဝိဂျက်ကို ရွှေ့ရန် (သို့) စိတ်ကြိုက်လုပ်ဆောင်ချက်များကို သုံးရန် နှစ်ချက်တို့ပြီး ဖိထားပါ။"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"အလျား %1$d နှင့် အမြင့် %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index a9e6c5d..bc688aa 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Apptilkoblingen er ikke tilgjengelig"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Trykk og hold for å flytte en modul."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dobbelttrykk og hold inne for å flytte en modul eller bruke tilpassede handlinger."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d bredde x %2$d høyde"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modul"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 7880c36..eddcefb 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"एप पेयर उपलब्ध छैन"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"कुनै विजेट सार्न डबल ट्याप गरेर छोइराख्नुहोस्।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"कुनै विजेट सार्न वा आफ्नो रोजाइका कारबाही प्रयोग गर्न डबल ट्याप गरेर छोइराख्नुहोस्।"</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"थप विकल्पहरू"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"सबै विजेटहरू देखाउनुहोस्"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d चौडाइ गुणा %2$d उचाइ"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 7b3f563..3402086 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"App-paar is niet beschikbaar"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Tik en houd vast om een widget te verplaatsen."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dubbeltik en houd vast om een widget te verplaatsen of aangepaste acties te gebruiken."</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"Meer opties"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Alle widgets tonen"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breed en %2$d hoog"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 33b7664..000ab13 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"ଆପ ପେୟାର ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ଏକ ୱିଜେଟକୁ ମୁଭ୍ କରିବା ପାଇଁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ଏକ ୱିଜେଟକୁ ମୁଭ୍ କରିବା ପାଇଁ ଦୁଇଥର-ଟାପ୍ କରି ଧରି ରଖନ୍ତୁ କିମ୍ବା କଷ୍ଟମ୍ କାର୍ଯ୍ୟଗୁଡ଼ିକୁ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ଓସାର ଓ %2$d ଉଚ୍ଚ"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ୱିଜେଟ୍"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 71c25eb..6e558c3 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"ਐਪ ਜੋੜਾਬੱਧ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ਕਿਸੇ ਵਿਜੇਟ ਨੂੰ ਲਿਜਾਉਣ ਲਈ ਸਪਰਸ਼ ਕਰਕੇ ਰੱਖੋ।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ਵਿਜੇਟ ਲਿਜਾਉਣ ਲਈ ਜਾਂ ਵਿਉਂਂਤੀਆਂ ਕਾਰਵਾਈਆਂ ਵਰਤਣ ਲਈ ਦੋ ਵਾਰ ਟੈਪ ਕਰਕੇ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ਚੌੜਾਈ ਅਤੇ %2$d ਲੰਬਾਈ"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ਵਿਜੇਟ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 587c40f..c2aaf69 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Para aplikacji jest niedostępna"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Naciśnij i przytrzymaj, aby przenieść widżet."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Naciśnij dwukrotnie i przytrzymaj, aby przenieść widżet lub użyć działań niestandardowych."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Szerokość %1$d, wysokość %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 67d93de..1f98805 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -38,6 +38,8 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"O par de apps não está disponível"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Toque sem soltar para mover um widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toque duas vezes sem soltar para mover um widget ou utilizar ações personalizadas."</string>
+ <string name="widget_picker_widget_options_button_description" msgid="4770099264476852363">"Mais opções"</string>
+ <string name="widget_picker_show_all_widgets_menu_item_title" msgid="9023638224586908119">"Mostrar todos os widgets"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largura por %2$d de altura"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 4302588..10cf03f 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"O Par de apps não está disponível"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Toque e pressione para mover um widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Toque duas vezes e mantenha a tela pressionada para mover um widget ou usar ações personalizadas."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d de largura por %2$d de altura"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index d9e0413..510f671 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Perechea de aplicații nu este disponibilă"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Atinge și ține apăsat pentru a muta un widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Atinge de două ori și ține apăsat pentru a muta un widget sau folosește acțiuni personalizate."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d lățime și %2$d înălțime"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widgetul <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 64a21f7..3add9fa 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Одновременное использование двух приложений недоступно"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Чтобы переместить виджет, нажмите на него и удерживайте"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Чтобы использовать специальные действия или перенести виджет, нажмите на него дважды и удерживайте."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d x %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Ширина %1$d, высота %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Виджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\""</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 71efc03..2adccc3 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"යෙදුම් යුගලයක් නොමැත"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"විජට් එකක් ගෙන යාමට ස්පර්ශ කර අල්ලා ගෙන සිටින්න."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"විජට් එකක් ගෙන යාමට හෝ අභිරුචි ක්රියා භාවිත කිරීමට දෙවරක් තට්ටු කර අල්ලා ගෙන සිටින්න."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"පළල %1$d උස %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> විජට්ටුව"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 43bc29c..2a44faf 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Pár aplikácií nie je k dispozícii"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Pridržaním presuňte miniaplikáciu."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvojitým klepnutím a pridržaním presuňte miniaplikáciu alebo použite vlastné akcie."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"šírka %1$d, výška %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Miniaplikácia <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 5d423ca..638f9e4 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Par aplikacij ni na voljo"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Pridržite pripomoček, da ga premaknete."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Dvakrat se dotaknite pripomočka in ga pridržite, da ga premaknete, ali pa uporabite dejanja po meri."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Širina %1$d, višina %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Pripomoček <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 8f4133d..72e4f04 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Çifti i aplikacioneve nuk ofrohet"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Prek dhe mbaj shtypur një miniaplikacion për ta zhvendosur."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Trokit dy herë dhe mbaje shtypur një miniapliikacion për ta zhvendosur atë ose për të përdorur veprimet e personalizuara."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d i gjerë me %2$d i lartë"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> miniaplikacion"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index cd6523c..0252765 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Пар апликација није доступан"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Додирните и задржите ради померања виџета."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Двапут додирните и задржите да бисте померали виџет или користите прилагођене радње."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d×%2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"ширина од %1$d и висина од %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виџет"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 4f95c67..6c03884 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"App-paret är inte tillgängligt"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Tryck länge för att flytta en widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Tryck snabbt två gånger och håll kvar för att flytta en widget eller använda anpassade åtgärder."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d bred gånger %2$d hög"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget för <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 53a9abe..cb93952 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Kipengele cha jozi ya programu hakipatikani"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Gusa na ushikilie ili usogeze wijeti."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Gusa mara mbili na ushikilie ili usogeze wijeti au utumie vitendo maalum."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Upana wa %1$d na kimo cha %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 738f85c..ef3635c 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"ஆப்ஸ் ஜோடி கிடைக்கவில்லை"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"விட்ஜெட்டை நகர்த்தத் தொட்டுப் பிடிக்கவும்."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"விட்ஜெட்டை நகர்த்த இருமுறை தட்டிப் பிடிக்கவும் அல்லது பிரத்தியேகச் செயல்களைப் பயன்படுத்தவும்."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d அகலத்திற்கு %2$d உயரம்"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> விட்ஜெட்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 0520ebf..12dfb60 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"యాప్ పెయిర్ అందుబాటులో లేదు"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"విడ్జెట్ను తరలించడానికి తాకి & నొక్కి ఉంచండి."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"విడ్జెట్ను తరలించడానికి లేదా అనుకూల చర్యలను ఉపయోగించడానికి రెండుసార్లు నొక్కండి & హోల్డ్ చేయి."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d వెడల్పు X %2$d ఎత్తు"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> విడ్జెట్"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 554fd94..9522e572 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"การจับคู่อุปกรณ์ไม่พร้อมให้บริการ"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"แตะค้างไว้เพื่อย้ายวิดเจ็ต"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"แตะสองครั้งค้างไว้เพื่อย้ายวิดเจ็ตหรือใช้การดำเนินการที่กำหนดเอง"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"กว้าง %1$d x สูง %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"วิดเจ็ต <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index cb6fe66..6c27385 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Hindi available ang pares ng app"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Pindutin nang matagal para ilipat ang widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"I-double tap at pindutin nang matagal para ilipat ang widget o gumamit ng mga custom na pagkilos."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ang lapad at %2$d ang taas"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index b12ec27..fe4d538 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Uygulama çifti kullanılamıyor"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Widget\'ı taşımak için dokunup basılı tutun."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Widget\'ı taşımak veya özel işlemleri kullanmak için iki kez dokunup basılı tutun."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"genişlik: %1$d, yükseklik: %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 2a01dae..cdb943e 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Одночасне використання двох додатків недоступне"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Натисніть і втримуйте, щоб перемістити віджет."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Двічі натисніть і втримуйте віджет, щоб перемістити його або виконати інші дії."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Ширина – %1$d, висота – %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Віджет <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 544357e..a12e8f9 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"ایپ کا جوڑا دستیاب نہیں ہے"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ویجیٹ منتقل کرنے کے لیے ٹچ کریں اور پکڑ کر رکھیں۔"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ویجیٹ کو منتقل کرنے یا حسب ضرورت کارروائیاں استعمال کرنے کے لیے دوبار تھپتھپائیں اور پکڑ کر رکھیں۔"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d چوڑا اور %2$d اونچا"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ویجیٹ"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 5038d4f..ad5137e 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Ikkita ilovadan bir vaqtda foydalanish mumkin emas"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Vidjetni bosib turgan holatda suring."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ikki marta bosib va bosib turgan holatda vidjetni tanlang yoki maxsus amaldan foydalaning."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Eni %1$d, bo‘yi %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ta vidjet"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index e5252b1..bcb4b98 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Hiện không có cặp ứng dụng này"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Chạm và giữ để di chuyển một tiện ích."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Nhấn đúp và giữ để di chuyển một tiện ích hoặc sử dụng các thao tác tùy chỉnh."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Rộng %1$d x cao %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Tiện ích <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 7a76158..b36f7d6 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"应用对不可用"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"轻触并按住即可移动微件。"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"点按两次并按住微件即可移动该微件或使用自定义操作。"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"宽 %1$d,高 %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index ed6e52f..d3de49c 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -27,7 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"在安全模式中無法使用小工具"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"沒有可用的捷徑"</string>
<string name="home_screen" msgid="5629429142036709174">"主畫面"</string>
- <string name="set_default_home_app" msgid="5808906607627586381">"前往「設定」將「<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>」設為預設主畫面應用程式"</string>
+ <string name="set_default_home_app" msgid="5808906607627586381">"在「設定」中將「<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>」設定為預設主頁應用程式"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割螢幕"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的應用程式資料"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"「%1$s」的用量設定"</string>
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"應用程式配對無法使用"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"輕觸並按住即可移動小工具。"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"㩒兩下之後㩒住,就可以郁小工具或者用自訂操作。"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d 闊,%2$d 高"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 264d607..5b65c35 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"這個應用程式配對無法使用"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"按住即可移動小工具。"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"輕觸兩下並按住即可移動小工具或使用自訂操作。"</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"寬度為 %1$d,高度為 %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index be6cd49..fb6d8f2 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -38,6 +38,10 @@
<string name="app_pair_not_available" msgid="3556767440808032031">"Ukubhangqwa kwe-app akutholakali"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Thinta uphinde ubambe ukuze uhambise iwijethi."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Thepha kabili uphinde ubambe ukuze uhambise iwijethi noma usebenzise izindlela ezingokwezifiso."</string>
+ <!-- no translation found for widget_picker_widget_options_button_description (4770099264476852363) -->
+ <skip />
+ <!-- no translation found for widget_picker_show_all_widgets_menu_item_title (9023638224586908119) -->
+ <skip />
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d ububanzi ngokungu-%2$d ukuya phezulu"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Iwijethi elingu-<xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 05724e2..af91b5a 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -172,8 +172,6 @@
<dimen name="padded_rounded_button_height">48dp</dimen>
<dimen name="rounded_button_height">48dp</dimen>
<dimen name="rounded_button_radius">200dp</dimen>
- <dimen name="rounded_button_padding">8dp</dimen>
-
<!-- Widget tray -->
<dimen name="widget_cell_vertical_padding">8dp</dimen>
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index f775673..0d4ebe0 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -162,14 +162,14 @@
animatorSet.play(ObjectAnimator.ofFloat(child, VIEW_TRANSLATE_X, tx));
}
}
- if (mQsb instanceof HorizontalInsettableView) {
- HorizontalInsettableView horizontalInsettableQsb = (HorizontalInsettableView) mQsb;
- ValueAnimator qsbAnimator = ValueAnimator.ofFloat(0f, 1f);
+ if (mQsb instanceof HorizontalInsettableView horizontalInsettableQsb) {
+ final float currentInsetFraction = horizontalInsettableQsb.getHorizontalInsets();
+ final float targetInsetFraction =
+ isBubbleBarVisible ? (float) dp.iconSizePx / dp.hotseatQsbWidth : 0;
+ ValueAnimator qsbAnimator =
+ ValueAnimator.ofFloat(currentInsetFraction, targetInsetFraction);
qsbAnimator.addUpdateListener(animation -> {
- float fraction = qsbAnimator.getAnimatedFraction();
- float insetFraction = isBubbleBarVisible
- ? (float) dp.iconSizePx * fraction / dp.hotseatQsbWidth
- : (float) dp.iconSizePx * (1 - fraction) / dp.hotseatQsbWidth;
+ float insetFraction = (float) animation.getAnimatedValue();
horizontalInsettableQsb.setHorizontalInsets(insetFraction);
});
animatorSet.play(qsbAnimator);
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5949732..6c706be 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -266,6 +266,7 @@
import com.android.launcher3.widget.custom.CustomWidgetManager;
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.launcher3.widget.util.WidgetSizes;
import com.android.systemui.plugins.LauncherOverlayPlugin;
import com.android.systemui.plugins.PluginListener;
@@ -371,6 +372,7 @@
private LauncherAccessibilityDelegate mAccessibilityDelegate;
private PopupDataProvider mPopupDataProvider;
+ private WidgetPickerDataProvider mWidgetPickerDataProvider;
// We only want to get the SharedPreferences once since it does an FS stat each time we get
// it from the context.
@@ -532,6 +534,7 @@
mFocusHandler, new CellLayout(mWorkspace.getContext(), mWorkspace));
mPopupDataProvider = new PopupDataProvider(this::updateNotificationDots);
+ mWidgetPickerDataProvider = new WidgetPickerDataProvider();
boolean internalStateHandled = ACTIVITY_TRACKER.handleCreate(this);
if (internalStateHandled) {
@@ -2702,6 +2705,7 @@
mDragLayer.dump(prefix, writer);
mStateManager.dump(prefix, writer);
mPopupDataProvider.dump(prefix, writer);
+ mWidgetPickerDataProvider.dump(prefix, writer);
mDeviceProfile.dump(this, prefix, writer);
mAppsView.getAppsStore().dump(prefix, writer);
@@ -3011,6 +3015,12 @@
return mPopupDataProvider;
}
+ @NonNull
+ @Override
+ public WidgetPickerDataProvider getWidgetPickerDataProvider() {
+ return mWidgetPickerDataProvider;
+ }
+
@Override
public DotInfo getDotInfoForItem(ItemInfo info) {
return mPopupDataProvider.getDotInfoForItem(info);
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index b41da0f..08ccfb2 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -115,9 +115,7 @@
if (BuildCompat.isAtLeastV() && Flags.enableSupportForArchiving()) {
ArchiveCompatibilityParams params = new ArchiveCompatibilityParams();
params.setEnableUnarchivalConfirmation(false);
- if (Flags.enableNewArchivingIcon()) {
- params.setEnableIconOverlay(false);
- }
+ params.setEnableIconOverlay(!Flags.enableNewArchivingIcon());
launcherApps.setArchiveCompatibility(params);
}
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index 83c34ce..d57f8a0 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -254,8 +254,8 @@
PopupContainerWithArrow.dismissInvalidPopup(launcher)
}
- override fun bindAllWidgets(allWidgets: List<WidgetsListBaseEntry?>?) {
- launcher.popupDataProvider.allWidgets = allWidgets
+ override fun bindAllWidgets(allWidgets: List<WidgetsListBaseEntry>) {
+ launcher.widgetPickerDataProvider.setWidgets(allWidgets, /* defaultWidgets= */ listOf())
}
/** Returns the ids of the workspaces to bind. */
@@ -304,7 +304,8 @@
}
val widgetsListBaseEntry: WidgetsListBaseEntry =
- launcher.popupDataProvider.allWidgets.firstOrNull { item: WidgetsListBaseEntry ->
+ launcher.widgetPickerDataProvider.get().allWidgets.firstOrNull {
+ item: WidgetsListBaseEntry ->
item.mPkgItem.packageName == BuildConfig.APPLICATION_ID
} ?: return
diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java
index a448228..53fed20 100644
--- a/src/com/android/launcher3/Utilities.java
+++ b/src/com/android/launcher3/Utilities.java
@@ -746,7 +746,8 @@
* | +--+ |
* | |
* +----------------+
- * This would be case delta % 4 == 2:
+ * This would be case delta % 4 == 2: // This is case was reverted to previous behaviour which
+ * doesn't match the illustration due to b/353965234
* +-------------+
* | |
* | |
@@ -768,7 +769,6 @@
int delta) {
int rdelta = ((delta % 4) + 4) % 4;
int origLeft = inOutBounds.left;
- int origTop = inOutBounds.top;
switch (rdelta) {
case 0:
return;
@@ -780,8 +780,6 @@
return;
case 2:
inOutBounds.left = parentWidth - inOutBounds.right;
- inOutBounds.top = parentHeight - inOutBounds.bottom;
- inOutBounds.bottom = parentHeight - origTop;
inOutBounds.right = parentWidth - origLeft;
return;
case 3:
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 56a7fef..ad660d2 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -71,6 +71,7 @@
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget.DragObject;
+import com.android.launcher3.Flags;
import com.android.launcher3.Insettable;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.R;
@@ -764,6 +765,16 @@
}
}
+ /**
+ * Force header height update with an offset. Used by {@link UniversalSearchInputView} to
+ * request {@link FloatingHeaderView} to update its maxTranslation for multiline search bar.
+ */
+ public void forceUpdateHeaderHeight(int offset) {
+ if (Flags.multilineSearchBar()) {
+ mHeader.updateSearchBarOffset(offset);
+ }
+ }
+
protected void updateHeaderScroll(int scrolledOffset) {
float prog1 = Utilities.boundToRange((float) scrolledOffset / mHeaderThreshold, 0f, 1f);
int headerColor = getHeaderColor(prog1);
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index 89e6adc..a4f130a 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -262,11 +262,12 @@
writer.println(prefix + "\tAllAppsStore Apps[] size: " + mApps.length);
for (int i = 0; i < mApps.length; i++) {
writer.println(String.format(Locale.getDefault(),
- "%s\tPackage index, name, and class: " + "%d/%s:%s",
+ "%s\tPackage index, name, class, and description: %d/%s:%s, %s",
prefix,
i,
mApps[i].componentName.getPackageName(),
- mApps[i].componentName.getClassName()));
+ mApps[i].componentName.getClassName(),
+ mApps[i].contentDescription));
}
}
}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
index 92c589c..a2bd5dd 100644
--- a/src/com/android/launcher3/allapps/FloatingHeaderView.java
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -30,6 +30,7 @@
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.launcher3.Flags;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
import com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder;
@@ -104,6 +105,8 @@
private boolean mFloatingRowsCollapsed;
// Total height of all current floating rows. Collapsed rows == 0 height.
private int mFloatingRowsHeight;
+ // Offset of search bar. Adds to the floating view height when multi-line is supported.
+ private int mSearchBarOffset = 0;
// This is initialized once during inflation and stays constant after that. Fixed views
// cannot be added or removed dynamically.
@@ -198,6 +201,14 @@
}
}
+ /**
+ * Offset floating rows height by search bar
+ */
+ void updateSearchBarOffset(int offset) {
+ mSearchBarOffset = offset;
+ onHeightUpdated();
+ }
+
@Override
public void onPluginDisconnected(AllAppsRow plugin) {
PluginHeaderRow row = mPluginRows.get(plugin);
@@ -258,9 +269,18 @@
mTabLayout.setVisibility(mTabsHidden ? GONE : visibility);
}
+ /** Returns whether search bar has multi-line support, and is currently in multi-line state. */
+ private boolean isSearchBarMultiline() {
+ return Flags.multilineSearchBar() && mSearchBarOffset > 0;
+ }
+
private void updateExpectedHeight() {
updateFloatingRowsHeight();
mMaxTranslation = 0;
+ boolean shouldAddSearchBarHeight = isSearchBarMultiline() && !Flags.floatingSearchBar();
+ if (shouldAddSearchBarHeight) {
+ mMaxTranslation += mSearchBarOffset;
+ }
if (mFloatingRowsCollapsed) {
return;
}
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index c1264d6..e215cab 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -403,6 +403,7 @@
mLockText.setHorizontallyScrolling(false);
mPrivateSpaceSettingsButton.setVisibility(
isPrivateSpaceSettingsAvailable() ? VISIBLE : GONE);
+ mPrivateSpaceSettingsButton.setClickable(isPrivateSpaceSettingsAvailable());
}
lockPill.setVisibility(VISIBLE);
lockPill.setOnClickListener(view -> lockingAction(/* lock */ true));
@@ -425,6 +426,7 @@
lockPill.setContentDescription(mLockedStateContentDesc);
mPrivateSpaceSettingsButton.setVisibility(GONE);
+ mPrivateSpaceSettingsButton.setClickable(false);
transitionView.setVisibility(GONE);
}
case STATE_TRANSITION -> {
@@ -660,10 +662,7 @@
return;
}
attachFloatingMaskView(expand);
- PropertySetter headerSetter = new AnimatedPropertySetter();
- headerSetter.add(updateSettingsGearAlpha(expand));
- headerSetter.add(updateLockTextAlpha(expand));
- AnimatorSet animatorSet = headerSetter.buildAnim();
+ AnimatorSet animatorSet = new AnimatedPropertySetter().buildAnim();
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationStart(Animator animation) {
@@ -708,12 +707,16 @@
}
}));
if (expand) {
- animatorSet.playTogether(animateAlphaOfIcons(true),
+ animatorSet.playTogether(updateSettingsGearAlpha(true),
+ updateLockTextAlpha(true),
+ animateAlphaOfIcons(true),
animatePillTransition(true),
translateFloatingMaskView(false));
} else {
AnimatorSet parallelSet = new AnimatorSet();
- parallelSet.playTogether(animateAlphaOfIcons(false),
+ parallelSet.playTogether(updateSettingsGearAlpha(false),
+ updateLockTextAlpha(false),
+ animateAlphaOfIcons(false),
animatePillTransition(false));
if (isPrivateSpaceHidden()) {
animatorSet.playSequentially(parallelSet,
@@ -794,6 +797,14 @@
@Override
public void onAnimationStart(Animator animator) {
mPrivateSpaceSettingsButton.setVisibility(VISIBLE);
+ mPrivateSpaceSettingsButton.setClickable(false);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ if (expand) {
+ mPrivateSpaceSettingsButton.setClickable(true);
+ }
}
});
return settingsAlphaAnim;
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index e44ea1d..a691e45 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -43,6 +43,7 @@
import android.view.animation.OvershootInterpolator;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
@@ -131,7 +132,8 @@
private float mCurrentPosition;
private float mFinalPosition;
private boolean mIsScrollPaused;
- private boolean mIsTwoPanels;
+ @VisibleForTesting
+ boolean mIsTwoPanels;
private ObjectAnimator mAnimator;
private @Nullable ObjectAnimator mAlphaAnimator;
@@ -477,6 +479,21 @@
return sTempRect;
}
+ @VisibleForTesting
+ int getActivePage() {
+ return mActivePage;
+ }
+
+ @VisibleForTesting
+ int getNumPages() {
+ return mNumPages;
+ }
+
+ @VisibleForTesting
+ float getCurrentPosition() {
+ return mCurrentPosition;
+ }
+
private class MyOutlineProver extends ViewOutlineProvider {
@Override
diff --git a/src/com/android/launcher3/pm/InstallSessionTracker.java b/src/com/android/launcher3/pm/InstallSessionTracker.java
index 24d58f3..c117be4 100644
--- a/src/com/android/launcher3/pm/InstallSessionTracker.java
+++ b/src/com/android/launcher3/pm/InstallSessionTracker.java
@@ -32,7 +32,6 @@
import androidx.annotation.WorkerThread;
import com.android.launcher3.Flags;
-import com.android.launcher3.Utilities;
import com.android.launcher3.util.PackageUserKey;
import java.lang.ref.WeakReference;
diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java
index 7339111..e861961 100644
--- a/src/com/android/launcher3/pm/UserCache.java
+++ b/src/com/android/launcher3/pm/UserCache.java
@@ -183,6 +183,11 @@
mUserToSerialMap.put(userHandle, info);
}
+ @VisibleForTesting
+ public void putToPreInstallCache(UserHandle userHandle, List<String> preInstalledApps) {
+ mUserToPreInstallAppMap.put(userHandle, preInstalledApps);
+ }
+
/**
* @see UserManager#getUserProfiles()
*/
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index 7e139c3..8a5e388 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -24,28 +24,20 @@
import androidx.annotation.Nullable;
import com.android.launcher3.dot.DotInfo;
-import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.notification.NotificationKeyData;
import com.android.launcher3.notification.NotificationListener;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.ShortcutUtil;
-import com.android.launcher3.widget.PendingAddWidgetInfo;
-import com.android.launcher3.widget.model.WidgetsListBaseEntry;
-import com.android.launcher3.widget.model.WidgetsListContentEntry;
-import com.android.launcher3.widget.picker.WidgetRecommendationCategory;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
-import java.util.Objects;
import java.util.function.Consumer;
-import java.util.function.Function;
import java.util.function.Predicate;
-import java.util.stream.Collectors;
/**
* Provides data for the popup menu that appears after long-clicking on apps.
@@ -62,18 +54,6 @@
/** Maps packages to their DotInfo's . */
private Map<PackageUserKey, DotInfo> mPackageUserToDotInfos = new HashMap<>();
- /** All installed widgets. */
- private List<WidgetsListBaseEntry> mAllWidgets = List.of();
- /**
- * Selectively chosen installed widgets which may be preferred for default display over the list
- * of all widgets.
- */
- private List<WidgetsListBaseEntry> mDefaultWidgets = List.of();
- /** Widgets that can be recommended to the users. */
- private List<ItemInfo> mRecommendedWidgets = List.of();
-
- private PopupDataChangeListener mChangeListener = PopupDataChangeListener.INSTANCE;
-
public PopupDataProvider(Consumer<Predicate<PackageUserKey>> notificationDotsChangeListener) {
mNotificationDotsChangeListener = notificationDotsChangeListener;
}
@@ -188,124 +168,8 @@
})) ? dotInfo : null;
}
- /**
- * Sets a list of recommended widgets ordered by their order of appearance in the widgets
- * recommendation UI.
- */
- public void setRecommendedWidgets(List<ItemInfo> recommendedWidgets) {
- mRecommendedWidgets = recommendedWidgets;
- mChangeListener.onRecommendedWidgetsBound();
- }
-
- public void setAllWidgets(List<WidgetsListBaseEntry> allWidgets) {
- mAllWidgets = allWidgets;
- mDefaultWidgets = List.of();
- mChangeListener.onWidgetsBound();
- }
-
- /**
- * Sets the list of widgets to be displayed by default and a complete list that can be displayed
- * when user chooses to show all widgets.
- */
- public void setAllWidgets(List<WidgetsListBaseEntry> allWidgets,
- List<WidgetsListBaseEntry> defaultWidgets) {
- mAllWidgets = allWidgets;
- mDefaultWidgets = defaultWidgets;
- mChangeListener.onWidgetsBound();
- }
-
- public void setChangeListener(PopupDataChangeListener listener) {
- mChangeListener = listener == null ? PopupDataChangeListener.INSTANCE : listener;
- }
-
- public List<WidgetsListBaseEntry> getAllWidgets() {
- return mAllWidgets;
- }
-
- /**
- * Returns a "selectively" chosen list of widgets that may be preferred to be shown by default
- * instead of a complete list.
- */
- public List<WidgetsListBaseEntry> getDefaultWidgets() {
- return mDefaultWidgets;
- }
-
- /** Returns a list of recommended widgets. */
- public List<WidgetItem> getRecommendedWidgets() {
- HashMap<ComponentKey, WidgetItem> allWidgetItems = new HashMap<>();
- mAllWidgets.stream()
- .filter(entry -> entry instanceof WidgetsListContentEntry)
- .forEach(entry -> ((WidgetsListContentEntry) entry).mWidgets
- .forEach(widget -> allWidgetItems.put(
- new ComponentKey(widget.componentName, widget.user), widget)));
- return mRecommendedWidgets.stream()
- .map(recommendedWidget -> allWidgetItems.get(
- new ComponentKey(recommendedWidget.getTargetComponent(),
- recommendedWidget.user)))
- .filter(Objects::nonNull)
- .collect(Collectors.toList());
- }
-
- /** Returns the recommended widgets mapped by their category. */
- @NonNull
- public Map<WidgetRecommendationCategory, List<WidgetItem>> getCategorizedRecommendedWidgets() {
- Map<ComponentKey, WidgetItem> allWidgetItems = mAllWidgets.stream()
- .filter(entry -> entry instanceof WidgetsListContentEntry)
- .flatMap(entry -> entry.mWidgets.stream())
- .distinct()
- .collect(Collectors.toMap(
- widget -> new ComponentKey(widget.componentName, widget.user),
- Function.identity()
- ));
- return mRecommendedWidgets.stream()
- .filter(itemInfo -> itemInfo instanceof PendingAddWidgetInfo
- && ((PendingAddWidgetInfo) itemInfo).recommendationCategory != null)
- .collect(Collectors.groupingBy(
- it -> ((PendingAddWidgetInfo) it).recommendationCategory,
- Collectors.collectingAndThen(
- Collectors.toList(),
- list -> list.stream()
- .map(it -> allWidgetItems.get(
- new ComponentKey(it.getTargetComponent(),
- it.user)))
- .filter(Objects::nonNull)
- .collect(Collectors.toList())
- )
- ));
- }
-
- public List<WidgetItem> getWidgetsForPackageUser(PackageUserKey packageUserKey) {
- return mAllWidgets.stream()
- .filter(row -> row instanceof WidgetsListContentEntry
- && row.mPkgItem.packageName.equals(packageUserKey.mPackageName))
- .flatMap(row -> ((WidgetsListContentEntry) row).mWidgets.stream())
- .filter(widget -> packageUserKey.mUser.equals(widget.user))
- .collect(Collectors.toList());
- }
-
- /** Gets the WidgetsListContentEntry for the currently selected header. */
- public WidgetsListContentEntry getSelectedAppWidgets(PackageUserKey packageUserKey,
- boolean useDefault) {
- List<WidgetsListBaseEntry> widgets = useDefault ? mDefaultWidgets : mAllWidgets;
- return (WidgetsListContentEntry) widgets.stream()
- .filter(row -> row instanceof WidgetsListContentEntry
- && PackageUserKey.fromPackageItemInfo(row.mPkgItem).equals(packageUserKey))
- .findAny()
- .orElse(null);
- }
-
public void dump(String prefix, PrintWriter writer) {
writer.println(prefix + "PopupDataProvider:");
writer.println(prefix + "\tmPackageUserToDotInfos:" + mPackageUserToDotInfos);
}
-
- public interface PopupDataChangeListener {
-
- PopupDataChangeListener INSTANCE = new PopupDataChangeListener() { };
-
- default void onWidgetsBound() { }
-
- /** A callback to get notified when recommended widgets are bound. */
- default void onRecommendedWidgetsBound() { }
- }
}
diff --git a/src/com/android/launcher3/popup/PopupLiveUpdateHandler.java b/src/com/android/launcher3/popup/PopupLiveUpdateHandler.java
index 4c94f94..1fd3557 100644
--- a/src/com/android/launcher3/popup/PopupLiveUpdateHandler.java
+++ b/src/com/android/launcher3/popup/PopupLiveUpdateHandler.java
@@ -19,6 +19,8 @@
import android.view.View;
import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
+import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider.WidgetPickerDataChangeListener;
/**
* Utility class to handle updates while the popup is visible (like widgets and
@@ -27,7 +29,7 @@
* @param <T> The activity on which the popup shows
*/
public abstract class PopupLiveUpdateHandler<T extends Context & ActivityContext> implements
- PopupDataProvider.PopupDataChangeListener, View.OnAttachStateChangeListener {
+ WidgetPickerDataChangeListener, View.OnAttachStateChangeListener {
protected final T mContext;
protected final PopupContainerWithArrow<T> mPopupContainerWithArrow;
@@ -40,19 +42,25 @@
@Override
public void onViewAttachedToWindow(View view) {
- PopupDataProvider popupDataProvider = mContext.getPopupDataProvider();
+ WidgetPickerDataProvider widgetsDataProvider = mContext.getWidgetPickerDataProvider();
- if (popupDataProvider != null) {
- popupDataProvider.setChangeListener(this);
+ if (widgetsDataProvider != null) {
+ widgetsDataProvider.setChangeListener(this);
}
}
@Override
public void onViewDetachedFromWindow(View view) {
- PopupDataProvider popupDataProvider = mContext.getPopupDataProvider();
+ WidgetPickerDataProvider widgetsDataProvider = mContext.getWidgetPickerDataProvider();
- if (popupDataProvider != null) {
- popupDataProvider.setChangeListener(null);
+ if (widgetsDataProvider != null) {
+ widgetsDataProvider.setChangeListener(null);
}
}
+
+ @Override
+ public void onWidgetsBound() {} // NO_OP
+
+ @Override
+ public void onRecommendedWidgetsBound() {} // NO_OP
}
diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java
index 83e9810..f7e1168 100644
--- a/src/com/android/launcher3/popup/SystemShortcut.java
+++ b/src/com/android/launcher3/popup/SystemShortcut.java
@@ -5,6 +5,7 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DONT_SUGGEST_APP_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP;
+import static com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.findAllWidgetsForPackageUser;
import android.app.ActivityOptions;
import android.content.ComponentName;
@@ -28,7 +29,6 @@
import com.android.launcher3.SecondaryDropTarget;
import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.PrivateProfileManager;
-import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.UserCache;
@@ -39,9 +39,9 @@
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.widget.WidgetsBottomSheet;
+import com.android.launcher3.widget.picker.model.data.WidgetPickerData;
import java.util.Arrays;
-import java.util.List;
/**
* Represents a system shortcut for a given app. The shortcut should have a label and icon, and an
@@ -107,11 +107,12 @@
}
public static final Factory<ActivityContext> WIDGETS = (context, itemInfo, originalView) -> {
- if (itemInfo.getTargetComponent() == null) return null;
- final List<WidgetItem> widgets =
- context.getPopupDataProvider().getWidgetsForPackageUser(new PackageUserKey(
- itemInfo.getTargetComponent().getPackageName(), itemInfo.user));
- if (widgets.isEmpty()) {
+ final PackageUserKey packageUserKey = PackageUserKey.fromItemInfo(itemInfo);
+ if (packageUserKey == null) return null;
+
+ final WidgetPickerData data = context.getWidgetPickerDataProvider().get();
+ if (findAllWidgetsForPackageUser(data, packageUserKey).isEmpty()) {
+ // hides widget picker shortcut if there are no widgets for the package.
return null;
}
return new Widgets(context, itemInfo, originalView);
diff --git a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
index 0299a23..9b3292d 100644
--- a/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
+++ b/src/com/android/launcher3/secondarydisplay/SecondaryDisplayLauncher.java
@@ -59,6 +59,7 @@
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
import java.util.HashMap;
import java.util.Map;
@@ -76,6 +77,7 @@
private View mAppsButton;
private PopupDataProvider mPopupDataProvider;
+ private WidgetPickerDataProvider mWidgetPickerDataProvider;
private boolean mAppDrawerShown = false;
@@ -315,6 +317,11 @@
}
@Override
+ public WidgetPickerDataProvider getWidgetPickerDataProvider() {
+ return mWidgetPickerDataProvider;
+ }
+
+ @Override
public OnClickListener getItemOnClickListener() {
return this::onIconClicked;
}
diff --git a/src/com/android/launcher3/settings/SettingsActivity.java b/src/com/android/launcher3/settings/SettingsActivity.java
index 52ce4e8..bd9298b 100644
--- a/src/com/android/launcher3/settings/SettingsActivity.java
+++ b/src/com/android/launcher3/settings/SettingsActivity.java
@@ -44,11 +44,13 @@
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartFragmentCallback;
import androidx.preference.PreferenceFragmentCompat.OnPreferenceStartScreenCallback;
+import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceGroup.PreferencePositionCallback;
import androidx.preference.PreferenceScreen;
import androidx.recyclerview.widget.RecyclerView;
import com.android.launcher3.BuildConfig;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherFiles;
import com.android.launcher3.R;
import com.android.launcher3.states.RotationHelper;
@@ -165,6 +167,7 @@
private boolean mRestartOnResume = false;
private String mHighLightKey;
+
private boolean mPreferenceHighlighted = false;
@Override
@@ -198,11 +201,62 @@
}
}
+ // If the target preference is not in the current preference screen, find the parent
+ // preference screen that contains the target preference and set it as the preference
+ // screen.
+ if (Flags.navigateToChildPreference()
+ && mHighLightKey != null
+ && !isKeyInPreferenceGroup(mHighLightKey, screen)) {
+ final PreferenceScreen parentPreferenceScreen =
+ findParentPreference(screen, mHighLightKey);
+ if (parentPreferenceScreen != null && getActivity() != null) {
+ if (!TextUtils.isEmpty(parentPreferenceScreen.getTitle())) {
+ getActivity().setTitle(parentPreferenceScreen.getTitle());
+ }
+ setPreferenceScreen(parentPreferenceScreen);
+ return;
+ }
+ }
+
if (getActivity() != null && !TextUtils.isEmpty(getPreferenceScreen().getTitle())) {
getActivity().setTitle(getPreferenceScreen().getTitle());
}
}
+ private boolean isKeyInPreferenceGroup(String targetKey, PreferenceGroup parent) {
+ for (int i = 0; i < parent.getPreferenceCount(); i++) {
+ Preference pref = parent.getPreference(i);
+ if (pref.getKey() != null && pref.getKey().equals(targetKey)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Finds the parent preference screen for the given target key.
+ *
+ * @param parent the parent preference screen
+ * @param targetKey the key of the preference to find
+ * @return the parent preference screen that contains the target preference
+ */
+ @Nullable
+ private PreferenceScreen findParentPreference(PreferenceScreen parent, String targetKey) {
+ for (int i = 0; i < parent.getPreferenceCount(); i++) {
+ Preference pref = parent.getPreference(i);
+ if (pref instanceof PreferenceScreen) {
+ PreferenceScreen foundKey = findParentPreference((PreferenceScreen) pref,
+ targetKey);
+ if (foundKey != null) {
+ return foundKey;
+ }
+ } else if (pref.getKey() != null && pref.getKey().equals(targetKey)) {
+ return parent;
+ }
+ }
+ return null;
+ }
+
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
diff --git a/src/com/android/launcher3/util/LogConfig.java b/src/com/android/launcher3/util/LogConfig.java
index 3d4b409..f183f18 100644
--- a/src/com/android/launcher3/util/LogConfig.java
+++ b/src/com/android/launcher3/util/LogConfig.java
@@ -76,4 +76,5 @@
* When turned on, we enable zero state web data loader related logging.
*/
public static final String ZERO_WEB_DATA_LOADER = "ZeroStateWebDataLoaderLog";
+ public static final String SEARCH_TARGET_UTIL_LOG = "SearchTargetUtilLog";
}
diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java
index cfac91a..d3160e0 100644
--- a/src/com/android/launcher3/views/ActivityContext.java
+++ b/src/com/android/launcher3/views/ActivityContext.java
@@ -81,6 +81,7 @@
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SplitConfigurationOptions;
import com.android.launcher3.util.ViewCache;
+import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
import java.util.List;
@@ -266,6 +267,14 @@
return null;
}
+ /**
+ * Returns the {@link WidgetPickerDataProvider} that can be used to read widgets for display.
+ */
+ @Nullable
+ default WidgetPickerDataProvider getWidgetPickerDataProvider() {
+ return null;
+ }
+
@Nullable
default StringCache getStringCache() {
return null;
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index c59e295..1c0d94c 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -45,13 +45,13 @@
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.R;
import com.android.launcher3.model.WidgetItem;
-import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.util.SystemUiController;
import com.android.launcher3.util.Themes;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.views.AbstractSlideInView;
+import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider.WidgetPickerDataChangeListener;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -60,7 +60,7 @@
*/
public abstract class BaseWidgetSheet extends AbstractSlideInView<BaseActivity>
implements OnClickListener, OnLongClickListener,
- PopupDataProvider.PopupDataChangeListener, Insettable, OnDeviceProfileChangeListener {
+ WidgetPickerDataChangeListener, Insettable, OnDeviceProfileChangeListener {
/** The default number of cells that can fit horizontally in a widget sheet. */
public static final int DEFAULT_MAX_HORIZONTAL_SPANS = 4;
@@ -106,14 +106,14 @@
WindowInsets windowInsets = WindowManagerProxy.INSTANCE.get(getContext())
.normalizeWindowInsets(getContext(), getRootWindowInsets(), new Rect());
mNavBarScrimHeight = getNavBarScrimHeight(windowInsets);
- mActivityContext.getPopupDataProvider().setChangeListener(this);
+ mActivityContext.getWidgetPickerDataProvider().setChangeListener(this);
mActivityContext.addOnDeviceProfileChangeListener(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- mActivityContext.getPopupDataProvider().setChangeListener(null);
+ mActivityContext.getWidgetPickerDataProvider().setChangeListener(null);
mActivityContext.removeOnDeviceProfileChangeListener(this);
}
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 894099d..ddbd291 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -17,6 +17,7 @@
package com.android.launcher3.widget;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_BOTTOM_WIDGETS_TRAY;
+import static com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.findAllWidgetsForPackageUser;
import android.content.Context;
import android.graphics.Rect;
@@ -40,6 +41,7 @@
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.widget.picker.model.data.WidgetPickerData;
import com.android.launcher3.widget.util.WidgetsTableUtils;
import java.util.List;
@@ -124,10 +126,10 @@
@Override
public void onWidgetsBound() {
- List<WidgetItem> widgets = mActivityContext.getPopupDataProvider().getWidgetsForPackageUser(
- new PackageUserKey(
- mOriginalItemInfo.getTargetComponent().getPackageName(),
- mOriginalItemInfo.user));
+ final WidgetPickerData data = mActivityContext.getWidgetPickerDataProvider().get();
+ final PackageUserKey packageUserKey = PackageUserKey.fromItemInfo(mOriginalItemInfo);
+ List<WidgetItem> widgets = packageUserKey != null ? findAllWidgetsForPackageUser(data,
+ packageUserKey) : List.of();
TableLayout widgetsTable = findViewById(R.id.widgets_table);
widgetsTable.removeAllViews();
@@ -247,4 +249,7 @@
}
}
}
+
+ @Override
+ public void onRecommendedWidgetsBound() {} // no op
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategory.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategory.java
index 072d1d5..a68effd 100644
--- a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategory.java
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategory.java
@@ -19,6 +19,8 @@
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
+import com.android.launcher3.R;
+
import java.util.Objects;
/**
@@ -26,6 +28,10 @@
* option in the pop-up opened on long press of launcher workspace).
*/
public class WidgetRecommendationCategory implements Comparable<WidgetRecommendationCategory> {
+ public static WidgetRecommendationCategory DEFAULT_WIDGET_RECOMMENDATION_CATEGORY =
+ new WidgetRecommendationCategory(
+ R.string.others_widget_recommendation_category_label, /*order=*/0);
+
/** Resource id that holds the user friendly label for the category. */
@StringRes
public final int categoryTitleRes;
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 21b7be4..2af8e6f 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -74,6 +74,7 @@
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -471,7 +472,7 @@
* Returns all displayable widgets.
*/
protected List<WidgetsListBaseEntry> getWidgetsToDisplay() {
- return mActivityContext.getPopupDataProvider().getAllWidgets();
+ return mActivityContext.getWidgetPickerDataProvider().get().getAllWidgets();
}
@Override
@@ -572,12 +573,11 @@
if (mIsInSearchMode) {
return;
}
-
if (enableCategorizedWidgetSuggestions()) {
// We avoid applying new recommendations when some are already displayed.
if (mRecommendedWidgetsMap.isEmpty()) {
mRecommendedWidgetsMap =
- mActivityContext.getPopupDataProvider().getCategorizedRecommendedWidgets();
+ mActivityContext.getWidgetPickerDataProvider().get().getRecommendations();
}
mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations(
mRecommendedWidgetsMap,
@@ -589,17 +589,20 @@
);
} else {
if (mRecommendedWidgets.isEmpty()) {
- mRecommendedWidgets =
- mActivityContext.getPopupDataProvider().getRecommendedWidgets();
+ mRecommendedWidgets = mActivityContext.getWidgetPickerDataProvider().get()
+ .getRecommendations()
+ .values().stream()
+ .flatMap(Collection::stream).toList();
+ mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations(
+ mRecommendedWidgets,
+ mDeviceProfile,
+ /* availableHeight= */ getMaxAvailableHeightForRecommendations(),
+ /* availableWidth= */ mMaxSpanPerRow,
+ /* cellPadding= */ mWidgetCellHorizontalPadding
+ );
}
- mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations(
- mRecommendedWidgets,
- mDeviceProfile,
- /* availableHeight= */ getMaxAvailableHeightForRecommendations(),
- /* availableWidth= */ mMaxSpanPerRow,
- /* cellPadding= */ mWidgetCellHorizontalPadding
- );
}
+
mWidgetRecommendationsContainer.setVisibility(
mRecommendedWidgetsCount > 0 ? VISIBLE : GONE);
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index c4c755a..c2cd903 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree;
import static com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree;
import static com.android.launcher3.widget.picker.WidgetsListItemAnimator.WIDGET_LIST_ITEM_APPEARANCE_DELAY;
+import static com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.findContentEntryForPackageUser;
import android.content.Context;
import android.graphics.Rect;
@@ -287,9 +288,9 @@
@Override
protected List<WidgetsListBaseEntry> getWidgetsToDisplay() {
List<WidgetsListBaseEntry> allWidgets =
- mActivityContext.getPopupDataProvider().getAllWidgets();
+ mActivityContext.getWidgetPickerDataProvider().get().getAllWidgets();
List<WidgetsListBaseEntry> defaultWidgets =
- mActivityContext.getPopupDataProvider().getDefaultWidgets();
+ mActivityContext.getWidgetPickerDataProvider().get().getDefaultWidgets();
if (allWidgets.isEmpty() || defaultWidgets.isEmpty()) {
// no menu if there are no default widgets to show
@@ -359,7 +360,7 @@
WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create(
packageItemInfo,
/*titleSectionName=*/ suggestionsHeaderTitle,
- /*items=*/ mActivityContext.getPopupDataProvider().getRecommendedWidgets(),
+ /*items=*/ List.of(), // not necessary
/*visibleWidgetsCount=*/ 0)
.withWidgetListShown();
@@ -509,11 +510,11 @@
final boolean isUserClick = mSelectedHeader != null
&& !getAccessibilityInitialFocusView().isAccessibilityFocused();
mSelectedHeader = selectedHeader;
- WidgetsListContentEntry contentEntry =
- mActivityContext.getPopupDataProvider().getSelectedAppWidgets(
- selectedHeader, /*useDefault=*/
- (mWidgetOptionsMenuState != null
- && !mWidgetOptionsMenuState.showAllWidgets));
+ final boolean showDefaultWidgets = mWidgetOptionsMenuState != null
+ && !mWidgetOptionsMenuState.showAllWidgets;
+ WidgetsListContentEntry contentEntry = findContentEntryForPackageUser(
+ mActivityContext.getWidgetPickerDataProvider().get(),
+ selectedHeader, showDefaultWidgets);
if (contentEntry == null || mRightPane == null) {
return;
diff --git a/src/com/android/launcher3/widget/picker/model/WidgetPickerDataProvider.kt b/src/com/android/launcher3/widget/picker/model/WidgetPickerDataProvider.kt
new file mode 100644
index 0000000..46d3e7a
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/model/WidgetPickerDataProvider.kt
@@ -0,0 +1,84 @@
+/*
+ * 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.widget.picker.model
+
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.widget.model.WidgetsListBaseEntry
+import com.android.launcher3.widget.picker.model.data.WidgetPickerData
+import com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.withRecommendedWidgets
+import com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.withWidgets
+import java.io.PrintWriter
+
+/**
+ * Provides [WidgetPickerData] to various views such as widget picker, app-specific widget picker,
+ * widgets shortcut.
+ */
+class WidgetPickerDataProvider {
+ /** All the widgets data provided for the views */
+ private var mWidgetPickerData: WidgetPickerData = WidgetPickerData()
+
+ private var changeListener: WidgetPickerDataChangeListener? = null
+
+ /** Sets a listener to be called back when widget data is updated. */
+ fun setChangeListener(changeListener: WidgetPickerDataChangeListener?) {
+ this.changeListener = changeListener
+ }
+
+ /** Returns the current snapshot of [WidgetPickerData]. */
+ fun get(): WidgetPickerData {
+ return mWidgetPickerData
+ }
+
+ /**
+ * Updates the widgets available to the widget picker.
+ *
+ * Generally called when the widgets model has new data.
+ */
+ @JvmOverloads
+ fun setWidgets(
+ allWidgets: List<WidgetsListBaseEntry>,
+ defaultWidgets: List<WidgetsListBaseEntry> = listOf()
+ ) {
+ mWidgetPickerData =
+ mWidgetPickerData.withWidgets(allWidgets = allWidgets, defaultWidgets = defaultWidgets)
+ changeListener?.onWidgetsBound()
+ }
+
+ /**
+ * Makes the widget recommendations available to the widget picker
+ *
+ * Generally called when new widget predictions are available.
+ */
+ fun setWidgetRecommendations(recommendations: List<ItemInfo>) {
+ mWidgetPickerData = mWidgetPickerData.withRecommendedWidgets(recommendations)
+ changeListener?.onRecommendedWidgetsBound()
+ }
+
+ /** Writes the current state to the provided writer. */
+ fun dump(prefix: String, writer: PrintWriter) {
+ writer.println(prefix + "WidgetPickerDataProvider:")
+ writer.println("$prefix\twidgetPickerData:$mWidgetPickerData")
+ }
+
+ interface WidgetPickerDataChangeListener {
+ /** A callback to get notified when widgets are bound. */
+ fun onWidgetsBound()
+
+ /** A callback to get notified when recommended widgets are bound. */
+ fun onRecommendedWidgetsBound()
+ }
+}
diff --git a/src/com/android/launcher3/widget/picker/model/data/WidgetPickerData.kt b/src/com/android/launcher3/widget/picker/model/data/WidgetPickerData.kt
new file mode 100644
index 0000000..3332ef0
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/model/data/WidgetPickerData.kt
@@ -0,0 +1,110 @@
+/*
+ * 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.widget.picker.model.data
+
+import com.android.launcher3.model.WidgetItem
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.util.ComponentKey
+import com.android.launcher3.util.PackageUserKey
+import com.android.launcher3.widget.PendingAddWidgetInfo
+import com.android.launcher3.widget.model.WidgetsListBaseEntry
+import com.android.launcher3.widget.model.WidgetsListContentEntry
+import com.android.launcher3.widget.picker.WidgetRecommendationCategory
+import com.android.launcher3.widget.picker.WidgetRecommendationCategory.DEFAULT_WIDGET_RECOMMENDATION_CATEGORY
+
+// This file contains WidgetPickerData and utility functions to operate on it.
+
+/** Widget data for display in the widget picker. */
+data class WidgetPickerData(
+ val allWidgets: List<WidgetsListBaseEntry> = listOf(),
+ val defaultWidgets: List<WidgetsListBaseEntry> = listOf(),
+ val recommendations: Map<WidgetRecommendationCategory, List<WidgetItem>> = mapOf(),
+)
+
+/** Provides utility methods to work with a [WidgetPickerData] object. */
+object WidgetPickerDataUtils {
+ /**
+ * Returns a [WidgetPickerData] with the provided widgets.
+ *
+ * When [defaultWidgets] is not passed, defaults from previous object are not copied over.
+ * Defaults (if supported) should be updated when all widgets are updated.
+ */
+ fun WidgetPickerData.withWidgets(
+ allWidgets: List<WidgetsListBaseEntry>,
+ defaultWidgets: List<WidgetsListBaseEntry> = listOf()
+ ): WidgetPickerData {
+ return copy(allWidgets = allWidgets, defaultWidgets = defaultWidgets)
+ }
+
+ /** Returns a [WidgetPickerData] with the given recommendations set. */
+ fun WidgetPickerData.withRecommendedWidgets(recommendations: List<ItemInfo>): WidgetPickerData {
+ val allWidgetsMap: Map<ComponentKey, WidgetItem> =
+ allWidgets
+ .filterIsInstance<WidgetsListContentEntry>()
+ .flatMap { it.mWidgets }
+ .filterNotNull()
+ .distinct()
+ .associateBy { it } // as ComponentKey
+
+ val categoriesMap =
+ recommendations
+ .filterIsInstance<PendingAddWidgetInfo>()
+ .filter { allWidgetsMap.containsKey(ComponentKey(it.targetComponent, it.user)) }
+ .groupBy { it.recommendationCategory ?: DEFAULT_WIDGET_RECOMMENDATION_CATEGORY }
+ .mapValues { (_, pendingAddWidgetInfos) ->
+ pendingAddWidgetInfos.map {
+ allWidgetsMap[ComponentKey(it.targetComponent, it.user)] as WidgetItem
+ }
+ }
+
+ return copy(recommendations = categoriesMap)
+ }
+
+ /** Finds all [WidgetItem]s available for the provided package user. */
+ @JvmStatic
+ fun findAllWidgetsForPackageUser(
+ widgetPickerData: WidgetPickerData,
+ packageUserKey: PackageUserKey
+ ): List<WidgetItem> {
+ return findContentEntryForPackageUser(widgetPickerData, packageUserKey)?.mWidgets
+ ?: emptyList()
+ }
+
+ /**
+ * Finds and returns the [WidgetsListContentEntry] for the given package user.
+ *
+ * Set [fromDefaultWidgets] to true to limit the content entry to default widgets.
+ */
+ @JvmOverloads
+ @JvmStatic
+ fun findContentEntryForPackageUser(
+ widgetPickerData: WidgetPickerData,
+ packageUserKey: PackageUserKey,
+ fromDefaultWidgets: Boolean = false
+ ): WidgetsListContentEntry? {
+ val widgetsListBaseEntries =
+ if (fromDefaultWidgets) {
+ widgetPickerData.defaultWidgets
+ } else {
+ widgetPickerData.allWidgets
+ }
+
+ return widgetsListBaseEntries.filterIsInstance<WidgetsListContentEntry>().firstOrNull {
+ PackageUserKey.fromPackageItemInfo(it.mPkgItem) == packageUserKey
+ }
+ }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/UtilitiesTest.kt b/tests/multivalentTests/src/com/android/launcher3/UtilitiesTest.kt
index 5a26087..d0aa7a8 100644
--- a/tests/multivalentTests/src/com/android/launcher3/UtilitiesTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/UtilitiesTest.kt
@@ -376,9 +376,10 @@
Utilities.rotateBounds(rect, 100, 100, 1)
assertEquals(Rect(70, 40, 80, 80), rect)
- rect = Rect(20, 70, 60, 80)
- Utilities.rotateBounds(rect, 100, 100, 2)
- assertEquals(Rect(40, 20, 80, 30), rect)
+ // case removed for b/28435189
+ // rect = Rect(20, 70, 60, 80)
+ // Utilities.rotateBounds(rect, 100, 100, 2)
+ // assertEquals(Rect(40, 20, 80, 30), rect)
rect = Rect(20, 70, 60, 80)
Utilities.rotateBounds(rect, 100, 100, 3)
diff --git a/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTests.kt b/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTests.kt
new file mode 100644
index 0000000..ac2c553
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/allapps/FloatingHeaderViewTests.kt
@@ -0,0 +1,92 @@
+/*
+ * 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.allapps
+
+import android.content.Context
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.Flags
+import com.android.launcher3.util.ActivityContextWrapper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class FloatingHeaderViewTests {
+
+ @get:Rule val mSetFlagsRule = SetFlagsRule()
+
+ private lateinit var context: Context
+ private lateinit var vut: FloatingHeaderView
+
+ @Before
+ fun setUp() {
+ context = ActivityContextWrapper(getApplicationContext())
+ // TODO(b/352161553): Inflate FloatingHeaderView or R.layout.all_apps_content with proper
+ // FloatingHeaderView#setup
+ vut = FloatingHeaderView(context)
+ vut.onFinishInflate()
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_FLOATING_SEARCH_BAR, Flags.FLAG_MULTILINE_SEARCH_BAR)
+ fun onHeightUpdated_whenNotMultiline_thenZeroHeight() {
+ vut.setFloatingRowsCollapsed(true)
+ val beforeHeight = vut.maxTranslation
+ vut.updateSearchBarOffset(HEADER_HEIGHT_OFFSET)
+
+ vut.onHeightUpdated()
+
+ assertThat(vut.maxTranslation).isEqualTo(beforeHeight)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_MULTILINE_SEARCH_BAR)
+ @DisableFlags(Flags.FLAG_FLOATING_SEARCH_BAR)
+ fun onHeightUpdated_whenMultiline_thenHeightIsOffset() {
+ vut.setFloatingRowsCollapsed(true)
+ vut.updateSearchBarOffset(HEADER_HEIGHT_OFFSET)
+
+ vut.onHeightUpdated()
+
+ assertThat(vut.maxTranslation).isEqualTo(HEADER_HEIGHT_OFFSET)
+ }
+
+ @Test
+ @DisableFlags(Flags.FLAG_MULTILINE_SEARCH_BAR)
+ @EnableFlags(Flags.FLAG_FLOATING_SEARCH_BAR)
+ fun onHeightUpdated_whenFloatingRowsShownAndNotMultiline_thenAddsOnlyFloatingRow() {
+ // Collapse floating rows and expand to trigger header height calculation
+ vut.setFloatingRowsCollapsed(true)
+ vut.setFloatingRowsCollapsed(false)
+ val defaultHeight = vut.maxTranslation
+ vut.updateSearchBarOffset(HEADER_HEIGHT_OFFSET)
+
+ vut.onHeightUpdated()
+
+ assertThat(vut.maxTranslation).isEqualTo(defaultHeight)
+ }
+
+ companion object {
+ private const val HEADER_HEIGHT_OFFSET = 50
+ }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutMethodsTest.kt b/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutMethodsTest.kt
index e8459d6..5bc57b0 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutMethodsTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutMethodsTest.kt
@@ -16,17 +16,15 @@
package com.android.launcher3.celllayout
-import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Rule
import org.junit.Test
-import org.junit.runner.RunWith
-@RunWith(AndroidJUnit4::class)
+// @RunWith(AndroidJUnit4::class) b/353965234
class CellLayoutMethodsTest {
@JvmField @Rule var cellLayoutBuilder = UnitTestCellLayoutBuilderRule()
- @Test
+ //@Test
fun pointToCellExact() {
val width = 1000
val height = 1000
diff --git a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java b/tests/multivalentTests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
similarity index 95%
rename from tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
rename to tests/multivalentTests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
index 260f556..6cfa6ee 100644
--- a/tests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/touch/SingleAxisSwipeDetectorTest.java
@@ -22,9 +22,9 @@
import static com.android.launcher3.touch.SingleAxisSwipeDetector.VERTICAL;
import static org.junit.Assert.assertTrue;
-import static org.mockito.Matchers.any;
-import static org.mockito.Matchers.anyBoolean;
-import static org.mockito.Matchers.anyFloat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.never;
@@ -41,6 +41,8 @@
import com.android.launcher3.testcomponent.TouchEventGenerator;
+import com.google.errorprone.annotations.FormatMethod;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,7 +54,8 @@
public class SingleAxisSwipeDetectorTest {
private static final String TAG = SingleAxisSwipeDetectorTest.class.getSimpleName();
- public static void L(String s, Object... parts) {
+ @FormatMethod
+ public static void logD(String s, Object... parts) {
Log.d(TAG, (parts.length == 0) ? s : String.format(s, parts));
}
@@ -82,7 +85,7 @@
mTouchSlop = orgConfig.getScaledTouchSlop();
doReturn(mTouchSlop).when(mMockConfig).getScaledTouchSlop();
- L("mTouchSlop=", mTouchSlop);
+ logD("mTouchSlop= %s", mTouchSlop);
}
@Test
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt
index 1de99c5..d3e27b6 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt
@@ -23,6 +23,7 @@
import android.os.Looper
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
import com.google.common.truth.Truth.assertThat
import java.util.function.Consumer
@@ -114,6 +115,7 @@
underTest = SimpleBroadcastReceiver(Handler(Looper.getMainLooper()), intentConsumer)
underTest.register(context, completionRunnable, 1, "test_action_1", "test_action_2")
+ getInstrumentation().waitForIdleSync()
verify(context).registerReceiver(same(underTest), intentFilterCaptor.capture(), eq(1))
verify(completionRunnable).run()
@@ -136,6 +138,7 @@
underTest = SimpleBroadcastReceiver(Handler(Looper.getMainLooper()), intentConsumer)
underTest.unregisterReceiverSafely(context)
+ getInstrumentation().waitForIdleSync()
verify(context).unregisterReceiver(same(underTest))
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/TestSandboxModelContextWrapper.java b/tests/multivalentTests/src/com/android/launcher3/util/TestSandboxModelContextWrapper.java
index 3f37563..71637f1 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/TestSandboxModelContextWrapper.java
+++ b/tests/multivalentTests/src/com/android/launcher3/util/TestSandboxModelContextWrapper.java
@@ -32,6 +32,7 @@
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
@@ -57,6 +58,8 @@
protected ActivityAllAppsContainerView<ActivityContextWrapper> mAppsView;
private final PopupDataProvider mPopupDataProvider = new PopupDataProvider(i -> {});
+ private final WidgetPickerDataProvider mWidgetPickerDataProvider =
+ new WidgetPickerDataProvider();
protected final UserCache mUserCache;
public TestSandboxModelContextWrapper(SandboxContext base) {
@@ -76,12 +79,19 @@
mAppsList = mAppsView.getPersonalAppList();
mAllAppsStore = mAppsView.getAppsStore();
}
+
@Nullable
@Override
public PopupDataProvider getPopupDataProvider() {
return mPopupDataProvider;
}
+ @Nullable
+ @Override
+ public WidgetPickerDataProvider getWidgetPickerDataProvider() {
+ return mWidgetPickerDataProvider;
+ }
+
@Override
public ActivityAllAppsContainerView<ActivityContextWrapper> getAppsView() {
return mAppsView;
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/picker/model/WidgetPickerDataProviderTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/picker/model/WidgetPickerDataProviderTest.kt
new file mode 100644
index 0000000..1822639
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/picker/model/WidgetPickerDataProviderTest.kt
@@ -0,0 +1,170 @@
+/*
+ * 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.widget.picker.model
+
+import android.content.ComponentName
+import android.content.Context
+import android.os.UserHandle
+import android.platform.test.rule.AllowedDevices
+import android.platform.test.rule.DeviceProduct
+import android.platform.test.rule.LimitDevicesRule
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.icons.ComponentWithLabel
+import com.android.launcher3.icons.IconCache
+import com.android.launcher3.model.WidgetItem
+import com.android.launcher3.model.data.PackageItemInfo
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.WidgetUtils
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
+import com.android.launcher3.widget.PendingAddWidgetInfo
+import com.android.launcher3.widget.model.WidgetsListBaseEntry
+import com.android.launcher3.widget.model.WidgetsListContentEntry
+import com.android.launcher3.widget.model.WidgetsListHeaderEntry
+import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider.WidgetPickerDataChangeListener
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.invocation.InvocationOnMock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.times
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.verifyNoMoreInteractions
+
+// Tests for the WidgetPickerDataProvider class
+
+@RunWith(AndroidJUnit4::class)
+@AllowedDevices(allowed = [DeviceProduct.ROBOLECTRIC])
+class WidgetPickerDataProviderTest {
+ @Rule @JvmField val limitDevicesRule = LimitDevicesRule()
+ @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var changeListener: WidgetPickerDataChangeListener
+
+ @Mock private lateinit var iconCache: IconCache
+
+ private lateinit var userHandle: UserHandle
+ private lateinit var context: Context
+ private lateinit var testInvariantProfile: InvariantDeviceProfile
+
+ private lateinit var appWidgetItem: WidgetItem
+
+ private var underTest = WidgetPickerDataProvider()
+
+ @Before
+ fun setUp() {
+ userHandle = UserHandle.CURRENT
+ context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+ testInvariantProfile = LauncherAppState.getIDP(context)
+
+ doAnswer { invocation: InvocationOnMock ->
+ val componentWithLabel = invocation.getArgument<Any>(0) as ComponentWithLabel
+ componentWithLabel.getComponent().shortClassName
+ }
+ .`when`(iconCache)
+ .getTitleNoCache(any<ComponentWithLabel>())
+
+ appWidgetItem = createWidgetItem()
+ }
+
+ @Test
+ fun setWidgets_invokesTheListener_andUpdatedWidgetsAvailable() {
+ assertThat(underTest.get().allWidgets).isEmpty()
+
+ underTest.setChangeListener(changeListener)
+ val allWidgets = appWidgetListBaseEntries()
+ underTest.setWidgets(allWidgets = allWidgets)
+
+ assertThat(underTest.get().allWidgets).containsExactlyElementsIn(allWidgets)
+ verify(changeListener, times(1)).onWidgetsBound()
+ verifyNoMoreInteractions(changeListener)
+ }
+
+ @Test
+ fun setWidgetRecommendations_callsBackTheListener_andUpdatedRecommendationsAvailable() {
+ underTest.setWidgets(allWidgets = appWidgetListBaseEntries())
+ assertThat(underTest.get().recommendations).isEmpty()
+
+ underTest.setChangeListener(changeListener)
+ val recommendations =
+ listOf(
+ PendingAddWidgetInfo(
+ appWidgetItem.widgetInfo,
+ LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION
+ ),
+ )
+ underTest.setWidgetRecommendations(recommendations)
+
+ assertThat(underTest.get().recommendations).hasSize(1)
+ verify(changeListener, times(1)).onRecommendedWidgetsBound()
+ verifyNoMoreInteractions(changeListener)
+ }
+
+ @Test
+ fun setChangeListener_null_noCallback() {
+ underTest.setChangeListener(changeListener)
+ underTest.setChangeListener(null) // reset
+
+ underTest.setWidgets(allWidgets = appWidgetListBaseEntries())
+ val recommendations =
+ listOf(
+ PendingAddWidgetInfo(
+ appWidgetItem.widgetInfo,
+ LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION
+ ),
+ )
+ underTest.setWidgetRecommendations(recommendations)
+
+ verifyNoMoreInteractions(changeListener)
+ }
+
+ private fun createWidgetItem(): WidgetItem {
+ val providerInfo =
+ WidgetUtils.createAppWidgetProviderInfo(
+ ComponentName.createRelative(APP_PACKAGE_NAME, APP_PROVIDER_1_CLASS_NAME)
+ )
+ val widgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(context, providerInfo)
+ return WidgetItem(widgetInfo, testInvariantProfile, iconCache, context)
+ }
+
+ private fun appWidgetListBaseEntries(): List<WidgetsListBaseEntry> {
+ val packageItemInfo = PackageItemInfo(APP_PACKAGE_NAME, userHandle)
+ packageItemInfo.title = APP_PACKAGE_TITLE
+ val widgets = listOf(appWidgetItem)
+
+ return buildList {
+ add(WidgetsListHeaderEntry.create(packageItemInfo, APP_SECTION_NAME, widgets))
+ add(WidgetsListContentEntry(packageItemInfo, APP_SECTION_NAME, widgets))
+ }
+ }
+
+ companion object {
+ const val APP_PACKAGE_NAME = "com.example.app"
+ const val APP_PACKAGE_TITLE = "SomeApp"
+ const val APP_SECTION_NAME = "S" // for fast popup
+ const val APP_PROVIDER_1_CLASS_NAME = "appProvider1"
+ }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/picker/model/data/WidgetPickerDataTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/picker/model/data/WidgetPickerDataTest.kt
new file mode 100644
index 0000000..e59e211
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/picker/model/data/WidgetPickerDataTest.kt
@@ -0,0 +1,379 @@
+/*
+ * 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.widget.picker.model.data
+
+import android.content.ComponentName
+import android.content.Context
+import android.os.UserHandle
+import android.platform.test.rule.AllowedDevices
+import android.platform.test.rule.DeviceProduct
+import android.platform.test.rule.LimitDevicesRule
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION
+import com.android.launcher3.icons.ComponentWithLabel
+import com.android.launcher3.icons.IconCache
+import com.android.launcher3.model.WidgetItem
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.PackageItemInfo
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.PackageUserKey
+import com.android.launcher3.util.WidgetUtils
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
+import com.android.launcher3.widget.PendingAddWidgetInfo
+import com.android.launcher3.widget.model.WidgetsListBaseEntry
+import com.android.launcher3.widget.model.WidgetsListContentEntry
+import com.android.launcher3.widget.model.WidgetsListHeaderEntry
+import com.android.launcher3.widget.picker.WidgetRecommendationCategory
+import com.android.launcher3.widget.picker.WidgetRecommendationCategory.DEFAULT_WIDGET_RECOMMENDATION_CATEGORY
+import com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.findAllWidgetsForPackageUser
+import com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.findContentEntryForPackageUser
+import com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.withRecommendedWidgets
+import com.android.launcher3.widget.picker.model.data.WidgetPickerDataUtils.withWidgets
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.invocation.InvocationOnMock
+import org.mockito.junit.MockitoJUnit
+import org.mockito.junit.MockitoRule
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doAnswer
+
+// Tests for code / classes in WidgetPickerData file.
+
+@RunWith(AndroidJUnit4::class)
+@AllowedDevices(allowed = [DeviceProduct.ROBOLECTRIC])
+class WidgetPickerDataTest {
+ @Rule @JvmField val limitDevicesRule = LimitDevicesRule()
+ @Rule @JvmField val mockitoRule: MockitoRule = MockitoJUnit.rule()
+
+ @Mock private lateinit var iconCache: IconCache
+
+ private lateinit var userHandle: UserHandle
+ private lateinit var context: Context
+ private lateinit var testInvariantProfile: InvariantDeviceProfile
+
+ private lateinit var app1PackageItemInfo: PackageItemInfo
+ private lateinit var app2PackageItemInfo: PackageItemInfo
+
+ private lateinit var app1WidgetItem1: WidgetItem
+ private lateinit var app1WidgetItem2: WidgetItem
+ private lateinit var app2WidgetItem1: WidgetItem
+
+ @Before
+ fun setUp() {
+ userHandle = UserHandle.CURRENT
+ context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+ testInvariantProfile = LauncherAppState.getIDP(context)
+
+ doAnswer { invocation: InvocationOnMock ->
+ val componentWithLabel = invocation.getArgument<Any>(0) as ComponentWithLabel
+ componentWithLabel.getComponent().shortClassName
+ }
+ .`when`(iconCache)
+ .getTitleNoCache(any<ComponentWithLabel>())
+
+ app1PackageItemInfo = packageItemInfoWithTitle(APP_1_PACKAGE_NAME, APP_1_PACKAGE_TITLE)
+ app2PackageItemInfo = packageItemInfoWithTitle(APP_2_PACKAGE_NAME, APP_2_PACKAGE_TITLE)
+
+ app1WidgetItem1 = createWidgetItem(APP_1_PACKAGE_NAME, APP_1_PROVIDER_1_CLASS_NAME)
+ app1WidgetItem2 = createWidgetItem(APP_1_PACKAGE_NAME, APP_1_PROVIDER_2_CLASS_NAME)
+ app2WidgetItem1 = createWidgetItem(APP_2_PACKAGE_NAME, APP_2_PROVIDER_1_CLASS_NAME)
+ }
+
+ @Test
+ fun withWidgets_returnsACopyWithProvidedWidgets() {
+ // only app two
+ val widgetPickerData = WidgetPickerData(allWidgets = appTwoWidgetsListBaseEntries())
+
+ // update: only app 1 and default list set
+ val newAllWidgets: List<WidgetsListBaseEntry> =
+ appOneWidgetsListBaseEntries(includeWidgetTwo = true)
+ val newDefaultWidgets: List<WidgetsListBaseEntry> =
+ appOneWidgetsListBaseEntries(includeWidgetTwo = false)
+
+ val newWidgetData = widgetPickerData.withWidgets(newAllWidgets, newDefaultWidgets)
+
+ assertThat(newWidgetData.allWidgets).containsExactlyElementsIn(newAllWidgets)
+ assertThat(newWidgetData.defaultWidgets).containsExactlyElementsIn(newDefaultWidgets)
+ }
+
+ @Test
+ fun withWidgets_noExplicitDefaults_unsetsOld() {
+ // only app two
+ val widgetPickerData =
+ WidgetPickerData(
+ allWidgets = appTwoWidgetsListBaseEntries(),
+ defaultWidgets = appTwoWidgetsListBaseEntries()
+ )
+
+ val newWidgetData =
+ widgetPickerData.withWidgets(allWidgets = appOneWidgetsListBaseEntries())
+
+ assertThat(newWidgetData.allWidgets)
+ .containsExactlyElementsIn(appOneWidgetsListBaseEntries())
+ assertThat(newWidgetData.defaultWidgets).isEmpty() // previous values cleared.
+ }
+
+ @Test
+ fun withRecommendedWidgets_returnsACopyWithProvidedRecommendedWidgets() {
+ val widgetPickerData =
+ WidgetPickerData(
+ allWidgets =
+ buildList {
+ addAll(appOneWidgetsListBaseEntries())
+ addAll(appTwoWidgetsListBaseEntries())
+ },
+ defaultWidgets = buildList { appTwoWidgetsListBaseEntries() }
+ )
+ val recommendations: List<ItemInfo> =
+ listOf(
+ PendingAddWidgetInfo(
+ app1WidgetItem1.widgetInfo,
+ CONTAINER_WIDGETS_PREDICTION,
+ CATEGORY_1
+ ),
+ PendingAddWidgetInfo(
+ app2WidgetItem1.widgetInfo,
+ CONTAINER_WIDGETS_PREDICTION,
+ CATEGORY_2
+ ),
+ )
+
+ val updatedData = widgetPickerData.withRecommendedWidgets(recommendations)
+
+ assertThat(updatedData.recommendations.keys).containsExactly(CATEGORY_1, CATEGORY_2)
+ assertThat(updatedData.recommendations[CATEGORY_1]).containsExactly(app1WidgetItem1)
+ assertThat(updatedData.recommendations[CATEGORY_2]).containsExactly(app2WidgetItem1)
+ }
+
+ @Test
+ fun withRecommendedWidgets_noCategory_usesDefault() {
+ val widgetPickerData =
+ WidgetPickerData(
+ allWidgets =
+ buildList {
+ addAll(appOneWidgetsListBaseEntries())
+ addAll(appTwoWidgetsListBaseEntries())
+ },
+ defaultWidgets = buildList { appTwoWidgetsListBaseEntries() }
+ )
+ val recommendations: List<ItemInfo> =
+ listOf(
+ PendingAddWidgetInfo(app1WidgetItem1.widgetInfo, CONTAINER_WIDGETS_PREDICTION),
+ PendingAddWidgetInfo(app2WidgetItem1.widgetInfo, CONTAINER_WIDGETS_PREDICTION),
+ )
+
+ val updatedData = widgetPickerData.withRecommendedWidgets(recommendations)
+
+ assertThat(updatedData.recommendations.keys)
+ .containsExactly(DEFAULT_WIDGET_RECOMMENDATION_CATEGORY)
+ assertThat(updatedData.recommendations[DEFAULT_WIDGET_RECOMMENDATION_CATEGORY])
+ .containsExactly(app1WidgetItem1, app2WidgetItem1)
+ }
+
+ @Test
+ fun withRecommendedWidgets_emptyRecommendations_clearsOld() {
+ val widgetPickerData =
+ WidgetPickerData(
+ allWidgets =
+ buildList {
+ addAll(appOneWidgetsListBaseEntries())
+ addAll(appTwoWidgetsListBaseEntries())
+ },
+ defaultWidgets = buildList { appTwoWidgetsListBaseEntries() },
+ recommendations = mapOf(CATEGORY_1 to listOf(app1WidgetItem1))
+ )
+
+ val updatedData = widgetPickerData.withRecommendedWidgets(listOf())
+
+ assertThat(updatedData.recommendations).isEmpty()
+ }
+
+ @Test
+ fun withRecommendedWidgets_widgetNotInAllWidgets_filteredOut() {
+ val widgetPickerData =
+ WidgetPickerData(
+ allWidgets =
+ buildList {
+ addAll(appOneWidgetsListBaseEntries(includeWidgetTwo = false))
+ addAll(appTwoWidgetsListBaseEntries())
+ },
+ defaultWidgets = buildList { appTwoWidgetsListBaseEntries() },
+ )
+
+ val recommendations: List<ItemInfo> =
+ listOf(
+ PendingAddWidgetInfo(app1WidgetItem2.widgetInfo, CONTAINER_WIDGETS_PREDICTION),
+ PendingAddWidgetInfo(app2WidgetItem1.widgetInfo, CONTAINER_WIDGETS_PREDICTION),
+ )
+ val updatedData = widgetPickerData.withRecommendedWidgets(recommendations)
+
+ assertThat(updatedData.recommendations).hasSize(1)
+ // no app1widget2
+ assertThat(updatedData.recommendations.values.first()).containsExactly(app2WidgetItem1)
+ }
+
+ @Test
+ fun findContentEntryForPackageUser_returnsCorrectEntry() {
+ val widgetPickerData =
+ WidgetPickerData(
+ allWidgets =
+ buildList {
+ addAll(appOneWidgetsListBaseEntries())
+ addAll(appTwoWidgetsListBaseEntries())
+ },
+ defaultWidgets = buildList { addAll(appTwoWidgetsListBaseEntries()) }
+ )
+ val app1PackageUserKey = PackageUserKey.fromPackageItemInfo(app1PackageItemInfo)
+
+ val contentEntry = findContentEntryForPackageUser(widgetPickerData, app1PackageUserKey)
+
+ assertThat(contentEntry).isNotNull()
+ assertThat(contentEntry?.mPkgItem).isEqualTo(app1PackageItemInfo)
+ assertThat(contentEntry?.mWidgets).hasSize(2)
+ }
+
+ @Test
+ fun findContentEntryForPackageUser_fromDefaults_returnsEntryFromDefaultWidgets() {
+ val widgetPickerData =
+ WidgetPickerData(
+ allWidgets =
+ buildList {
+ addAll(appOneWidgetsListBaseEntries())
+ addAll(appTwoWidgetsListBaseEntries())
+ },
+ defaultWidgets =
+ buildList { addAll(appOneWidgetsListBaseEntries(includeWidgetTwo = false)) }
+ )
+ val app1PackageUserKey = PackageUserKey.fromPackageItemInfo(app1PackageItemInfo)
+
+ val contentEntry =
+ findContentEntryForPackageUser(
+ widgetPickerData = widgetPickerData,
+ packageUserKey = app1PackageUserKey,
+ fromDefaultWidgets = true
+ )
+
+ assertThat(contentEntry).isNotNull()
+ assertThat(contentEntry?.mPkgItem).isEqualTo(app1PackageItemInfo)
+ // only one widget (since default widgets had only one widget for app A
+ assertThat(contentEntry?.mWidgets).hasSize(1)
+ }
+
+ @Test
+ fun findContentEntryForPackageUser_noMatch_returnsNull() {
+ val app2PackageUserKey = PackageUserKey.fromPackageItemInfo(app2PackageItemInfo)
+ val widgetPickerData =
+ WidgetPickerData(allWidgets = buildList { addAll(appOneWidgetsListBaseEntries()) })
+
+ val contentEntry = findContentEntryForPackageUser(widgetPickerData, app2PackageUserKey)
+
+ assertThat(contentEntry).isNull()
+ }
+
+ @Test
+ fun findAllWidgetsForPackageUser_returnsListOfWidgets() {
+ val app1PackageUserKey = PackageUserKey.fromPackageItemInfo(app1PackageItemInfo)
+ val widgetPickerData =
+ WidgetPickerData(
+ allWidgets =
+ buildList {
+ addAll(appOneWidgetsListBaseEntries())
+ addAll(appTwoWidgetsListBaseEntries())
+ },
+ defaultWidgets =
+ buildList { addAll(appOneWidgetsListBaseEntries(includeWidgetTwo = false)) }
+ )
+
+ val widgets = findAllWidgetsForPackageUser(widgetPickerData, app1PackageUserKey)
+
+ // both widgets returned irrespective of default widgets list
+ assertThat(widgets).hasSize(2)
+ }
+
+ @Test
+ fun findAllWidgetsForPackageUser_noMatch_returnsEmptyList() {
+ val widgetPickerData =
+ WidgetPickerData(
+ allWidgets = buildList { addAll(appTwoWidgetsListBaseEntries()) },
+ )
+ val app1PackageUserKey = PackageUserKey.fromPackageItemInfo(app1PackageItemInfo)
+
+ val widgets = findAllWidgetsForPackageUser(widgetPickerData, app1PackageUserKey)
+
+ assertThat(widgets).isEmpty()
+ }
+
+ private fun packageItemInfoWithTitle(packageName: String, title: String): PackageItemInfo {
+ val packageItemInfo = PackageItemInfo(packageName, userHandle)
+ packageItemInfo.title = title
+ return packageItemInfo
+ }
+
+ private fun createWidgetItem(packageName: String, widgetProviderName: String): WidgetItem {
+ val providerInfo =
+ WidgetUtils.createAppWidgetProviderInfo(
+ ComponentName.createRelative(packageName, widgetProviderName)
+ )
+ val widgetInfo = LauncherAppWidgetProviderInfo.fromProviderInfo(context, providerInfo)
+ return WidgetItem(widgetInfo, testInvariantProfile, iconCache, context)
+ }
+
+ private fun appTwoWidgetsListBaseEntries(): List<WidgetsListBaseEntry> = buildList {
+ val widgets = listOf(app2WidgetItem1)
+ add(WidgetsListHeaderEntry.create(app2PackageItemInfo, APP_2_SECTION_NAME, widgets))
+ add(WidgetsListContentEntry(app2PackageItemInfo, APP_2_SECTION_NAME, widgets))
+ }
+
+ private fun appOneWidgetsListBaseEntries(
+ includeWidgetTwo: Boolean = true
+ ): List<WidgetsListBaseEntry> = buildList {
+ val widgets =
+ if (includeWidgetTwo) {
+ listOf(app1WidgetItem1, app1WidgetItem2)
+ } else {
+ listOf(app1WidgetItem1)
+ }
+
+ add(WidgetsListHeaderEntry.create(app1PackageItemInfo, APP_1_SECTION_NAME, widgets))
+ add(WidgetsListContentEntry(app1PackageItemInfo, APP_1_SECTION_NAME, widgets))
+ }
+
+ companion object {
+ private const val APP_1_PACKAGE_NAME = "com.example.app1"
+ private const val APP_1_PACKAGE_TITLE = "App1"
+ private const val APP_1_SECTION_NAME = "A" // for fast popup
+ private const val APP_1_PROVIDER_1_CLASS_NAME = "app1Provider1"
+ private const val APP_1_PROVIDER_2_CLASS_NAME = "app1Provider2"
+
+ private const val APP_2_PACKAGE_NAME = "com.example.app2"
+ private const val APP_2_PACKAGE_TITLE = "SomeApp2"
+ private const val APP_2_SECTION_NAME = "S" // for fast popup
+ private const val APP_2_PROVIDER_1_CLASS_NAME = "app2Provider1"
+
+ private val CATEGORY_1 =
+ WidgetRecommendationCategory(/* categoryTitleRes= */ 0, /* order= */ 0)
+ private val CATEGORY_2 =
+ WidgetRecommendationCategory(/* categoryTitleRes= */ 1, /* order= */ 1)
+ }
+}
diff --git a/tests/src/com/android/launcher3/folder/FolderNameInfosTest.kt b/tests/src/com/android/launcher3/folder/FolderNameInfosTest.kt
new file mode 100644
index 0000000..b491f17
--- /dev/null
+++ b/tests/src/com/android/launcher3/folder/FolderNameInfosTest.kt
@@ -0,0 +1,201 @@
+/*
+ * 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.folder
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.folder.FolderNameInfos.*
+import org.junit.Test
+import org.junit.runner.RunWith
+
+data class Label(val index: Int, val label: String, val score: Float)
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class FolderNameInfosTest {
+
+ companion object {
+ val statusList =
+ listOf(
+ SUCCESS,
+ HAS_PRIMARY,
+ HAS_SUGGESTIONS,
+ ERROR_NO_PROVIDER,
+ ERROR_APP_LOOKUP_FAILED,
+ ERROR_ALL_APP_LOOKUP_FAILED,
+ ERROR_NO_LABELS_GENERATED,
+ ERROR_LABEL_LOOKUP_FAILED,
+ ERROR_ALL_LABEL_LOOKUP_FAILED,
+ ERROR_NO_PACKAGES,
+ )
+ }
+
+ @Test
+ fun status() {
+ assertStatus(statusList)
+ assertStatus(
+ listOf(
+ ERROR_NO_PROVIDER,
+ ERROR_APP_LOOKUP_FAILED,
+ ERROR_ALL_APP_LOOKUP_FAILED,
+ ERROR_NO_LABELS_GENERATED,
+ ERROR_LABEL_LOOKUP_FAILED,
+ ERROR_ALL_LABEL_LOOKUP_FAILED,
+ ERROR_NO_PACKAGES,
+ )
+ )
+ assertStatus(
+ listOf(
+ SUCCESS,
+ HAS_PRIMARY,
+ HAS_SUGGESTIONS,
+ )
+ )
+ assertStatus(
+ listOf(
+ SUCCESS,
+ HAS_PRIMARY,
+ HAS_SUGGESTIONS,
+ )
+ )
+ }
+
+ fun assertStatus(statusList: List<Int>) {
+ var infos = FolderNameInfos()
+ statusList.forEach { infos.setStatus(it) }
+ assert(infos.status() == statusList.sum()) {
+ "There is an overlap on the status constants!"
+ }
+ }
+
+ @Test
+ fun hasPrimary() {
+ assertHasPrimary(
+ createNameInfos(listOf(Label(0, "label", 1f)), statusList),
+ hasPrimary = true
+ )
+ assertHasPrimary(
+ createNameInfos(listOf(Label(1, "label", 1f)), statusList),
+ hasPrimary = false
+ )
+ assertHasPrimary(
+ createNameInfos(
+ listOf(Label(0, "label", 1f)),
+ listOf(
+ ERROR_NO_PROVIDER,
+ ERROR_APP_LOOKUP_FAILED,
+ ERROR_ALL_APP_LOOKUP_FAILED,
+ ERROR_NO_LABELS_GENERATED,
+ ERROR_LABEL_LOOKUP_FAILED,
+ ERROR_ALL_LABEL_LOOKUP_FAILED,
+ ERROR_NO_PACKAGES,
+ )
+ ),
+ hasPrimary = false
+ )
+ }
+
+ private fun assertHasPrimary(nameInfos: FolderNameInfos, hasPrimary: Boolean) =
+ assert(nameInfos.hasPrimary() == hasPrimary)
+
+ private fun createNameInfos(labels: List<Label>?, statusList: List<Int>?): FolderNameInfos {
+ val infos = FolderNameInfos()
+ labels?.forEach { infos.setLabel(it.index, it.label, it.score) }
+ statusList?.forEach { infos.setStatus(it) }
+ return infos
+ }
+
+ @Test
+ fun hasSuggestions() {
+ assertHasSuggestions(
+ createNameInfos(listOf(Label(0, "label", 1f)), null),
+ hasSuggestions = true
+ )
+ assertHasSuggestions(createNameInfos(null, null), hasSuggestions = false)
+ // There is a max of 4 suggestions
+ assertHasSuggestions(
+ createNameInfos(listOf(Label(5, "label", 1f)), null),
+ hasSuggestions = false
+ )
+ assertHasSuggestions(
+ createNameInfos(
+ listOf(
+ Label(0, "label", 1f),
+ Label(1, "label", 1f),
+ Label(2, "label", 1f),
+ Label(3, "label", 1f)
+ ),
+ null
+ ),
+ hasSuggestions = true
+ )
+ }
+
+ private fun assertHasSuggestions(nameInfos: FolderNameInfos, hasSuggestions: Boolean) =
+ assert(nameInfos.hasSuggestions() == hasSuggestions)
+
+ @Test
+ fun hasContains() {
+ assertContains(
+ createNameInfos(
+ listOf(
+ Label(0, "label1", 1f),
+ Label(1, "label2", 1f),
+ Label(2, "label3", 1f),
+ Label(3, "label4", 1f)
+ ),
+ null
+ ),
+ label = Label(-1, "label3", -1f),
+ contains = true
+ )
+ assertContains(
+ createNameInfos(
+ listOf(
+ Label(0, "label1", 1f),
+ Label(1, "label2", 1f),
+ Label(2, "label3", 1f),
+ Label(3, "label4", 1f)
+ ),
+ null
+ ),
+ label = Label(-1, "label5", -1f),
+ contains = false
+ )
+ assertContains(
+ createNameInfos(null, null),
+ label = Label(-1, "label1", -1f),
+ contains = false
+ )
+ assertContains(
+ createNameInfos(
+ listOf(
+ Label(0, "label1", 1f),
+ Label(1, "label2", 1f),
+ Label(2, "lAbel3", 1f),
+ Label(3, "lEbel4", 1f)
+ ),
+ null
+ ),
+ label = Label(-1, "LaBEl3", -1f),
+ contains = true
+ )
+ }
+
+ private fun assertContains(nameInfos: FolderNameInfos, label: Label, contains: Boolean) =
+ assert(nameInfos.contains(label.label) == contains)
+}
diff --git a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
index da14425..5516f45 100644
--- a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
+++ b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
@@ -23,7 +23,7 @@
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
-import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.THEMED_ICONS
import com.android.launcher3.LauncherPrefs.Companion.get
import com.android.launcher3.icons.BaseIconFactory
import com.android.launcher3.icons.FastBitmapDrawable
@@ -51,6 +51,8 @@
private lateinit var modelHelper: LauncherModelHelper
private lateinit var folderIcon: FolderIcon
+ private var defaultThemedIcons = false
+
@Before
fun setup() {
getInstrumentation().runOnMainSync {
@@ -127,16 +129,20 @@
previewItemManager.mIconSize
)
)
+
+ defaultThemedIcons = get(context).get(THEMED_ICONS)
}
+
@After
@Throws(Exception::class)
fun tearDown() {
+ get(context).put(THEMED_ICONS, defaultThemedIcons)
modelHelper.destroy()
}
@Test
fun checkThemedIconWithThemingOn_iconShouldBeThemed() {
- get(context).put(LauncherPrefs.THEMED_ICONS, true)
+ get(context).put(THEMED_ICONS, true)
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
previewItemManager.setDrawable(drawingParams, folderItems[0])
@@ -146,7 +152,7 @@
@Test
fun checkThemedIconWithThemingOff_iconShouldNotBeThemed() {
- get(context).put(LauncherPrefs.THEMED_ICONS, false)
+ get(context).put(THEMED_ICONS, false)
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
previewItemManager.setDrawable(drawingParams, folderItems[0])
@@ -156,7 +162,7 @@
@Test
fun checkUnthemedIconWithThemingOn_iconShouldNotBeThemed() {
- get(context).put(LauncherPrefs.THEMED_ICONS, true)
+ get(context).put(THEMED_ICONS, true)
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
previewItemManager.setDrawable(drawingParams, folderItems[1])
@@ -166,7 +172,7 @@
@Test
fun checkUnthemedIconWithThemingOff_iconShouldNotBeThemed() {
- get(context).put(LauncherPrefs.THEMED_ICONS, false)
+ get(context).put(THEMED_ICONS, false)
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
previewItemManager.setDrawable(drawingParams, folderItems[1])
@@ -176,7 +182,7 @@
@Test
fun checkThemedIconWithBadgeWithThemingOn_iconAndBadgeShouldBeThemed() {
- get(context).put(LauncherPrefs.THEMED_ICONS, true)
+ get(context).put(THEMED_ICONS, true)
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
previewItemManager.setDrawable(drawingParams, folderItems[2])
@@ -189,7 +195,7 @@
@Test
fun checkUnthemedIconWithBadgeWithThemingOn_badgeShouldBeThemed() {
- get(context).put(LauncherPrefs.THEMED_ICONS, true)
+ get(context).put(THEMED_ICONS, true)
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
previewItemManager.setDrawable(drawingParams, folderItems[3])
@@ -202,7 +208,7 @@
@Test
fun checkUnthemedIconWithBadgeWithThemingOff_iconAndBadgeShouldNotBeThemed() {
- get(context).put(LauncherPrefs.THEMED_ICONS, false)
+ get(context).put(THEMED_ICONS, false)
val drawingParams = PreviewItemDrawingParams(0f, 0f, 0f)
previewItemManager.setDrawable(drawingParams, folderItems[3])
diff --git a/tests/src/com/android/launcher3/pageindicators/PageIndicatorDotsTest.kt b/tests/src/com/android/launcher3/pageindicators/PageIndicatorDotsTest.kt
new file mode 100644
index 0000000..9a8f957
--- /dev/null
+++ b/tests/src/com/android/launcher3/pageindicators/PageIndicatorDotsTest.kt
@@ -0,0 +1,64 @@
+/*
+ * 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.pageindicators
+
+import android.content.Context
+import androidx.test.core.app.ApplicationProvider
+import com.android.launcher3.util.ActivityContextWrapper
+import junit.framework.TestCase.assertEquals
+import org.junit.Test
+import org.mockito.Mockito
+
+class PageIndicatorDotsTest {
+
+ private val context: Context =
+ ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+ private val pageIndicatorDots: PageIndicatorDots = Mockito.spy(PageIndicatorDots(context))
+
+ @Test
+ fun `setActiveMarker should set the active page to the parameter passed`() {
+ pageIndicatorDots.setActiveMarker(2)
+
+ assertEquals(2, pageIndicatorDots.activePage)
+ }
+
+ @Test
+ fun `setActiveMarker should set the active page to the parameter passed divided by two in two panel layouts`() {
+ pageIndicatorDots.mIsTwoPanels = true
+
+ pageIndicatorDots.setActiveMarker(5)
+
+ assertEquals(2, pageIndicatorDots.activePage)
+ }
+
+ @Test
+ fun `setMarkersCount should set the number of pages to the passed parameter and if the last page gets removed we want to go to the previous page`() {
+ pageIndicatorDots.setMarkersCount(3)
+
+ assertEquals(3, pageIndicatorDots.numPages)
+ }
+
+ @Test
+ fun `for setMarkersCount if the last page gets removed we want to go to the previous page`() {
+ pageIndicatorDots.setActiveMarker(2)
+
+ pageIndicatorDots.setMarkersCount(2)
+
+ assertEquals(1, pageIndicatorDots.activePage)
+ assertEquals(pageIndicatorDots.activePage.toFloat(), pageIndicatorDots.currentPosition)
+ }
+}
diff --git a/tests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt b/tests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
new file mode 100644
index 0000000..b531adb
--- /dev/null
+++ b/tests/src/com/android/launcher3/pm/InstallSessionTrackerTest.kt
@@ -0,0 +1,228 @@
+/*
+ * 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.pm
+
+import android.content.pm.LauncherApps
+import android.content.pm.PackageInstaller
+import android.os.Build
+import android.os.UserHandle
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SdkSuppress
+import androidx.test.filters.SmallTest
+import com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING
+import com.android.launcher3.util.Executors.MODEL_EXECUTOR
+import com.android.launcher3.util.LauncherModelHelper
+import com.android.launcher3.util.PackageUserKey
+import org.junit.After
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class InstallSessionTrackerTest {
+ @get:Rule val setFlagsRule = SetFlagsRule()
+
+ private val mockInstallSessionHelper: InstallSessionHelper = mock()
+ private val mockCallback: InstallSessionTracker.Callback = mock()
+ private val mockPackageInstaller: PackageInstaller = mock()
+
+ private val launcherModelHelper = LauncherModelHelper()
+ private val sandboxContext = launcherModelHelper.sandboxContext
+
+ lateinit var launcherApps: LauncherApps
+ lateinit var installSessionTracker: InstallSessionTracker
+
+ @Before
+ fun setup() {
+ launcherApps = sandboxContext.spyService(LauncherApps::class.java)
+ installSessionTracker =
+ InstallSessionTracker(
+ mockInstallSessionHelper,
+ mockCallback,
+ mockPackageInstaller,
+ launcherApps
+ )
+ }
+
+ @After
+ fun teardown() {
+ launcherModelHelper.destroy()
+ }
+
+ @Test
+ fun `onCreated triggers callbacks for setting up new install session`() {
+ // Given
+ val expectedSessionId = 1
+ val expectedSession =
+ PackageInstaller.SessionInfo().apply {
+ sessionId = expectedSessionId
+ appPackageName = "appPackageName"
+ userId = 0
+ }
+ val expectedPackageKey = PackageUserKey("appPackageName", UserHandle(0))
+ whenever(mockInstallSessionHelper.getVerifiedSessionInfo(expectedSessionId))
+ .thenReturn(expectedSession)
+ // When
+ installSessionTracker.onCreated(expectedSessionId)
+ // Then
+ verify(mockCallback).onInstallSessionCreated(any())
+ verify(mockCallback).onUpdateSessionDisplay(expectedPackageKey, expectedSession)
+ verify(mockInstallSessionHelper).tryQueuePromiseAppIcon(expectedSession)
+ }
+
+ @Test
+ @EnableFlags(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
+ fun `onCreated for unarchival triggers onPackageStateChanged`() {
+ // Given
+ val expectedSessionId = 1
+ val expectedSession =
+ spy(PackageInstaller.SessionInfo()).apply {
+ sessionId = expectedSessionId
+ appPackageName = "appPackageName"
+ userId = 0
+ whenever(isUnarchival).thenReturn(true)
+ }
+ whenever(mockInstallSessionHelper.getVerifiedSessionInfo(expectedSessionId))
+ .thenReturn(expectedSession)
+ // When
+ installSessionTracker.onCreated(expectedSessionId)
+ // Then
+ verify(mockCallback).onPackageStateChanged(any())
+ }
+
+ @Test
+ fun `onFinished triggers onPackageStateChanged if session found in cache`() {
+ // Given
+ val expectedSessionId = 1
+ val expectedSession =
+ PackageInstaller.SessionInfo().apply {
+ sessionId = expectedSessionId
+ appPackageName = "appPackageName"
+ userId = 0
+ }
+ val expectedPackageKey = PackageUserKey("appPackageName", UserHandle(0))
+ whenever(mockInstallSessionHelper.getVerifiedSessionInfo(expectedSessionId))
+ .thenReturn(expectedSession)
+ whenever(mockInstallSessionHelper.activeSessions)
+ .thenReturn(hashMapOf(expectedPackageKey to expectedSession))
+ // When
+ installSessionTracker.onFinished(expectedSessionId, /* success */ true)
+ // Then
+ verify(mockCallback).onPackageStateChanged(any())
+ }
+
+ @Test
+ fun `onFinished failure calls onSessionFailure and promise icon removal for existing icon`() {
+ // Given
+ val expectedSessionId = 1
+ val expectedPackage = "appPackageName"
+ val expectedSession =
+ PackageInstaller.SessionInfo().apply {
+ sessionId = expectedSessionId
+ appPackageName = expectedPackage
+ userId = 0
+ }
+ val expectedPackageKey = PackageUserKey(expectedPackage, UserHandle(0))
+ whenever(mockInstallSessionHelper.getVerifiedSessionInfo(expectedSessionId))
+ .thenReturn(expectedSession)
+ whenever(mockInstallSessionHelper.activeSessions)
+ .thenReturn(hashMapOf(expectedPackageKey to expectedSession))
+ whenever(mockInstallSessionHelper.promiseIconAddedForId(expectedSessionId)).thenReturn(true)
+ // When
+ installSessionTracker.onFinished(expectedSessionId, /* success */ false)
+ // Then
+ verify(mockCallback).onSessionFailure(expectedPackage, expectedPackageKey.mUser)
+ verify(mockInstallSessionHelper).removePromiseIconId(expectedSessionId)
+ }
+
+ @Test
+ fun `onProgressChanged triggers onPackageStateChanged if verified session found`() {
+ // Given
+ val expectedSessionId = 1
+ val expectedSession =
+ PackageInstaller.SessionInfo().apply {
+ sessionId = expectedSessionId
+ appPackageName = "appPackageName"
+ userId = 0
+ }
+ whenever(mockInstallSessionHelper.getVerifiedSessionInfo(expectedSessionId))
+ .thenReturn(expectedSession)
+ // When
+ installSessionTracker.onProgressChanged(expectedSessionId, /* progress */ 50f)
+ // Then
+ verify(mockCallback).onPackageStateChanged(any())
+ }
+
+ @Test
+ fun `onBadgingChanged triggers session display update and queues promise icon if verified`() {
+ // Given
+ val expectedSessionId = 1
+ val expectedSession =
+ PackageInstaller.SessionInfo().apply {
+ sessionId = expectedSessionId
+ appPackageName = "appPackageName"
+ userId = 0
+ }
+ val expectedPackageKey = PackageUserKey("appPackageName", UserHandle(0))
+ whenever(mockInstallSessionHelper.getVerifiedSessionInfo(expectedSessionId))
+ .thenReturn(expectedSession)
+ // When
+ installSessionTracker.onBadgingChanged(expectedSessionId)
+ // Then
+ verify(mockCallback).onUpdateSessionDisplay(expectedPackageKey, expectedSession)
+ verify(mockInstallSessionHelper).tryQueuePromiseAppIcon(expectedSession)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
+ fun `register triggers registerPackageInstallerSessionCallback for versions from Q`() {
+ // Given
+ whenever(
+ launcherApps.registerPackageInstallerSessionCallback(
+ MODEL_EXECUTOR,
+ installSessionTracker
+ )
+ )
+ .then { /* no-op */ }
+ // When
+ installSessionTracker.register()
+ // Then
+ verify(launcherApps)
+ .registerPackageInstallerSessionCallback(MODEL_EXECUTOR, installSessionTracker)
+ }
+
+ @Test
+ @SdkSuppress(minSdkVersion = Build.VERSION_CODES.Q)
+ fun `unregister triggers unregisterPackageInstallerSessionCallback for versions from Q`() {
+ // Given
+ whenever(launcherApps.unregisterPackageInstallerSessionCallback(installSessionTracker))
+ .then { /* no-op */ }
+ // When
+ installSessionTracker.unregister()
+ // Then
+ verify(launcherApps).unregisterPackageInstallerSessionCallback(installSessionTracker)
+ }
+}
diff --git a/tests/src/com/android/launcher3/pm/UserCacheTest.kt b/tests/src/com/android/launcher3/pm/UserCacheTest.kt
new file mode 100644
index 0000000..b21219e
--- /dev/null
+++ b/tests/src/com/android/launcher3/pm/UserCacheTest.kt
@@ -0,0 +1,140 @@
+/*
+ * 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.pm
+
+import android.os.Process.myUserHandle
+import android.os.UserHandle
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.util.Executors.MODEL_EXECUTOR
+import com.android.launcher3.util.LauncherModelHelper
+import com.android.launcher3.util.TestUtil
+import com.android.launcher3.util.UserIconInfo
+import com.google.common.truth.Truth.assertThat
+import org.junit.After
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class UserCacheTest {
+ private val launcherModelHelper = LauncherModelHelper()
+ private val sandboxContext = launcherModelHelper.sandboxContext
+ private lateinit var userCache: UserCache
+
+ @Before
+ fun setup() {
+ userCache = UserCache.getInstance(sandboxContext)
+ }
+
+ @After
+ fun teardown() {
+ launcherModelHelper.destroy()
+ }
+
+ @Test
+ fun `getBadgeDrawable only returns a UserBadgeDrawable given a user in the cache`() {
+ // Given
+ val expectedIconInfo = UserIconInfo(myUserHandle(), UserIconInfo.TYPE_WORK)
+ TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
+ userCache.putToCache(myUserHandle(), expectedIconInfo)
+ }
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+ // When
+ val actualDrawable = UserCache.getBadgeDrawable(sandboxContext, myUserHandle())
+ val unexpectedDrawable = UserCache.getBadgeDrawable(sandboxContext, UserHandle(66))
+ // Then
+ assertThat(actualDrawable).isNotNull()
+ assertThat(unexpectedDrawable).isNull()
+ }
+
+ @Test
+ fun `getPreInstallApps returns list of pre installed apps given a user`() {
+ // Given
+ val expectedApps = listOf("Google")
+ TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
+ userCache.putToPreInstallCache(myUserHandle(), expectedApps)
+ }
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+ // When
+ val actualApps = userCache.getPreInstallApps(myUserHandle())
+ // Then
+ assertThat(actualApps).isEqualTo(expectedApps)
+ }
+
+ @Test
+ fun `getUserProfiles returns copy of UserCache profiles`() {
+ // Given
+ val expectedProfiles = listOf(myUserHandle())
+ val expectedIconInfo = UserIconInfo(myUserHandle(), UserIconInfo.TYPE_MAIN)
+ TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
+ userCache.putToCache(myUserHandle(), expectedIconInfo)
+ }
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+ // When
+ val actualProfiles = userCache.userProfiles
+ // Then
+ assertThat(actualProfiles).isEqualTo(expectedProfiles)
+ }
+
+ @Test
+ fun `getUserForSerialNumber returns user key matching given entry serial number`() {
+ // Given
+ val expectedSerial = 42L
+ val expectedProfile = UserHandle(42)
+ val expectedIconInfo = UserIconInfo(myUserHandle(), UserIconInfo.TYPE_MAIN, expectedSerial)
+ TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
+ userCache.putToCache(expectedProfile, expectedIconInfo)
+ }
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+ // When
+ val actualProfile = userCache.getUserForSerialNumber(expectedSerial)
+ // Then
+ assertThat(actualProfile).isEqualTo(expectedProfile)
+ }
+
+ @Test
+ fun `getUserInfo returns cached UserIconInfo given user key`() {
+ // Given
+ val expectedProfile = UserHandle(1)
+ val expectedIconInfo = UserIconInfo(myUserHandle(), UserIconInfo.TYPE_WORK)
+ TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
+ userCache.putToCache(expectedProfile, expectedIconInfo)
+ }
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+ // When
+ val actualIconInfo = userCache.getUserInfo(expectedProfile)
+ // Then
+ assertThat(actualIconInfo).isEqualTo(expectedIconInfo)
+ }
+
+ @Test
+ fun `getSerialNumberForUser returns cached UserIconInfo serial number given user key`() {
+ // Given
+ val expectedSerial = 42L
+ val expectedProfile = UserHandle(1)
+ val expectedIconInfo = UserIconInfo(myUserHandle(), UserIconInfo.TYPE_WORK, expectedSerial)
+ TestUtil.runOnExecutorSync(MODEL_EXECUTOR) {
+ userCache.putToCache(expectedProfile, expectedIconInfo)
+ }
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync()
+ // When
+ val actualSerial = userCache.getSerialNumberForUser(expectedProfile)
+ // Then
+ assertThat(actualSerial).isEqualTo(expectedSerial)
+ }
+}
diff --git a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
index 98b6b4b..dcfcad5 100644
--- a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
+++ b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
@@ -63,6 +63,8 @@
import com.android.launcher3.util.TestSandboxModelContextWrapper;
import com.android.launcher3.util.UserIconInfo;
import com.android.launcher3.views.BaseDragLayer;
+import com.android.launcher3.widget.picker.model.WidgetPickerDataProvider;
+import com.android.launcher3.widget.picker.model.data.WidgetPickerData;
import org.junit.After;
import org.junit.Assert;
@@ -73,8 +75,6 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
-import java.util.ArrayList;
-
@SmallTest
@RunWith(LauncherMultivalentJUnit.class)
public class SystemShortcutTest {
@@ -86,7 +86,7 @@
private TestSandboxModelContextWrapper mTestContext;
private final SandboxModelContext mSandboxContext = new SandboxModelContext();
private PrivateProfileManager mPrivateProfileManager;
- private PopupDataProvider mPopupDataProvider;
+ private WidgetPickerDataProvider mWidgetPickerDataProvider;
private AppInfo mAppInfo;
@Mock UserCache mUserCache;
@Mock ApiWrapper mApiWrapper;
@@ -119,8 +119,8 @@
spyOn(mPrivateProfileManager);
when(mPrivateProfileManager.getProfileUser()).thenReturn(PRIVATE_HANDLE);
- mPopupDataProvider = mTestContext.getPopupDataProvider();
- spyOn(mPopupDataProvider);
+ mWidgetPickerDataProvider = mTestContext.getWidgetPickerDataProvider();
+ spyOn(mWidgetPickerDataProvider);
}
@After
@@ -141,7 +141,7 @@
mAppInfo = new AppInfo();
mAppInfo.componentName = new ComponentName(mTestContext, getClass());
assertNotNull(mAppInfo.getTargetComponent());
- doReturn(new ArrayList<>()).when(mPopupDataProvider).getWidgetsForPackageUser(any());
+ doReturn(new WidgetPickerData()).when(mWidgetPickerDataProvider).get();
spyOn(mAppInfo);
SystemShortcut systemShortcut = SystemShortcut.WIDGETS
.getShortcut(mTestContext, mAppInfo, mView);