Merge "Util classes for the Taskbar Customization Framework" into main
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index ff97b22..9051ca8 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -5,7 +5,7 @@
ktfmt = --kotlinlang-style
[Tool Paths]
-ktfmt = ${REPO_ROOT}/prebuilts/build-tools/common/framework/ktfmt.jar
+ktfmt = ${REPO_ROOT}/external/ktfmt/ktfmt.sh
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --config_xml tools/checkstyle.xml --sha ${PREUPLOAD_COMMIT}
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index fecc43d..9c945b9 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -302,3 +302,10 @@
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "floating_search_bar"
+ namespace: "launcher"
+ description: "Search bar persists at the bottom of the screen across Launcher states"
+ bug: "346408388"
+}
diff --git a/quickstep/res/layout/transient_taskbar.xml b/quickstep/res/layout/transient_taskbar.xml
index 7c55bf8..f3c3383 100644
--- a/quickstep/res/layout/transient_taskbar.xml
+++ b/quickstep/res/layout/transient_taskbar.xml
@@ -45,8 +45,6 @@
android:layout_gravity="bottom|end"
android:layout_marginHorizontal="@dimen/transient_taskbar_bottom_margin"
android:paddingTop="@dimen/bubblebar_pointer_visible_size"
- android:paddingEnd="@dimen/taskbar_icon_spacing"
- android:paddingStart="@dimen/taskbar_icon_spacing"
android:visibility="gone"
android:gravity="center"
android:clipChildren="false"
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index f7bf719..73c8129 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Wys nog # app.}other{Wys nog # apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Wys # rekenaarapp.}other{Wys # rekenaarapps.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Borrel"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 1700823..f9eed39 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ተጨማሪ # መተግበሪያ አሳይ።}one{ተጨማሪ # መተግበሪያ አሳይ።}other{ተጨማሪ # መተግበሪያዎች አሳይ።}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# የዴስክቶፕ መተግበሪያ አሳይ።}one{# የዴስክቶፕ መተግበሪያ አሳይ።}other{# የዴስክቶፕ መተግበሪያዎች አሳይ።}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> እና <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"አረፋ"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 38e9f70..7a0be9b 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{إظهار تطبيق واحد آخر}zero{إظهار # تطبيق آخر}two{إظهار تطبيقَين آخرَين}few{إظهار # تطبيقات أخرى}many{إظهار # تطبيقًا آخر}other{إظهار # تطبيق آخر}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{عرض تطبيق واحد متوافق مع الكمبيوتر المكتبي}zero{عرض # تطبيق متوافق مع الكمبيوتر المكتبي}two{عرض تطبيقَين متوافقين مع الكمبيوتر المكتبي}few{عرض # تطبيقات متوافقة مع الكمبيوتر المكتبي}many{عرض # تطبيقًا متوافقًا مع الكمبيوتر المكتبي}other{عرض # تطبيق متوافق مع الكمبيوتر المكتبي}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"\"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" و\"<xliff:g id="APP_NAME_2">%2$s</xliff:g>\""</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"فقاعة"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 5ba9163..d440400 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{আৰু # টা এপ্ দেখুৱাওক।}one{আৰু # টা এপ্ দেখুৱাওক।}other{আৰু # টা এপ্ দেখুৱাওক।}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# টা ডেস্কটপ এপ্ দেখুৱাওক।}one{# টা ডেস্কটপ এপ্ দেখুৱাওক।}other{# টা ডেস্কটপ এপ্ দেখুৱাওক।}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> আৰু <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index ab75367..9cdcc01 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Daha # tətbiqi göstərin.}other{Daha # tətbiqi göstərin.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# masaüstü tətbiqini göstərin.}other{# masaüstü tətbiqini göstərin.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> və <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Yumrucuq"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index d23ba50..b6271a9 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju.}one{Prikaži još # aplikaciju.}few{Prikaži još # aplikacije.}other{Prikaži još # aplikacija.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # aplikaciju za računare.}one{Prikaži # aplikaciju za računare.}few{Prikaži # aplikacije za računare.}other{Prikaži # aplikacija za računare.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 2829fd9..bb6c764 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Паказаць ячшэ # праграму.}one{Паказаць ячшэ # праграму.}few{Паказаць ячшэ # праграмы.}many{Паказаць ячшэ # праграм.}other{Паказаць ячшэ # праграмы.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Паказаць # праграму для ПК.}one{Паказаць # праграму для ПК.}few{Паказаць # праграмы для ПК.}many{Паказаць # праграм для ПК.}other{Паказаць # праграмы для ПК.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> і <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бурбалкі"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index bb7d7be..d674dbc 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показване на още # приложение.}other{Показване на още # приложения.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показване на # настолно приложение.}other{Показване на # настолни приложения.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index ebde96d..3e974f5 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{আরও #টি অ্যাপ দেখুন।}one{আরও #টি অ্যাপ দেখুন।}other{আরও #টি অ্যাপ দেখুন।}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{#টি ডেস্কটপ অ্যাপ দেখুন।}one{#টি ডেস্কটপ অ্যাপ দেখুন।}other{#টি ডেস্কটপ অ্যাপ দেখুন।}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ও <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 89cdc28..19268be 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju.}one{Prikaži još # aplikaciju.}few{Prikaži još # aplikacije.}other{Prikaži još # aplikacija.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # aplikaciju za računar.}one{Prikaži # aplikaciju za računar.}few{Prikaži # aplikacije za računar.}other{Prikaži # aplikacija za računar.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index f1768aa..6a6f131 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # aplicació més.}other{Mostra # aplicacions més.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostra # aplicació per a ordinadors.}other{Mostra # aplicacions per a ordinadors.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bombolla"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 6c523ca..e134850 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -73,7 +73,7 @@
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Přejeďte prstem nahoru z dolního okraje obrazovky"</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Zkuste podržet okno delší dobu, než ho uvolníte"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Přejeďte prstem přímo nahoru a pak udělejte pauzu"</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili jste se používat gesta. Vypnout je můžete v nastavení."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili jste se používat gesta. Vypnout je můžete v Nastavení."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Dokončili jste gesto pro přepínání aplikací"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Přepínání aplikací přejetím prstem"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Přejeďte nahoru z dolního okraje obrazovky, podržte obrazovku a uvolněte."</string>
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobrazit # další aplikaci.}few{Zobrazit # další aplikace.}many{Zobrazit # další aplikace.}other{Zobrazit # dalších aplikací.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Zobrazit # aplikaci pro počítač.}few{Zobrazit # aplikace pro počítač.}many{Zobrazit # aplikace pro počítač.}other{Zobrazit # aplikací pro počítač.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index a8d3612..e9cdbce 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app mere.}one{Vis # app mere.}other{Vis # apps mere.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Vis # computerprogram.}one{Vis # computerprogram.}other{Vis # computerprogrammer.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index bc15ca5..9e5cb12 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# weitere App anzeigen}other{# weitere Apps anzeigen}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# Desktop-App anzeigen.}other{# Desktop-Apps anzeigen.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> und <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index c317aa4..bbb1282 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Εμφάνιση # ακόμα εφαρμογής.}other{Εμφάνιση # ακόμα εφαρμογών.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Εμφάνιση # εφαρμογής υπολογιστή.}other{Εμφάνιση # εφαρμογών υπολογιστή.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> και <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Συννεφάκι"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index 519146b..eedb29e 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 4205e49..88cd0dd 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index 519146b..eedb29e 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index 519146b..eedb29e 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index 44afedd..76dab0d 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 4930c0b..58d540f 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # app más.}other{Mostrar # apps más.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computadoras.}other{Mostrar # apps para computadoras.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 4b45f5e..2a956f0 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación más.}other{Mostrar # aplicaciones más.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # aplicación para ordenadores.}other{Mostrar # aplicaciones para ordenadores.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index d6b9e78..0ecc0c0 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Kuva veel # rakendus.}other{Kuva veel # rakendust.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Kuva # töölauarakendus.}other{Kuva # töölauarakendust.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Mull"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index bcecfea..e83ee28 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Erakutsi beste # aplikazio.}other{Erakutsi beste # aplikazio.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Erakutsi ordenagailuetarako # aplikazio.}other{Erakutsi ordenagailuetarako # aplikazio.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> eta <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuila"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index a68d77c..b296080 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{نمایش # برنامه دیگر.}one{نمایش # برنامه دیگر.}other{نمایش # برنامه دیگر.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{نمایش # برنامه رایانه.}one{نمایش # برنامه رایانه.}other{نمایش # برنامه رایانه.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> و <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"حبابک"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index bb0516c..5ac124a 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Näytä # muu sovellus.}other{Näytä # muuta sovellusta.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Näytä # työpöytäsovellus.}other{Näytä # työpöytäsovellusta.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kupla"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index dd36f2e..edfb59e 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre application.}one{Afficher # autre application.}other{Afficher # autres applications.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # appli de bureau.}one{Afficher # appli de bureau.}other{Afficher # applis de bureau.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index de335bf..60f8944 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli}one{Afficher # autre appli}other{Afficher # autre applis}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # application de bureau.}one{Afficher # application de bureau.}other{Afficher # applications de bureau.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index b116332..bf081d4 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación máis.}other{Mostrar # aplicacións máis.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # aplicación para ordenadores.}other{Mostrar # aplicacións para ordenadores.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulla"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index efba149..b20f771 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{વધુ # ઍપ બતાવો.}one{વધુ # ઍપ બતાવો.}other{વધુ # ઍપ બતાવો.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ડેસ્કટૉપ ઍપ બતાવો.}one{# ડેસ્કટૉપ ઍપ બતાવો.}other{# ડેસ્કટૉપ ઍપ બતાવો.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> અને <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"બબલ"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 205be27..a645186 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# और ऐप्लिकेशन दिखाएं.}one{# और ऐप्लिकेशन दिखाएं.}other{# और ऐप्लिकेशन दिखाएं.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}one{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}other{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> और <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index d189268..c96381d 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju}one{Prikaži još # aplikaciju}few{Prikaži još # aplikacije}other{Prikaži još # aplikacija}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # računalnu aplikaciju.}one{Prikaži # računalnu aplikaciju.}few{Prikaži # računalne aplikacije.}other{Prikaži # računalnih aplikacija.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 975966e..03235aa 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# további alkalmazás megjelenítése.}other{# további alkalmazás megjelenítése.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# asztali alkalmazás megjelenítése.}other{# asztali alkalmazás megjelenítése.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> és <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Buborék"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 7e56258..3cb7990 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Ցուցադրել ևս # հավելված։}one{Ցուցադրել ևս # հավելված։}other{Ցուցադրել ևս # հավելված։}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Ցույց տալ # համակարգչային հավելված։}one{Ցույց տալ # համակարգչային հավելված։}other{Ցույց տալ # համակարգչային հավելված։}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> և <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ամպիկ"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index d0a7a91..015b09e 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tampilkan # aplikasi lainnya.}other{Tampilkan # aplikasi lainnya.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Tampilkan # aplikasi desktop.}other{Tampilkan # aplikasi desktop.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index 34e5f26..883fe82 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Sýna # forrit í viðbót.}one{Sýna # forrit í viðbót.}other{Sýna # forrit í viðbót.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Sýna # skjáborðsforrit.}one{Sýna # skjáborðsforrit.}other{Sýna # skjáborðsforrit.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Blaðra"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index a5d11f8..59b195a 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # altra app.}other{Mostra altre # app.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostra # app desktop.}other{Mostra # app desktop.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Fumetto"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 30c53d5..9f0ed14 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{הצגת אפליקציה אחת (#) נוספת.}one{הצגת # אפליקציות נוספות.}two{הצגת # אפליקציות נוספות.}other{הצגת # אפליקציות נוספות.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{הצגת אפליקציה אחת (#) למחשב.}one{הצגת # אפליקציות למחשב.}two{הצגת # אפליקציות למחשב.}other{הצגת # אפליקציות למחשב.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ו-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"בועה"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index ead3c19..4f1a162 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{他 # 件のアプリを表示できます。}other{他 # 件のアプリを表示できます。}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# 個のデスクトップ アプリが表示されます。}other{# 個のデスクトップ アプリが表示されます。}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> と <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ふきだし"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index bcc28b4..1fb6077 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{#-ით მეტი აპის ჩენება}other{#-ით მეტი აპის ჩვენება.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# დესკტოპის აპის ჩვენება.}other{# დესკტოპის აპის ჩვენება.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> და <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ბუშტი"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 0002024..d83e2d3 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Тағы # қолданбаны көрсету.}other{Тағы # қолданбаны көрсету.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерге арналған # қолданбаны көрсету}other{Компьютерге арналған # қолданбаны көрсету}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> және <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Қалқыма терезе"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 8c38c48..5448433 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{បង្ហាញកម្មវិធី # ទៀត។}other{បង្ហាញកម្មវិធី # ទៀត។}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{បង្ហាញកម្មវិធីកុំព្យូទ័រ #។}other{បង្ហាញកម្មវិធីកុំព្យូទ័រ #។}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> និង <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ផ្ទាំងសារ"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 1231157..74c7750 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ಇನ್ನೂ # ಆ್ಯಪ್ ಅನ್ನು ತೋರಿಸಿ.}one{ಇನ್ನೂ # ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}other{ಇನ್ನೂ # ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ಡೆಸ್ಕ್ಟಾಪ್ ಆ್ಯಪ್ ತೋರಿಸಿ.}one{# ಡೆಸ್ಕ್ಟಾಪ್ ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}other{# ಡೆಸ್ಕ್ಟಾಪ್ ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ಮತ್ತು <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ಬಬಲ್"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index e0fc21f..1f4275a 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{앱 #개 더 표시}other{앱 #개 더 표시}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{데스크톱 앱 #개를 표시합니다.}other{데스크톱 앱 #개를 표시합니다.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> 및 <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"풍선"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index fbb1c42..f0d2af8 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Дагы # колдонмону көрсөтүү.}other{Дагы # колдонмону көрсөтүү.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# иш такта колдонмосун көрсөтүү.}other{# иш такта колдонмосун көрсөтүү.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> жана <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Көбүкчө"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index bb36330..f54c712 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ສະແດງອີກ # ແອັບ.}other{ສະແດງອີກ # ແອັບ.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{ສະແດງແອັບເດັສທັອບ # ລາຍການ.}other{ສະແດງແອັບເດັສທັອບ # ລາຍການ.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ແລະ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ຟອງ"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index b5dceb6..554745e 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rodyti dar # programą.}one{Rodyti dar # programą.}few{Rodyti dar # programas.}many{Rodyti dar # programos.}other{Rodyti dar # programų.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Rodyti # darbalaukio programą.}one{Rodyti # darbalaukio programą.}few{Rodyti # darbalaukio programas.}many{Rodyti # darbalaukio programos.}other{Rodyti # darbalaukio programų.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"„<xliff:g id="APP_NAME_1">%1$s</xliff:g>“ ir „<xliff:g id="APP_NAME_2">%2$s</xliff:g>“"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulas"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 2b6208a..a6a0dab 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rādīt vēl # lietotni}zero{Rādīt vēl # lietotnes}one{Rādīt vēl # lietotni}other{Rādīt vēl # lietotnes}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Rādīt # datora lietotni.}zero{Rādīt # datora lietotnes.}one{Rādīt # datora lietotni.}other{Rādīt # datora lietotnes.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"“<xliff:g id="APP_NAME_1">%1$s</xliff:g>” un “<xliff:g id="APP_NAME_2">%2$s</xliff:g>”"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulis"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 6b8c592..4859055 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Прикажи уште # апликација.}one{Прикажи уште # апликација.}other{Прикажи уште # апликации.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Прикажи # апликација за компјутер.}one{Прикажи # апликација за компјутер.}other{Прикажи # апликации за компјутер.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index d401c20..85b093d 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# ആപ്പ് കൂടി കാണിക്കുക.}other{# ആപ്പുകൾ കൂടി കാണിക്കുക.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ഡെസ്ക്ടോപ്പ് ആപ്പ് കാണിക്കുക.}other{# ഡെസ്ക്ടോപ്പ് ആപ്പുകൾ കാണിക്കുക.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ബബിൾ"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index 4491c37..7a4c7e9 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Өөр # аппыг харуулна уу.}other{Өөр # аппыг харуулна уу.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерын # аппыг харуулна уу.}other{Компьютерын # аппыг харуулна уу.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> болон <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бөмбөлөг"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 3938fd4..7941156 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{आणखी # अॅप दाखवा.}other{आणखी # अॅप्स दाखवा.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटॉप अॅप दाखवा.}other{# डेस्कटॉप अॅप्स दाखवा.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> आणि <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 0db53d6..c0219e0 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tunjukkan # lagi apl.}other{Tunjukkan # lagi apl.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Tunjukkan # apl desktop.}other{Tunjukkan # apl desktop.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Gelembung"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 4ac838a..7c7ff82 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{နောက်ထပ်အက်ပ် # ခု ပြပါ။}other{နောက်ထပ်အက်ပ် # ခု ပြပါ။}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{ဒက်စတော့ အက်ပ် # ခု ပြပါ။}other{ဒက်စတော့ အက်ပ် # ခု ပြပါ။}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> နှင့် <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ပူဖောင်းကွက်"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 46bf14b..dd3d16e 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app til.}other{Vis # apper til.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Vis # datamaskinprogram.}other{Vis # datamaskinprogrammer.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 07437ca..d49fd2d 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{थप # एप देखाउनुहोस्।}other{थप # वटा एप देखाउनुहोस्।}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटप एप देखाउनुहोस्।}other{# वटा डेस्कटप एप देखाउनुहोस्।}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> र <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 3dedd7b..ca44a69 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Nog # app tonen.}other{Nog # apps tonen.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# desktop-app tonen.}other{# desktop-apps tonen.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbel"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 67a5b13..bf0bdc8 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ଅଧିକ #ଟି ଆପ ଦେଖାନ୍ତୁ।}other{ଅଧିକ #ଟି ଆପ୍ସ ଦେଖାନ୍ତୁ।}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ଡେସ୍କଟପ ଆପ ଦେଖାନ୍ତୁ।}other{# ଡେସ୍କଟପ ଆପ୍ସ ଦେଖାନ୍ତୁ।}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ଏବଂ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ବବଲ"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 78f1c79..fc60396 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}one{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}other{# ਹੋਰ ਐਪਾਂ ਦਿਖਾਓ।}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ਡੈਸਕਟਾਪ ਐਪ ਦਿਖਾਓ।}one{# ਡੈਸਕਟਾਪ ਐਪ ਦਿਖਾਓ।}other{# ਡੈਸਕਟਾਪ ਐਪਾਂ ਦਿਖਾਓ।}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ਅਤੇ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ਬਬਲ"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 41ac736..d88e28a 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Pokaż jeszcze # aplikację.}few{Pokaż jeszcze # aplikacje.}many{Pokaż jeszcze # aplikacji.}other{Pokaż jeszcze # aplikacji.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Pokaż # aplikację komputerową.}few{Pokaż # aplikacje komputerowe.}many{Pokaż # aplikacji komputerowych.}other{Pokaż # aplikacji komputerowej.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Dymek"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index f674d68..dd00469 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computador.}other{Mostrar # apps para computador.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 4f3d75a..4fec4f8 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}one{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computador.}one{Mostrar # app para computador.}other{Mostrar # apps para computador.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index dee1ac6..c839602 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afișează încă # aplicație}few{Afișează încă # aplicații}other{Afișează încă # de aplicații}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afișează # aplicație pentru computer.}few{Afișează # aplicații pentru computer.}other{Afișează # de aplicații pentru computer.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> și <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index a78561a..da49ad3 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показать ещё # приложение}one{Показать ещё # приложение}few{Показать ещё # приложения}many{Показать ещё # приложений}other{Показать ещё # приложения}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показать # компьютерное приложение.}one{Показать # компьютерное приложение.}few{Показать # компьютерных приложения.}many{Показать # компьютерных приложений.}other{Показать # компьютерного приложения.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Всплывающая подсказка"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index c1dfa9d..9cbe837 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{තවත් # යෙදුමක් පෙන්වන්න.}one{තවත් යෙදුම් #ක් පෙන්වන්න.}other{තවත් යෙදුම් #ක් පෙන්වන්න.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ඩෙස්ක්ටොප් යෙදුමක් පෙන්වන්න.}one{ඩෙස්ක්ටොප් යෙදුම් # ක් පෙන්වන්න.}other{ඩෙස්ක්ටොප් යෙදුම් # ක් පෙන්වන්න.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> සහ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"බුබුළු"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 51f09aa..3eca787 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobraziť # ďalšiu aplikáciu.}few{Zobraziť # ďalšie aplikácie.}many{Show # more apps.}other{Zobraziť # ďalších aplikácií.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Zobraziť # aplikáciu pre počítač.}few{Zobraziť # aplikácie pre počítač.}many{Show # desktop apps.}other{Zobraziť # aplikácií pre počítač.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index ea1fd45..52faeb7 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Pokaži še # aplikacijo.}one{Pokaži še # aplikacijo.}two{Pokaži še # aplikaciji.}few{Pokaži še # aplikacije.}other{Pokaži še # aplikacij.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaz # aplikacije za namizni računalnik.}one{Prikaz # aplikacije za namizni računalnik.}two{Prikaz # aplikacij za namizni računalnik.}few{Prikaz # aplikacij za namizni računalnik.}other{Prikaz # aplikacij za namizni računalnik.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> in <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblaček"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 6cc894a..cdb9cf9 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Shfaq # aplikacion tjetër.}other{Shfaq # aplikacione të tjera.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Shfaq # aplikacion për desktop.}other{Shfaq # aplikacione për desktop.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dhe <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Flluska"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 7828868..7456a36 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Прикажи још # апликацију.}one{Прикажи још # апликацију.}few{Прикажи још # апликације.}other{Прикажи још # апликација.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Прикажи # апликацију за рачунаре.}one{Прикажи # апликацију за рачунаре.}few{Прикажи # апликације за рачунаре.}other{Прикажи # апликација за рачунаре.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Облачић"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 4fecddd..f369dae 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Visa # app till.}other{Visa # appar till.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Visa # datorapp.}other{Visa # datorappar.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> och <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbla"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 3c4e5e5..3d8277b 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Onyesha programu # zaidi.}other{Onyesha programu # zaidi.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Onyesha programu # ya kompyuta ya mezani.}other{Onyesha programu # za kompyuta ya mezani.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> na <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kiputo"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index b259dbf..ed3ebee 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{மேலும் # ஆப்ஸைக் காட்டு.}other{மேலும் # ஆப்ஸைக் காட்டு.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# டெஸ்க்டாப் ஆப்ஸைக் காட்டு.}other{# டெஸ்க்டாப் ஆப்ஸைக் காட்டு.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> மற்றும் <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"குமிழ்"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 20fc77d..a4e1cbf 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{మరో # యాప్ను చూడండి.}other{మరో # యాప్లను చూడండి.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# డెస్క్టాప్ యాప్ను చూపండి.}other{# డెస్క్టాప్ యాప్లను చూపండి.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"బబుల్"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index 4adcc52..1bbb137 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{แสดงเพิ่มเติมอีก # แอป}other{แสดงเพิ่มเติมอีก # แอป}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{แสดงแอปบนเดสก์ท็อป # รายการ}other{แสดงแอปบนเดสก์ท็อป # รายการ}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> และ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"บับเบิล"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index 66ecc00..978a5a3 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Magpakita ng # pang app.}one{Magpakita ng # pang app.}other{Magpakita ng # pang app.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Ipakita ang # desktop app.}one{Ipakita ang # desktop app.}other{Ipakita ang # na desktop app.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> at <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index dc5fa6b..0cc5d7f 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# uygulama daha göster.}other{# uygulama daha göster}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# masaüstü uygulamasını göster.}other{# masaüstü uygulamasını göster.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ve <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 5119e56..9c706a8 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показати ще # додаток.}one{Показати ще # додаток.}few{Показати ще # додатки.}many{Показати ще # додатків.}other{Показати ще # додатка.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показати # комп’ютерну програму.}one{Показати # комп’ютерну програму.}few{Показати # комп’ютерні програми.}many{Показати # комп’ютерних програм.}other{Показати # комп’ютерної програми.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> та <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Повідомлення"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index c42a601..e125248 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# مزید ایپ دکھائیں۔}other{# مزید ایپس دکھائیں۔}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ڈیسک ٹاپ ایپ دکھائیں۔}other{# ڈیسک ٹاپ ایپس دکھائیں۔}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> اور <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ببل"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 810c8f0..3f4f981 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Yana # ta ilovani chiqarish}other{Yana # ta ilovani chiqarish}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ta desktop ilovani chiqarish.}other{# ta desktop ilovani chiqarish.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> va <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Pufak"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index 8291ac7..9bc526f 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Hiện thêm # ứng dụng.}other{Hiện thêm # ứng dụng.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Hiện # ứng dụng dành cho máy tính.}other{Hiện # ứng dụng dành cho máy tính.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> và <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bong bóng"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index e00e932..a89227e 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{显示另外 # 个应用。}other{显示另外 # 个应用。}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{显示 # 款桌面应用。}other{显示 # 款桌面应用。}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>和<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"气泡框"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 3a77369..b9d8eb7 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{顯示另外 # 個應用程式。}other{顯示另外 # 個應用程式。}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{顯示 # 個桌面應用程式。}other{顯示 # 個桌面應用程式。}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"對話氣泡"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 3b59966..90140cb 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{再多顯示 # 個應用程式。}other{再多顯示 # 個應用程式。}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{顯示 # 個電腦版應用程式。}other{顯示 # 個電腦版應用程式。}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"泡泡"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index b3ef1e7..73be445 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -140,12 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Bonisa i-app e-# ngaphezulu.}one{Bonisa ama-app angu-# ngaphezulu.}other{Bonisa ama-app angu-# ngaphezulu.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Bonisa i-app engu-# yedeskithophu.}one{Bonisa ama-app angu-# wedeskithophu.}other{Bonisa ama-app angu-# wedeskithophu.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"I-<xliff:g id="APP_NAME_1">%1$s</xliff:g> ne-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
- <!-- no translation found for bubble_bar_bubble_fallback_description (7811684548953452009) -->
- <skip />
- <!-- no translation found for bubble_bar_overflow_description (8617628132733151708) -->
- <skip />
- <!-- no translation found for bubble_bar_bubble_description (1882466152448446446) -->
- <skip />
- <!-- no translation found for bubble_bar_description_multiple_bubbles (3922207715357143648) -->
- <skip />
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ibhamuza"</string>
+ <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>
</resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 6b76311..5c82c99 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -367,6 +367,7 @@
<dimen name="transient_taskbar_min_width">150dp</dimen>
<dimen name="transient_taskbar_bottom_margin">24dp</dimen>
<dimen name="transient_taskbar_shadow_blur">40dp</dimen>
+ <dimen name="transient_taskbar_stroke_width">1dp</dimen>
<dimen name="transient_taskbar_key_shadow_distance">10dp</dimen>
<dimen name="transient_taskbar_stashed_height">32dp</dimen>
<dimen name="transient_taskbar_all_apps_button_translation_x_offset">8dp</dimen>
@@ -384,6 +385,11 @@
<!-- Taskbar swipe down threshold -->
<dimen name="taskbar_to_nav_threshold">24dp</dimen>
+ <!-- Taskbar variables that help determine when to animate the Taskbar background -->
+ <!-- Velocity defined as dp per s. Negative because the gesture is an upwards motion. -->
+ <dimen name="taskbar_slow_velocity_y_threshold">-288dp</dimen>
+ <integer name="taskbar_background_duration">80</integer>
+
<!-- Taskbar swipe up threshold multipliers -->
<item name="taskbar_nav_threshold_mult" format="float" type="dimen">4.5</item>
<item name="taskbar_app_window_threshold_mult" format="float" type="dimen">10</item>
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
index 0000c0d..9178062 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
@@ -35,7 +35,7 @@
/** Manage recents related operations with desktop tasks */
class DesktopRecentsTransitionController(
- private val stateManager: StateManager<*>,
+ private val stateManager: StateManager<*, *>,
private val systemUiProxy: SystemUiProxy,
private val appThread: IApplicationThread,
private val depthController: DepthController?
@@ -64,7 +64,7 @@
private class RemoteDesktopLaunchTransitionRunner(
private val desktopTaskView: DesktopTaskView,
- private val stateManager: StateManager<*>,
+ private val stateManager: StateManager<*, *>,
private val depthController: DepthController?,
private val successCallback: Consumer<Boolean>?
) : RemoteTransitionStub() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 61877f0..6b62c86 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -62,7 +62,6 @@
import android.util.Log;
import android.view.Display;
import android.view.Gravity;
-import android.view.RoundedCorner;
import android.view.Surface;
import android.view.View;
import android.view.WindowInsets;
@@ -166,7 +165,6 @@
private final TaskbarControllers mControllers;
private final WindowManager mWindowManager;
- private final @Nullable RoundedCorner mLeftCorner, mRightCorner;
private DeviceProfile mDeviceProfile;
private WindowManager.LayoutParams mWindowLayoutParams;
private boolean mIsFullscreen;
@@ -227,16 +225,8 @@
Context c = getApplicationContext();
mWindowManager = c.getSystemService(WindowManager.class);
- boolean phoneMode = isPhoneMode();
- mLeftCorner = phoneMode
- ? null
- : display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT);
- mRightCorner = phoneMode
- ? null
- : display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT);
-
// Inflate views.
- int taskbarLayout = DisplayController.isTransientTaskbar(this) && !phoneMode
+ int taskbarLayout = DisplayController.isTransientTaskbar(this) && !isPhoneMode()
? R.layout.transient_taskbar
: R.layout.taskbar;
mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(taskbarLayout, null, false);
@@ -615,12 +605,9 @@
return mImeDrawsImeNavBar;
}
- public int getLeftCornerRadius() {
- return mLeftCorner == null ? 0 : mLeftCorner.getRadius();
- }
-
- public int getRightCornerRadius() {
- return mRightCorner == null ? 0 : mRightCorner.getRadius();
+ public int getCornerRadius() {
+ return isPhoneMode() ? 0 : getResources().getDimensionPixelSize(
+ R.dimen.persistent_taskbar_corner_radius);
}
public WindowManager.LayoutParams getWindowLayoutParams() {
@@ -1013,7 +1000,7 @@
return mDeviceProfile.taskbarHeight
- + Math.max(getLeftCornerRadius(), getRightCornerRadius())
+ + getCornerRadius()
+ extraHeightForTaskbarTooltips;
}
@@ -1396,6 +1383,13 @@
}
/**
+ * Plays the taskbar background alpha animation if one is not currently playing.
+ */
+ public void playTaskbarBackgroundAlphaAnimation() {
+ mControllers.taskbarStashController.playTaskbarBackgroundAlphaAnimation();
+ }
+
+ /**
* Called to start the taskbar translation spring to its settled translation (0).
*/
public void startTranslationSpring() {
@@ -1595,4 +1589,9 @@
boolean canToggleHomeAllApps() {
return mControllers.uiController.canToggleHomeAllApps();
}
+
+ @VisibleForTesting
+ public TaskbarControllers getControllers() {
+ return mControllers;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index bafd059..2737cbd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -37,8 +37,6 @@
class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
private val isInSetup: Boolean = !context.isUserSetupComplete
- private val DARK_THEME_SHADOW_ALPHA = 51f
- private val LIGHT_THEME_SHADOW_ALPHA = 25f
private val maxTransientTaskbarHeight =
context.transientTaskbarDeviceProfile.taskbarHeight.toFloat()
@@ -54,6 +52,7 @@
var isAnimatingPinning = false
val paint = Paint()
+ private val strokePaint = Paint()
val lastDrawnTransientRect = RectF()
var backgroundHeight = context.deviceProfile.taskbarHeight.toFloat()
var translationYForSwipe = 0f
@@ -62,19 +61,18 @@
private val transientBackgroundBounds = context.transientTaskbarBounds
private val shadowAlpha: Float
+ private val strokeAlpha: Int
private var shadowBlur = 0f
private var keyShadowDistance = 0f
private var bottomMargin = 0
- private val fullLeftCornerRadius = context.leftCornerRadius.toFloat()
- private val fullRightCornerRadius = context.rightCornerRadius.toFloat()
- private var leftCornerRadius = fullLeftCornerRadius
- private var rightCornerRadius = fullRightCornerRadius
+ private val fullCornerRadius = context.cornerRadius.toFloat()
+ private var cornerRadius = fullCornerRadius
private var widthInsetPercentage = 0f
- private val square: Path = Path()
- private val circle: Path = Path()
- private val invertedLeftCornerPath: Path = Path()
- private val invertedRightCornerPath: Path = Path()
+ private val square = Path()
+ private val circle = Path()
+ private val invertedLeftCornerPath = Path()
+ private val invertedRightCornerPath = Path()
private var stashedHandleWidth =
context.resources.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width)
@@ -86,10 +84,18 @@
paint.color = context.getColor(R.color.taskbar_background)
paint.flags = Paint.ANTI_ALIAS_FLAG
paint.style = Paint.Style.FILL
-
- shadowAlpha =
- if (Utilities.isDarkTheme(context)) DARK_THEME_SHADOW_ALPHA
- else LIGHT_THEME_SHADOW_ALPHA
+ strokePaint.color = context.getColor(R.color.taskbar_stroke)
+ strokePaint.flags = Paint.ANTI_ALIAS_FLAG
+ strokePaint.style = Paint.Style.STROKE
+ strokePaint.strokeWidth =
+ context.resources.getDimension(R.dimen.transient_taskbar_stroke_width)
+ if (Utilities.isDarkTheme(context)) {
+ strokeAlpha = DARK_THEME_STROKE_ALPHA
+ shadowAlpha = DARK_THEME_SHADOW_ALPHA
+ } else {
+ strokeAlpha = LIGHT_THEME_STROKE_ALPHA
+ shadowAlpha = LIGHT_THEME_SHADOW_ALPHA
+ }
setCornerRoundness(DEFAULT_ROUNDNESS)
}
@@ -106,7 +112,7 @@
}
/**
- * Sets the roundness of the round corner above Taskbar. No effect on transient Taskkbar.
+ * Sets the roundness of the round corner above Taskbar. No effect on transient Taskbar.
*
* @param cornerRoundness 0 has no round corner, 1 has complete round corner.
*/
@@ -115,21 +121,18 @@
return
}
- leftCornerRadius = fullLeftCornerRadius * cornerRoundness
- rightCornerRadius = fullRightCornerRadius * cornerRoundness
+ cornerRadius = fullCornerRadius * cornerRoundness
// Create the paths for the inverted rounded corners above the taskbar. Start with a filled
// square, and then subtract out a circle from the appropriate corner.
square.reset()
- square.addRect(0f, 0f, leftCornerRadius, leftCornerRadius, Path.Direction.CW)
+ square.addRect(0f, 0f, cornerRadius, cornerRadius, Path.Direction.CW)
circle.reset()
- circle.addCircle(leftCornerRadius, 0f, leftCornerRadius, Path.Direction.CW)
+ circle.addCircle(cornerRadius, 0f, cornerRadius, Path.Direction.CW)
invertedLeftCornerPath.op(square, circle, Path.Op.DIFFERENCE)
- square.reset()
- square.addRect(0f, 0f, rightCornerRadius, rightCornerRadius, Path.Direction.CW)
circle.reset()
- circle.addCircle(0f, 0f, rightCornerRadius, Path.Direction.CW)
+ circle.addCircle(0f, 0f, cornerRadius, Path.Direction.CW)
invertedRightCornerPath.op(square, circle, Path.Op.DIFFERENCE)
}
@@ -163,10 +166,10 @@
}
// Draw the inverted rounded corners above the taskbar.
- canvas.translate(0f, -leftCornerRadius)
+ canvas.translate(0f, -cornerRadius)
canvas.drawPath(invertedLeftCornerPath, paint)
- canvas.translate(0f, leftCornerRadius)
- canvas.translate(canvas.width - rightCornerRadius, -rightCornerRadius)
+ canvas.translate(0f, cornerRadius)
+ canvas.translate(canvas.width - cornerRadius, -cornerRadius)
canvas.drawPath(invertedRightCornerPath, paint)
}
@@ -236,6 +239,7 @@
keyShadowDistance,
setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
)
+ strokePaint.alpha = (paint.alpha * strokeAlpha) / 255
lastDrawnTransientRect.set(
transientBackgroundBounds.left + halfWidthDelta,
@@ -247,6 +251,7 @@
lastDrawnTransientRect.inset(horizontalInset, 0f)
canvas.drawRoundRect(lastDrawnTransientRect, radius, radius, paint)
+ canvas.drawRoundRect(lastDrawnTransientRect, radius, radius, strokePaint)
}
/**
@@ -259,5 +264,9 @@
companion object {
const val DEFAULT_ROUNDNESS = 1f
+ private const val DARK_THEME_STROKE_ALPHA = 51
+ private const val LIGHT_THEME_STROKE_ALPHA = 41
+ private const val DARK_THEME_SHADOW_ALPHA = 51f
+ private const val LIGHT_THEME_SHADOW_ALPHA = 25f
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 84874a9..f703463 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -18,6 +18,7 @@
import static android.view.KeyEvent.ACTION_UP;
import static android.view.KeyEvent.KEYCODE_BACK;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import android.content.Context;
@@ -41,6 +42,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.views.BaseDragLayer;
@@ -104,7 +106,10 @@
mTaskbarBackgroundAlpha = new MultiPropertyFactory<>(this, BG_ALPHA, INDEX_COUNT,
(a, b) -> a * b, 1f);
mTaskbarBackgroundAlpha.get(INDEX_ALL_OTHER_STATES).setValue(0);
- mTaskbarBackgroundAlpha.get(INDEX_STASH_ANIM).setValue(1);
+ mTaskbarBackgroundAlpha.get(INDEX_STASH_ANIM).setValue(
+ enableScalingRevealHomeAnimation() && DisplayController.isTransientTaskbar(context)
+ ? 0
+ : 1);
}
public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index ec2cee2..2a58db2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -611,7 +611,8 @@
}
}
- private void addTaskbarRootViewToWindow() {
+ @VisibleForTesting
+ void addTaskbarRootViewToWindow() {
if (enableTaskbarNoRecreate() && !mAddedWindow && mTaskbarActivityContext != null) {
mWindowManager.addView(mTaskbarRootLayout,
mTaskbarActivityContext.getWindowLayoutParams());
@@ -619,7 +620,8 @@
}
}
- private void removeTaskbarRootViewFromWindow() {
+ @VisibleForTesting
+ void removeTaskbarRootViewFromWindow() {
if (enableTaskbarNoRecreate() && mAddedWindow) {
mWindowManager.removeViewImmediate(mTaskbarRootLayout);
mAddedWindow = false;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 995a652..7ff887c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -22,6 +22,7 @@
import static com.android.app.animation.Interpolators.INSTANT;
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.internal.jank.InteractionJankMonitor.Configuration;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_SHOW;
@@ -38,6 +39,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
import android.app.RemoteAction;
import android.graphics.drawable.Icon;
import android.os.SystemClock;
@@ -241,6 +243,10 @@
private final Alarm mTimeoutAlarm = new Alarm();
private boolean mEnableBlockingTimeoutDuringTests = false;
+ private Animator mTaskbarBackgroundAlphaAnimator;
+ private long mTaskbarBackgroundDuration;
+ private boolean mIsGoingHome;
+
// Evaluate whether the handle should be stashed
private final LongPredicate mIsStashedPredicate = flags -> {
boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP);
@@ -265,6 +271,8 @@
mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
mAccessibilityManager = mActivity.getSystemService(AccessibilityManager.class);
+ mTaskbarBackgroundDuration =
+ activity.getResources().getInteger(R.integer.taskbar_background_duration);
if (mActivity.isPhoneMode()) {
mUnstashedHeight = mActivity.getResources().getDimensionPixelSize(
R.dimen.taskbar_phone_size);
@@ -759,9 +767,16 @@
backgroundAndHandleAlphaStartDelay,
backgroundAndHandleAlphaDuration, LINEAR);
- play(as, mTaskbarBackgroundAlphaForStash.animateToValue(backgroundAlphaTarget),
- backgroundAndHandleAlphaStartDelay,
- backgroundAndHandleAlphaDuration, LINEAR);
+ if (enableScalingRevealHomeAnimation() && !isStashed) {
+ play(as, getTaskbarBackgroundAnimatorWhenNotGoingHome(duration),
+ 0, 0, LINEAR);
+ as.addListener(AnimatorListeners.forEndCallback(
+ () -> mTaskbarBackgroundAlphaForStash.setValue(backgroundAlphaTarget)));
+ } else {
+ play(as, mTaskbarBackgroundAlphaForStash.animateToValue(backgroundAlphaTarget),
+ backgroundAndHandleAlphaStartDelay,
+ backgroundAndHandleAlphaDuration, LINEAR);
+ }
// The rest of the animations might be "skipped" in TRANSITION_HANDLE_FADE transitions.
AnimatorSet skippable = as;
@@ -804,6 +819,62 @@
.setDuration(isStashed ? duration / 2 : duration));
}
+ private Animator getTaskbarBackgroundAnimatorWhenNotGoingHome(long duration) {
+ ValueAnimator a = ValueAnimator.ofFloat(0, 1);
+ a.setDuration(duration);
+ a.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ // This value is arbitrary.
+ private static final float ANIMATED_FRACTION_THRESHOLD = 0.25f;
+ private boolean mTaskbarBgAlphaAnimationStarted = false;
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ if (mIsGoingHome) {
+ mTaskbarBgAlphaAnimationStarted = true;
+ }
+ if (mTaskbarBgAlphaAnimationStarted) {
+ return;
+ }
+
+ if (valueAnimator.getAnimatedFraction() >= ANIMATED_FRACTION_THRESHOLD) {
+ if (!mIsGoingHome) {
+ playTaskbarBackgroundAlphaAnimation();
+ setUserIsGoingHome(false);
+ mTaskbarBgAlphaAnimationStarted = true;
+ }
+ }
+ }
+ });
+ return a;
+ }
+
+ /**
+ * Sets whether the user is going home based on the current gesture.
+ */
+ public void setUserIsGoingHome(boolean isGoingHome) {
+ mIsGoingHome = isGoingHome;
+ }
+
+ /**
+ * Plays the taskbar background alpha animation if one is not currently playing.
+ */
+ public void playTaskbarBackgroundAlphaAnimation() {
+ if (mTaskbarBackgroundAlphaAnimator != null
+ && mTaskbarBackgroundAlphaAnimator.isRunning()) {
+ return;
+ }
+ mTaskbarBackgroundAlphaAnimator = mTaskbarBackgroundAlphaForStash
+ .animateToValue(1f)
+ .setDuration(mTaskbarBackgroundDuration);
+ mTaskbarBackgroundAlphaAnimator.setInterpolator(LINEAR);
+ mTaskbarBackgroundAlphaAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTaskbarBackgroundAlphaAnimator = null;
+ }
+ });
+ mTaskbarBackgroundAlphaAnimator.start();
+ }
+
private static void play(AnimatorSet as, @Nullable Animator a, long startDelay, long duration,
Interpolator interpolator) {
if (a == null) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 2b68b52..593285f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -411,4 +411,11 @@
public void setSkipNextRecentsAnimEnd() {
// Overridden
}
+
+ /**
+ * Sets whether the user is going home based on the current gesture.
+ */
+ public void setUserIsGoingHome(boolean isGoingHome) {
+ mControllers.taskbarStashController.setUserIsGoingHome(isGoingHome);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 23495ad..55745b5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -347,6 +347,11 @@
float allAppIconTranslateRange = mapRange(scale, transientTaskbarAllAppsOffset,
persistentTaskbarAllAppsOffset);
+ // no x translation required when all apps button is the only icon in taskbar.
+ if (iconViews.length <= 1) {
+ allAppIconTranslateRange = 0f;
+ }
+
if (mIsRtl) {
allAppIconTranslateRange *= -1;
}
@@ -377,7 +382,7 @@
-finalMarginScale * (iconIndex - halfIconCount));
}
- if (iconView.equals(mTaskbarView.getAllAppsButtonView()) && iconViews.length > 1) {
+ if (iconView.equals(mTaskbarView.getAllAppsButtonView())) {
((IconButtonView) iconView).setTranslationXForTaskbarAllAppsIcon(
allAppIconTranslateRange);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index a59e81b..25939e1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -19,7 +19,9 @@
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.ColorFilter
+import android.graphics.Matrix
import android.graphics.Paint
+import android.graphics.Path
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
import com.android.app.animation.Interpolators
@@ -28,28 +30,28 @@
import com.android.launcher3.Utilities.mapToRange
import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
import com.android.launcher3.popup.RoundedArrowDrawable
+import kotlin.math.max
+import kotlin.math.min
/** Drawable for the background of the bubble bar. */
class BubbleBarBackground(context: Context, private var backgroundHeight: Float) : Drawable() {
- private val DARK_THEME_SHADOW_ALPHA = 51f
- private val LIGHT_THEME_SHADOW_ALPHA = 25f
-
- private val paint: Paint = Paint()
- private val pointerWidth: Float
- private val pointerHeight: Float
- private val pointerTipRadius: Float
- private val pointerVisibleHeight: Float
+ private val fillPaint: Paint = Paint()
+ private val strokePaint: Paint = Paint()
+ private val arrowWidth: Float
+ private val arrowHeight: Float
+ private val arrowTipRadius: Float
+ private val arrowVisibleHeight: Float
private val shadowAlpha: Float
private var shadowBlur = 0f
private var keyShadowDistance = 0f
+ private var arrowHeightFraction = 1f
var arrowPositionX: Float = 0f
private set
private var showingArrow: Boolean = false
- private var arrowDrawable: RoundedArrowDrawable
var width: Float = 0f
@@ -70,34 +72,31 @@
}
init {
- paint.color = context.getColor(R.color.taskbar_background)
- paint.flags = Paint.ANTI_ALIAS_FLAG
- paint.style = Paint.Style.FILL
-
val res = context.resources
+ // configure fill paint
+ fillPaint.color = context.getColor(R.color.taskbar_background)
+ fillPaint.flags = Paint.ANTI_ALIAS_FLAG
+ fillPaint.style = Paint.Style.FILL
+ // configure stroke paint
+ strokePaint.color = context.getColor(R.color.taskbar_stroke)
+ strokePaint.flags = Paint.ANTI_ALIAS_FLAG
+ strokePaint.style = Paint.Style.STROKE
+ strokePaint.strokeWidth = res.getDimension(R.dimen.transient_taskbar_stroke_width)
+ // apply theme alpha attributes
+ if (Utilities.isDarkTheme(context)) {
+ strokePaint.alpha = DARK_THEME_STROKE_ALPHA
+ shadowAlpha = DARK_THEME_SHADOW_ALPHA
+ } else {
+ strokePaint.alpha = LIGHT_THEME_STROKE_ALPHA
+ shadowAlpha = LIGHT_THEME_SHADOW_ALPHA
+ }
+
shadowBlur = res.getDimension(R.dimen.transient_taskbar_shadow_blur)
keyShadowDistance = res.getDimension(R.dimen.transient_taskbar_key_shadow_distance)
- pointerWidth = res.getDimension(R.dimen.bubblebar_pointer_width)
- pointerHeight = res.getDimension(R.dimen.bubblebar_pointer_height)
- pointerVisibleHeight = res.getDimension(R.dimen.bubblebar_pointer_visible_size)
- pointerTipRadius = res.getDimension(R.dimen.bubblebar_pointer_radius)
-
- shadowAlpha =
- if (Utilities.isDarkTheme(context)) {
- DARK_THEME_SHADOW_ALPHA
- } else {
- LIGHT_THEME_SHADOW_ALPHA
- }
-
- arrowDrawable =
- RoundedArrowDrawable.createVerticalRoundedArrow(
- pointerWidth,
- pointerHeight,
- pointerTipRadius,
- /* isPointingUp= */ true,
- context.getColor(R.color.taskbar_background)
- )
- arrowDrawable.setBounds(0, 0, pointerWidth.toInt(), pointerHeight.toInt())
+ arrowWidth = res.getDimension(R.dimen.bubblebar_pointer_width)
+ arrowHeight = res.getDimension(R.dimen.bubblebar_pointer_height)
+ arrowVisibleHeight = res.getDimension(R.dimen.bubblebar_pointer_visible_size)
+ arrowTipRadius = res.getDimension(R.dimen.bubblebar_pointer_radius)
}
fun showArrow(show: Boolean) {
@@ -115,40 +114,54 @@
// TODO (b/277359345): Should animate the alpha similar to taskbar (see TaskbarDragLayer)
// Draw shadows.
val newShadowAlpha =
- mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, shadowAlpha, Interpolators.LINEAR)
- paint.setShadowLayer(
+ mapToRange(fillPaint.alpha.toFloat(), 0f, 255f, 0f, shadowAlpha, Interpolators.LINEAR)
+ fillPaint.setShadowLayer(
shadowBlur,
0f,
keyShadowDistance,
setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
)
- arrowDrawable.setShadowLayer(
- shadowBlur,
- 0f,
- keyShadowDistance,
- setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
- )
-
- // Draw background.
+ // Create background path
+ val backgroundPath = Path()
+ val topOffset = backgroundHeight - bounds.height().toFloat()
val radius = backgroundHeight / 2f
val left = bounds.left + (if (anchorLeft) 0f else bounds.width().toFloat() - width)
val right = bounds.left + (if (anchorLeft) width else bounds.width().toFloat())
- val top = bounds.top + pointerVisibleHeight
+ val top = bounds.top - topOffset + arrowVisibleHeight
+
val bottom = bounds.top + bounds.height().toFloat()
- canvas.drawRoundRect(left, top, right, bottom, radius, radius, paint)
+ backgroundPath.addRoundRect(left, top, right, bottom, radius, radius, Path.Direction.CW)
+ addArrowPathIfNeeded(backgroundPath, topOffset)
- if (showingArrow) {
- // Draw arrow.
- val transX = bounds.left + arrowPositionX - pointerWidth / 2f
- canvas.translate(transX, 0f)
- arrowDrawable.draw(canvas)
- }
-
+ // Draw background.
+ canvas.drawPath(backgroundPath, fillPaint)
+ canvas.drawPath(backgroundPath, strokePaint)
canvas.restore()
}
+ private fun addArrowPathIfNeeded(sourcePath: Path, topOffset: Float) {
+ if (!showingArrow || arrowHeightFraction <= 0) return
+ val arrowPath = Path()
+ RoundedArrowDrawable.addDownPointingRoundedTriangleToPath(
+ arrowWidth,
+ arrowHeight,
+ arrowTipRadius,
+ arrowPath
+ )
+ // flip it horizontally
+ val pathTransform = Matrix()
+ pathTransform.setRotate(180f, arrowWidth * 0.5f, arrowHeight * 0.5f)
+ arrowPath.transform(pathTransform)
+ // shift to arrow position
+ val arrowStart = bounds.left + arrowPositionX - (arrowWidth / 2f)
+ val arrowTop = (1 - arrowHeightFraction) * arrowVisibleHeight - topOffset
+ arrowPath.offset(arrowStart, arrowTop)
+ // union with rectangle
+ sourcePath.op(arrowPath, Path.Op.UNION)
+ }
+
override fun getOpacity(): Int {
- return when (paint.alpha) {
+ return when (fillPaint.alpha) {
255 -> PixelFormat.OPAQUE
0 -> PixelFormat.TRANSPARENT
else -> PixelFormat.TRANSLUCENT
@@ -156,24 +169,40 @@
}
override fun setAlpha(alpha: Int) {
- paint.alpha = alpha
- arrowDrawable.alpha = alpha
+ fillPaint.alpha = alpha
invalidateSelf()
}
override fun getAlpha(): Int {
- return paint.alpha
+ return fillPaint.alpha
}
override fun setColorFilter(colorFilter: ColorFilter?) {
- paint.colorFilter = colorFilter
+ fillPaint.colorFilter = colorFilter
}
- fun setArrowAlpha(alpha: Int) {
- arrowDrawable.alpha = alpha
- }
-
- fun setHeight(newHeight: Float) {
+ fun setBackgroundHeight(newHeight: Float) {
backgroundHeight = newHeight
}
+
+ /**
+ * Set fraction of the arrow height that should be displayed. Allowed values range are [0..1].
+ * If value passed is out of range it will be converted to the closest value in tha allowed
+ * range.
+ */
+ fun setArrowHeightFraction(arrowHeightFraction: Float) {
+ var newHeightFraction = arrowHeightFraction
+ if (newHeightFraction !in 0f..1f) {
+ newHeightFraction = min(max(newHeightFraction, 0f), 1f)
+ }
+ this.arrowHeightFraction = newHeightFraction
+ invalidateSelf()
+ }
+
+ companion object {
+ private const val DARK_THEME_STROKE_ALPHA = 51
+ private const val LIGHT_THEME_STROKE_ALPHA = 41
+ private const val DARK_THEME_SHADOW_ALPHA = 51f
+ private const val LIGHT_THEME_SHADOW_ALPHA = 25f
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 046f5b6..028df34 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -135,7 +135,6 @@
private static final Executor BUBBLE_STATE_EXECUTOR = Executors.newSingleThreadExecutor(
new SimpleThreadFactory("BubbleStateUpdates-", THREAD_PRIORITY_BACKGROUND));
- private final Executor mMainExecutor;
private final LauncherApps mLauncherApps;
private final BubbleIconFactory mIconFactory;
private final SystemUiProxy mSystemUiProxy;
@@ -198,7 +197,6 @@
if (sBubbleBarEnabled) {
mSystemUiProxy.setBubblesListener(this);
}
- mMainExecutor = MAIN_EXECUTOR;
mLauncherApps = context.getSystemService(LauncherApps.class);
mIconFactory = new BubbleIconFactory(context,
context.getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size),
@@ -241,7 +239,7 @@
private void createAndAddOverflowIfNeeded() {
if (mOverflowBubble == null) {
BubbleBarOverflow overflow = createOverflow(mContext);
- mMainExecutor.execute(() -> {
+ MAIN_EXECUTOR.execute(() -> {
// we're on the main executor now, so check that the overflow hasn't been created
// again to avoid races.
if (mOverflowBubble == null) {
@@ -303,12 +301,12 @@
}
viewUpdate.currentBubbles = currentBubbles;
}
- mMainExecutor.execute(() -> applyViewChanges(viewUpdate));
+ MAIN_EXECUTOR.execute(() -> applyViewChanges(viewUpdate));
});
} else {
// No bubbles to load, immediately apply the changes.
BUBBLE_STATE_EXECUTOR.execute(
- () -> mMainExecutor.execute(() -> applyViewChanges(viewUpdate)));
+ () -> MAIN_EXECUTOR.execute(() -> applyViewChanges(viewUpdate)));
}
}
@@ -496,7 +494,7 @@
@Override
public void animateBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
- mMainExecutor.execute(
+ MAIN_EXECUTOR.execute(
() -> mBubbleBarViewController.animateBubbleBarLocation(bubbleBarLocation));
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index a0cad90..c7c63e8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -24,6 +24,7 @@
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -44,6 +45,7 @@
import com.android.launcher3.R;
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.util.DisplayController;
+import com.android.wm.shell.Flags;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
import java.util.List;
@@ -85,6 +87,7 @@
private static final int MAX_VISIBLE_BUBBLES_COLLAPSED = 2;
private static final int ARROW_POSITION_ANIMATION_DURATION_MS = 200;
private static final int WIDTH_ANIMATION_DURATION_MS = 200;
+ private static final int SCALE_ANIMATION_DURATION_MS = 200;
private static final long FADE_OUT_ANIM_ALPHA_DURATION_MS = 50L;
private static final long FADE_OUT_ANIM_ALPHA_DELAY_MS = 50L;
@@ -135,13 +138,12 @@
private float mBubbleBarPadding;
// The size of a bubble in the bar
private float mIconSize;
+ // The scale of bubble icons
+ private float mIconScale = 1f;
// The elevation of the bubbles within the bar
private final float mBubbleElevation;
private final float mDragElevation;
private final int mPointerSize;
-
- private final Rect mTempBackgroundBounds = new Rect();
-
// Whether the bar is expanded (i.e. the bubble activity is being displayed).
private boolean mIsBarExpanded = false;
// The currently selected bubble view.
@@ -162,7 +164,8 @@
/** An animator used for scaling in a new bubble to the bubble bar while expanded. */
@Nullable
private ValueAnimator mNewBubbleScaleInAnimator = null;
-
+ @Nullable
+ private ValueAnimator mScalePaddingAnimator;
@Nullable
private Animator mBubbleBarLocationAnimator = null;
@@ -217,42 +220,74 @@
setBackgroundDrawable(mBubbleBarBackground);
mWidthAnimator.setDuration(WIDTH_ANIMATION_DURATION_MS);
- mWidthAnimator.addUpdateListener(animation -> {
- updateBubblesLayoutProperties(mBubbleBarLocation);
- invalidate();
- });
- mWidthAnimator.addListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationCancel(Animator animation) {
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- mBubbleBarBackground.showArrow(mIsBarExpanded);
- if (!mIsBarExpanded && mReorderRunnable != null) {
- mReorderRunnable.run();
- mReorderRunnable = null;
- }
- // If the bar was just collapsed and the overflow was the last bubble that was
- // selected, set the first bubble as selected.
- if (!mIsBarExpanded && mUpdateSelectedBubbleAfterCollapse != null
- && mSelectedBubbleView != null
- && mSelectedBubbleView.getBubble() instanceof BubbleBarOverflow) {
- BubbleView firstBubble = (BubbleView) getChildAt(0);
- mUpdateSelectedBubbleAfterCollapse.accept(firstBubble.getBubble().getKey());
- }
- updateWidth();
- }
+ addAnimationCallBacks(mWidthAnimator,
+ /* onStart= */ () -> mBubbleBarBackground.showArrow(true),
+ /* onEnd= */ () -> {
+ mBubbleBarBackground.showArrow(mIsBarExpanded);
+ if (!mIsBarExpanded && mReorderRunnable != null) {
+ mReorderRunnable.run();
+ mReorderRunnable = null;
+ }
+ // If the bar was just collapsed and the overflow was the last bubble that was
+ // selected, set the first bubble as selected.
+ if (!mIsBarExpanded && mUpdateSelectedBubbleAfterCollapse != null
+ && mSelectedBubbleView != null
+ && mSelectedBubbleView.getBubble() instanceof BubbleBarOverflow) {
+ BubbleView firstBubble = (BubbleView) getChildAt(0);
+ mUpdateSelectedBubbleAfterCollapse.accept(firstBubble.getBubble().getKey());
+ }
+ updateWidth();
+ },
+ /* onUpdate= */ animator -> {
+ updateBubblesLayoutProperties(mBubbleBarLocation);
+ invalidate();
+ });
+ }
- @Override
- public void onAnimationRepeat(Animator animation) {
- }
- @Override
- public void onAnimationStart(Animator animation) {
- mBubbleBarBackground.showArrow(true);
- }
- });
+ /**
+ * Animates icon sizes and spacing between icons and bubble bar borders.
+ *
+ * @param newIconSize new icon size
+ * @param newBubbleBarPadding spacing between icons and bubble bar borders.
+ */
+ public void animateBubbleBarIconSize(float newIconSize, float newBubbleBarPadding) {
+ if (!isIconSizeOrPaddingUpdated(newIconSize, newBubbleBarPadding)) {
+ return;
+ }
+ if (!Flags.animateBubbleSizeChange()) {
+ setIconSizeAndPadding(newIconSize, newBubbleBarPadding);
+ }
+ if (mScalePaddingAnimator != null && mScalePaddingAnimator.isRunning()) {
+ mScalePaddingAnimator.cancel();
+ }
+ ValueAnimator scalePaddingAnimator = ValueAnimator.ofFloat(0f, 1f);
+ scalePaddingAnimator.setDuration(SCALE_ANIMATION_DURATION_MS);
+ boolean isPaddingUpdated = isPaddingUpdated(newBubbleBarPadding);
+ boolean isIconSizeUpdated = isIconSizeUpdated(newIconSize);
+ float initialScale = mIconScale;
+ float initialPadding = mBubbleBarPadding;
+ float targetScale = newIconSize / getScaledIconSize();
+
+ addAnimationCallBacks(scalePaddingAnimator,
+ /* onStart= */ null,
+ /* onEnd= */ () -> setIconSizeAndPadding(newIconSize, newBubbleBarPadding),
+ /* onUpdate= */ animator -> {
+ float transitionProgress = (float) animator.getAnimatedValue();
+ if (isIconSizeUpdated) {
+ mIconScale =
+ initialScale + (targetScale - initialScale) * transitionProgress;
+ }
+ if (isPaddingUpdated) {
+ mBubbleBarPadding = initialPadding
+ + (newBubbleBarPadding - initialPadding) * transitionProgress;
+ }
+ updateBubblesLayoutProperties(mBubbleBarLocation);
+ invalidate();
+ });
+ scalePaddingAnimator.start();
+ mScalePaddingAnimator = scalePaddingAnimator;
}
@Override
@@ -267,28 +302,37 @@
}
/**
- * Sets new icon size and spacing between icons and bubble bar borders.
+ * Sets new icon sizes and newBubbleBarPadding between icons and bubble bar borders.
*
- * @param newIconSize new icon size
- * @param spacing spacing between icons and bubble bar borders.
+ * @param newIconSize new icon size
+ * @param newBubbleBarPadding newBubbleBarPadding between icons and bubble bar borders.
*/
- // TODO(b/335575529): animate bubble bar icons size change
- public void setIconSizeAndPadding(float newIconSize, float spacing) {
+ public void setIconSizeAndPadding(float newIconSize, float newBubbleBarPadding) {
// TODO(b/335457839): handle new bubble animation during the size change
- mBubbleBarPadding = spacing;
+ if (!isIconSizeOrPaddingUpdated(newIconSize, newBubbleBarPadding)) {
+ return;
+ }
+ mIconScale = 1f;
+ mBubbleBarPadding = newBubbleBarPadding;
mIconSize = newIconSize;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View childView = getChildAt(i);
+ childView.setScaleY(mIconScale);
+ childView.setScaleY(mIconScale);
FrameLayout.LayoutParams params = (LayoutParams) childView.getLayoutParams();
params.height = (int) mIconSize;
params.width = (int) mIconSize;
childView.setLayoutParams(params);
}
- mBubbleBarBackground.setHeight(getBubbleBarExpandedHeight());
+ mBubbleBarBackground.setBackgroundHeight(getBubbleBarHeight());
updateLayoutParams();
}
+ private float getScaledIconSize() {
+ return mIconSize * mIconScale;
+ }
+
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
@@ -698,6 +742,11 @@
setLayoutParams(lp);
}
+ private float getBubbleBarHeight() {
+ return mIsBarExpanded ? getBubbleBarExpandedHeight()
+ : getBubbleBarCollapsedHeight();
+ }
+
/** @return the horizontal margin between the bubble bar and the edge of the screen. */
int getHorizontalMargin() {
LayoutParams lp = (FrameLayout.LayoutParams) getLayoutParams();
@@ -714,7 +763,10 @@
final float expandedWidth = expandedWidth();
final float collapsedWidth = collapsedWidth();
int bubbleCount = getChildCount();
- final float ty = (mBubbleBarBounds.height() - mIconSize) / 2f;
+ float viewBottom = mBubbleBarBounds.height() + (isExpanded() ? mPointerSize : 0);
+ float bubbleBarAnimatedTop = viewBottom - getBubbleBarHeight();
+ // When translating X & Y the scale is ignored, so need to deduct it from the translations
+ final float ty = bubbleBarAnimatedTop + mBubbleBarPadding - getScaleIconShift();
final boolean animate = getVisibility() == VISIBLE;
final boolean onLeft = bubbleBarLocation.isOnLeft(isLayoutRtl());
// elevation state is opposite to widthState - when expanded all icons are flat
@@ -729,8 +781,9 @@
bv.setDragTranslationX(0f);
bv.setOffsetX(0f);
+ bv.setScaleX(mIconScale);
+ bv.setScaleY(mIconScale);
bv.setTranslationY(ty);
-
// the position of the bubble when the bar is fully expanded
final float expandedX = getExpandedBubbleTranslationX(i, bubbleCount, onLeft);
// the position of the bubble when the bar is fully collapsed
@@ -793,23 +846,30 @@
}
}
mBubbleBarBackground.setArrowPosition(arrowPosition);
- mBubbleBarBackground.setArrowAlpha((int) (255 * widthState));
+ mBubbleBarBackground.setArrowHeightFraction(widthState);
mBubbleBarBackground.setWidth(interpolatedWidth);
+ mBubbleBarBackground.setBackgroundHeight(getBubbleBarExpandedHeight());
+ }
+
+ private float getScaleIconShift() {
+ return (mIconSize - getScaledIconSize()) / 2;
}
private float getExpandedBubbleTranslationX(int bubbleIndex, int bubbleCount, boolean onLeft) {
if (bubbleIndex < 0 || bubbleIndex >= bubbleCount) {
return 0;
}
- final float iconAndSpacing = mIconSize + mExpandedBarIconsSpacing;
+ final float iconAndSpacing = getScaledIconSize() + mExpandedBarIconsSpacing;
+ float translationX;
if (mNewBubbleScaleInAnimator != null && mNewBubbleScaleInAnimator.isRunning()) {
- return getExpandedBubbleTranslationXDuringScaleAnimation(
+ translationX = getExpandedBubbleTranslationXDuringScaleAnimation(
bubbleIndex, bubbleCount, onLeft);
} else if (onLeft) {
- return (bubbleCount - bubbleIndex - 1) * iconAndSpacing;
+ translationX = mBubbleBarPadding + (bubbleCount - bubbleIndex - 1) * iconAndSpacing;
} else {
- return bubbleIndex * iconAndSpacing;
+ translationX = mBubbleBarPadding + bubbleIndex * iconAndSpacing;
}
+ return translationX - getScaleIconShift();
}
/**
@@ -830,17 +890,17 @@
// compiler doesn't know that.
return 0;
}
- final float iconAndSpacing = mIconSize + mExpandedBarIconsSpacing;
+ final float iconAndSpacing = getScaledIconSize() + mExpandedBarIconsSpacing;
final float newBubbleScale = mNewBubbleScaleInAnimator.getAnimatedFraction();
// the new bubble is scaling in from the center, so we need to adjust its translation so
// that the distance to the adjacent bubble scales at the same rate.
- final float pivotAdjustment = -(1 - newBubbleScale) * mIconSize / 2f;
+ final float pivotAdjustment = -(1 - newBubbleScale) * getScaledIconSize() / 2f;
if (onLeft) {
if (bubbleIndex == 0) {
// this is the animating bubble. use scaled spacing between it and the bubble to
// its left
- return (bubbleCount - 1) * mIconSize
+ return (bubbleCount - 1) * getScaledIconSize()
+ (bubbleCount - 2) * mExpandedBarIconsSpacing
+ newBubbleScale * mExpandedBarIconsSpacing
+ pivotAdjustment;
@@ -862,13 +922,16 @@
if (bubbleIndex < 0 || bubbleIndex >= bubbleCount) {
return 0;
}
+ float translationX;
if (onLeft) {
// Shift the first bubble only if there are more bubbles in addition to overflow
- return bubbleIndex == 0 && bubbleCount > MAX_VISIBLE_BUBBLES_COLLAPSED
- ? mIconOverlapAmount : 0;
+ translationX = mBubbleBarPadding + (
+ bubbleIndex == 0 && bubbleCount > MAX_VISIBLE_BUBBLES_COLLAPSED
+ ? mIconOverlapAmount : 0);
} else {
- return bubbleIndex == 0 ? 0 : mIconOverlapAmount;
+ translationX = mBubbleBarPadding + (bubbleIndex == 0 ? 0 : mIconOverlapAmount);
}
+ return translationX - getScaleIconShift();
}
/**
@@ -976,7 +1039,7 @@
final int index = indexOfChild(mSelectedBubbleView);
final float selectedBubbleTranslationX = getExpandedBubbleTranslationX(
index, getChildCount(), bubbleBarLocation.isOnLeft(isLayoutRtl()));
- return getPaddingStart() + selectedBubbleTranslationX + mIconSize / 2f;
+ return selectedBubbleTranslationX + mIconSize / 2f;
}
private float arrowPositionForSelectedWhenCollapsed(BubbleBarLocation bubbleBarLocation) {
@@ -987,9 +1050,10 @@
// bubbles than the current bubble and overflow.
bubblePosition = index == 0 && getChildCount() > MAX_VISIBLE_BUBBLES_COLLAPSED ? 1 : 0;
} else {
- bubblePosition = index;
+ bubblePosition = index >= MAX_VISIBLE_BUBBLES_COLLAPSED
+ ? MAX_VISIBLE_BUBBLES_COLLAPSED - 1 : index;
}
- return getPaddingStart() + bubblePosition * (mIconOverlapAmount) + mIconSize / 2f;
+ return mBubbleBarPadding + bubblePosition * (mIconOverlapAmount) + getScaledIconSize() / 2f;
}
@Override
@@ -1037,7 +1101,6 @@
*/
public float expandedWidth() {
final int childCount = getChildCount();
- final int horizontalPadding = getPaddingStart() + getPaddingEnd();
// spaces amount is less than child count by 1, or 0 if no child views
final float totalSpace;
final float totalIconSize;
@@ -1046,22 +1109,22 @@
// expanded, so we have at least 2 bubbles in the bubble bar.
final float newBubbleScale = mNewBubbleScaleInAnimator.getAnimatedFraction();
totalSpace = (childCount - 2 + newBubbleScale) * mExpandedBarIconsSpacing;
- totalIconSize = (childCount - 1 + newBubbleScale) * mIconSize;
+ totalIconSize = (childCount - 1 + newBubbleScale) * getScaledIconSize();
} else {
totalSpace = Math.max(childCount - 1, 0) * mExpandedBarIconsSpacing;
- totalIconSize = childCount * mIconSize;
+ totalIconSize = childCount * getScaledIconSize();
}
- return totalIconSize + totalSpace + horizontalPadding;
+ return totalIconSize + totalSpace + 2 * mBubbleBarPadding;
}
private float collapsedWidth() {
final int childCount = getChildCount();
- final int horizontalPadding = getPaddingStart() + getPaddingEnd();
+ final float horizontalPadding = 2 * mBubbleBarPadding;
// If there are more than 2 bubbles, the first 2 should be visible when collapsed.
// Otherwise just the first bubble should be visible because we don't show the overflow.
return childCount > MAX_VISIBLE_BUBBLES_COLLAPSED
- ? mIconSize + mIconOverlapAmount + horizontalPadding
- : mIconSize + horizontalPadding;
+ ? getScaledIconSize() + mIconOverlapAmount + horizontalPadding
+ : getScaledIconSize() + horizontalPadding;
}
private float getBubbleBarExpandedHeight() {
@@ -1070,7 +1133,7 @@
float getBubbleBarCollapsedHeight() {
// the pointer is invisible when collapsed
- return mIconSize + mBubbleBarPadding * 2;
+ return getScaledIconSize() + mBubbleBarPadding * 2;
}
/**
@@ -1102,6 +1165,7 @@
return mIsAnimatingNewBubble;
}
+
private boolean hasOverview() {
// Overview is always the last bubble
View lastChild = getChildAt(getChildCount() - 1);
@@ -1143,6 +1207,46 @@
setContentDescription(contentDesc);
}
+ private boolean isIconSizeOrPaddingUpdated(float newIconSize, float newBubbleBarPadding) {
+ return isIconSizeUpdated(newIconSize) || isPaddingUpdated(newBubbleBarPadding);
+ }
+
+ private boolean isIconSizeUpdated(float newIconSize) {
+ return Float.compare(mIconSize, newIconSize) != 0;
+ }
+
+ private boolean isPaddingUpdated(float newBubbleBarPadding) {
+ return Float.compare(mBubbleBarPadding, newBubbleBarPadding) != 0;
+ }
+
+ private void addAnimationCallBacks(@NonNull ValueAnimator animator,
+ @Nullable Runnable onStart,
+ @Nullable Runnable onEnd,
+ @Nullable ValueAnimator.AnimatorUpdateListener onUpdate) {
+ if (onUpdate != null) animator.addUpdateListener(onUpdate);
+ animator.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationCancel(Animator animator) {
+
+ }
+
+ @Override
+ public void onAnimationStart(Animator animator) {
+ if (onStart != null) onStart.run();
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animator) {
+ if (onEnd != null) onEnd.run();
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animator) {
+
+ }
+ });
+ }
+
/** Interface for BubbleBarView to communicate with its controller. */
interface Controller {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 0bfd1d7..eec095d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -108,9 +108,11 @@
mBubbleDragController = bubbleControllers.bubbleDragController;
mTaskbarStashController = controllers.taskbarStashController;
mTaskbarInsetsController = controllers.taskbarInsetsController;
+ mBubbleBarViewAnimator = new BubbleBarViewAnimator(mBarView, mBubbleStashController);
- mActivity.addOnDeviceProfileChangeListener(dp -> setBubbleBarIconSize(dp.taskbarIconSize));
- setBubbleBarIconSize(mActivity.getDeviceProfile().taskbarIconSize);
+ mActivity.addOnDeviceProfileChangeListener(
+ dp -> updateBubbleBarIconSize(dp.taskbarIconSize, /* animate= */ true));
+ updateBubbleBarIconSize(mActivity.getDeviceProfile().taskbarIconSize, /* animate= */ false);
mBubbleBarScale.updateValue(1f);
mBubbleClickListener = v -> onBubbleClicked(v);
mBubbleBarClickListener = v -> onBubbleBarClicked();
@@ -123,8 +125,6 @@
mBoundsChangeListener.onBoundsChanged();
}
});
-
- mBubbleBarViewAnimator = new BubbleBarViewAnimator(mBarView, mBubbleStashController);
mBarView.setController(new BubbleBarView.Controller() {
@Override
public float getBubbleBarTranslationY() {
@@ -299,33 +299,6 @@
}
}
- private void setBubbleBarIconSize(int newIconSize) {
- if (newIconSize == mIconSize) {
- return;
- }
- Resources res = mActivity.getResources();
- DisplayMetrics dm = res.getDisplayMetrics();
- float smallIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- APP_ICON_SMALL_DP, dm);
- float mediumIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- APP_ICON_MEDIUM_DP, dm);
- float largeIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
- APP_ICON_LARGE_DP, dm);
- float smallMediumThreshold = (smallIconSize + mediumIconSize) / 2f;
- float mediumLargeThreshold = (mediumIconSize + largeIconSize) / 2f;
- mIconSize = newIconSize <= smallMediumThreshold
- ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_size_small) :
- res.getDimensionPixelSize(R.dimen.bubblebar_icon_size);
- float bubbleBarPadding = newIconSize >= mediumLargeThreshold
- ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing_large) :
- res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
-
- mBarView.setIconSizeAndPadding(mIconSize, bubbleBarPadding);
- mBarView.setPadding((int) bubbleBarPadding, mBarView.getPaddingTop(),
- (int) bubbleBarPadding,
- mBarView.getPaddingBottom());
- }
-
/** Sets a callback that updates the selected bubble after the bubble bar collapses. */
public void setUpdateSelectedBubbleAfterCollapse(
Consumer<String> updateSelectedBubbleAfterCollapse) {
@@ -360,6 +333,30 @@
// Modifying view related properties.
//
+ private void updateBubbleBarIconSize(int newIconSize, boolean animate) {
+ Resources res = mActivity.getResources();
+ DisplayMetrics dm = res.getDisplayMetrics();
+ float smallIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ APP_ICON_SMALL_DP, dm);
+ float mediumIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ APP_ICON_MEDIUM_DP, dm);
+ float largeIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
+ APP_ICON_LARGE_DP, dm);
+ float smallMediumThreshold = (smallIconSize + mediumIconSize) / 2f;
+ float mediumLargeThreshold = (mediumIconSize + largeIconSize) / 2f;
+ mIconSize = newIconSize <= smallMediumThreshold
+ ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_size_small) :
+ res.getDimensionPixelSize(R.dimen.bubblebar_icon_size);
+ float bubbleBarPadding = newIconSize >= mediumLargeThreshold
+ ? res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing_large) :
+ res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
+ if (animate) {
+ mBarView.animateBubbleBarIconSize(mIconSize, bubbleBarPadding);
+ } else {
+ mBarView.setIconSizeAndPadding(mIconSize, bubbleBarPadding);
+ }
+ }
+
/**
* Sets the translation of the bubble bar during the swipe up gesture.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
index adbec65..7eb34a5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
@@ -133,16 +133,19 @@
* <p>
* This method should be called after an exit animation finishes, if applicable.
*/
- @SuppressLint("WrongConstant")
void maybeCloseWindow() {
- if (mOverlayContext != null && (AbstractFloatingView.hasOpenView(mOverlayContext, TYPE_ALL)
- || mOverlayContext.getDragController().isSystemDragInProgress())) {
- return;
- }
+ if (!canCloseWindow()) return;
mProxyView.close(false);
onDestroy();
}
+ @SuppressLint("WrongConstant")
+ private boolean canCloseWindow() {
+ if (mOverlayContext == null) return true;
+ if (AbstractFloatingView.hasOpenView(mOverlayContext, TYPE_ALL)) return false;
+ return !mOverlayContext.getDragController().isSystemDragInProgress();
+ }
+
/** Destroys the controller and any overlay window if present. */
public void onDestroy() {
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
@@ -212,10 +215,17 @@
@Override
protected void handleClose(boolean animate) {
- if (mIsOpen) {
- mTaskbarContext.getDragLayer().removeView(this);
- Optional.ofNullable(mOverlayContext).ifPresent(c -> closeAllOpenViews(c, animate));
- }
+ if (!mIsOpen) return;
+ mTaskbarContext.getDragLayer().removeView(this);
+ Optional.ofNullable(mOverlayContext).ifPresent(c -> {
+ if (canCloseWindow()) {
+ onDestroy(); // Window is already ready to be destroyed.
+ } else {
+ // Close window's AFVs before destroying it. Its drag layer will attempt to
+ // close the proxy view again once its children are removed.
+ closeAllOpenViews(c, animate);
+ }
+ });
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index e3a2bab..2168f7a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -1118,7 +1118,7 @@
}
@Override
- protected void collectStateHandlers(List<StateHandler> out) {
+ public void collectStateHandlers(List<StateHandler<LauncherState>> out) {
super.collectStateHandlers(out);
out.add(getDepthController());
out.add(new RecentsViewStateController(this));
diff --git a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
index 146ff3d..0469636 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
+++ b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
@@ -17,24 +17,32 @@
import android.app.ActivityOptions
import android.app.PendingIntent
+import android.app.role.RoleManager
import android.content.Context
+import android.content.IIntentReceiver
+import android.content.IIntentSender
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps
import android.content.pm.ShortcutInfo
+import android.os.Bundle
import android.os.Flags.allowPrivateProfile
+import android.os.IBinder
import android.os.UserHandle
import android.os.UserManager
import android.util.ArrayMap
+import android.widget.Toast
import android.window.RemoteTransition
import com.android.launcher3.Flags.enablePrivateSpace
import com.android.launcher3.Flags.enablePrivateSpaceInstallShortcut
import com.android.launcher3.Flags.privateSpaceAppInstallerButton
import com.android.launcher3.Flags.privateSpaceSysAppsSeparation
+import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.proxy.ProxyActivityStarter
import com.android.launcher3.util.ApiWrapper
+import com.android.launcher3.util.Executors
import com.android.launcher3.util.StartActivityParams
import com.android.launcher3.util.UserIconInfo
import com.android.quickstep.util.FadeOutRemoteTransition
@@ -115,8 +123,7 @@
intentSender =
mContext
.getSystemService(LauncherApps::class.java)
- ?.privateSpaceSettingsIntent
- ?: return null
+ ?.privateSpaceSettingsIntent ?: return null
options =
ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
@@ -130,4 +137,50 @@
override fun isNonResizeableActivity(lai: LauncherActivityInfo) =
lai.activityInfo.resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE
+
+ /**
+ * Starts an Activity which can be used to set this Launcher as the HOME app, via a consent
+ * screen. In case the consent screen cannot be shown, or the user does not set current Launcher
+ * as HOME app, a toast asking the user to do the latter is shown.
+ */
+ override fun assignDefaultHomeRole(context: Context) {
+ val roleManager = context.getSystemService(RoleManager::class.java)
+ if (
+ (roleManager!!.isRoleAvailable(RoleManager.ROLE_HOME) &&
+ !roleManager.isRoleHeld(RoleManager.ROLE_HOME))
+ ) {
+ val roleRequestIntent = roleManager.createRequestRoleIntent(RoleManager.ROLE_HOME)
+ val pendingIntent =
+ PendingIntent(
+ object : IIntentSender.Stub() {
+ override fun send(
+ code: Int,
+ intent: Intent,
+ resolvedType: String?,
+ allowlistToken: IBinder?,
+ finishedReceiver: IIntentReceiver?,
+ requiredPermission: String?,
+ options: Bundle?
+ ) {
+ if (code != -1) {
+ Executors.MAIN_EXECUTOR.execute {
+ Toast.makeText(
+ context,
+ context.getString(
+ R.string.set_default_home_app,
+ context.getString(R.string.derived_app_name)
+ ),
+ Toast.LENGTH_LONG
+ )
+ .show()
+ }
+ }
+ }
+ }
+ )
+ val params = StartActivityParams(pendingIntent, 0)
+ params.intent = roleRequestIntent
+ context.startActivity(ProxyActivityStarter.getLaunchIntent(context, params))
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 3199076..1acafab 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -32,6 +32,7 @@
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.PagedView.INVALID_PAGE;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
@@ -1193,6 +1194,10 @@
setDividerShown(true);
break;
}
+ if (mContainerInterface.getTaskbarController() != null) {
+ // Resets this value as the gesture is now complete.
+ mContainerInterface.getTaskbarController().setUserIsGoingHome(false);
+ }
ActiveGestureLog.INSTANCE.addLog(
new ActiveGestureLog.CompoundString("onSettledOnEndTarget ")
.append(endTarget.name()),
@@ -1341,6 +1346,13 @@
mGestureState.setEndTarget(endTarget, false /* isAtomic */);
mAnimationFactory.setEndTarget(endTarget);
+ if (enableScalingRevealHomeAnimation()
+ && mIsTransientTaskbar
+ && mContainerInterface.getTaskbarController() != null) {
+ mContainerInterface.getTaskbarController()
+ .setUserIsGoingHome(endTarget == GestureState.GestureEndTarget.HOME);
+ }
+
float endShift = endTarget == ALL_APPS ? mDragLengthFactor
: endTarget.isLauncher ? 1 : 0;
final float startShift;
diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
index 9e896fd..89fbf4a 100644
--- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java
@@ -154,7 +154,8 @@
@Override
public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) {
- final StateManager<RecentsState> stateManager = getCreatedContainer().getStateManager();
+ final StateManager<RecentsState, RecentsActivity> stateManager =
+ getCreatedContainer().getStateManager();
if (stateManager.getState() == HOME) {
exitRunnable.run();
notifyRecentsOfOrientation(deviceState);
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 08c2e1c..c428827 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -36,6 +36,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Flags;
+import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.LauncherInitListener;
import com.android.launcher3.LauncherState;
@@ -242,7 +243,8 @@
@Override
public void onExitOverview(RotationTouchHelper deviceState, Runnable exitRunnable) {
- final StateManager<LauncherState> stateManager = getCreatedContainer().getStateManager();
+ final StateManager<LauncherState, Launcher> stateManager =
+ getCreatedContainer().getStateManager();
stateManager.addStateListener(
new StateManager.StateListener<LauncherState>() {
@Override
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 26a7c2f..7da92bc 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -228,8 +228,9 @@
}
BaseActivityInterface<?, T> activityInterface =
mOverviewComponentObserver.getActivityInterface();
- RecentsView visibleRecentsView = activityInterface.getVisibleRecentsView();
- RecentsView createdRecentsView;
+
+ RecentsView<?, ?> visibleRecentsView = activityInterface.getVisibleRecentsView();
+ RecentsView<?, ?> createdRecentsView;
Log.d(TAG, "executeCommand: " + cmd
+ " - visibleRecentsView: " + visibleRecentsView);
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 37b4dca..b08a46f 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -75,7 +75,7 @@
private ArrayList<ActivityManager.RunningTaskInfo> mRunningTasks;
public RecentTasksList(LooperExecutor mainThreadExecutor, KeyguardManager keyguardManager,
- SystemUiProxy sysUiProxy) {
+ SystemUiProxy sysUiProxy, TopTaskTracker topTaskTracker) {
mMainThreadExecutor = mainThreadExecutor;
mKeyguardManager = keyguardManager;
mChangeId = 1;
@@ -106,6 +106,13 @@
RecentTasksList.this.onRunningTaskChanged(taskInfo);
});
}
+
+ @Override
+ public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+ mMainThreadExecutor.execute(() -> {
+ topTaskTracker.onTaskMovedToFront(taskInfo);
+ });
+ }
});
// We may receive onRunningTaskAppeared events later for tasks which have already been
// included in the list returned by mSysUiProxy.getRunningTasks(), or may receive
@@ -135,7 +142,7 @@
* Asynchronously fetches the list of recent tasks, reusing cached list if available.
*
* @param loadKeysOnly Whether to load other associated task data, or just the key
- * @param callback The callback to receive the list of recent tasks
+ * @param callback The callback to receive the list of recent tasks
* @return The change id of the current task list
*/
public synchronized int getTasks(boolean loadKeysOnly,
@@ -200,7 +207,7 @@
mChangeId++;
}
- /**
+ /**
* Registers a listener for running tasks
*/
public void registerRunningTasksListener(RecentsModel.RunningTasksListener listener) {
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 3df62da..13e9844 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -115,7 +115,7 @@
private TISBindHelper mTISBindHelper;
private @Nullable FallbackTaskbarUIController mTaskbarUIController;
- private StateManager<RecentsState> mStateManager;
+ private StateManager<RecentsState, RecentsActivity> mStateManager;
// Strong refs to runners which are cleared when the activity is destroyed
private RemoteAnimationFactory mActivityLaunchAnimationRunner;
@@ -386,6 +386,11 @@
}
}
+ @Override
+ public boolean shouldAnimateStateChange() {
+ return false;
+ }
+
/**
* Initialize/update the device profile.
*/
@@ -462,12 +467,12 @@
};
@Override
- protected void collectStateHandlers(List<StateHandler> out) {
+ public void collectStateHandlers(List<StateHandler<RecentsState>> out) {
out.add(new FallbackRecentsStateController(this));
}
@Override
- public StateManager<RecentsState> getStateManager() {
+ public StateManager<RecentsState, RecentsActivity> getStateManager() {
return mStateManager;
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 8bcdaa3..7adce74 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -45,6 +45,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED;
import android.app.ActivityTaskManager;
import android.content.Context;
@@ -386,7 +387,7 @@
boolean canStartWithNavHidden = (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
|| (mSystemUiStateFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0
|| mRotationTouchHelper.isTaskListFrozen();
- return canStartWithNavHidden && canStartTrackpadGesture();
+ return canStartWithNavHidden && canStartAnyGesture();
}
/**
@@ -395,14 +396,24 @@
* mode.
*/
public boolean canStartTrackpadGesture() {
- return (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
- && (mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING) == 0
- && (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0
- && (mSystemUiStateFlags & SYSUI_STATE_MAGNIFICATION_OVERLAP) == 0
- && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
- || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0)
- && (mSystemUiStateFlags & SYSUI_STATE_DEVICE_DREAMING) == 0
- && (mSystemUiStateFlags & SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION) == 0;
+ boolean trackpadGesturesEnabled =
+ (mSystemUiStateFlags & SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED) == 0;
+ return trackpadGesturesEnabled && canStartAnyGesture();
+ }
+
+ /**
+ * Common logic to determine if either trackpad or finger gesture can be started
+ */
+ private boolean canStartAnyGesture() {
+ boolean homeOrOverviewEnabled = (mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
+ || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0;
+ long gestureDisablingStates = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+ | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
+ | SYSUI_STATE_QUICK_SETTINGS_EXPANDED
+ | SYSUI_STATE_MAGNIFICATION_OVERLAP
+ | SYSUI_STATE_DEVICE_DREAMING
+ | SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
+ return (gestureDisablingStates & mSystemUiStateFlags) == 0 && homeOrOverviewEnabled;
}
/**
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 98c1eb4..6eefe4a 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -90,7 +90,8 @@
this(context,
new RecentTasksList(MAIN_EXECUTOR,
context.getSystemService(KeyguardManager.class),
- SystemUiProxy.INSTANCE.get(context)),
+ SystemUiProxy.INSTANCE.get(context),
+ TopTaskTracker.INSTANCE.get(context)),
new TaskIconCache(context, RECENTS_MODEL_EXECUTOR, iconProvider),
new TaskThumbnailCache(context, RECENTS_MODEL_EXECUTOR),
iconProvider,
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index 29c80fd..6ed05c8 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -64,7 +64,7 @@
implements TaskStackChangeListener, SafeCloseable {
private static final String TAG = "TopTaskTracker";
-
+
private static final boolean DEBUG = true;
public static MainThreadInitializedObject<TopTaskTracker> INSTANCE =
@@ -204,7 +204,7 @@
/**
* @return index 0 will be task in left/top position, index 1 in right/bottom position.
- * Will return empty array if device is not in staged split
+ * Will return empty array if device is not in staged split
*/
public int[] getRunningSplitTaskIds() {
if (mMainStagePosition.taskId == INVALID_TASK_ID
@@ -295,7 +295,7 @@
* If the given task holds an activity that is excluded from recents, and there
* is another running task that is not excluded from recents, returns that underlying task.
*/
- public @Nullable CachedTaskInfo otherVisibleTaskThisIsExcludedOver() {
+ public @Nullable CachedTaskInfo getVisibleNonExcludedTask() {
if (mTopTask == null
|| (mTopTask.baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
// Not an excluded task.
@@ -303,7 +303,9 @@
}
List<RunningTaskInfo> visibleNonExcludedTasks = mAllCachedTasks.stream()
.filter(t -> t.isVisible
- && (t.baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)
+ && (t.baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0
+ && t.getActivityType() != ACTIVITY_TYPE_HOME
+ && t.getActivityType() != ACTIVITY_TYPE_RECENTS)
.toList();
return visibleNonExcludedTasks.isEmpty() ? null
: new CachedTaskInfo(visibleNonExcludedTasks);
@@ -337,7 +339,7 @@
*/
public Task[] getPlaceholderTasks() {
return mTopTask == null ? new Task[0]
- : new Task[] {Task.from(new TaskKey(mTopTask), mTopTask, false)};
+ : new Task[]{Task.from(new TaskKey(mTopTask), mTopTask, false)};
}
/**
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index e9046b9..bfdc3df 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -510,6 +510,9 @@
private boolean isTrackpadDevice(int deviceId) {
InputDevice inputDevice = mInputManager.getInputDevice(deviceId);
+ if (inputDevice == null) {
+ return false;
+ }
return inputDevice.getSources() == (InputDevice.SOURCE_MOUSE
| InputDevice.SOURCE_TOUCHPAD);
}
@@ -576,6 +579,7 @@
mMainChoreographer = Choreographer.getInstance();
mAM = ActivityManagerWrapper.getInstance();
mDeviceState = new RecentsAnimationDeviceState(this, true);
+ mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
mAllAppsActionManager = new AllAppsActionManager(
this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent);
mInputManager = getSystemService(InputManager.class);
@@ -588,7 +592,6 @@
}
}
mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager, mNavCallbacks);
- mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
// Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
@@ -1242,7 +1245,7 @@
// running activity as the task behind the overlay.
TopTaskTracker.CachedTaskInfo otherVisibleTask = runningTask == null
? null
- : runningTask.otherVisibleTaskThisIsExcludedOver();
+ : runningTask.getVisibleNonExcludedTask();
if (otherVisibleTask != null) {
ActiveGestureLog.INSTANCE.addLog(new CompoundString("Changing active task to ")
.append(otherVisibleTask.getPackageName())
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 485d6c4..f4a2738 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -93,7 +93,7 @@
}
@Override
- public StateManager<RecentsState> getStateManager() {
+ public StateManager<RecentsState, RecentsActivity> getStateManager() {
return mContainer.getStateManager();
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index 9a25c32..95295b0 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -21,6 +21,7 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.launcher3.Flags.enableCursorHoverStates;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TOUCHING;
@@ -32,6 +33,7 @@
import android.os.Looper;
import android.view.InputDevice;
import android.view.MotionEvent;
+import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import androidx.annotation.Nullable;
@@ -55,6 +57,9 @@
public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
private static final int HOVER_TASKBAR_UNSTASH_TIMEOUT = 500;
+
+ private static final int NUM_MOTION_MOVE_THRESHOLD = 3;
+
private static final Handler sUnstashHandler = new Handler(Looper.getMainLooper());
private final TaskbarActivityContext mTaskbarActivityContext;
@@ -83,6 +88,11 @@
private final @Nullable TransitionCallback mTransitionCallback;
private final GestureState mGestureState;
+ private VelocityTracker mVelocityTracker;
+ private boolean mCanPlayTaskbarBgAlphaAnimation = true;
+ private int mMotionMoveCount = 0;
+ // Velocity defined as dp per s
+ private float mTaskbarSlowVelocityYThreshold;
public TaskbarUnstashInputConsumer(Context context, InputConsumer delegate,
InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext,
@@ -101,6 +111,8 @@
mIsTaskbarAllAppsOpen = mTaskbarActivityContext.isTaskbarAllAppsOpen();
mIsTransientTaskbar = DisplayController.isTransientTaskbar(context);
+ mTaskbarSlowVelocityYThreshold =
+ res.getDimensionPixelSize(R.dimen.taskbar_slow_velocity_y_threshold);
mBottomScreenEdge = res.getDimensionPixelSize(
R.dimen.taskbar_stashed_screen_edge_hover_deadzone_height);
@@ -125,6 +137,9 @@
@Override
public void onMotionEvent(MotionEvent ev) {
+ if (enableScalingRevealHomeAnimation() && mIsTransientTaskbar) {
+ checkVelocityForTaskbarBackground(ev);
+ }
if (mState != STATE_ACTIVE) {
boolean isStashedTaskbarHovered = isMouseEvent(ev)
&& isStashedTaskbarHovered((int) ev.getX(), (int) ev.getY());
@@ -254,6 +269,31 @@
}
}
+ private void checkVelocityForTaskbarBackground(MotionEvent ev) {
+ int actionMasked = ev.getActionMasked();
+ if (actionMasked == MotionEvent.ACTION_DOWN && mVelocityTracker != null) {
+ mVelocityTracker.clear();
+ }
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ mVelocityTracker.addMovement(ev);
+
+ mVelocityTracker.computeCurrentVelocity(1000);
+ if (ev.getAction() == ACTION_MOVE) {
+ mMotionMoveCount++;
+ }
+
+ float velocityYPxPerS = mVelocityTracker.getYVelocity();
+ if (mCanPlayTaskbarBgAlphaAnimation
+ && mMotionMoveCount >= NUM_MOTION_MOVE_THRESHOLD // Arbitrary value
+ && velocityYPxPerS != 0 // Ignore these
+ && velocityYPxPerS >= mTaskbarSlowVelocityYThreshold) {
+ mTaskbarActivityContext.playTaskbarBackgroundAlphaAnimation();
+ mCanPlayTaskbarBgAlphaAnimation = false;
+ }
+ }
+
private void cleanupAfterMotionEvent() {
mTaskbarActivityContext.setAutohideSuspendFlag(
FLAG_AUTOHIDE_SUSPEND_TOUCHING, false);
@@ -264,6 +304,13 @@
mIsInBubbleBarArea = false;
mIsVerticalGestureOverBubbleBar = false;
mIsPassedBubbleBarSlop = false;
+
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ }
+ mVelocityTracker = null;
+ mCanPlayTaskbarBgAlphaAnimation = true;
+ mMotionMoveCount = 0;
}
private boolean isInBubbleBarArea(float x) {
diff --git a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
index 4f1dbbe..36ea926 100644
--- a/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/GestureSandboxActivity.java
@@ -59,6 +59,7 @@
@Nullable private TutorialType[] mTutorialSteps;
private GestureSandboxFragment mCurrentFragment;
+ private GestureSandboxFragment mPendingFragment;
private int mCurrentStep;
private int mNumSteps;
@@ -176,16 +177,26 @@
&& getResources().getConfiguration().orientation
== ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
- showFragment(showRotationPrompt
+ GestureSandboxFragment fragment = showRotationPrompt
? new RotationPromptFragment()
- : mCurrentFragment.canRecreateFragment()
- ? mCurrentFragment.recreateFragment() : mCurrentFragment);
+ : mCurrentFragment.canRecreateFragment() || mPendingFragment == null
+ ? mCurrentFragment.recreateFragment()
+ : mPendingFragment.recreateFragment();
+ showFragment(fragment == null ? mCurrentFragment : fragment);
+
} else {
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
}
private void showFragment(@NonNull GestureSandboxFragment fragment) {
+ // Store the current fragment in mPendingFragment so that it can be recreated after the
+ // new fragment is shown.
+ if (mCurrentFragment.canRecreateFragment()) {
+ mPendingFragment = mCurrentFragment;
+ } else {
+ mPendingFragment = null;
+ }
mCurrentFragment = fragment;
getSupportFragmentManager().beginTransaction()
.replace(R.id.gesture_tutorial_fragment_container, mCurrentFragment)
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index c9647f5..c7c04ed 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -39,6 +39,7 @@
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.AllAppsSwipeController;
import com.android.quickstep.DeviceConfigWrapper;
@@ -163,7 +164,8 @@
recentsOrientedState.getContainerInterface().getCreatedContainer();
if (container != null) {
RecentsView recentsView = container.getOverviewPanel();
- StateManager<LauncherState> stateManager = recentsView.getStateManager();
+ StateManager<LauncherState, StatefulActivity<LauncherState>> stateManager =
+ recentsView.getStateManager();
if (stateManager.isInStableState(LauncherState.BACKGROUND_APP)
&& stateManager.isInTransition()) {
diff --git a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
index 132d1c1..492c801 100644
--- a/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
+++ b/quickstep/src/com/android/quickstep/util/OverviewToHomeAnim.java
@@ -62,7 +62,7 @@
* {@link WorkspaceRevealAnim}.
*/
public void animateWithVelocity(float velocity) {
- StateManager<LauncherState> stateManager = mLauncher.getStateManager();
+ StateManager<LauncherState, Launcher> stateManager = mLauncher.getStateManager();
LauncherState startState = stateManager.getState();
if (startState != OVERVIEW) {
Log.e(TAG, "animateFromOverviewToHome: unexpected start state " + startState);
diff --git a/quickstep/src/com/android/quickstep/util/PhoneSplitToConfirmTimings.java b/quickstep/src/com/android/quickstep/util/PhoneSplitToConfirmTimings.java
index 3d9e09e..cbe0f19 100644
--- a/quickstep/src/com/android/quickstep/util/PhoneSplitToConfirmTimings.java
+++ b/quickstep/src/com/android/quickstep/util/PhoneSplitToConfirmTimings.java
@@ -27,6 +27,8 @@
public int getPlaceholderIconFadeInEnd() { return 133; }
public int getStagedRectSlideStart() { return 0; }
public int getStagedRectSlideEnd() { return 333; }
+ public int getBackingScrimFadeInStart() { return 0; }
+ public int getBackingScrimFadeInEnd() { return 266; }
public int getDuration() { return PHONE_CONFIRM_DURATION; }
}
diff --git a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
index 2a27dea..cfe5b2c 100644
--- a/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
+++ b/quickstep/src/com/android/quickstep/util/QuickstepOnboardingPrefs.java
@@ -27,6 +27,7 @@
import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN;
import static com.android.launcher3.util.OnboardingPrefs.HOTSEAT_DISCOVERY_TIP_COUNT;
+import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
@@ -48,7 +49,7 @@
* Sets up the initial onboarding behavior for the launcher
*/
public static void setup(QuickstepLauncher launcher) {
- StateManager<LauncherState> stateManager = launcher.getStateManager();
+ StateManager<LauncherState, Launcher> stateManager = launcher.getStateManager();
if (!HOME_BOUNCE_SEEN.get(launcher)) {
stateManager.addStateListener(new StateListener<LauncherState>() {
@Override
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 8243ede..7ea04b1 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -281,64 +281,45 @@
}
/**
- * Creates and returns a view to fade in at .4 animation progress and adds it to the provided
- * [pendingAnimation]. Assumes that animation will be the final split placeholder launch anim.
- *
- * [secondPlaceholderEndingBounds] refers to the second placeholder view that gets added on
- * screen, not the logical second app. For landscape it's the left app and for portrait the top
- * one.
+ * Creates and returns a fullscreen scrim to fade in behind the split confirm animation, and
+ * adds it to the provided [pendingAnimation].
*/
- fun addDividerPlaceholderViewToAnim(
+ fun addScrimBehindAnim(
pendingAnimation: PendingAnimation,
container: RecentsViewContainer,
- secondPlaceholderEndingBounds: Rect,
context: Context
): View {
- val mSplitDividerPlaceholderView = View(context)
+ val scrim = View(context)
val recentsView = container.getOverviewPanel<RecentsView<*, *>>()
- val dp: com.android.launcher3.DeviceProfile = container.getDeviceProfile()
+ val dp: DeviceProfile = container.getDeviceProfile()
// Add it before/under the most recently added first floating taskView
val firstAddedSplitViewIndex: Int =
container
.getDragLayer()
.indexOfChild(recentsView.splitSelectController.firstFloatingTaskView)
- container.getDragLayer().addView(mSplitDividerPlaceholderView, firstAddedSplitViewIndex)
- val lp = mSplitDividerPlaceholderView.layoutParams as InsettableFrameLayout.LayoutParams
+ container.getDragLayer().addView(scrim, firstAddedSplitViewIndex)
+ // Make the scrim fullscreen
+ val lp = scrim.layoutParams as InsettableFrameLayout.LayoutParams
lp.topMargin = 0
+ lp.height = dp.heightPx
+ lp.width = dp.widthPx
- if (dp.isLeftRightSplit) {
- lp.height = secondPlaceholderEndingBounds.height()
- lp.width =
- container
- .asContext()
- .resources
- .getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
- mSplitDividerPlaceholderView.translationX =
- secondPlaceholderEndingBounds.right - lp.width / 2f
- mSplitDividerPlaceholderView.translationY = 0f
- } else {
- lp.height =
- container
- .asContext()
- .resources
- .getDimensionPixelSize(R.dimen.split_divider_handle_region_height)
- lp.width = secondPlaceholderEndingBounds.width()
- mSplitDividerPlaceholderView.translationY =
- secondPlaceholderEndingBounds.top - lp.height / 2f
- mSplitDividerPlaceholderView.translationX = 0f
- }
-
- mSplitDividerPlaceholderView.alpha = 0f
- mSplitDividerPlaceholderView.setBackgroundColor(
+ scrim.alpha = 0f
+ scrim.setBackgroundColor(
container.asContext().resources.getColor(R.color.taskbar_background_dark)
)
- val timings = AnimUtils.getDeviceSplitToConfirmTimings(dp.isTablet)
+ val timings = AnimUtils.getDeviceSplitToConfirmTimings(dp.isTablet) as SplitToConfirmTimings
pendingAnimation.setViewAlpha(
- mSplitDividerPlaceholderView,
+ scrim,
1f,
- Interpolators.clampToProgress(timings.stagedRectScaleXInterpolator, 0.4f, 1f)
+ Interpolators.clampToProgress(
+ timings.backingScrimFadeInterpolator,
+ timings.backingScrimFadeInStartOffset,
+ timings.backingScrimFadeInEndOffset
+ )
)
- return mSplitDividerPlaceholderView
+
+ return scrim
}
/** Does not play any animation if user is not currently in split selection state. */
@@ -510,7 +491,7 @@
apps: Array<RemoteAnimationTarget>?,
wallpapers: Array<RemoteAnimationTarget>?,
nonApps: Array<RemoteAnimationTarget>?,
- stateManager: StateManager<*>,
+ stateManager: StateManager<*, *>,
depthController: DepthController?,
info: TransitionInfo?,
t: Transaction?,
@@ -589,7 +570,7 @@
@VisibleForTesting
fun composeRecentsSplitLaunchAnimator(
launchingTaskView: GroupedTaskView,
- stateManager: StateManager<*>,
+ stateManager: StateManager<*, *>,
depthController: DepthController?,
info: TransitionInfo,
t: Transaction,
@@ -617,7 +598,7 @@
apps: Array<RemoteAnimationTarget>,
wallpapers: Array<RemoteAnimationTarget>,
nonApps: Array<RemoteAnimationTarget>,
- stateManager: StateManager<*>,
+ stateManager: StateManager<*, *>,
depthController: DepthController?,
finishCallback: Runnable
) {
diff --git a/quickstep/src/com/android/quickstep/util/SplitToConfirmTimings.java b/quickstep/src/com/android/quickstep/util/SplitToConfirmTimings.java
index d1ec2b6..7557ad1 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToConfirmTimings.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToConfirmTimings.java
@@ -17,6 +17,7 @@
package com.android.quickstep.util;
import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.app.animation.Interpolators.LINEAR;
import android.view.animation.Interpolator;
@@ -31,6 +32,8 @@
abstract public int getPlaceholderIconFadeInEnd();
abstract public int getStagedRectSlideStart();
abstract public int getStagedRectSlideEnd();
+ abstract public int getBackingScrimFadeInStart();
+ abstract public int getBackingScrimFadeInEnd();
// Common timings
public int getInstructionsFadeStart() { return 0; }
@@ -39,6 +42,7 @@
public Interpolator getStagedRectYInterpolator() { return EMPHASIZED; }
public Interpolator getStagedRectScaleXInterpolator() { return EMPHASIZED; }
public Interpolator getStagedRectScaleYInterpolator() { return EMPHASIZED; }
+ public Interpolator getBackingScrimFadeInterpolator() { return LINEAR; }
abstract public int getDuration();
@@ -48,4 +52,10 @@
public float getInstructionsFadeEndOffset() {
return (float) getInstructionsFadeEnd() / getDuration();
}
+ public float getBackingScrimFadeInStartOffset() {
+ return (float) getBackingScrimFadeInStart() / getDuration();
+ }
+ public float getBackingScrimFadeInEndOffset() {
+ return (float) getBackingScrimFadeInEnd() / getDuration();
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index 2396512..4962367 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -163,9 +163,8 @@
new RectF(firstTaskStartingBounds), firstTaskEndingBounds,
false /* fadeWithThumbnail */, true /* isStagedTask */);
- View mSplitDividerPlaceholderView = recentsView.getSplitSelectController()
- .getSplitAnimationController().addDividerPlaceholderViewToAnim(pendingAnimation,
- mLauncher, secondTaskEndingBounds, view.getContext());
+ View backingScrim = recentsView.getSplitSelectController().getSplitAnimationController()
+ .addScrimBehindAnim(pendingAnimation, mLauncher, view.getContext());
FloatingTaskView secondFloatingTaskView = FloatingTaskView.getFloatingTaskView(mLauncher,
view, bitmap, icon, secondTaskStartingBounds);
@@ -197,7 +196,7 @@
private void cleanUp() {
mLauncher.getDragLayer().removeView(firstFloatingTaskView);
mLauncher.getDragLayer().removeView(secondFloatingTaskView);
- mLauncher.getDragLayer().removeView(mSplitDividerPlaceholderView);
+ mLauncher.getDragLayer().removeView(backingScrim);
mController.getSplitAnimationController().removeSplitInstructionsView(mLauncher);
mController.resetState();
}
diff --git a/quickstep/src/com/android/quickstep/util/TabletSplitToConfirmTimings.java b/quickstep/src/com/android/quickstep/util/TabletSplitToConfirmTimings.java
index 3756b4a..d74473c 100644
--- a/quickstep/src/com/android/quickstep/util/TabletSplitToConfirmTimings.java
+++ b/quickstep/src/com/android/quickstep/util/TabletSplitToConfirmTimings.java
@@ -27,6 +27,8 @@
public int getPlaceholderIconFadeInEnd() { return 250; }
public int getStagedRectSlideStart() { return 0; }
public int getStagedRectSlideEnd() { return 500; }
+ public int getBackingScrimFadeInStart() { return 0; }
+ public int getBackingScrimFadeInEnd() { return 400; }
public int getDuration() { return TABLET_CONFIRM_DURATION; }
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 5284b44..e48a7c6 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -37,6 +37,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.desktop.DesktopRecentsTransitionController;
@@ -104,7 +105,7 @@
}
@Override
- public StateManager<LauncherState> getStateManager() {
+ public StateManager<LauncherState, Launcher> getStateManager() {
return mContainer.getStateManager();
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 9096b75..4f802c9 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -152,6 +152,7 @@
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.touch.OverScroll;
@@ -738,7 +739,11 @@
private int mSplitHiddenTaskViewIndex = -1;
@Nullable
private FloatingTaskView mSecondFloatingTaskView;
- private View mSplitDividerPlaceholderView;
+ /**
+ * A fullscreen scrim that goes behind the splitscreen animation to hide color conflicts and
+ * possible flickers. Removed after tasks + divider finish animating in.
+ */
+ private View mSplitScrim;
/**
* The task to be removed and immediately re-added. Should not be added to task pool.
@@ -2487,7 +2492,9 @@
/** Returns whether user can start home based on state in {@link OverviewCommandHelper}. */
protected abstract boolean canStartHomeSafely();
- public abstract StateManager<STATE_TYPE> getStateManager();
+ /** Returns the state manager used in RecentsView **/
+ public abstract StateManager<STATE_TYPE,
+ ? extends StatefulContainer<STATE_TYPE>> getStateManager();
public void reset() {
setCurrentTask(-1);
@@ -4926,9 +4933,8 @@
mSplitSelectStateController.getActiveSplitStagePosition(), firstTaskEndingBounds,
secondTaskEndingBounds);
- mSplitDividerPlaceholderView = mSplitSelectStateController
- .getSplitAnimationController().addDividerPlaceholderViewToAnim(pendingAnimation,
- mContainer, secondTaskEndingBounds, getContext());
+ mSplitScrim = mSplitSelectStateController.getSplitAnimationController()
+ .addScrimBehindAnim(pendingAnimation, mContainer, getContext());
FloatingTaskView firstFloatingTaskView =
mSplitSelectStateController.getFirstFloatingTaskView();
firstFloatingTaskView.getBoundsOnScreen(firstTaskStartingBounds);
@@ -4983,7 +4989,7 @@
safeRemoveDragLayerView(mSplitSelectStateController.getFirstFloatingTaskView());
safeRemoveDragLayerView(mSecondFloatingTaskView);
safeRemoveDragLayerView(mSplitSelectStateController.getSplitInstructionsView());
- safeRemoveDragLayerView(mSplitDividerPlaceholderView);
+ safeRemoveDragLayerView(mSplitScrim);
mSecondFloatingTaskView = null;
mSplitSelectSource = null;
mSplitSelectStateController.getSplitAnimationController()
diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
index 447002f..4283d0e 100644
--- a/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
+++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailViewDeprecated.java
@@ -61,6 +61,8 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.recents.utilities.PreviewPositionHelper;
+import java.util.Objects;
+
/**
* A task in the Recents view.
*
@@ -222,14 +224,16 @@
public void setThumbnail(@Nullable Task task, @Nullable ThumbnailData thumbnailData,
boolean refreshNow) {
mTask = task;
- boolean thumbnailWasNull = mThumbnailData == null;
+ ThumbnailData oldThumbnailData = mThumbnailData;
mThumbnailData = (thumbnailData != null && thumbnailData.getThumbnail() != null)
? thumbnailData : null;
if (mTask != null) {
updateSplashView(mTask.icon);
}
if (refreshNow) {
- refresh(thumbnailWasNull && mThumbnailData != null);
+ Long oldSnapshotId = oldThumbnailData != null ? oldThumbnailData.getSnapshotId() : null;
+ Long snapshotId = mThumbnailData != null ? mThumbnailData.getSnapshotId() : null;
+ refresh(snapshotId != null && !Objects.equals(oldSnapshotId, snapshotId));
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 5e79743..9c1aaa6 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -63,6 +63,7 @@
import com.android.launcher3.testing.TestLogging
import com.android.launcher3.testing.shared.TestProtocol
import com.android.launcher3.util.CancellableTask
+import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.Executors
import com.android.launcher3.util.MultiPropertyFactory
import com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE
@@ -76,6 +77,7 @@
import com.android.launcher3.util.TransformingTouchDelegate
import com.android.launcher3.util.ViewPool
import com.android.launcher3.util.rects.set
+import com.android.launcher3.views.ActivityContext
import com.android.quickstep.RecentsModel
import com.android.quickstep.RemoteAnimationTargets
import com.android.quickstep.TaskAnimationManager
@@ -1574,7 +1576,20 @@
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
open fun computeWindowCornerRadius(context: Context): Float {
- return QuickStepContract.getWindowCornerRadius(context)
+ val activityContext: ActivityContext? = ActivityContext.lookupContextNoThrow(context)
+
+ // The corner radius is fixed to match when Taskbar is persistent mode
+ return if (
+ activityContext != null &&
+ activityContext.deviceProfile?.isTaskbarPresent == true &&
+ DisplayController.isTransientTaskbar(context)
+ ) {
+ context.resources
+ .getDimensionPixelSize(R.dimen.persistent_taskbar_corner_radius)
+ .toFloat()
+ } else {
+ QuickStepContract.getWindowCornerRadius(context)
+ }
}
/** Sets the progress in range [0, 1] */
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarUnitTestRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarUnitTestRule.kt
new file mode 100644
index 0000000..a999e7f
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarUnitTestRule.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.app.Instrumentation
+import android.app.PendingIntent
+import android.content.IIntentSender
+import android.content.Intent
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.rule.ServiceTestRule
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks
+import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
+import com.android.launcher3.util.LauncherMultivalentJUnit.Companion.isRunningInRobolectric
+import com.android.quickstep.AllAppsActionManager
+import com.android.quickstep.TouchInteractionService
+import com.android.quickstep.TouchInteractionService.TISBinder
+import org.junit.Assume.assumeTrue
+import org.junit.rules.MethodRule
+import org.junit.runners.model.FrameworkMethod
+import org.junit.runners.model.Statement
+
+/**
+ * Manages the Taskbar lifecycle for unit tests.
+ *
+ * See [InjectController] for grabbing controller(s) under test with minimal boilerplate.
+ *
+ * The rule interacts with [TaskbarManager] on the main thread. A good rule of thumb for tests is
+ * that code that is executed on the main thread in production should also happen on that thread
+ * when tested.
+ *
+ * `@UiThreadTest` is a simple way to run an entire test body on the main thread. But if a test
+ * executes code that appends message(s) to the main thread's `MessageQueue`, the annotation will
+ * prevent those messages from being processed until after the test body finishes.
+ *
+ * To test pending messages, instead use something like [Instrumentation.runOnMainSync] to perform
+ * only sections of the test body on the main thread synchronously:
+ * ```
+ * @Test
+ * fun example() {
+ * instrumentation.runOnMainSync { doWorkThatPostsMessage() }
+ * // Second lambda will not execute until message is processed.
+ * instrumentation.runOnMainSync { verifyMessageResults() }
+ * }
+ * ```
+ */
+class TaskbarUnitTestRule : MethodRule {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val serviceTestRule = ServiceTestRule()
+
+ private lateinit var taskbarManager: TaskbarManager
+ private lateinit var target: Any
+
+ val activityContext: TaskbarActivityContext
+ get() {
+ return taskbarManager.currentActivityContext
+ ?: throw RuntimeException("Failed to obtain TaskbarActivityContext.")
+ }
+
+ override fun apply(base: Statement, method: FrameworkMethod, target: Any): Statement {
+ return object : Statement() {
+ override fun evaluate() {
+ this@TaskbarUnitTestRule.target = target
+
+ val context = instrumentation.targetContext
+ instrumentation.runOnMainSync {
+ assumeTrue(
+ LauncherAppState.getIDP(context).getDeviceProfile(context).isTaskbarPresent
+ )
+ }
+
+ // Check for existing Taskbar instance from Launcher process.
+ val launcherTaskbarManager: TaskbarManager? =
+ if (!isRunningInRobolectric) {
+ try {
+ val tisBinder =
+ serviceTestRule.bindService(
+ Intent(context, TouchInteractionService::class.java)
+ ) as? TISBinder
+ tisBinder?.taskbarManager
+ } catch (_: Exception) {
+ null
+ }
+ } else {
+ null
+ }
+
+ instrumentation.runOnMainSync {
+ taskbarManager =
+ TaskbarManager(
+ context,
+ AllAppsActionManager(context, UI_HELPER_EXECUTOR) {
+ PendingIntent(IIntentSender.Default())
+ },
+ object : TaskbarNavButtonCallbacks {},
+ )
+ }
+
+ try {
+ // Replace Launcher Taskbar window with test instance.
+ instrumentation.runOnMainSync {
+ launcherTaskbarManager?.removeTaskbarRootViewFromWindow()
+ taskbarManager.onUserUnlocked() // Required to complete initialization.
+ }
+
+ injectControllers()
+ base.evaluate()
+ } finally {
+ // Revert Taskbar window.
+ instrumentation.runOnMainSync {
+ taskbarManager.destroy()
+ launcherTaskbarManager?.addTaskbarRootViewToWindow()
+ }
+ }
+ }
+ }
+ }
+
+ /** Simulates Taskbar recreation lifecycle. */
+ fun recreateTaskbar() {
+ taskbarManager.recreateTaskbar()
+ injectControllers()
+ }
+
+ private fun injectControllers() {
+ val controllers = activityContext.controllers
+ val controllerFieldsByType = controllers.javaClass.fields.associateBy { it.type }
+ target.javaClass.fields
+ .filter { it.isAnnotationPresent(InjectController::class.java) }
+ .forEach {
+ it.set(
+ target,
+ controllerFieldsByType[it.type]?.get(controllers)
+ ?: throw NoSuchElementException("Failed to find controller for ${it.type}"),
+ )
+ }
+ }
+
+ /**
+ * Annotates test controller fields to inject the corresponding controllers from the current
+ * [TaskbarControllers] instance.
+ *
+ * Controllers are injected during test setup and upon calling [recreateTaskbar].
+ *
+ * Multiple controllers can be injected if needed.
+ */
+ @Retention(AnnotationRetention.RUNTIME)
+ @Target(AnnotationTarget.FIELD)
+ annotation class InjectController
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsControllerTest.kt
new file mode 100644
index 0000000..c09dcf2
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsControllerTest.kt
@@ -0,0 +1,185 @@
+/*
+ * 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.allapps
+
+import android.content.ComponentName
+import android.content.Intent
+import android.os.Process
+import androidx.test.annotation.UiThreadTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.BubbleTextView
+import com.android.launcher3.appprediction.PredictionRowView
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.notification.NotificationKeyData
+import com.android.launcher3.taskbar.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayController
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.launcher3.util.PackageUserKey
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023", "pixelTablet2023"])
+class TaskbarAllAppsControllerTest {
+
+ @get:Rule val taskbarUnitTestRule = TaskbarUnitTestRule()
+
+ @InjectController lateinit var allAppsController: TaskbarAllAppsController
+ @InjectController lateinit var overlayController: TaskbarOverlayController
+
+ @Test
+ @UiThreadTest
+ fun testToggle_once_showsAllApps() {
+ allAppsController.toggle()
+ assertThat(allAppsController.isOpen).isTrue()
+ }
+
+ @Test
+ @UiThreadTest
+ fun testToggle_twice_closesAllApps() {
+ allAppsController.toggle()
+ allAppsController.toggle()
+ assertThat(allAppsController.isOpen).isFalse()
+ }
+
+ @Test
+ @UiThreadTest
+ fun testToggle_taskbarRecreated_allAppsReopened() {
+ allAppsController.toggle()
+ taskbarUnitTestRule.recreateTaskbar()
+ assertThat(allAppsController.isOpen).isTrue()
+ }
+
+ @Test
+ @UiThreadTest
+ fun testSetApps_beforeOpened_cachesInfo() {
+ allAppsController.setApps(TEST_APPS, 0, emptyMap())
+ allAppsController.toggle()
+
+ val overlayContext = overlayController.requestWindow()
+ assertThat(overlayContext.appsView.appsStore.apps).isEqualTo(TEST_APPS)
+ }
+
+ @Test
+ @UiThreadTest
+ fun testSetApps_afterOpened_updatesStore() {
+ allAppsController.toggle()
+ allAppsController.setApps(TEST_APPS, 0, emptyMap())
+
+ val overlayContext = overlayController.requestWindow()
+ assertThat(overlayContext.appsView.appsStore.apps).isEqualTo(TEST_APPS)
+ }
+
+ @Test
+ @UiThreadTest
+ fun testSetPredictedApps_beforeOpened_cachesInfo() {
+ allAppsController.setPredictedApps(TEST_PREDICTED_APPS)
+ allAppsController.toggle()
+
+ val predictedApps =
+ overlayController
+ .requestWindow()
+ .appsView
+ .floatingHeaderView
+ .findFixedRowByType(PredictionRowView::class.java)
+ .predictedApps
+ assertThat(predictedApps).isEqualTo(TEST_PREDICTED_APPS)
+ }
+
+ @Test
+ @UiThreadTest
+ fun testSetPredictedApps_afterOpened_cachesInfo() {
+ allAppsController.toggle()
+ allAppsController.setPredictedApps(TEST_PREDICTED_APPS)
+
+ val predictedApps =
+ overlayController
+ .requestWindow()
+ .appsView
+ .floatingHeaderView
+ .findFixedRowByType(PredictionRowView::class.java)
+ .predictedApps
+ assertThat(predictedApps).isEqualTo(TEST_PREDICTED_APPS)
+ }
+
+ @Test
+ fun testUpdateNotificationDots_appInfo_hasDot() {
+ getInstrumentation().runOnMainSync {
+ allAppsController.setApps(TEST_APPS, 0, emptyMap())
+ allAppsController.toggle()
+ taskbarUnitTestRule.activityContext.popupDataProvider.onNotificationPosted(
+ PackageUserKey.fromItemInfo(TEST_APPS[0]),
+ NotificationKeyData("key"),
+ )
+ }
+
+ // Ensure the recycler view fully inflates before trying to grab an icon.
+ getInstrumentation().runOnMainSync {
+ val btv =
+ overlayController
+ .requestWindow()
+ .appsView
+ .activeRecyclerView
+ .findViewHolderForAdapterPosition(0)
+ ?.itemView as? BubbleTextView
+ assertThat(btv?.hasDot()).isTrue()
+ }
+ }
+
+ @Test
+ @UiThreadTest
+ fun testUpdateNotificationDots_predictedApp_hasDot() {
+ allAppsController.setPredictedApps(TEST_PREDICTED_APPS)
+ allAppsController.toggle()
+
+ taskbarUnitTestRule.activityContext.popupDataProvider.onNotificationPosted(
+ PackageUserKey.fromItemInfo(TEST_PREDICTED_APPS[0]),
+ NotificationKeyData("key"),
+ )
+
+ val predictionRowView =
+ overlayController
+ .requestWindow()
+ .appsView
+ .floatingHeaderView
+ .findFixedRowByType(PredictionRowView::class.java)
+ val btv = predictionRowView.getChildAt(0) as BubbleTextView
+ assertThat(btv.hasDot()).isTrue()
+ }
+
+ private companion object {
+ private val TEST_APPS =
+ Array(16) {
+ AppInfo(
+ ComponentName(
+ getInstrumentation().context,
+ "com.android.launcher3.tests.Activity$it",
+ ),
+ "Test App $it",
+ Process.myUserHandle(),
+ Intent(),
+ )
+ }
+
+ private val TEST_PREDICTED_APPS = TEST_APPS.take(4).map { WorkspaceItemInfo(it) }
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayControllerTest.kt
new file mode 100644
index 0000000..eebd8f9
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayControllerTest.kt
@@ -0,0 +1,252 @@
+/*
+ * 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.overlay
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.view.MotionEvent
+import androidx.test.annotation.UiThreadTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.AbstractFloatingView
+import com.android.launcher3.AbstractFloatingView.TYPE_OPTIONS_POPUP
+import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS
+import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY
+import com.android.launcher3.AbstractFloatingView.hasOpenView
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.launcher3.views.BaseDragLayer
+import com.android.systemui.shared.system.TaskStackChangeListeners
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023"])
+class TaskbarOverlayControllerTest {
+
+ @get:Rule val taskbarUnitTestRule = TaskbarUnitTestRule()
+ @InjectController lateinit var overlayController: TaskbarOverlayController
+
+ private val taskbarContext: TaskbarActivityContext
+ get() = taskbarUnitTestRule.activityContext
+
+ @Test
+ @UiThreadTest
+ fun testRequestWindow_twice_reusesWindow() {
+ val context1 = overlayController.requestWindow()
+ val context2 = overlayController.requestWindow()
+ assertThat(context1).isSameInstanceAs(context2)
+ }
+
+ @Test
+ @UiThreadTest
+ fun testRequestWindow_afterHidingExistingWindow_createsNewWindow() {
+ val context1 = overlayController.requestWindow()
+ overlayController.hideWindow()
+
+ val context2 = overlayController.requestWindow()
+ assertThat(context1).isNotSameInstanceAs(context2)
+ }
+
+ @Test
+ @UiThreadTest
+ fun testRequestWindow_afterHidingOverlay_createsNewWindow() {
+ val context1 = overlayController.requestWindow()
+ TestOverlayView.show(context1)
+ overlayController.hideWindow()
+
+ val context2 = overlayController.requestWindow()
+ assertThat(context1).isNotSameInstanceAs(context2)
+ }
+
+ @Test
+ @UiThreadTest
+ fun testRequestWindow_addsProxyView() {
+ TestOverlayView.show(overlayController.requestWindow())
+ assertThat(hasOpenView(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)).isTrue()
+ }
+
+ @Test
+ @UiThreadTest
+ fun testRequestWindow_closeProxyView_closesOverlay() {
+ val overlay = TestOverlayView.show(overlayController.requestWindow())
+ AbstractFloatingView.closeOpenContainer(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)
+ assertThat(overlay.isOpen).isFalse()
+ }
+
+ @Test
+ fun testRequestWindow_attachesDragLayer() {
+ lateinit var dragLayer: BaseDragLayer<*>
+ getInstrumentation().runOnMainSync {
+ dragLayer = overlayController.requestWindow().dragLayer
+ }
+
+ // Allow drag layer to attach before checking.
+ getInstrumentation().runOnMainSync { assertThat(dragLayer.isAttachedToWindow).isTrue() }
+ }
+
+ @Test
+ @UiThreadTest
+ fun testHideWindow_closesOverlay() {
+ val overlay = TestOverlayView.show(overlayController.requestWindow())
+ overlayController.hideWindow()
+ assertThat(overlay.isOpen).isFalse()
+ }
+
+ @Test
+ fun testHideWindow_detachesDragLayer() {
+ lateinit var dragLayer: BaseDragLayer<*>
+ getInstrumentation().runOnMainSync {
+ dragLayer = overlayController.requestWindow().dragLayer
+ }
+
+ // Wait for drag layer to be attached to window before hiding.
+ getInstrumentation().runOnMainSync {
+ overlayController.hideWindow()
+ assertThat(dragLayer.isAttachedToWindow).isFalse()
+ }
+ }
+
+ @Test
+ @UiThreadTest
+ fun testTwoOverlays_closeOne_windowStaysOpen() {
+ val context = overlayController.requestWindow()
+ val overlay1 = TestOverlayView.show(context)
+ val overlay2 = TestOverlayView.show(context)
+
+ overlay1.close(false)
+ assertThat(overlay2.isOpen).isTrue()
+ assertThat(hasOpenView(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)).isTrue()
+ }
+
+ @Test
+ @UiThreadTest
+ fun testTwoOverlays_closeAll_closesWindow() {
+ val context = overlayController.requestWindow()
+ val overlay1 = TestOverlayView.show(context)
+ val overlay2 = TestOverlayView.show(context)
+
+ overlay1.close(false)
+ overlay2.close(false)
+ assertThat(hasOpenView(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)).isFalse()
+ }
+
+ @Test
+ @UiThreadTest
+ fun testRecreateTaskbar_closesWindow() {
+ TestOverlayView.show(overlayController.requestWindow())
+ taskbarUnitTestRule.recreateTaskbar()
+ assertThat(hasOpenView(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)).isFalse()
+ }
+
+ @Test
+ fun testTaskMovedToFront_closesOverlay() {
+ lateinit var overlay: TestOverlayView
+ getInstrumentation().runOnMainSync {
+ overlay = TestOverlayView.show(overlayController.requestWindow())
+ }
+
+ TaskStackChangeListeners.getInstance().listenerImpl.onTaskMovedToFront(RunningTaskInfo())
+ // Make sure TaskStackChangeListeners' Handler posts the callback before checking state.
+ getInstrumentation().runOnMainSync { assertThat(overlay.isOpen).isFalse() }
+ }
+
+ @Test
+ fun testTaskStackChanged_allAppsClosed_overlayStaysOpen() {
+ lateinit var overlay: TestOverlayView
+ getInstrumentation().runOnMainSync {
+ overlay = TestOverlayView.show(overlayController.requestWindow())
+ taskbarContext.controllers.sharedState?.allAppsVisible = false
+ }
+
+ TaskStackChangeListeners.getInstance().listenerImpl.onTaskStackChanged()
+ getInstrumentation().runOnMainSync { assertThat(overlay.isOpen).isTrue() }
+ }
+
+ @Test
+ fun testTaskStackChanged_allAppsOpen_closesOverlay() {
+ lateinit var overlay: TestOverlayView
+ getInstrumentation().runOnMainSync {
+ overlay = TestOverlayView.show(overlayController.requestWindow())
+ taskbarContext.controllers.sharedState?.allAppsVisible = true
+ }
+
+ TaskStackChangeListeners.getInstance().listenerImpl.onTaskStackChanged()
+ getInstrumentation().runOnMainSync { assertThat(overlay.isOpen).isFalse() }
+ }
+
+ @Test
+ @UiThreadTest
+ fun testUpdateLauncherDeviceProfile_overlayNotRebindSafe_closesOverlay() {
+ val overlayContext = overlayController.requestWindow()
+ val overlay = TestOverlayView.show(overlayContext).apply { type = TYPE_OPTIONS_POPUP }
+
+ overlayController.updateLauncherDeviceProfile(
+ overlayController.launcherDeviceProfile
+ .toBuilder(overlayContext)
+ .setGestureMode(false)
+ .build()
+ )
+
+ assertThat(overlay.isOpen).isFalse()
+ }
+
+ @Test
+ @UiThreadTest
+ fun testUpdateLauncherDeviceProfile_overlayRebindSafe_overlayStaysOpen() {
+ val overlayContext = overlayController.requestWindow()
+ val overlay = TestOverlayView.show(overlayContext).apply { type = TYPE_TASKBAR_ALL_APPS }
+
+ overlayController.updateLauncherDeviceProfile(
+ overlayController.launcherDeviceProfile
+ .toBuilder(overlayContext)
+ .setGestureMode(false)
+ .build()
+ )
+
+ assertThat(overlay.isOpen).isTrue()
+ }
+
+ private class TestOverlayView
+ private constructor(
+ private val overlayContext: TaskbarOverlayContext,
+ ) : AbstractFloatingView(overlayContext, null) {
+
+ var type = TYPE_OPTIONS_POPUP
+
+ private fun show() {
+ mIsOpen = true
+ overlayContext.dragLayer.addView(this)
+ }
+
+ override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean = false
+
+ override fun handleClose(animate: Boolean) = overlayContext.dragLayer.removeView(this)
+
+ override fun isOfType(type: Int): Boolean = (type and this.type) != 0
+
+ companion object {
+ /** Adds a generic View to the Overlay window for testing. */
+ fun show(context: TaskbarOverlayContext): TestOverlayView {
+ return TestOverlayView(context).apply { show() }
+ }
+ }
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
index 250dc7b..d40f8ab 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -78,7 +78,7 @@
private val mockSplitSourceDrawable: Drawable = mock()
private val mockSplitSourceView: View = mock()
- private val stateManager: StateManager<*> = mock()
+ private val stateManager: StateManager<*, *> = mock()
private val depthController: DepthController = mock()
private val transitionInfo: TransitionInfo = mock()
private val transaction: Transaction = mock()
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index aa08ca4..bab84ef 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -31,6 +31,7 @@
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.statehandlers.DepthController
import com.android.launcher3.statemanager.StateManager
+import com.android.launcher3.statemanager.StatefulActivity
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.quickstep.RecentsModel
@@ -61,7 +62,7 @@
private val depthController: DepthController = mock()
private val statsLogManager: StatsLogManager = mock()
private val statsLogger: StatsLogger = mock()
- private val stateManager: StateManager<LauncherState> = mock()
+ private val stateManager: StateManager<LauncherState, StatefulActivity<LauncherState>> = mock()
private val handler: Handler = mock()
private val context: RecentsViewContainer = mock()
private val recentsModel: RecentsModel = mock()
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/FallbackTaskbarUIControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/FallbackTaskbarUIControllerTest.kt
index f3115c6..04012c0 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/FallbackTaskbarUIControllerTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/FallbackTaskbarUIControllerTest.kt
@@ -37,7 +37,7 @@
lateinit var stateListener: StateManager.StateListener<RecentsState>
private val recentsActivity: RecentsActivity = mock()
- private val stateManager: StateManager<RecentsState> = mock()
+ private val stateManager: StateManager<RecentsState, RecentsActivity> = mock()
@Before
override fun setup() {
diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
index ed5526f..03244eb 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
+++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
@@ -48,6 +48,8 @@
@Mock
private SystemUiProxy mockSystemUiProxy;
+ @Mock
+ private TopTaskTracker mTopTaskTracker;
// Class under test
private RecentTasksList mRecentTasksList;
@@ -58,7 +60,7 @@
LooperExecutor mockMainThreadExecutor = mock(LooperExecutor.class);
KeyguardManager mockKeyguardManager = mock(KeyguardManager.class);
mRecentTasksList = new RecentTasksList(mockMainThreadExecutor, mockKeyguardManager,
- mockSystemUiProxy);
+ mockSystemUiProxy, mTopTaskTracker);
}
@Test
diff --git a/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt b/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
index 5157c71..80fbce7 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
@@ -9,8 +9,19 @@
import com.android.launcher3.util.DisplayController.CHANGE_ROTATION
import com.android.launcher3.util.DisplayController.Info
import com.android.launcher3.util.NavigationMode
-import com.android.launcher3.util.window.WindowManagerProxy
import com.android.quickstep.util.GestureExclusionManager
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -28,7 +39,6 @@
class RecentsAnimationDeviceStateTest {
@Mock private lateinit var exclusionManager: GestureExclusionManager
- @Mock private lateinit var windowManagerProxy: WindowManagerProxy
@Mock private lateinit var info: Info
private val context = ApplicationProvider.getApplicationContext() as Context
@@ -108,4 +118,88 @@
verifyZeroInteractions(exclusionManager)
}
+
+ @Test
+ fun trackpadGesturesNotAllowedForSelectedStates() {
+ val disablingStates = GESTURE_DISABLING_SYSUI_STATES +
+ SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED
+
+ allSysUiStates().forEach { state ->
+ val canStartGesture = !disablingStates.contains(state)
+ underTest.setSystemUiFlags(state)
+ assertThat(underTest.canStartTrackpadGesture()).isEqualTo(canStartGesture)
+ }
+ }
+
+ @Test
+ fun trackpadGesturesNotAllowedIfHomeAndOverviewIsDisabled() {
+ val stateToExpectedResult = mapOf(
+ SYSUI_STATE_HOME_DISABLED to true,
+ SYSUI_STATE_OVERVIEW_DISABLED to true,
+ DEFAULT_STATE
+ .enable(SYSUI_STATE_OVERVIEW_DISABLED)
+ .enable(SYSUI_STATE_HOME_DISABLED) to false
+ )
+
+ stateToExpectedResult.forEach { (state, allowed) ->
+ underTest.setSystemUiFlags(state)
+ assertThat(underTest.canStartTrackpadGesture()).isEqualTo(allowed)
+ }
+ }
+
+ @Test
+ fun systemGesturesNotAllowedForSelectedStates() {
+ val disablingStates = GESTURE_DISABLING_SYSUI_STATES + SYSUI_STATE_NAV_BAR_HIDDEN
+
+ allSysUiStates().forEach { state ->
+ val canStartGesture = !disablingStates.contains(state)
+ underTest.setSystemUiFlags(state)
+ assertThat(underTest.canStartSystemGesture()).isEqualTo(canStartGesture)
+ }
+ }
+
+ @Test
+ fun systemGesturesNotAllowedWhenGestureStateDisabledAndNavBarVisible() {
+ val stateToExpectedResult = mapOf(
+ DEFAULT_STATE
+ .enable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
+ .disable(SYSUI_STATE_NAV_BAR_HIDDEN) to true,
+ DEFAULT_STATE
+ .enable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
+ .enable(SYSUI_STATE_NAV_BAR_HIDDEN) to true,
+ DEFAULT_STATE
+ .disable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
+ .disable(SYSUI_STATE_NAV_BAR_HIDDEN) to true,
+ DEFAULT_STATE
+ .disable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
+ .enable(SYSUI_STATE_NAV_BAR_HIDDEN) to false,
+ )
+
+ stateToExpectedResult.forEach {(state, gestureAllowed) ->
+ underTest.setSystemUiFlags(state)
+ assertThat(underTest.canStartSystemGesture()).isEqualTo(gestureAllowed)
+ }
+ }
+
+ private fun allSysUiStates(): List<Long> {
+ // SYSUI_STATES_* are binary flags
+ return (0..SYSUI_STATES_COUNT).map { 1L shl it }
+ }
+
+ companion object {
+ private val GESTURE_DISABLING_SYSUI_STATES = listOf(
+ SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
+ SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
+ SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
+ SYSUI_STATE_MAGNIFICATION_OVERLAP,
+ SYSUI_STATE_DEVICE_DREAMING,
+ SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION,
+ )
+ private const val SYSUI_STATES_COUNT = 33
+ private const val DEFAULT_STATE = 0L
+ }
+
+ private fun Long.enable(state: Long) = this or state
+
+ private fun Long.disable(state: Long) = this and state.inv()
}
diff --git a/res/color-night-v31/taskbar_stroke.xml b/res/color-night-v31/taskbar_stroke.xml
new file mode 100644
index 0000000..db7a510
--- /dev/null
+++ b/res/color-night-v31/taskbar_stroke.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#9AA0A6" />
+</selector>
\ No newline at end of file
diff --git a/res/color/taskbar_stroke.xml b/res/color/taskbar_stroke.xml
new file mode 100644
index 0000000..b691082
--- /dev/null
+++ b/res/color/taskbar_stroke.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#BDC1C6" />
+</selector>
\ No newline at end of file
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index e838b29..325d65d 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -192,6 +192,6 @@
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privatno, zaključano."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Zaključaj"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Prelazak u privatan prostor"</string>
- <string name="ps_add_button_label" msgid="8127988716897128773">"Instaliraj"</string>
+ <string name="ps_add_button_label" msgid="8127988716897128773">"Instalirajte"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instaliranje aplikacija u privatni prostor"</string>
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index ec2285d..7f89246 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -186,7 +186,7 @@
<string name="remote_action_failed" msgid="1383965239183576790">"Fehler: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Vertrauliches Profil"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Zum Einrichten oder Öffnen tippen"</string>
- <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
+ <string name="ps_container_title" msgid="4391796149519594205">"Vertraulich"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Einstellungen für vertrauliches Profil"</string>
<string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat, entsperrt."</string>
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat, gesperrt."</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 5ff367e..00880b0 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -48,7 +48,7 @@
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Kaikki tarvittava"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Uutiset ja aikakauslehdet"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Viihde"</string>
- <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sosiaalinen"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Some"</string>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sinulle ehdotetut"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widgetit oikealla, haku ja vaihtoehdot vasemmalla"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgetiä}}"</string>
@@ -85,7 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Poista asennus"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Sovelluksen tiedot"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Asenna yksityisesti"</string>
- <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Sovelluksen poistaminen"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Poista sovellus"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Asenna"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Älä ehdota sovellusta"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Kiinnitä sovellus"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 0ea277b..580d02f 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -85,7 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Désinstaller"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Infos sur l\'appli"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer en mode privé"</string>
- <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Désinstaller l\'application"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Désinstaller l\'appli"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'appli"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index b504260..f1117ba 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -49,7 +49,7 @@
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"खबरों और पत्रिकाओं वाले ऐप्लिकेशन"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"मनोरंजन से जुड़े ऐप्लिकेशन"</string>
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"सोशल मीडिया ऐप्लिकेशन"</string>
- <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"आपके लिए सुझाए गए ऐप्लिकेशन"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"आपके लिए सुझाए गए"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> के विजेट दाईं ओर, खोज का विजेट और अन्य विकल्प बाईं ओर"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}one{# विजेट}other{# विजेट}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# शॉर्टकट}one{# शॉर्टकट}other{# शॉर्टकट}}"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 21581c3..e00e851 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -83,7 +83,7 @@
<string name="all_apps_button_work_label" msgid="7270707118948892488">"רשימת אפליקציות עבודה"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"הסרה"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"להסרת התקנה"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"פרטי אפליקציה"</string>
+ <string name="app_info_drop_target_label" msgid="692894985365717661">"פרטי האפליקציה"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"התקנה במרחב הפרטי"</string>
<string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"הסרת האפליקציה"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"התקנה"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index d7d4e7d..c2e5ebd 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -88,7 +88,7 @@
<string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"App verwijderen"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installeren"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Geen app voorstellen"</string>
- <string name="pin_prediction" msgid="4196423321649756498">"Vastzetvoorspelling"</string>
+ <string name="pin_prediction" msgid="4196423321649756498">"Voorspelling vastzetten"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Snelle links instellen"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Een app toestaan snelkoppelingen toe te voegen zonder tussenkomst van de gebruiker."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"instellingen en snelkoppelingen op startscherm lezen"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index a049a80..a7eb0a7 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -184,7 +184,7 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Ativar"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrar"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Falha: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
- <string name="private_space_label" msgid="2359721649407947001">"Espaço particular"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Espaço privado"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Toque para configurar ou abrir"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Particular"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Configurações do Espaço particular"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index ebc55ca..c45b3dd 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -192,6 +192,6 @@
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"தனிப்பட்டது, லாக் செய்யப்பட்டுள்ளது."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"பூட்டு"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"தனிப்பட்ட சேமிப்பிடத்திற்கு மாற்றுகிறது"</string>
- <string name="ps_add_button_label" msgid="8127988716897128773">"நிறுவுதல்"</string>
+ <string name="ps_add_button_label" msgid="8127988716897128773">"நிறுவுக"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"தனிப்பட்ட சேமிப்பிடத்தில் ஆப்ஸை நிறுவும்"</string>
</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 0681e3d..e8c7593 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -85,7 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Kaldır"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Uygulama bilgileri"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Özel olarak yükle"</string>
- <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uygulamanın yüklemesini kaldır"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uygulamayı kaldır"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Yükle"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Uygulamayı önerme"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Tahmini Sabitle"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index aa83c01..05724e2 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -448,6 +448,9 @@
<!-- Size of the maximum radius for the enforced rounded rectangles. -->
<dimen name="enforced_rounded_corner_max_radius">16dp</dimen>
+ <!-- Size of the radius for the rounded corners of Persistent Taskbar. -->
+ <dimen name="persistent_taskbar_corner_radius">16dp</dimen>
+
<!-- Base Swipe Detector, speed in dp/s -->
<dimen name="base_swift_detector_fling_release_velocity">1dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index a9cca6d..d33adc4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -36,6 +36,8 @@
<string name="shortcut_not_available">Shortcut isn\'t available</string>
<!-- User visible name for the launcher/home screen. [CHAR_LIMIT=30] -->
<string name="home_screen">Home</string>
+ <!-- Description for setting the current launcher as the default home app. [CHAR_LIMIT=none]-->
+ <string name="set_default_home_app">Set <xliff:g id="launcher_name" example="Launcher3">%1$s</xliff:g> as default home app in Settings</string>
<!-- Options for recent tasks -->
<!-- Title for an option to enter split screen mode for a given app -->
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 0daabb1..00db3a3 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -53,7 +53,6 @@
import com.android.launcher3.CellLayout.ContainerType;
import com.android.launcher3.DevicePaddings.DevicePadding;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.IconNormalizer;
import com.android.launcher3.model.data.ItemInfo;
@@ -714,7 +713,7 @@
overviewTaskThumbnailTopMarginPx =
enableOverviewIconMenu() ? 0 : overviewTaskIconSizePx + overviewTaskMarginPx;
// Don't add margin with floating search bar to minimize risk of overlapping.
- overviewActionsTopMarginPx = FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() ? 0
+ overviewActionsTopMarginPx = Flags.floatingSearchBar() ? 0
: res.getDimensionPixelSize(R.dimen.overview_actions_top_margin);
overviewPageSpacing = res.getDimensionPixelSize(R.dimen.overview_page_spacing);
overviewActionsButtonSpacing = res.getDimensionPixelSize(
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 2b30dc4..4e566ab 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -38,6 +38,7 @@
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_BIND_PENDING_APPWIDGET;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_CREATE_APPWIDGET;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_CREATE_SHORTCUT;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_HOME_ROLE;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_PICK_APPWIDGET;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
@@ -151,6 +152,7 @@
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
+import android.widget.Toast;
import android.window.BackEvent;
import android.window.OnBackAnimationCallback;
@@ -164,6 +166,7 @@
import androidx.core.os.BuildCompat;
import androidx.window.embedding.RuleController;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
@@ -309,7 +312,7 @@
private static boolean sIsNewProcess = true;
- private StateManager<LauncherState> mStateManager;
+ private StateManager<LauncherState, Launcher> mStateManager;
private static final int ON_ACTIVITY_RESULT_ANIMATION_DELAY = 500;
@@ -891,6 +894,17 @@
}
mPendingActivityResult = null;
+ if (requestCode == REQUEST_HOME_ROLE) {
+ if (resultCode != RESULT_OK) {
+ Toast.makeText(
+ this,
+ this.getString(R.string.set_default_home_app,
+ this.getString(R.string.derived_app_name)),
+ Toast.LENGTH_LONG).show();
+ }
+ return;
+ }
+
// Reset the startActivity waiting flag
final PendingRequestArgs requestArgs = mPendingRequestArgs;
setWaitingForResult(null);
@@ -2761,7 +2775,7 @@
}
@Override
- protected void collectStateHandlers(List<StateHandler> out) {
+ public void collectStateHandlers(List<StateHandler<LauncherState>> out) {
out.add(getAllAppsController());
out.add(getWorkspace());
}
@@ -2783,7 +2797,8 @@
}
private void updateDisallowBack() {
- if (BuildCompat.isAtLeastV() && Flags.enableDesktopWindowingMode()) {
+ if (BuildCompat.isAtLeastV() && Flags.enableDesktopWindowingMode()
+ && mDeviceProfile.isTablet) {
// TODO(b/330183377) disable back in launcher when when we productionize
return;
}
@@ -2981,7 +2996,7 @@
}
@Override
- public StateManager<LauncherState> getStateManager() {
+ public StateManager<LauncherState, Launcher> getStateManager() {
return mStateManager;
}
diff --git a/src/com/android/launcher3/LauncherConstants.java b/src/com/android/launcher3/LauncherConstants.java
index 1abfeb9..445fb41 100644
--- a/src/com/android/launcher3/LauncherConstants.java
+++ b/src/com/android/launcher3/LauncherConstants.java
@@ -41,6 +41,7 @@
public static final int REQUEST_BIND_PENDING_APPWIDGET = 12;
public static final int REQUEST_RECONFIGURE_APPWIDGET = 13;
+ public static final int REQUEST_HOME_ROLE = 14;
static final int REQUEST_CREATE_SHORTCUT = 1;
static final int REQUEST_CREATE_APPWIDGET = 5;
static final int REQUEST_PICK_APPWIDGET = 9;
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 47a7115..ca1b2a9 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -480,7 +480,7 @@
}
}
- if (!removedIds.isEmpty()) {
+ if (!removedIds.isEmpty() && !isAppArchived) {
taskController.deleteAndBindComponentsRemoved(
ItemInfoMatcher.ofItemIds(removedIds),
"removed because install session failed");
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index d2d56f2..102189b 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -440,7 +440,7 @@
*/
public void onBackInvoked(Launcher launcher) {
if (this != NORMAL) {
- StateManager<LauncherState> lsm = launcher.getStateManager();
+ StateManager<LauncherState, Launcher> lsm = launcher.getStateManager();
LauncherState lastState = lsm.getLastState();
lsm.goToState(lastState, forEndCallback(this::onBackAnimationCompleted));
}
@@ -461,7 +461,7 @@
*/
public void onBackProgressed(
Launcher launcher, @FloatRange(from = 0.0, to = 1.0) float backProgress) {
- StateManager<LauncherState> lsm = launcher.getStateManager();
+ StateManager<LauncherState, Launcher> lsm = launcher.getStateManager();
LauncherState toState = lsm.getLastState();
lsm.onBackProgressed(toState, backProgress);
}
@@ -471,7 +471,7 @@
* predictive back gesture.
*/
public void onBackCancelled(Launcher launcher) {
- StateManager<LauncherState> lsm = launcher.getStateManager();
+ StateManager<LauncherState, Launcher> lsm = launcher.getStateManager();
LauncherState toState = lsm.getLastState();
lsm.onBackCancelled(toState);
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 584d089..e601a3e 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -526,7 +526,7 @@
}
updateChildrenLayersEnabled();
- StateManager<LauncherState> stateManager = mLauncher.getStateManager();
+ StateManager<LauncherState, Launcher> stateManager = mLauncher.getStateManager();
stateManager.addStateListener(new StateManager.StateListener<LauncherState>() {
@Override
public void onStateTransitionComplete(LauncherState finalState) {
diff --git a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
index 63a168e..1e0f289 100644
--- a/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/LauncherAllAppsContainerView.java
@@ -56,7 +56,7 @@
return false;
}
Launcher launcher = mActivityContext;
- StateManager<LauncherState> manager = launcher.getStateManager();
+ StateManager<LauncherState, Launcher> manager = launcher.getStateManager();
if (manager.isInTransition() && manager.getTargetState() != null) {
return manager.getTargetState().shouldFloatingSearchBarUsePillWhenUnfocused(launcher);
}
@@ -70,7 +70,7 @@
return super.getFloatingSearchBarRestingMarginBottom();
}
Launcher launcher = mActivityContext;
- StateManager<LauncherState> stateManager = launcher.getStateManager();
+ StateManager<LauncherState, Launcher> stateManager = launcher.getStateManager();
// We want to rest at the current state's resting position, unless we are in transition and
// the target state's resting position is higher (that way if we are closing the keyboard,
@@ -95,7 +95,7 @@
return super.getFloatingSearchBarRestingMarginStart();
}
- StateManager<LauncherState> stateManager = mActivityContext.getStateManager();
+ StateManager<LauncherState, Launcher> stateManager = mActivityContext.getStateManager();
// Special case to not expand the search bar when exiting All Apps on phones.
if (stateManager.getCurrentStableState() == LauncherState.ALL_APPS
@@ -117,7 +117,7 @@
return super.getFloatingSearchBarRestingMarginEnd();
}
- StateManager<LauncherState> stateManager = mActivityContext.getStateManager();
+ StateManager<LauncherState, Launcher> stateManager = mActivityContext.getStateManager();
// Special case to not expand the search bar when exiting All Apps on phones.
if (stateManager.getCurrentStableState() == LauncherState.ALL_APPS
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 5cacf60..6f021ea 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -281,11 +281,29 @@
@Override
public void setQuietMode(boolean enable) {
- super.setQuietMode(enable);
+ UI_HELPER_EXECUTOR.post(() ->
+ mUserCache.getUserProfiles()
+ .stream()
+ .filter(getUserMatcher())
+ .findFirst()
+ .ifPresent(userHandle -> setQuietModeSafely(enable, userHandle)));
mReadyToAnimate = true;
}
/**
+ * Sets Quiet Mode for Private Profile.
+ * If {@link SecurityException} is thrown, prompts the user to set this launcher as HOME app.
+ */
+ private void setQuietModeSafely(boolean enable, UserHandle userHandle) {
+ try {
+ mUserManager.requestQuietModeEnabled(enable, userHandle);
+ } catch (SecurityException ex) {
+ ApiWrapper.INSTANCE.get(mAllApps.mActivityContext)
+ .assignDefaultHomeRole(mAllApps.mActivityContext);
+ }
+ }
+
+ /**
* Expand the private space after the app list has been added and updated from
* {@link AlphabeticalAppsList#onAppsUpdated()}
*/
diff --git a/src/com/android/launcher3/allapps/UserProfileManager.java b/src/com/android/launcher3/allapps/UserProfileManager.java
index eb74d20..93b6b29 100644
--- a/src/com/android/launcher3/allapps/UserProfileManager.java
+++ b/src/com/android/launcher3/allapps/UserProfileManager.java
@@ -55,12 +55,11 @@
public @interface UserProfileState { }
protected final StatsLogManager mStatsLogManager;
+ protected final UserManager mUserManager;
+ protected final UserCache mUserCache;
+
@UserProfileState
private int mCurrentState;
-
- private final UserManager mUserManager;
- private final UserCache mUserCache;
-
protected UserProfileManager(UserManager userManager,
StatsLogManager statsLogManager,
UserCache userCache) {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 4b908bf..33e6f91 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -84,11 +84,6 @@
+ "data preparation for loading the home screen");
// TODO(Block 4): Cleanup flags
- public static final BooleanFlag ENABLE_FLOATING_SEARCH_BAR =
- getReleaseFlag(268388460, "ENABLE_FLOATING_SEARCH_BAR", DISABLED,
- "Allow search bar to persist and animate across states, and attach to"
- + " the keyboard from the bottom of the screen");
-
public static final BooleanFlag ENABLE_ALL_APPS_FROM_OVERVIEW =
getDebugFlag(275132633, "ENABLE_ALL_APPS_FROM_OVERVIEW", DISABLED,
"Allow entering All Apps from Overview (e.g. long swipe up from app)");
diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java
index cc20cd1..f443f81 100644
--- a/src/com/android/launcher3/model/FirstScreenBroadcast.java
+++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java
@@ -96,7 +96,7 @@
.collect(groupingBy(SessionInfo::getInstallerPackageName,
mapping(SessionInfo::getAppPackageName, Collectors.toSet())))
.forEach((installer, packages) ->
- sendBroadcastToInstaller(context, installer, packages, firstScreenItems));
+ sendBroadcastToInstaller(context, installer, packages, firstScreenItems));
}
/**
diff --git a/src/com/android/launcher3/model/FirstScreenBroadcastHelper.kt b/src/com/android/launcher3/model/FirstScreenBroadcastHelper.kt
new file mode 100644
index 0000000..aa62c32
--- /dev/null
+++ b/src/com/android/launcher3/model/FirstScreenBroadcastHelper.kt
@@ -0,0 +1,387 @@
+/*
+ * 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.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageInstaller.SessionInfo
+import android.os.Process
+import android.util.Log
+import androidx.annotation.AnyThread
+import androidx.annotation.VisibleForTesting
+import androidx.annotation.WorkerThread
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
+import com.android.launcher3.model.data.CollectionInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.pm.InstallSessionHelper
+import com.android.launcher3.util.Executors
+import com.android.launcher3.util.PackageManagerHelper
+import com.android.launcher3.util.PackageUserKey
+
+/**
+ * Helper class to send broadcasts to package installers that have:
+ * - Pending Items on first screen
+ * - Installed/Archived Items on first screen
+ * - Installed/Archived Widgets on every screen
+ *
+ * The packages are broken down by: folder items, workspace items, hotseat items, and widgets.
+ * Package installers only receive data for items that they are installing or have installed.
+ */
+object FirstScreenBroadcastHelper {
+ @VisibleForTesting const val MAX_BROADCAST_SIZE = 70
+
+ private const val TAG = "FirstScreenBroadcastHelper"
+ private const val DEBUG = true
+ private const val ACTION_FIRST_SCREEN_ACTIVE_INSTALLS =
+ "com.android.launcher3.action.FIRST_SCREEN_ACTIVE_INSTALLS"
+ // String retained as "folderItem" for back-compatibility reasons.
+ private const val PENDING_COLLECTION_ITEM_EXTRA = "folderItem"
+ private const val PENDING_WORKSPACE_ITEM_EXTRA = "workspaceItem"
+ private const val PENDING_HOTSEAT_ITEM_EXTRA = "hotseatItem"
+ private const val PENDING_WIDGET_ITEM_EXTRA = "widgetItem"
+ // Extras containing all installed items, including Archived Apps.
+ private const val INSTALLED_WORKSPACE_ITEMS_EXTRA = "workspaceInstalledItems"
+ private const val INSTALLED_HOTSEAT_ITEMS_EXTRA = "hotseatInstalledItems"
+ // This includes installed widgets on all screens, not just first.
+ private const val ALL_INSTALLED_WIDGETS_ITEM_EXTRA = "widgetInstalledItems"
+ private const val VERIFICATION_TOKEN_EXTRA = "verificationToken"
+
+ /**
+ * Return list of [FirstScreenBroadcastModel] for each installer and their
+ * installing/installed/archived items. If the FirstScreenBroadcastModel data is greater in size
+ * than [MAX_BROADCAST_SIZE], then we will truncate the data until it meets the size limit to
+ * avoid overloading the broadcast.
+ *
+ * @param packageManagerHelper helper for querying PackageManager
+ * @param firstScreenItems every ItemInfo on first screen
+ * @param userKeyToSessionMap map of pending SessionInfo's for installing items
+ * @param allWidgets list of all Widgets added to every screen
+ */
+ @WorkerThread
+ @JvmStatic
+ fun createModelsForFirstScreenBroadcast(
+ packageManagerHelper: PackageManagerHelper,
+ firstScreenItems: List<ItemInfo>,
+ userKeyToSessionMap: Map<PackageUserKey, SessionInfo>,
+ allWidgets: List<LauncherAppWidgetInfo>
+ ): List<FirstScreenBroadcastModel> {
+
+ // installers for installing items
+ val pendingItemInstallerMap: Map<String, MutableSet<String>> =
+ createPendingItemsMap(userKeyToSessionMap)
+ val installingPackages = pendingItemInstallerMap.values.flatten().toSet()
+
+ // installers for installed items on first screen
+ val installedItemInstallerMap: Map<String, MutableSet<ItemInfo>> =
+ createInstalledItemsMap(firstScreenItems, installingPackages, packageManagerHelper)
+
+ // installers for widgets on all screens
+ val allInstalledWidgetsMap: Map<String, MutableSet<LauncherAppWidgetInfo>> =
+ createAllInstalledWidgetsMap(allWidgets, installingPackages, packageManagerHelper)
+
+ val allInstallers: Set<String> =
+ pendingItemInstallerMap.keys +
+ installedItemInstallerMap.keys +
+ allInstalledWidgetsMap.keys
+ val models = mutableListOf<FirstScreenBroadcastModel>()
+ // create broadcast for each installer, with extras for each item category
+ allInstallers.forEach { installer ->
+ val installingItems = pendingItemInstallerMap[installer]
+ val broadcastModel =
+ FirstScreenBroadcastModel(installerPackage = installer).apply {
+ addPendingItems(installingItems, firstScreenItems)
+ addInstalledItems(installer, installedItemInstallerMap)
+ addAllScreenWidgets(installer, allInstalledWidgetsMap)
+ }
+ broadcastModel.truncateModelForBroadcast()
+ models.add(broadcastModel)
+ }
+ return models
+ }
+
+ /** From the model data, create Intents to send broadcasts and fire them. */
+ @WorkerThread
+ @JvmStatic
+ fun sendBroadcastsForModels(context: Context, models: List<FirstScreenBroadcastModel>) {
+ for (model in models) {
+ model.printDebugInfo()
+ val intent =
+ Intent(ACTION_FIRST_SCREEN_ACTIVE_INSTALLS)
+ .setPackage(model.installerPackage)
+ .putExtra(
+ VERIFICATION_TOKEN_EXTRA,
+ PendingIntent.getActivity(
+ context,
+ 0 /* requestCode */,
+ Intent(),
+ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
+ )
+ )
+ .putStringArrayListExtra(
+ PENDING_COLLECTION_ITEM_EXTRA,
+ ArrayList(model.pendingCollectionItems)
+ )
+ .putStringArrayListExtra(
+ PENDING_WORKSPACE_ITEM_EXTRA,
+ ArrayList(model.pendingWorkspaceItems)
+ )
+ .putStringArrayListExtra(
+ PENDING_HOTSEAT_ITEM_EXTRA,
+ ArrayList(model.pendingHotseatItems)
+ )
+ .putStringArrayListExtra(
+ PENDING_WIDGET_ITEM_EXTRA,
+ ArrayList(model.pendingWidgetItems)
+ )
+ .putStringArrayListExtra(
+ INSTALLED_WORKSPACE_ITEMS_EXTRA,
+ ArrayList(model.installedWorkspaceItems)
+ )
+ .putStringArrayListExtra(
+ INSTALLED_HOTSEAT_ITEMS_EXTRA,
+ ArrayList(model.installedHotseatItems)
+ )
+ .putStringArrayListExtra(
+ ALL_INSTALLED_WIDGETS_ITEM_EXTRA,
+ ArrayList(
+ model.firstScreenInstalledWidgets +
+ model.secondaryScreenInstalledWidgets
+ )
+ )
+ context.sendBroadcast(intent)
+ }
+ }
+
+ /** Maps Installer packages to Set of app packages from install sessions */
+ private fun createPendingItemsMap(
+ userKeyToSessionMap: Map<PackageUserKey, SessionInfo>
+ ): Map<String, MutableSet<String>> {
+ val myUser = Process.myUserHandle()
+ val result = mutableMapOf<String, MutableSet<String>>()
+ userKeyToSessionMap.forEach { entry ->
+ if (!myUser.equals(InstallSessionHelper.getUserHandle(entry.value))) return@forEach
+ val installer = entry.value.installerPackageName
+ val appPackage = entry.value.appPackageName
+ if (installer.isNullOrEmpty() || appPackage.isNullOrEmpty()) return@forEach
+ result.getOrPut(installer) { mutableSetOf() }.add(appPackage)
+ }
+ return result
+ }
+
+ /**
+ * Maps Installer packages to Set of ItemInfo from first screen. Filter out installing packages.
+ */
+ private fun createInstalledItemsMap(
+ firstScreenItems: List<ItemInfo>,
+ installingPackages: Set<String>,
+ packageManagerHelper: PackageManagerHelper
+ ): Map<String, MutableSet<ItemInfo>> {
+ val result = mutableMapOf<String, MutableSet<ItemInfo>>()
+ firstScreenItems.forEach { item ->
+ val appPackage = getPackageName(item) ?: return@forEach
+ if (installingPackages.contains(appPackage)) return@forEach
+ val installer = packageManagerHelper.getAppInstallerPackage(appPackage)
+ if (installer.isNullOrEmpty()) return@forEach
+ result.getOrPut(installer) { mutableSetOf() }.add(item)
+ }
+ return result
+ }
+
+ /**
+ * Maps Installer packages to Set of AppWidget packages installed on all screens. Filter out
+ * installing packages.
+ */
+ private fun createAllInstalledWidgetsMap(
+ allWidgets: List<LauncherAppWidgetInfo>,
+ installingPackages: Set<String>,
+ packageManagerHelper: PackageManagerHelper
+ ): Map<String, MutableSet<LauncherAppWidgetInfo>> {
+ val result = mutableMapOf<String, MutableSet<LauncherAppWidgetInfo>>()
+ allWidgets
+ .sortedBy { widget -> widget.screenId }
+ .forEach { widget ->
+ val appPackage = getPackageName(widget) ?: return@forEach
+ if (installingPackages.contains(appPackage)) return@forEach
+ val installer = packageManagerHelper.getAppInstallerPackage(appPackage)
+ if (installer.isNullOrEmpty()) return@forEach
+ result.getOrPut(installer) { mutableSetOf() }.add(widget)
+ }
+ return result
+ }
+
+ /**
+ * Add first screen Pending Items from Map to [FirstScreenBroadcastModel] for given installer
+ */
+ private fun FirstScreenBroadcastModel.addPendingItems(
+ installingItems: Set<String>?,
+ firstScreenItems: List<ItemInfo>
+ ) {
+ if (installingItems == null) return
+ for (info in firstScreenItems) {
+ addCollectionItems(info, installingItems)
+ val packageName = getPackageName(info) ?: continue
+ if (!installingItems.contains(packageName)) continue
+ when {
+ info is LauncherAppWidgetInfo -> pendingWidgetItems.add(packageName)
+ info.container == CONTAINER_HOTSEAT -> pendingHotseatItems.add(packageName)
+ info.container == CONTAINER_DESKTOP -> pendingWorkspaceItems.add(packageName)
+ }
+ }
+ }
+
+ /**
+ * Add first screen installed Items from Map to [FirstScreenBroadcastModel] for given installer
+ */
+ private fun FirstScreenBroadcastModel.addInstalledItems(
+ installer: String,
+ installedItemInstallerMap: Map<String, Set<ItemInfo>>,
+ ) {
+ installedItemInstallerMap[installer]?.forEach { info ->
+ val packageName: String = getPackageName(info) ?: return@forEach
+ when (info.container) {
+ CONTAINER_HOTSEAT -> installedHotseatItems.add(packageName)
+ CONTAINER_DESKTOP -> installedWorkspaceItems.add(packageName)
+ }
+ }
+ }
+
+ /** Add Widgets on every screen from Map to [FirstScreenBroadcastModel] for given installer */
+ private fun FirstScreenBroadcastModel.addAllScreenWidgets(
+ installer: String,
+ allInstalledWidgetsMap: Map<String, Set<LauncherAppWidgetInfo>>
+ ) {
+ allInstalledWidgetsMap[installer]?.forEach { widget ->
+ val packageName: String = getPackageName(widget) ?: return@forEach
+ if (widget.screenId == 0) {
+ firstScreenInstalledWidgets.add(packageName)
+ } else {
+ secondaryScreenInstalledWidgets.add(packageName)
+ }
+ }
+ }
+
+ private fun FirstScreenBroadcastModel.addCollectionItems(
+ info: ItemInfo,
+ installingPackages: Set<String>
+ ) {
+ if (info !is CollectionInfo) return
+ pendingCollectionItems.addAll(
+ cloneOnMainThread(info.getAppContents())
+ .mapNotNull { getPackageName(it) }
+ .filter { installingPackages.contains(it) }
+ )
+ }
+
+ /**
+ * Creates a copy of [FirstScreenBroadcastModel] with items truncated to meet
+ * [MAX_BROADCAST_SIZE] in a prioritized order.
+ */
+ @VisibleForTesting
+ fun FirstScreenBroadcastModel.truncateModelForBroadcast() {
+ val totalItemCount = getTotalItemCount()
+ if (totalItemCount <= MAX_BROADCAST_SIZE) return
+ var extraItemCount = totalItemCount - MAX_BROADCAST_SIZE
+
+ while (extraItemCount > 0) {
+ // In this order, remove items until we meet the max size limit.
+ when {
+ pendingCollectionItems.isNotEmpty() ->
+ pendingCollectionItems.apply { remove(last()) }
+ pendingHotseatItems.isNotEmpty() -> pendingHotseatItems.apply { remove(last()) }
+ installedHotseatItems.isNotEmpty() -> installedHotseatItems.apply { remove(last()) }
+ secondaryScreenInstalledWidgets.isNotEmpty() ->
+ secondaryScreenInstalledWidgets.apply { remove(last()) }
+ pendingWidgetItems.isNotEmpty() -> pendingWidgetItems.apply { remove(last()) }
+ firstScreenInstalledWidgets.isNotEmpty() ->
+ firstScreenInstalledWidgets.apply { remove(last()) }
+ pendingWorkspaceItems.isNotEmpty() -> pendingWorkspaceItems.apply { remove(last()) }
+ installedWorkspaceItems.isNotEmpty() ->
+ installedWorkspaceItems.apply { remove(last()) }
+ }
+ extraItemCount--
+ }
+ }
+
+ /** Returns count of all Items held by [FirstScreenBroadcastModel]. */
+ @VisibleForTesting
+ fun FirstScreenBroadcastModel.getTotalItemCount() =
+ pendingCollectionItems.size +
+ pendingWorkspaceItems.size +
+ pendingHotseatItems.size +
+ pendingWidgetItems.size +
+ installedWorkspaceItems.size +
+ installedHotseatItems.size +
+ firstScreenInstalledWidgets.size +
+ secondaryScreenInstalledWidgets.size
+
+ private fun FirstScreenBroadcastModel.printDebugInfo() {
+ if (DEBUG) {
+ Log.d(
+ TAG,
+ "Sending First Screen Broadcast for installer=$installerPackage" +
+ ", total packages=${getTotalItemCount()}"
+ )
+ pendingCollectionItems.forEach {
+ Log.d(TAG, "$installerPackage:Pending Collection item:$it")
+ }
+ pendingWorkspaceItems.forEach {
+ Log.d(TAG, "$installerPackage:Pending Workspace item:$it")
+ }
+ pendingHotseatItems.forEach { Log.d(TAG, "$installerPackage:Pending Hotseat item:$it") }
+ pendingWidgetItems.forEach { Log.d(TAG, "$installerPackage:Pending Widget item:$it") }
+ installedWorkspaceItems.forEach {
+ Log.d(TAG, "$installerPackage:Installed Workspace item:$it")
+ }
+ installedHotseatItems.forEach {
+ Log.d(TAG, "$installerPackage:Installed Hotseat item:$it")
+ }
+ firstScreenInstalledWidgets.forEach {
+ Log.d(TAG, "$installerPackage:Installed Widget item (first screen):$it")
+ }
+ secondaryScreenInstalledWidgets.forEach {
+ Log.d(TAG, "$installerPackage:Installed Widget item (secondary screens):$it")
+ }
+ }
+ }
+
+ private fun getPackageName(info: ItemInfo): String? {
+ var packageName: String? = null
+ if (info is LauncherAppWidgetInfo) {
+ info.providerName?.let { packageName = info.providerName.packageName }
+ } else if (info.targetComponent != null) {
+ packageName = info.targetComponent?.packageName
+ }
+ return packageName
+ }
+
+ /**
+ * Clone the provided list on UI thread. This is used for [FolderInfo.getContents] which is
+ * always modified on UI thread.
+ */
+ @AnyThread
+ private fun cloneOnMainThread(list: ArrayList<WorkspaceItemInfo>): List<WorkspaceItemInfo> {
+ return try {
+ return Executors.MAIN_EXECUTOR.submit<ArrayList<WorkspaceItemInfo>> { ArrayList(list) }
+ .get()
+ } catch (e: Exception) {
+ emptyList()
+ }
+ }
+}
diff --git a/src/com/android/launcher3/model/FirstScreenBroadcastModel.kt b/src/com/android/launcher3/model/FirstScreenBroadcastModel.kt
new file mode 100644
index 0000000..ba5c526
--- /dev/null
+++ b/src/com/android/launcher3/model/FirstScreenBroadcastModel.kt
@@ -0,0 +1,39 @@
+/*
+ * 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
+
+/** Data model for the information used for [FirstScreenBroadcastHelper] Broadcast Extras */
+data class FirstScreenBroadcastModel(
+ // Package name of the installer for all items
+ val installerPackage: String,
+ // Installing items in Folders
+ val pendingCollectionItems: MutableSet<String> = mutableSetOf(),
+ // Installing items on first screen
+ val pendingWorkspaceItems: MutableSet<String> = mutableSetOf(),
+ // Installing items on hotseat
+ val pendingHotseatItems: MutableSet<String> = mutableSetOf(),
+ // Installing widgets on first screen
+ val pendingWidgetItems: MutableSet<String> = mutableSetOf(),
+ // Installed/Archived Items on first screen
+ val installedWorkspaceItems: MutableSet<String> = mutableSetOf(),
+ // Installed/Archived items on hotseat
+ val installedHotseatItems: MutableSet<String> = mutableSetOf(),
+ // Installed/Archived Widgets on first screen
+ val firstScreenInstalledWidgets: MutableSet<String> = mutableSetOf(),
+ // Installed Archived Widgets on secondary screens
+ val secondaryScreenInstalledWidgets: MutableSet<String> = mutableSetOf()
+)
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index 0d40a24..dc6968c 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -47,6 +47,7 @@
import android.os.Trace;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.util.ArrayMap;
import android.util.Log;
import android.util.LongSparseArray;
@@ -195,17 +196,32 @@
}
private void sendFirstScreenActiveInstallsBroadcast() {
- ArrayList<ItemInfo> firstScreenItems = new ArrayList<>();
- ArrayList<ItemInfo> allItems = mBgDataModel.getAllWorkspaceItems();
-
// Screen set is never empty
IntArray allScreens = mBgDataModel.collectWorkspaceScreens();
final int firstScreen = allScreens.get(0);
IntSet firstScreens = IntSet.wrap(firstScreen);
+ ArrayList<ItemInfo> allItems = mBgDataModel.getAllWorkspaceItems();
+ ArrayList<ItemInfo> firstScreenItems = new ArrayList<>();
filterCurrentWorkspaceItems(firstScreens, allItems, firstScreenItems,
new ArrayList<>() /* otherScreenItems are ignored */);
- mFirstScreenBroadcast.sendBroadcasts(mApp.getContext(), firstScreenItems);
+ final int launcherBroadcastInstalledApps = Settings.Secure.getInt(
+ mApp.getContext().getContentResolver(),
+ "launcher_broadcast_installed_apps",
+ /* def= */ 0);
+ if (launcherBroadcastInstalledApps == 1) {
+ List<FirstScreenBroadcastModel> broadcastModels =
+ FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
+ mPmHelper,
+ firstScreenItems,
+ mInstallingPkgsCached,
+ mBgDataModel.appWidgets
+ );
+ logASplit("Sending first screen broadcast with additional archiving Extras");
+ FirstScreenBroadcastHelper.sendBroadcastsForModels(mApp.getContext(), broadcastModels);
+ } else {
+ mFirstScreenBroadcast.sendBroadcasts(mApp.getContext(), firstScreenItems);
+ }
}
public void run() {
@@ -249,7 +265,7 @@
mModelDelegate.workspaceLoadComplete();
// Notify the installer packages of packages with active installs on the first screen.
sendFirstScreenActiveInstallsBroadcast();
- logASplit("sendFirstScreenActiveInstallsBroadcast");
+ logASplit("sendFirstScreenBroadcast");
// Take a break
waitForIdle();
diff --git a/src/com/android/launcher3/notification/NotificationKeyData.java b/src/com/android/launcher3/notification/NotificationKeyData.java
index 4115b3d..e38824c 100644
--- a/src/com/android/launcher3/notification/NotificationKeyData.java
+++ b/src/com/android/launcher3/notification/NotificationKeyData.java
@@ -22,6 +22,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.Utilities;
@@ -38,6 +39,11 @@
public final String[] personKeysFromNotification;
public int count;
+ @VisibleForTesting
+ public NotificationKeyData(String notificationKey) {
+ this(notificationKey, null, 1, new String[]{});
+ }
+
private NotificationKeyData(String notificationKey, String shortcutId, int count,
String[] personKeysFromNotification) {
this.notificationKey = notificationKey;
diff --git a/src/com/android/launcher3/popup/RoundedArrowDrawable.java b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
index 575052c..2610bd6 100644
--- a/src/com/android/launcher3/popup/RoundedArrowDrawable.java
+++ b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
@@ -175,7 +175,10 @@
mPaint.setShadowLayer(shadowBlur, dx, dy, shadowColor);
}
- private static void addDownPointingRoundedTriangleToPath(float width, float height,
+ /**
+ * Adds rounded triangle pointing down to the provided {@link Path path} argument
+ */
+ public static void addDownPointingRoundedTriangleToPath(float width, float height,
float radius, Path path) {
// Calculated for the arrow pointing down, will be flipped later if needed.
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index a4ff29f..21897bf 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -418,9 +418,7 @@
DeviceGridState deviceGridState = new DeviceGridState(context);
FileLog.d(TAG, "restore initiated from backup: DeviceGridState=" + deviceGridState);
LauncherPrefs.get(context).putSync(RESTORE_DEVICE.to(deviceGridState.getDeviceType()));
- if (enableLauncherBrMetricsFixed()) {
- LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(true));
- }
+ LauncherPrefs.get(context).putSync(IS_FIRST_LOAD_AFTER_RESTORE.to(true));
}
@WorkerThread
diff --git a/src/com/android/launcher3/statemanager/BaseState.java b/src/com/android/launcher3/statemanager/BaseState.java
index a01d402..b81729a 100644
--- a/src/com/android/launcher3/statemanager/BaseState.java
+++ b/src/com/android/launcher3/statemanager/BaseState.java
@@ -21,7 +21,7 @@
import com.android.launcher3.views.ActivityContext;
/**
- * Interface representing a state of a StatefulActivity
+ * Interface representing a state of a StatefulContainer
*/
public interface BaseState<T extends BaseState> {
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index eea1a7d..ac07c0f 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -26,6 +26,7 @@
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.content.Context;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
@@ -47,8 +48,11 @@
/**
* Class to manage transitions between different states for a StatefulActivity based on different
* states
+ * @param STATE_TYPE Basestate used by the state manager
+ * @param STATEFUL_CONTAINER container object used to manage state
*/
-public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> {
+public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>,
+ STATEFUL_CONTAINER extends Context & StatefulContainer<STATE_TYPE>> {
public static final String TAG = "StateManager";
// b/279059025, b/325463989
@@ -56,7 +60,7 @@
private final AnimationState mConfig = new AnimationState();
private final Handler mUiHandler;
- private final StatefulActivity<STATE_TYPE> mActivity;
+ private final STATEFUL_CONTAINER mStatefulContainer;
private final ArrayList<StateListener<STATE_TYPE>> mListeners = new ArrayList<>();
private final STATE_TYPE mBaseState;
@@ -71,12 +75,12 @@
private STATE_TYPE mRestState;
- public StateManager(StatefulActivity<STATE_TYPE> l, STATE_TYPE baseState) {
+ public StateManager(STATEFUL_CONTAINER container, STATE_TYPE baseState) {
mUiHandler = new Handler(Looper.getMainLooper());
- mActivity = l;
+ mStatefulContainer = container;
mBaseState = baseState;
mState = mLastStableState = mCurrentStableState = baseState;
- mAtomicAnimationFactory = l.createAtomicAnimationFactory();
+ mAtomicAnimationFactory = container.createAtomicAnimationFactory();
}
public STATE_TYPE getState() {
@@ -109,10 +113,10 @@
writer.println(prefix + "\tisInTransition:" + isInTransition());
}
- public StateHandler[] getStateHandlers() {
+ public StateHandler<STATE_TYPE>[] getStateHandlers() {
if (mStateHandlers == null) {
- ArrayList<StateHandler> handlers = new ArrayList<>();
- mActivity.collectStateHandlers(handlers);
+ ArrayList<StateHandler<STATE_TYPE>> handlers = new ArrayList<>();
+ mStatefulContainer.collectStateHandlers(handlers);
mStateHandlers = handlers.toArray(new StateHandler[handlers.size()]);
}
return mStateHandlers;
@@ -130,7 +134,7 @@
* Returns true if the state changes should be animated.
*/
public boolean shouldAnimateStateChange() {
- return !mActivity.isForceInvisible() && mActivity.isStarted();
+ return mStatefulContainer.shouldAnimateStateChange();
}
/**
@@ -245,7 +249,7 @@
}
animated &= areAnimatorsEnabled();
- if (mActivity.isInState(state)) {
+ if (mStatefulContainer.isInState(state)) {
if (mConfig.currentAnimation == null) {
// Run any queued runnable
if (listener != null) {
@@ -302,8 +306,8 @@
// Since state mBaseState can be reached from multiple states, just assume that the
// transition plays in reverse and use the same duration as previous state.
mConfig.duration = state == mBaseState
- ? fromState.getTransitionDuration(mActivity, false /* isToState */)
- : state.getTransitionDuration(mActivity, true /* isToState */);
+ ? fromState.getTransitionDuration(mStatefulContainer, false /* isToState */)
+ : state.getTransitionDuration(mStatefulContainer, true /* isToState */);
prepareForAtomicAnimation(fromState, state, mConfig);
AnimatorSet animation = createAnimationToNewWorkspaceInternal(state).buildAnim();
if (listener != null) {
@@ -336,7 +340,7 @@
PendingAnimation builder = new PendingAnimation(config.duration);
prepareForAtomicAnimation(fromState, toState, config);
- for (StateHandler handler : mActivity.getStateManager().getStateHandlers()) {
+ for (StateHandler handler : mStatefulContainer.getStateManager().getStateHandlers()) {
handler.setStateWithAnimation(toState, config, builder);
}
return builder.buildAnim();
@@ -402,7 +406,7 @@
private void onStateTransitionStart(STATE_TYPE state) {
mState = state;
- mActivity.onStateSetStart(mState);
+ mStatefulContainer.onStateSetStart(mState);
if (DEBUG) {
Log.d(TAG, "onStateTransitionStart - state: " + state);
@@ -419,7 +423,7 @@
mCurrentStableState = state;
}
- mActivity.onStateSetEnd(state);
+ mStatefulContainer.onStateSetEnd(state);
if (state == mBaseState) {
setRestState(null);
}
diff --git a/src/com/android/launcher3/statemanager/StatefulActivity.java b/src/com/android/launcher3/statemanager/StatefulActivity.java
index 30ba703..28f2def 100644
--- a/src/com/android/launcher3/statemanager/StatefulActivity.java
+++ b/src/com/android/launcher3/statemanager/StatefulActivity.java
@@ -18,7 +18,6 @@
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
-import static com.android.launcher3.LauncherState.FLAG_CLOSE_POPUPS;
import static com.android.launcher3.LauncherState.FLAG_NON_INTERACTIVE;
import android.content.res.Configuration;
@@ -29,11 +28,9 @@
import androidx.annotation.CallSuper;
-import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.LauncherRootView;
import com.android.launcher3.Utilities;
-import com.android.launcher3.statemanager.StateManager.AtomicAnimationFactory;
import com.android.launcher3.statemanager.StateManager.StateHandler;
import com.android.launcher3.util.window.WindowManagerProxy;
import com.android.launcher3.views.BaseDragLayer;
@@ -45,7 +42,7 @@
* @param <STATE_TYPE> Type of state object
*/
public abstract class StatefulActivity<STATE_TYPE extends BaseState<STATE_TYPE>>
- extends BaseDraggingActivity {
+ extends BaseDraggingActivity implements StatefulContainer<STATE_TYPE> {
public final Handler mHandler = new Handler();
private final Runnable mHandleDeferredResume = this::handleDeferredResume;
@@ -67,19 +64,9 @@
/**
* Create handlers to control the property changes for this activity
*/
- protected abstract void collectStateHandlers(List<StateHandler> out);
- /**
- * Returns true if the activity is in the provided state
- */
- public boolean isInState(STATE_TYPE state) {
- return getStateManager().getState() == state;
- }
-
- /**
- * Returns the state manager for this activity
- */
- public abstract StateManager<STATE_TYPE> getStateManager();
+ @Override
+ public abstract void collectStateHandlers(List<StateHandler<STATE_TYPE>> out);
protected void inflateRootView(int layoutId) {
mRootView = (LauncherRootView) LayoutInflater.from(this).inflate(layoutId, null);
@@ -106,22 +93,12 @@
if (mDeferredResumePending) {
handleDeferredResume();
}
-
- if (state.hasFlag(FLAG_CLOSE_POPUPS)) {
- AbstractFloatingView.closeAllOpenViews(this, !state.hasFlag(FLAG_NON_INTERACTIVE));
- }
+ StatefulContainer.super.onStateSetStart(state);
}
- /**
- * Called when transition to state ends
- */
- public void onStateSetEnd(STATE_TYPE state) { }
-
- /**
- * Creates a factory for atomic state animations
- */
- public AtomicAnimationFactory<STATE_TYPE> createAtomicAnimationFactory() {
- return new AtomicAnimationFactory(0);
+ @Override
+ public boolean shouldAnimateStateChange() {
+ return !isForceInvisible() && isStarted();
}
@Override
diff --git a/src/com/android/launcher3/statemanager/StatefulContainer.java b/src/com/android/launcher3/statemanager/StatefulContainer.java
new file mode 100644
index 0000000..0cf0a27
--- /dev/null
+++ b/src/com/android/launcher3/statemanager/StatefulContainer.java
@@ -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.statemanager;
+
+
+import static com.android.launcher3.LauncherState.FLAG_CLOSE_POPUPS;
+import static com.android.launcher3.statemanager.BaseState.FLAG_NON_INTERACTIVE;
+
+import androidx.annotation.CallSuper;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.views.ActivityContext;
+
+import java.util.List;
+
+/**
+ * Interface for a container that can be managed by a state manager.
+ *
+ * @param <STATE_TYPE> The type of state that the container can be in.
+ */
+public interface StatefulContainer<STATE_TYPE extends BaseState<STATE_TYPE>> extends
+ ActivityContext {
+
+ /**
+ * Creates a factory for atomic state animations
+ */
+ default StateManager.AtomicAnimationFactory<STATE_TYPE> createAtomicAnimationFactory() {
+ return new StateManager.AtomicAnimationFactory<>(0);
+ }
+
+ /**
+ * Create handlers to control the property changes for this activity
+ */
+ void collectStateHandlers(List<StateManager.StateHandler<STATE_TYPE>> out);
+
+ /**
+ * Retrieves state manager for given container
+ */
+ StateManager<STATE_TYPE, ?> getStateManager();
+
+ /**
+ * Called when transition to state ends
+ * @param state current state of State_Type
+ */
+ default void onStateSetEnd(STATE_TYPE state) { }
+
+ /**
+ * Called when transition to state starts
+ * @param state current state of State_Type
+ */
+ @CallSuper
+ default void onStateSetStart(STATE_TYPE state) {
+ if (state.hasFlag(FLAG_CLOSE_POPUPS)) {
+ AbstractFloatingView.closeAllOpenViews(this, !state.hasFlag(FLAG_NON_INTERACTIVE));
+ }
+ }
+
+ /**
+ * Returns true if the activity is in the provided state
+ * @param state current state of State_Type
+ */
+ default boolean isInState(STATE_TYPE state) {
+ return getStateManager().getState() == state;
+ }
+
+ /**
+ * Returns true if state change should transition with animation
+ */
+ boolean shouldAnimateStateChange();
+}
diff --git a/src/com/android/launcher3/util/ApiWrapper.java b/src/com/android/launcher3/util/ApiWrapper.java
index 6429a43..095518c 100644
--- a/src/com/android/launcher3/util/ApiWrapper.java
+++ b/src/com/android/launcher3/util/ApiWrapper.java
@@ -16,10 +16,12 @@
package com.android.launcher3.util;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_HOME_ROLE;
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
import android.app.ActivityOptions;
import android.app.Person;
+import android.app.role.RoleManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
@@ -33,6 +35,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.BuildConfig;
+import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -136,6 +139,23 @@
return false;
}
+ /**
+ * Starts an Activity which can be used to set this Launcher as the HOME app, via a consent
+ * screen. In case the consent screen cannot be shown, or the user does not set current Launcher
+ * as HOME app, a toast asking the user to do the latter is shown.
+ */
+ public void assignDefaultHomeRole(Context context) {
+ RoleManager roleManager = context.getSystemService(RoleManager.class);
+ assert roleManager != null;
+ if (roleManager.isRoleAvailable(RoleManager.ROLE_HOME)
+ && !roleManager.isRoleHeld(RoleManager.ROLE_HOME)) {
+ Intent roleRequestIntent = roleManager.createRequestRoleIntent(
+ RoleManager.ROLE_HOME);
+ Launcher launcher = Launcher.getLauncher(context);
+ launcher.startActivityForResult(roleRequestIntent, REQUEST_HOME_ROLE);
+ }
+ }
+
@Override
public void close() { }
diff --git a/src/com/android/launcher3/util/CannedAnimationCoordinator.kt b/src/com/android/launcher3/util/CannedAnimationCoordinator.kt
index 85f81f5..749caac 100644
--- a/src/com/android/launcher3/util/CannedAnimationCoordinator.kt
+++ b/src/com/android/launcher3/util/CannedAnimationCoordinator.kt
@@ -113,10 +113,9 @@
// flags accordingly
animationController =
controller.apply {
- activity.stateManager.setCurrentAnimation(
- this,
- USER_CONTROLLED or HANDLE_STATE_APPLY
- )
+ activity
+ .stateManager
+ .setCurrentAnimation(this, USER_CONTROLLED or HANDLE_STATE_APPLY)
}
recreateAnimation(provider)
}
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index f7c4df4..8c5a76e 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -16,9 +16,10 @@
package com.android.launcher3.util;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
import static android.view.WindowManager.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE;
+
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
@@ -151,6 +152,18 @@
}
/**
+ * Returns the installing app package for the given package
+ */
+ public String getAppInstallerPackage(@NonNull final String packageName) {
+ try {
+ return mPm.getInstallSourceInfo(packageName).getInstallingPackageName();
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "Failed to get installer package for app package:" + packageName, e);
+ return null;
+ }
+ }
+
+ /**
* Returns the application info for the provided package or null
*/
@Nullable
diff --git a/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index 3405635..8770859 100644
--- a/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -57,7 +57,7 @@
*
* For an implementation that mocks InvariantDeviceProfile, use [FakeInvariantDeviceProfileTest]
*/
-@AllowedDevices(allowed = [DeviceProduct.CF_PHONE, DeviceProduct.HOST_SIDE_X86_64])
+@AllowedDevices(allowed = [DeviceProduct.CF_PHONE, DeviceProduct.ROBOLECTRIC])
@IgnoreLimit(ignoreLimit = BuildConfig.IS_STUDIO_BUILD)
abstract class AbstractDeviceProfileTest {
protected val testContext: Context = InstrumentationRegistry.getInstrumentation().context
@@ -341,4 +341,9 @@
protected fun Int.dpToPx(): Int {
return ResourceUtils.pxFromDp(this.toFloat(), context!!.resources.displayMetrics)
}
+
+ protected fun String.xmlToId(): Int {
+ val context = InstrumentationRegistry.getInstrumentation().context
+ return context.resources.getIdentifier(this, "xml", context.packageName)
+ }
}
diff --git a/tests/src/com/android/launcher3/UtilitiesKtTest.kt b/tests/multivalentTests/src/com/android/launcher3/UtilitiesKtTest.kt
similarity index 86%
rename from tests/src/com/android/launcher3/UtilitiesKtTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/UtilitiesKtTest.kt
index 9aa0369..0d13e77 100644
--- a/tests/src/com/android/launcher3/UtilitiesKtTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/UtilitiesKtTest.kt
@@ -17,9 +17,8 @@
package com.android.launcher3
import android.content.Context
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
+import android.widget.LinearLayout
+import android.widget.TextView
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
@@ -27,28 +26,20 @@
import com.android.launcher3.UtilitiesKt.CLIP_TO_PADDING_FALSE_MODIFIER
import com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree
import com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree
-import com.android.launcher3.tests.R
import com.google.common.truth.Truth.assertThat
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class UtilitiesKtTest {
-
val context: Context = InstrumentationRegistry.getInstrumentation().context
- private lateinit var rootView: ViewGroup
- private lateinit var midView: ViewGroup
- private lateinit var childView: View
- @Before
- fun setup() {
- rootView =
- LayoutInflater.from(context).inflate(R.layout.utilities_test_view, null) as ViewGroup
- midView = rootView.requireViewById(R.id.mid_view)
- childView = rootView.requireViewById(R.id.child_view)
- }
+ private val childView = TextView(context)
+
+ private val midView = LinearLayout(context).apply { addView(childView) }
+
+ private val rootView = LinearLayout(context).apply { addView(midView) }
@Test
fun set_clipChildren_false() {
diff --git a/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt b/tests/multivalentTests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
similarity index 93%
rename from tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
index c99da96..3dca35e 100644
--- a/tests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/responsive/AllAppsSpecsTest.kt
@@ -22,7 +22,6 @@
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.AbstractDeviceProfileTest
import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
-import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -45,7 +44,7 @@
fun parseValidFile() {
val allAppsSpecs =
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.valid_all_apps_file),
+ TestResourceHelper(context, "valid_all_apps_file".xmlToId()),
ResponsiveSpecType.AllApps
)
@@ -114,7 +113,7 @@
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_missingTag_throwsError() {
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.invalid_all_apps_file_case_1),
+ TestResourceHelper(context, "invalid_all_apps_file_case_1".xmlToId()),
ResponsiveSpecType.AllApps
)
}
@@ -122,7 +121,7 @@
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.invalid_all_apps_file_case_2),
+ TestResourceHelper(context, "invalid_all_apps_file_case_2".xmlToId()),
ResponsiveSpecType.AllApps
)
}
@@ -130,7 +129,7 @@
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_valueBiggerThan1_throwsError() {
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.invalid_all_apps_file_case_3),
+ TestResourceHelper(context, "invalid_all_apps_file_case_3".xmlToId()),
ResponsiveSpecType.AllApps
)
}
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt b/tests/multivalentTests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
similarity index 94%
rename from tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
index 1cc5ed2..8346492 100644
--- a/tests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/responsive/CalculatedAllAppsSpecTest.kt
@@ -23,7 +23,6 @@
import com.android.launcher3.AbstractDeviceProfileTest
import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
-import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -52,7 +51,7 @@
val workspaceSpecs =
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.valid_workspace_file),
+ TestResourceHelper(context, "valid_workspace_file".xmlToId()),
ResponsiveSpecType.Workspace
)
val widthSpec =
@@ -62,7 +61,7 @@
val allAppsSpecs =
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.valid_all_apps_file),
+ TestResourceHelper(context, "valid_all_apps_file".xmlToId()),
ResponsiveSpecType.AllApps
)
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecTest.kt b/tests/multivalentTests/src/com/android/launcher3/responsive/CalculatedFolderSpecTest.kt
similarity index 95%
rename from tests/src/com/android/launcher3/responsive/CalculatedFolderSpecTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/responsive/CalculatedFolderSpecTest.kt
index c4e2d2a..46d6cb9 100644
--- a/tests/src/com/android/launcher3/responsive/CalculatedFolderSpecTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/responsive/CalculatedFolderSpecTest.kt
@@ -23,7 +23,6 @@
import com.android.launcher3.AbstractDeviceProfileTest
import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
-import com.android.launcher3.tests.R
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -47,12 +46,12 @@
val columns = 6
// Loading workspace specs
- val resourceHelperWorkspace = TestResourceHelper(context, R.xml.valid_workspace_file)
+ val resourceHelperWorkspace = TestResourceHelper(context, "valid_workspace_file".xmlToId())
val workspaceSpecs =
ResponsiveSpecsProvider.create(resourceHelperWorkspace, ResponsiveSpecType.Workspace)
// Loading folders specs
- val resourceHelperFolder = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val resourceHelperFolder = TestResourceHelper(context, "valid_folders_specs".xmlToId())
val folderSpecs =
ResponsiveSpecsProvider.create(resourceHelperFolder, ResponsiveSpecType.Folder)
val specs = folderSpecs.getSpecsByAspectRatio(aspectRatio)
@@ -123,12 +122,12 @@
val rows = 5
// Loading workspace specs
- val resourceHelperWorkspace = TestResourceHelper(context, R.xml.valid_workspace_file)
+ val resourceHelperWorkspace = TestResourceHelper(context, "valid_workspace_file".xmlToId())
val workspaceSpecs =
ResponsiveSpecsProvider.create(resourceHelperWorkspace, ResponsiveSpecType.Workspace)
// Loading folders specs
- val resourceHelperFolder = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val resourceHelperFolder = TestResourceHelper(context, "valid_folders_specs".xmlToId())
val folderSpecs =
ResponsiveSpecsProvider.create(resourceHelperFolder, ResponsiveSpecType.Folder)
val specs = folderSpecs.getSpecsByAspectRatio(aspectRatio)
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt b/tests/multivalentTests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt
similarity index 95%
rename from tests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt
index 1a564ac..5ab44f3 100644
--- a/tests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/responsive/CalculatedHotseatSpecTest.kt
@@ -22,7 +22,6 @@
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.AbstractDeviceProfileTest
import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
-import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -47,7 +46,7 @@
val availableHeight = deviceSpec.naturalSize.second
val hotseatSpecsProvider =
- HotseatSpecsProvider.create(TestResourceHelper(context, TestR.xml.valid_hotseat_file))
+ HotseatSpecsProvider.create(TestResourceHelper(context, "valid_hotseat_file".xmlToId()))
val heightSpec =
hotseatSpecsProvider.getCalculatedSpec(
aspectRatio,
@@ -73,7 +72,7 @@
val availableHeight = deviceSpec.naturalSize.second
val hotseatSpecsProvider =
- HotseatSpecsProvider.create(TestResourceHelper(context, TestR.xml.valid_hotseat_file))
+ HotseatSpecsProvider.create(TestResourceHelper(context, "valid_hotseat_file".xmlToId()))
val heightSpec =
hotseatSpecsProvider.getCalculatedSpec(
aspectRatio,
@@ -99,7 +98,7 @@
val hotseatSpecsProvider =
HotseatSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.valid_hotseat_land_file)
+ TestResourceHelper(context, "valid_hotseat_land_file".xmlToId())
)
val widthSpec =
hotseatSpecsProvider.getCalculatedSpec(aspectRatio, DimensionType.WIDTH, availableWidth)
diff --git a/tests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt b/tests/multivalentTests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt
similarity index 95%
rename from tests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt
index 0c5d347..dea98b6 100644
--- a/tests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/responsive/CalculatedWorkspaceSpecTest.kt
@@ -23,7 +23,6 @@
import com.android.launcher3.AbstractDeviceProfileTest
import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
-import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
import org.junit.Test
@@ -53,7 +52,7 @@
val workspaceSpecs =
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.valid_workspace_file),
+ TestResourceHelper(context, "valid_workspace_file".xmlToId()),
ResponsiveSpecType.Workspace
)
val widthSpec =
@@ -96,7 +95,7 @@
val workspaceSpecs =
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.valid_workspace_file),
+ TestResourceHelper(context, "valid_workspace_file".xmlToId()),
ResponsiveSpecType.Workspace
)
val widthSpec =
@@ -138,7 +137,7 @@
val availableHeight = deviceSpec.naturalSize.second - deviceSpec.statusBarNaturalPx - 640
val workspaceSpecs =
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.valid_workspace_unsorted_file),
+ TestResourceHelper(context, "valid_workspace_unsorted_file".xmlToId()),
ResponsiveSpecType.Workspace
)
val widthSpec =
diff --git a/tests/src/com/android/launcher3/responsive/FolderSpecTest.kt b/tests/multivalentTests/src/com/android/launcher3/responsive/FolderSpecTest.kt
similarity index 91%
rename from tests/src/com/android/launcher3/responsive/FolderSpecTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/responsive/FolderSpecTest.kt
index 5cfa49f..d2b264b 100644
--- a/tests/src/com/android/launcher3/responsive/FolderSpecTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/responsive/FolderSpecTest.kt
@@ -23,7 +23,6 @@
import com.android.launcher3.AbstractDeviceProfileTest
import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
-import com.android.launcher3.tests.R
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -44,7 +43,7 @@
@Test
fun parseValidFile() {
- val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val resourceHelper = TestResourceHelper(context, "valid_folders_specs".xmlToId())
val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
val specs = folderSpecs.getSpecsByAspectRatio(aspectRatio)
@@ -92,25 +91,25 @@
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_missingTag_throwsError() {
- val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_1)
+ val resourceHelper = TestResourceHelper(context, "invalid_folders_specs_1".xmlToId())
ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
- val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_2)
+ val resourceHelper = TestResourceHelper(context, "invalid_folders_specs_2".xmlToId())
ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_valueBiggerThan1_throwsError() {
- val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_3)
+ val resourceHelper = TestResourceHelper(context, "invalid_folders_specs_3".xmlToId())
ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_missingSpecs_throwsError() {
- val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_4)
+ val resourceHelper = TestResourceHelper(context, "invalid_folders_specs_4".xmlToId())
ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
}
@@ -132,7 +131,7 @@
val calculatedWorkspaceSpec =
CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
- val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_5)
+ val resourceHelper = TestResourceHelper(context, "invalid_folders_specs_5".xmlToId())
val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
folderSpecs.getCalculatedSpec(
aspectRatio,
@@ -161,7 +160,7 @@
val calculatedWorkspaceSpec =
CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
- val resourceHelper = TestResourceHelper(context, R.xml.invalid_folders_specs_5)
+ val resourceHelper = TestResourceHelper(context, "invalid_folders_specs_5".xmlToId())
val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
folderSpecs.getCalculatedSpec(
aspectRatio,
@@ -190,7 +189,7 @@
val calculatedWorkspaceSpec =
CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
- val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val resourceHelper = TestResourceHelper(context, "valid_folders_specs".xmlToId())
val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
val calculatedWidthSpec =
folderSpecs.getCalculatedSpec(
@@ -227,7 +226,7 @@
val calculatedWorkspaceSpec =
CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
- val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val resourceHelper = TestResourceHelper(context, "valid_folders_specs".xmlToId())
val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
folderSpecs.getCalculatedSpec(
aspectRatio,
@@ -256,7 +255,7 @@
val calculatedWorkspaceSpec =
CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
- val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val resourceHelper = TestResourceHelper(context, "valid_folders_specs".xmlToId())
val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
val calculatedHeightSpec =
folderSpecs.getCalculatedSpec(
@@ -293,7 +292,7 @@
val calculatedWorkspaceSpec =
CalculatedResponsiveSpec(aspectRatio, availableSpace, cells, workspaceSpec)
- val resourceHelper = TestResourceHelper(context, R.xml.valid_folders_specs)
+ val resourceHelper = TestResourceHelper(context, "valid_folders_specs".xmlToId())
val folderSpecs = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Folder)
folderSpecs.getCalculatedSpec(
aspectRatio,
diff --git a/tests/src/com/android/launcher3/responsive/HotseatSpecsProviderTest.kt b/tests/multivalentTests/src/com/android/launcher3/responsive/HotseatSpecsProviderTest.kt
similarity index 93%
rename from tests/src/com/android/launcher3/responsive/HotseatSpecsProviderTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/responsive/HotseatSpecsProviderTest.kt
index 78cb1ac..58324e1 100644
--- a/tests/src/com/android/launcher3/responsive/HotseatSpecsProviderTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/responsive/HotseatSpecsProviderTest.kt
@@ -22,7 +22,6 @@
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.AbstractDeviceProfileTest
import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
-import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -44,7 +43,7 @@
@Test
fun parseValidFile() {
val hotseatSpecsProvider =
- HotseatSpecsProvider.create(TestResourceHelper(context, TestR.xml.valid_hotseat_file))
+ HotseatSpecsProvider.create(TestResourceHelper(context, "valid_hotseat_file".xmlToId()))
val specs = hotseatSpecsProvider.getSpecsByAspectRatio(aspectRatio)
val expectedHeightSpecs =
@@ -76,7 +75,7 @@
fun parseValidLandscapeFile() {
val hotseatSpecsProvider =
HotseatSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.valid_hotseat_land_file)
+ TestResourceHelper(context, "valid_hotseat_land_file".xmlToId())
)
val specs = hotseatSpecsProvider.getSpecsByAspectRatio(aspectRatio)
assertThat(specs.heightSpecs.size).isEqualTo(0)
@@ -107,14 +106,14 @@
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_spaceIsNotFixedSize_throwsError() {
HotseatSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.invalid_hotseat_file_case_1)
+ TestResourceHelper(context, "invalid_hotseat_file_case_1".xmlToId())
)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_invalidFixedSize_throwsError() {
HotseatSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.invalid_hotseat_file_case_2)
+ TestResourceHelper(context, "invalid_hotseat_file_case_2".xmlToId())
)
}
}
diff --git a/tests/src/com/android/launcher3/responsive/ResponsiveCellSpecsProviderTest.kt b/tests/multivalentTests/src/com/android/launcher3/responsive/ResponsiveCellSpecsProviderTest.kt
similarity index 92%
rename from tests/src/com/android/launcher3/responsive/ResponsiveCellSpecsProviderTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/responsive/ResponsiveCellSpecsProviderTest.kt
index 50cd358..11161bd 100644
--- a/tests/src/com/android/launcher3/responsive/ResponsiveCellSpecsProviderTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/responsive/ResponsiveCellSpecsProviderTest.kt
@@ -22,7 +22,6 @@
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.AbstractDeviceProfileTest
import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
-import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -43,7 +42,7 @@
@Test
fun parseValidFile() {
- val testResourceHelper = TestResourceHelper(context, TestR.xml.valid_cell_specs_file)
+ val testResourceHelper = TestResourceHelper(context, "valid_cell_specs_file".xmlToId())
val provider = ResponsiveCellSpecsProvider.create(testResourceHelper)
// Validate Portrait
@@ -98,21 +97,21 @@
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_IsNotFixedSizeOrMatchWorkspace_throwsError() {
ResponsiveCellSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.invalid_cell_specs_1)
+ TestResourceHelper(context, "invalid_cell_specs_1".xmlToId())
)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_dimensionTypeIsNotHeight_throwsError() {
ResponsiveCellSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.invalid_cell_specs_2)
+ TestResourceHelper(context, "invalid_cell_specs_2".xmlToId())
)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_invalidFixedSize_throwsError() {
ResponsiveCellSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.invalid_cell_specs_3)
+ TestResourceHelper(context, "invalid_cell_specs_3".xmlToId())
)
}
}
diff --git a/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt b/tests/multivalentTests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
similarity index 93%
rename from tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
index 54a1dc5..c74f7a8 100644
--- a/tests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/responsive/ResponsiveSpecsProviderTest.kt
@@ -23,7 +23,6 @@
import com.android.launcher3.AbstractDeviceProfileTest
import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
import com.android.launcher3.responsive.ResponsiveSpec.DimensionType
-import com.android.launcher3.tests.R
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -44,7 +43,7 @@
@Test
fun parseValidFile() {
- val resourceHelper = TestResourceHelper(context, R.xml.valid_responsive_spec_unsorted)
+ val resourceHelper = TestResourceHelper(context, "valid_responsive_spec_unsorted".xmlToId())
val provider = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
// Validate Portrait
@@ -111,44 +110,44 @@
@Test(expected = IllegalStateException::class)
fun parseValidFile_invalidAspectRatio_throwsError() {
- val resourceHelper = TestResourceHelper(context, R.xml.valid_responsive_spec_unsorted)
+ val resourceHelper = TestResourceHelper(context, "valid_responsive_spec_unsorted".xmlToId())
val provider = ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
provider.getSpecsByAspectRatio(0f)
}
@Test(expected = InvalidResponsiveGridSpec::class)
fun parseInvalidFile_missingGroups_throwsError() {
- val resourceHelper = TestResourceHelper(context, R.xml.invalid_responsive_spec_1)
+ val resourceHelper = TestResourceHelper(context, "invalid_responsive_spec_1".xmlToId())
ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
}
@Test(expected = InvalidResponsiveGridSpec::class)
fun parseInvalidFile_partialGroups_throwsError() {
- val resourceHelper = TestResourceHelper(context, R.xml.invalid_responsive_spec_2)
+ val resourceHelper = TestResourceHelper(context, "invalid_responsive_spec_2".xmlToId())
ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_invalidAspectRatio_throwsError() {
- val resourceHelper = TestResourceHelper(context, R.xml.invalid_responsive_spec_3)
+ val resourceHelper = TestResourceHelper(context, "invalid_responsive_spec_3".xmlToId())
ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_invalidRemainderSpace_throwsError() {
- val resourceHelper = TestResourceHelper(context, R.xml.invalid_responsive_spec_4)
+ val resourceHelper = TestResourceHelper(context, "invalid_responsive_spec_4".xmlToId())
ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_invalidAvailableSpace_throwsError() {
- val resourceHelper = TestResourceHelper(context, R.xml.invalid_responsive_spec_5)
+ val resourceHelper = TestResourceHelper(context, "invalid_responsive_spec_5".xmlToId())
ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
}
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_invalidFixedSize_throwsError() {
- val resourceHelper = TestResourceHelper(context, R.xml.invalid_responsive_spec_6)
+ val resourceHelper = TestResourceHelper(context, "invalid_responsive_spec_6".xmlToId())
ResponsiveSpecsProvider.create(resourceHelper, ResponsiveSpecType.Workspace)
}
diff --git a/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt b/tests/multivalentTests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
similarity index 94%
rename from tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
index 17b0ee4..bc133ba 100644
--- a/tests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/responsive/WorkspaceSpecsTest.kt
@@ -22,7 +22,6 @@
import androidx.test.platform.app.InstrumentationRegistry
import com.android.launcher3.AbstractDeviceProfileTest
import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecType
-import com.android.launcher3.tests.R as TestR
import com.android.launcher3.util.TestResourceHelper
import com.google.common.truth.Truth.assertThat
import org.junit.Before
@@ -45,7 +44,7 @@
fun parseValidFile() {
val workspaceSpecs =
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.valid_workspace_file),
+ TestResourceHelper(context, "valid_workspace_file".xmlToId()),
ResponsiveSpecType.Workspace
)
@@ -169,7 +168,7 @@
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_missingTag_throwsError() {
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.invalid_workspace_file_case_1),
+ TestResourceHelper(context, "invalid_workspace_file_case_1".xmlToId()),
ResponsiveSpecType.Workspace
)
}
@@ -177,7 +176,7 @@
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_moreThanOneValuePerTag_throwsError() {
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.invalid_workspace_file_case_2),
+ TestResourceHelper(context, "invalid_workspace_file_case_2".xmlToId()),
ResponsiveSpecType.Workspace
)
}
@@ -185,7 +184,7 @@
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_valueBiggerThan1_throwsError() {
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.invalid_workspace_file_case_3),
+ TestResourceHelper(context, "invalid_workspace_file_case_3".xmlToId()),
ResponsiveSpecType.Workspace
)
}
@@ -193,7 +192,7 @@
@Test(expected = IllegalStateException::class)
fun parseInvalidFile_matchWorkspace_true_throwsError() {
ResponsiveSpecsProvider.create(
- TestResourceHelper(context, TestR.xml.invalid_workspace_file_case_4),
+ TestResourceHelper(context, "invalid_workspace_file_case_4".xmlToId()),
ResponsiveSpecType.Workspace
)
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/TestResourceHelper.kt b/tests/multivalentTests/src/com/android/launcher3/util/TestResourceHelper.kt
new file mode 100644
index 0000000..d95c6f8
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/util/TestResourceHelper.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import android.content.Context
+import android.content.res.TypedArray
+import android.util.AttributeSet
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.R
+import kotlin.IntArray
+
+class TestResourceHelper(private val context: Context, specsFileId: Int) :
+ ResourceHelper(context, specsFileId) {
+
+ val responsiveStyleables = listOf(
+ R.styleable.SizeSpec,
+ R.styleable.WorkspaceSpec,
+ R.styleable.FolderSpec,
+ R.styleable.AllAppsSpec,
+ R.styleable.ResponsiveSpecGroup
+ )
+
+ override fun obtainStyledAttributes(attrs: AttributeSet, styleId: IntArray): TypedArray {
+ val clone =
+ if (responsiveStyleables.any { styleId.contentEquals(it) }) {
+ convertStyleId(styleId)
+ } else {
+ styleId.clone()
+ }
+
+ return context.obtainStyledAttributes(attrs, clone)
+ }
+
+ private fun convertStyleId(styleableArr: IntArray): IntArray {
+ val targetContextRes = getInstrumentation().targetContext.resources
+ val context = getInstrumentation().context
+ return styleableArr
+ .map { attrId -> targetContextRes.getResourceName(attrId).split(":").last() }
+ .map { attrName ->
+ // Get required attr from context instead of targetContext
+ context.resources.getIdentifier(attrName, null, context.packageName)
+ }
+ .toIntArray()
+ }
+}
diff --git a/tests/res/layout/utilities_test_view.xml b/tests/res/layout/utilities_test_view.xml
deleted file mode 100644
index dc2a515..0000000
--- a/tests/res/layout/utilities_test_view.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2024 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/root_view">
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:id="@+id/mid_view">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/child_view" />
- </LinearLayout>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt b/tests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
new file mode 100644
index 0000000..aadf72e
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/FirstScreenBroadcastHelperTest.kt
@@ -0,0 +1,386 @@
+/*
+ * 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.PendingIntent
+import android.content.ComponentName
+import android.content.Intent
+import android.content.pm.PackageInstaller.SessionInfo
+import android.os.UserHandle
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_DESKTOP
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
+import com.android.launcher3.model.FirstScreenBroadcastHelper.MAX_BROADCAST_SIZE
+import com.android.launcher3.model.FirstScreenBroadcastHelper.getTotalItemCount
+import com.android.launcher3.model.FirstScreenBroadcastHelper.truncateModelForBroadcast
+import com.android.launcher3.model.data.FolderInfo
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.util.PackageManagerHelper
+import com.android.launcher3.util.PackageUserKey
+import junit.framework.Assert.assertEquals
+import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
+
+class FirstScreenBroadcastHelperTest {
+ private val context = spy(InstrumentationRegistry.getInstrumentation().targetContext)
+ private val mockPmHelper = mock<PackageManagerHelper>()
+ private val expectedAppPackage = "appPackageExpected"
+ private val expectedComponentName = ComponentName(expectedAppPackage, "expectedClass")
+ private val expectedInstallerPackage = "installerPackage"
+ private val expectedIntent =
+ Intent().apply {
+ component = expectedComponentName
+ setPackage(expectedAppPackage)
+ }
+ private val unexpectedAppPackage = "appPackageUnexpected"
+ private val unexpectedComponentName = ComponentName(expectedAppPackage, "unexpectedClass")
+ private val firstScreenItems =
+ listOf(
+ WorkspaceItemInfo().apply {
+ container = CONTAINER_DESKTOP
+ intent = expectedIntent
+ },
+ WorkspaceItemInfo().apply {
+ container = CONTAINER_HOTSEAT
+ intent = expectedIntent
+ },
+ LauncherAppWidgetInfo().apply { providerName = expectedComponentName }
+ )
+
+ @Test
+ fun `Broadcast Models are created with Pending Items from first screen`() {
+ // Given
+ val sessionInfoExpected =
+ SessionInfo().apply {
+ installerPackageName = expectedInstallerPackage
+ appPackageName = expectedAppPackage
+ }
+ val sessionInfoUnexpected =
+ SessionInfo().apply {
+ installerPackageName = expectedInstallerPackage
+ appPackageName = unexpectedAppPackage
+ }
+ val sessionInfoMap: HashMap<PackageUserKey, SessionInfo> =
+ hashMapOf(
+ PackageUserKey(unexpectedAppPackage, UserHandle(0)) to sessionInfoExpected,
+ PackageUserKey(expectedAppPackage, UserHandle(0)) to sessionInfoUnexpected
+ )
+
+ // When
+ val actualResult =
+ FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
+ packageManagerHelper = mockPmHelper,
+ firstScreenItems = firstScreenItems,
+ userKeyToSessionMap = sessionInfoMap,
+ allWidgets = listOf()
+ )
+
+ // Then
+ val expectedResult =
+ listOf(
+ FirstScreenBroadcastModel(
+ installerPackage = expectedInstallerPackage,
+ pendingWorkspaceItems = mutableSetOf(expectedAppPackage),
+ pendingHotseatItems = mutableSetOf(expectedAppPackage),
+ pendingWidgetItems = mutableSetOf(expectedAppPackage)
+ )
+ )
+
+ assertEquals(expectedResult, actualResult)
+ }
+
+ @Test
+ fun `Broadcast Models are created with Installed Items from first screen`() {
+ // Given
+ whenever(mockPmHelper.getAppInstallerPackage(expectedAppPackage))
+ .thenReturn(expectedInstallerPackage)
+
+ // When
+ val actualResult =
+ FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
+ packageManagerHelper = mockPmHelper,
+ firstScreenItems = firstScreenItems,
+ userKeyToSessionMap = hashMapOf(),
+ allWidgets =
+ listOf(
+ LauncherAppWidgetInfo().apply {
+ providerName = expectedComponentName
+ screenId = 0
+ }
+ )
+ )
+
+ // Then
+ val expectedResult =
+ listOf(
+ FirstScreenBroadcastModel(
+ installerPackage = expectedInstallerPackage,
+ installedHotseatItems = mutableSetOf(expectedAppPackage),
+ installedWorkspaceItems = mutableSetOf(expectedAppPackage),
+ firstScreenInstalledWidgets = mutableSetOf(expectedAppPackage)
+ )
+ )
+ assertEquals(expectedResult, actualResult)
+ }
+
+ @Test
+ fun `Broadcast Models are created with Installed Widgets from every screen`() {
+ // Given
+ val expectedAppPackage2 = "appPackageExpected2"
+ val expectedComponentName2 = ComponentName(expectedAppPackage2, "expectedClass2")
+ whenever(mockPmHelper.getAppInstallerPackage(expectedAppPackage))
+ .thenReturn(expectedInstallerPackage)
+ whenever(mockPmHelper.getAppInstallerPackage(expectedAppPackage2))
+ .thenReturn(expectedInstallerPackage)
+
+ // When
+ val actualResult =
+ FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
+ packageManagerHelper = mockPmHelper,
+ firstScreenItems = listOf(),
+ userKeyToSessionMap = hashMapOf(),
+ allWidgets =
+ listOf(
+ LauncherAppWidgetInfo().apply {
+ providerName = expectedComponentName
+ screenId = 0
+ },
+ LauncherAppWidgetInfo().apply {
+ providerName = expectedComponentName2
+ screenId = 1
+ },
+ LauncherAppWidgetInfo().apply {
+ providerName = unexpectedComponentName
+ screenId = 0
+ }
+ )
+ )
+
+ // Then
+ val expectedResult =
+ listOf(
+ FirstScreenBroadcastModel(
+ installerPackage = expectedInstallerPackage,
+ installedHotseatItems = mutableSetOf(),
+ installedWorkspaceItems = mutableSetOf(),
+ firstScreenInstalledWidgets = mutableSetOf(expectedAppPackage),
+ secondaryScreenInstalledWidgets = mutableSetOf(expectedAppPackage2)
+ )
+ )
+ assertEquals(expectedResult, actualResult)
+ }
+
+ @Test
+ fun `Broadcast Models are created with Pending Items in Collections from the first screen`() {
+ // Given
+ val sessionInfoExpected =
+ SessionInfo().apply {
+ installerPackageName = expectedInstallerPackage
+ appPackageName = expectedAppPackage
+ }
+ val sessionInfoUnexpected =
+ SessionInfo().apply {
+ installerPackageName = expectedInstallerPackage
+ appPackageName = unexpectedAppPackage
+ }
+ val sessionInfoMap: HashMap<PackageUserKey, SessionInfo> =
+ hashMapOf(
+ PackageUserKey(unexpectedAppPackage, UserHandle(0)) to sessionInfoExpected,
+ PackageUserKey(expectedAppPackage, UserHandle(0)) to sessionInfoUnexpected,
+ )
+ val expectedItemInfo = WorkspaceItemInfo().apply { intent = expectedIntent }
+ val expectedFolderInfo = FolderInfo().apply { add(expectedItemInfo) }
+ val firstScreenItems = listOf(expectedFolderInfo)
+
+ // When
+ val actualResult =
+ FirstScreenBroadcastHelper.createModelsForFirstScreenBroadcast(
+ packageManagerHelper = mockPmHelper,
+ firstScreenItems = firstScreenItems,
+ userKeyToSessionMap = sessionInfoMap,
+ allWidgets = listOf()
+ )
+
+ // Then
+ val expectedResult =
+ listOf(
+ FirstScreenBroadcastModel(
+ installerPackage = expectedInstallerPackage,
+ pendingCollectionItems = mutableSetOf(expectedAppPackage)
+ )
+ )
+ assertEquals(expectedResult, actualResult)
+ }
+
+ @Test
+ fun `Models with too many items get truncated to max Broadcast size`() {
+ // given
+ val broadcastModel =
+ FirstScreenBroadcastModel(
+ installerPackage = expectedInstallerPackage,
+ pendingCollectionItems =
+ mutableSetOf<String>().apply { repeat(20) { add(it.toString()) } },
+ pendingWorkspaceItems =
+ mutableSetOf<String>().apply { repeat(20) { add(it.toString()) } },
+ pendingHotseatItems =
+ mutableSetOf<String>().apply { repeat(20) { add(it.toString()) } },
+ pendingWidgetItems =
+ mutableSetOf<String>().apply { repeat(20) { add(it.toString()) } },
+ installedWorkspaceItems =
+ mutableSetOf<String>().apply { repeat(20) { add(it.toString()) } },
+ installedHotseatItems =
+ mutableSetOf<String>().apply { repeat(20) { add(it.toString()) } },
+ firstScreenInstalledWidgets =
+ mutableSetOf<String>().apply { repeat(20) { add(it.toString()) } },
+ secondaryScreenInstalledWidgets =
+ mutableSetOf<String>().apply { repeat(20) { add(it.toString()) } }
+ )
+
+ // When
+ broadcastModel.truncateModelForBroadcast()
+
+ // Then
+ assertEquals(MAX_BROADCAST_SIZE, broadcastModel.getTotalItemCount())
+ }
+
+ @Test
+ fun `Broadcast truncates installed Hotseat items before other installed items`() {
+ // Given
+ val broadcastModel =
+ FirstScreenBroadcastModel(
+ installerPackage = expectedInstallerPackage,
+ installedWorkspaceItems =
+ mutableSetOf<String>().apply { repeat(50) { add(it.toString()) } },
+ firstScreenInstalledWidgets =
+ mutableSetOf<String>().apply { repeat(10) { add(it.toString()) } },
+ secondaryScreenInstalledWidgets =
+ mutableSetOf<String>().apply { repeat(10) { add((it + 10).toString()) } },
+ installedHotseatItems =
+ mutableSetOf<String>().apply { repeat(10) { add(it.toString()) } },
+ )
+
+ // When
+ broadcastModel.truncateModelForBroadcast()
+
+ // Then
+ assertEquals(MAX_BROADCAST_SIZE, broadcastModel.getTotalItemCount())
+ assertEquals(50, broadcastModel.installedWorkspaceItems.size)
+ assertEquals(10, broadcastModel.firstScreenInstalledWidgets.size)
+ assertEquals(10, broadcastModel.secondaryScreenInstalledWidgets.size)
+ assertEquals(0, broadcastModel.installedHotseatItems.size)
+ }
+
+ @Test
+ fun `Broadcast truncates Widgets before the rest of the first screen items`() {
+ // Given
+ val broadcastModel =
+ FirstScreenBroadcastModel(
+ installerPackage = expectedInstallerPackage,
+ installedWorkspaceItems =
+ mutableSetOf<String>().apply { repeat(70) { add(it.toString()) } },
+ firstScreenInstalledWidgets =
+ mutableSetOf<String>().apply { repeat(20) { add(it.toString()) } },
+ secondaryScreenInstalledWidgets =
+ mutableSetOf<String>().apply { repeat(20) { add(it.toString()) } },
+ )
+
+ // When
+ broadcastModel.truncateModelForBroadcast()
+
+ // Then
+ assertEquals(MAX_BROADCAST_SIZE, broadcastModel.getTotalItemCount())
+ assertEquals(70, broadcastModel.installedWorkspaceItems.size)
+ assertEquals(0, broadcastModel.firstScreenInstalledWidgets.size)
+ assertEquals(0, broadcastModel.secondaryScreenInstalledWidgets.size)
+ }
+
+ @Test
+ fun `Broadcasts are correctly formed with Extras for each Installer`() {
+ // Given
+ val broadcastModels: List<FirstScreenBroadcastModel> =
+ listOf(
+ FirstScreenBroadcastModel(
+ installerPackage = expectedInstallerPackage,
+ pendingCollectionItems = mutableSetOf("pendingCollectionItem"),
+ pendingWorkspaceItems = mutableSetOf("pendingWorkspaceItem"),
+ pendingHotseatItems = mutableSetOf("pendingHotseatItems"),
+ pendingWidgetItems = mutableSetOf("pendingWidgetItems"),
+ installedWorkspaceItems = mutableSetOf("installedWorkspaceItems"),
+ installedHotseatItems = mutableSetOf("installedHotseatItems"),
+ firstScreenInstalledWidgets = mutableSetOf("firstScreenInstalledWidgetItems"),
+ secondaryScreenInstalledWidgets = mutableSetOf("secondaryInstalledWidgetItems")
+ )
+ )
+ val expectedPendingIntent =
+ PendingIntent.getActivity(
+ context,
+ 0 /* requestCode */,
+ Intent(),
+ PendingIntent.FLAG_ONE_SHOT or PendingIntent.FLAG_IMMUTABLE
+ )
+
+ // When
+ FirstScreenBroadcastHelper.sendBroadcastsForModels(context, broadcastModels)
+
+ // Then
+ val argumentCaptor = ArgumentCaptor.forClass(Intent::class.java)
+ verify(context).sendBroadcast(argumentCaptor.capture())
+
+ assertEquals(
+ "com.android.launcher3.action.FIRST_SCREEN_ACTIVE_INSTALLS",
+ argumentCaptor.value.action
+ )
+ assertEquals(expectedInstallerPackage, argumentCaptor.value.`package`)
+ assertEquals(
+ expectedPendingIntent,
+ argumentCaptor.value.getParcelableExtra("verificationToken")
+ )
+ assertEquals(
+ arrayListOf("pendingCollectionItem"),
+ argumentCaptor.value.getStringArrayListExtra("folderItem")
+ )
+ assertEquals(
+ arrayListOf("pendingWorkspaceItem"),
+ argumentCaptor.value.getStringArrayListExtra("workspaceItem")
+ )
+ assertEquals(
+ arrayListOf("pendingHotseatItems"),
+ argumentCaptor.value.getStringArrayListExtra("hotseatItem")
+ )
+ assertEquals(
+ arrayListOf("pendingWidgetItems"),
+ argumentCaptor.value.getStringArrayListExtra("widgetItem")
+ )
+ assertEquals(
+ arrayListOf("installedWorkspaceItems"),
+ argumentCaptor.value.getStringArrayListExtra("workspaceInstalledItems")
+ )
+ assertEquals(
+ arrayListOf("installedHotseatItems"),
+ argumentCaptor.value.getStringArrayListExtra("hotseatInstalledItems")
+ )
+ assertEquals(
+ arrayListOf("firstScreenInstalledWidgetItems", "secondaryInstalledWidgetItems"),
+ argumentCaptor.value.getStringArrayListExtra("widgetInstalledItems")
+ )
+ }
+}
diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
index 4a67600..342eedf 100644
--- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
+++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3Test.java
@@ -21,9 +21,8 @@
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.util.rule.ScreenRecordRule.KeepRecordOnSuccess;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
+import com.android.launcher3.Launcher;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -32,7 +31,6 @@
@RunWith(AndroidJUnit4.class)
public class TaplTestsLauncher3Test extends AbstractLauncherUiTest<Launcher> {
- @KeepRecordOnSuccess
@ScreenRecord // b/322823478
@Test
public void testDevicePressMenu() throws Exception {
diff --git a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
index 69b42cb..b2e413d 100644
--- a/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
+++ b/tests/src/com/android/launcher3/ui/TaplWorkProfileTest.java
@@ -45,7 +45,6 @@
import com.android.launcher3.allapps.WorkProfileManager;
import com.android.launcher3.tapl.LauncherInstrumentation;
import com.android.launcher3.util.TestUtil;
-import com.android.launcher3.util.rule.ScreenRecordRule.KeepRecordOnSuccess;
import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.util.rule.TestStabilityRule.Stability;
@@ -196,7 +195,6 @@
}
- @KeepRecordOnSuccess
@ScreenRecord // b/322823478
@Test
public void testEdu() {
diff --git a/tests/src/com/android/launcher3/util/TestResourceHelper.kt b/tests/src/com/android/launcher3/util/TestResourceHelper.kt
deleted file mode 100644
index b4d3ba8..0000000
--- a/tests/src/com/android/launcher3/util/TestResourceHelper.kt
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.util
-
-import android.content.Context
-import android.content.res.TypedArray
-import android.util.AttributeSet
-import com.android.launcher3.R
-import com.android.launcher3.tests.R as TestR
-import kotlin.IntArray
-
-class TestResourceHelper(private val context: Context, specsFileId: Int) :
- ResourceHelper(context, specsFileId) {
- override fun obtainStyledAttributes(attrs: AttributeSet, styleId: IntArray): TypedArray {
- val clone =
- when {
- styleId.contentEquals(R.styleable.SizeSpec) -> TestR.styleable.SizeSpec
- styleId.contentEquals(R.styleable.WorkspaceSpec) -> TestR.styleable.WorkspaceSpec
- styleId.contentEquals(R.styleable.FolderSpec) -> TestR.styleable.FolderSpec
- styleId.contentEquals(R.styleable.AllAppsSpec) -> TestR.styleable.AllAppsSpec
- styleId.contentEquals(R.styleable.ResponsiveSpecGroup) ->
- TestR.styleable.ResponsiveSpecGroup
- else -> styleId.clone()
- }
-
- return context.obtainStyledAttributes(attrs, clone)
- }
-}
diff --git a/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java b/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java
index ff96afb..7a5cf2c 100644
--- a/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java
+++ b/tests/src/com/android/launcher3/util/rule/ScreenRecordRule.java
@@ -49,9 +49,6 @@
return base;
}
- final Boolean keepRecordOnSuccess = description.getAnnotation(KeepRecordOnSuccess.class)
- != null;
-
return new Statement() {
@Override
public void evaluate() throws Throwable {
@@ -73,7 +70,7 @@
device.executeShellCommand("kill -INT " + screenRecordPid);
Log.e(TAG, "Screenrecord captured at: " + outputFile);
output.close();
- if (success && !keepRecordOnSuccess) {
+ if (success) {
automation.executeShellCommand("rm " + outputFile);
}
}
@@ -88,14 +85,4 @@
@Target(ElementType.METHOD)
public @interface ScreenRecord {
}
-
-
- /**
- * Interface to indicate that we should keep the screen record even if the test succeeds, use
- * sparingly since it uses a lof of memory.
- */
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.METHOD)
- public @interface KeepRecordOnSuccess {
- }
}
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 567a8bd..27f6c16 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -45,7 +45,6 @@
* Common overview panel for both Launcher and fallback recents
*/
public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
- private static final String TAG = "BaseOverview";
protected static final String TASK_RES_ID = "task";
private static final Pattern EVENT_ALT_ESC_UP = Pattern.compile(
"Key event: KeyEvent.*?action=ACTION_UP.*?keyCode=KEYCODE_ESCAPE.*?metaState=0");
@@ -385,32 +384,39 @@
}
protected boolean isActionsViewVisible() {
- if (!hasTasks() || isClearAllVisible()) {
- Log.d(TAG, "Not expecting an actions bar: no tasks/'Clear all' is visible");
+ boolean hasTasks = hasTasks();
+ if (!hasTasks || isClearAllVisible()) {
+ LauncherInstrumentation.log("Not expecting an actions bar:"
+ + (!hasTasks ? "no recent tasks" : "clear all button is visible"));
return false;
}
boolean isTablet = mLauncher.isTablet();
if (isTablet && mLauncher.isGridOnlyOverviewEnabled()) {
- Log.d(TAG, "Not expecting an actions bar: device is tablet with grid-only Overview");
+ LauncherInstrumentation.log("Not expecting an actions bar: "
+ + "device is tablet with grid-only Overview");
return false;
}
OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
if (task == null) {
- Log.d(TAG, "Not expecting an actions bar: no current task");
+ LauncherInstrumentation.log("Not expecting an actions bar: no focused task");
return false;
}
+ float centerOffset = Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX());
// In tablets, if focused task is not in center, overview actions aren't visible.
- if (isTablet && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) {
- Log.d(TAG, "Not expecting an actions bar: device is tablet and task is not centered");
+ if (isTablet && centerOffset >= 1) {
+ LauncherInstrumentation.log("Not expecting an actions bar: "
+ + "device is tablet and task is not centered; center offset by "
+ + centerOffset + "px");
return false;
}
if (task.isTaskSplit() && (!mLauncher.isAppPairsEnabled() || !isTablet)) {
- Log.d(TAG, "Not expecting an actions bar: device is phone and task is split");
+ LauncherInstrumentation.log("Not expecting an actions bar: "
+ + "device is phone and task is split");
// Overview actions aren't visible for split screen tasks, except for save app pair
// button on tablets.
return false;
}
- Log.d(TAG, "Expecting an actions bar");
+ LauncherInstrumentation.log("Expecting an actions bar");
return true;
}
@@ -493,13 +499,18 @@
throw new IllegalStateException("Must be run on tablet device.");
}
final List<UiObject2> taskViews = getTasks();
- if (taskViews.size() == 0) {
+ if (!hasTasks()) {
+ LauncherInstrumentation.log("no recent tasks");
return null;
}
int focusedTaskHeight = mLauncher.getFocusedTaskHeightForTablet();
for (UiObject2 task : taskViews) {
OverviewTask overviewTask = new OverviewTask(mLauncher, task, this);
+ LauncherInstrumentation.log("checking task height ("
+ + overviewTask.getVisibleHeight()
+ + ") against defined focused task height ("
+ + focusedTaskHeight + ")");
if (overviewTask.getVisibleHeight() == focusedTaskHeight) {
return overviewTask;
}
diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
index 4be46ab..c58d16e 100644
--- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
+++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java
@@ -17,10 +17,12 @@
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
-import android.text.TextUtils;
+import android.graphics.Rect;
import android.widget.TextView;
import androidx.test.uiautomator.By;
+import androidx.test.uiautomator.BySelector;
+import androidx.test.uiautomator.Direction;
import androidx.test.uiautomator.UiObject2;
import java.util.ArrayList;
@@ -34,10 +36,12 @@
// This particular ID change should happen with caution
private static final String SEARCH_CONTAINER_RES_ID = "search_results_list_view";
protected final LauncherInstrumentation mLauncher;
+ private final UiObject2 mSearchContainer;
SearchResultFromQsb(LauncherInstrumentation launcher) {
mLauncher = launcher;
mLauncher.waitForLauncherObject("search_container_all_apps");
+ mSearchContainer = mLauncher.waitForSystemLauncherObject(SEARCH_CONTAINER_RES_ID);
}
/** Find the app from search results with app name. */
@@ -52,18 +56,9 @@
/** Find the web suggestion from search suggestion's title text */
public SearchWebSuggestion findWebSuggestion(String text) {
- ArrayList<UiObject2> webSuggestions =
- new ArrayList<>(mLauncher.waitForObjectsInContainer(
- mLauncher.waitForSystemLauncherObject(SEARCH_CONTAINER_RES_ID),
- By.clazz(TextView.class)));
- for (UiObject2 uiObject: webSuggestions) {
- String currentString = uiObject.getText();
- if (currentString.equals(text)) {
- return createWebSuggestion(uiObject);
- }
- }
- mLauncher.fail("Web suggestion title: " + text + " not found");
- return null;
+ UiObject2 webSuggestion = mLauncher.waitForObjectInContainer(mSearchContainer,
+ getSearchResultSelector(text));
+ return createWebSuggestion(webSuggestion);
}
protected SearchWebSuggestion createWebSuggestion(UiObject2 webSuggestion) {
@@ -73,13 +68,25 @@
/** Find the total amount of views being displayed and return the size */
public int getSearchResultItemSize() {
ArrayList<UiObject2> searchResultItems =
- new ArrayList<>(mLauncher.waitForObjectsInContainer(
- mLauncher.waitForSystemLauncherObject(SEARCH_CONTAINER_RES_ID),
+ new ArrayList<>(mLauncher.waitForObjectsInContainer(mSearchContainer,
By.clazz(TextView.class)));
return searchResultItems.size();
}
/**
+ * Scroll down to make next page search results rendered.
+ */
+ public void getNextPageSearchResults() {
+ final int searchContainerHeight = mLauncher.getVisibleBounds(mSearchContainer).height();
+ // Start scrolling from center of the screen to top of the screen.
+ mLauncher.scroll(mSearchContainer,
+ Direction.DOWN,
+ new Rect(0, 0, 0, searchContainerHeight / 2),
+ /* steps= */ 10,
+ /*slowDown= */ false);
+ }
+
+ /**
* Taps outside bottom sheet to dismiss and return to workspace. Available on tablets only.
* @param tapRight Tap on the right of bottom sheet if true, or left otherwise.
*/
@@ -121,25 +128,13 @@
/** Verify a tile is present by checking its title and subtitle. */
public void verifyTileIsPresent(String title, String subtitle) {
- ArrayList<UiObject2> searchResults =
- new ArrayList<>(mLauncher.waitForObjectsInContainer(
- mLauncher.waitForSystemLauncherObject(SEARCH_CONTAINER_RES_ID),
- By.clazz(TextView.class)));
- boolean foundTitle = false;
- boolean foundSubtitle = false;
- for (UiObject2 uiObject: searchResults) {
- String currentString = uiObject.getText();
- if (TextUtils.equals(currentString, title)) {
- foundTitle = true;
- } else if (TextUtils.equals(currentString, subtitle)) {
- foundSubtitle = true;
- }
- }
- if (!foundTitle) {
- mLauncher.fail("Tile not found for title: " + title);
- }
- if (!foundSubtitle) {
- mLauncher.fail("Tile not found for subtitle: " + subtitle);
- }
+ mLauncher.waitForObjectInContainer(mSearchContainer,
+ getSearchResultSelector(title));
+ mLauncher.waitForObjectInContainer(mSearchContainer,
+ getSearchResultSelector(subtitle));
+ }
+
+ private BySelector getSearchResultSelector(String text) {
+ return By.clazz(TextView.class).text(text);
}
}
diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java
index 4fa93ef..9ac6768 100644
--- a/tests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -444,6 +444,8 @@
Runnable expectLongClickEvents) {
try (LauncherInstrumentation.Closable c = launcher.addContextLayer(
"uninstalling app icon")) {
+
+ final String appNameToUninstall = homeAppIcon.getAppName();
dragIconToWorkspace(
launcher,
homeAppIcon,
@@ -468,7 +470,10 @@
try (LauncherInstrumentation.Closable c1 = launcher.addContextLayer(
"uninstalled app by dragging to the drop bar")) {
- return new Workspace(launcher);
+ final Workspace newWorkspace = new Workspace(launcher);
+ launcher.waitUntilLauncherObjectGone(
+ AppIcon.getAppIconSelector(appNameToUninstall));
+ return newWorkspace;
}
}
}