Merge "Cancel animations after reading MotionPauseDetector#isPaused()" into main
diff --git a/Android.bp b/Android.bp
index 78db013..cdada0a 100644
--- a/Android.bp
+++ b/Android.bp
@@ -201,6 +201,8 @@
"Launcher3ResLib",
"launcher-testing-shared",
"animationlib",
+ "kotlinx_coroutines_android",
+ "kotlinx_coroutines",
"com_android_launcher3_flags_lib",
"com_android_wm_shell_flags_lib",
"android.appwidget.flags-aconfig-java",
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 462d947..634caa7 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -90,6 +90,9 @@
namespace: "launcher"
description: "Enables full width two pane widget picker for tablets in landscape and portrait"
bug: "315055849"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
@@ -171,13 +174,17 @@
}
flag {
+ name: "force_monochrome_app_icons"
+ namespace: "launcher"
+ description: "Enable the ability to generate monochromatic icons, if it is not provided by the app"
+ bug: "270396209"
+}
+
+flag {
name: "enable_add_app_widget_via_config_activity_v2"
namespace: "launcher"
description: "When adding app widget through config activity, directly add it to workspace to reduce flicker"
bug: "284236964"
- metadata {
- purpose: PURPOSE_BUGFIX
- }
}
flag {
@@ -188,21 +195,37 @@
}
flag {
- name: "grid_migration_fix"
+ name: "enable_grid_migration_fix"
namespace: "launcher"
description: "Keep items in place when migrating to a bigger grid"
bug: "325286145"
+ is_fixed_read_only: true
metadata {
purpose: PURPOSE_BUGFIX
}
}
flag {
- name: "narrow_grid_restore"
+ name: "enable_narrow_grid_restore"
namespace: "launcher"
description: "Using only the most recent workspace when restoring to avoid confusion."
+ is_fixed_read_only: true
bug: "325285743"
metadata {
purpose: PURPOSE_BUGFIX
}
}
+
+flag {
+ name: "enable_scaling_reveal_home_animation"
+ namespace: "launcher"
+ description: "Enables the Home gesture animation"
+ bug: "308801666"
+}
+
+flag {
+ name: "enable_widget_tap_to_add"
+ namespace: "launcher"
+ description: "Enables an add button in the widget picker"
+ bug: "323886237"
+}
diff --git a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
index 69e1574..38df756 100644
--- a/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout-land/keyboard_quick_switch_taskview.xml
@@ -36,19 +36,19 @@
app:layout_constraintEnd_toEndOf="parent">
<include
- layout="@layout/keyboard_quick_switch_thumbnail"
- android:id="@+id/thumbnail1"
+ layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+ android:id="@+id/thumbnail_1"
android:layout_width="0dp"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintEnd_toStartOf="@id/thumbnail2"/>
+ app:layout_constraintEnd_toStartOf="@id/thumbnail_2"/>
<include
- layout="@layout/keyboard_quick_switch_thumbnail"
- android:id="@+id/thumbnail2"
+ layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+ android:id="@+id/thumbnail_2"
android:layout_width="0dp"
android:layout_height="match_parent"
android:visibility="gone"
@@ -56,31 +56,33 @@
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintStart_toEndOf="@id/thumbnail1"
+ app:layout_constraintStart_toEndOf="@id/thumbnail_1"
app:layout_constraintEnd_toEndOf="parent"/>
<ImageView
- android:id="@+id/icon1"
+ android:id="@+id/icon_1"
android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
- android:layout_marginTop="@dimen/keyboard_quick_switch_taskview_icon_margin"
- android:layout_marginStart="@dimen/keyboard_quick_switch_taskview_icon_margin"
android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
- app:layout_constraintTop_toTopOf="@id/thumbnail1"
- app:layout_constraintStart_toStartOf="@id/thumbnail1"/>
+ app:layout_constraintTop_toTopOf="@id/thumbnail_1"
+ app:layout_constraintBottom_toBottomOf="@id/thumbnail_1"
+ app:layout_constraintStart_toStartOf="@id/thumbnail_1"
+ app:layout_constraintEnd_toEndOf="@id/thumbnail_1"/>
<ImageView
- android:id="@+id/icon2"
+ android:id="@+id/icon_2"
android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
- android:layout_marginTop="@dimen/keyboard_quick_switch_taskview_icon_margin"
- android:layout_marginStart="@dimen/keyboard_quick_switch_taskview_icon_margin"
android:importantForAccessibility="no"
android:visibility="gone"
+ android:scaleType="centerCrop"
- app:layout_constraintTop_toTopOf="@id/thumbnail2"
- app:layout_constraintStart_toStartOf="@id/thumbnail2"/>
+ app:layout_constraintTop_toTopOf="@id/thumbnail_2"
+ app:layout_constraintBottom_toBottomOf="@id/thumbnail_2"
+ app:layout_constraintStart_toStartOf="@id/thumbnail_2"
+ app:layout_constraintEnd_toEndOf="@id/thumbnail_2"/>
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/quickstep/res/layout/keyboard_quick_switch_taskview.xml b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
index 6ed3c6e..c0ace9a 100644
--- a/quickstep/res/layout/keyboard_quick_switch_taskview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_taskview.xml
@@ -36,51 +36,53 @@
app:layout_constraintEnd_toEndOf="parent">
<include
- layout="@layout/keyboard_quick_switch_thumbnail"
- android:id="@+id/thumbnail1"
+ layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+ android:id="@+id/thumbnail_1"
android:layout_width="match_parent"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@id/thumbnail2"
+ app:layout_constraintBottom_toTopOf="@id/thumbnail_2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<include
- layout="@layout/keyboard_quick_switch_thumbnail"
- android:id="@+id/thumbnail2"
+ layout="@layout/keyboard_quick_switch_taskview_thumbnail"
+ android:id="@+id/thumbnail_2"
android:layout_width="match_parent"
android:layout_height="0dp"
android:visibility="gone"
android:layout_marginTop="@dimen/keyboard_quick_switch_split_view_spacing"
- app:layout_constraintTop_toBottomOf="@id/thumbnail1"
+ app:layout_constraintTop_toBottomOf="@id/thumbnail_1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"/>
<ImageView
- android:id="@+id/icon1"
+ android:id="@+id/icon_1"
android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
- android:layout_marginTop="@dimen/keyboard_quick_switch_taskview_icon_margin"
- android:layout_marginStart="@dimen/keyboard_quick_switch_taskview_icon_margin"
android:importantForAccessibility="no"
+ android:scaleType="centerCrop"
- app:layout_constraintTop_toTopOf="@id/thumbnail1"
- app:layout_constraintStart_toStartOf="@id/thumbnail1"/>
+ app:layout_constraintTop_toTopOf="@id/thumbnail_1"
+ app:layout_constraintBottom_toBottomOf="@id/thumbnail_1"
+ app:layout_constraintStart_toStartOf="@id/thumbnail_1"
+ app:layout_constraintEnd_toEndOf="@id/thumbnail_1"/>
<ImageView
- android:id="@+id/icon2"
+ android:id="@+id/icon_2"
android:layout_width="@dimen/keyboard_quick_switch_taskview_icon_size"
android:layout_height="@dimen/keyboard_quick_switch_taskview_icon_size"
- android:layout_marginTop="@dimen/keyboard_quick_switch_taskview_icon_margin"
- android:layout_marginStart="@dimen/keyboard_quick_switch_taskview_icon_margin"
android:importantForAccessibility="no"
android:visibility="gone"
+ android:scaleType="centerCrop"
- app:layout_constraintTop_toTopOf="@id/thumbnail2"
- app:layout_constraintStart_toStartOf="@id/thumbnail2"/>
+ app:layout_constraintTop_toTopOf="@id/thumbnail_2"
+ app:layout_constraintBottom_toBottomOf="@id/thumbnail_2"
+ app:layout_constraintStart_toStartOf="@id/thumbnail_2"
+ app:layout_constraintEnd_toEndOf="@id/thumbnail_2"/>
</androidx.constraintlayout.widget.ConstraintLayout>
diff --git a/quickstep/res/layout/keyboard_quick_switch_thumbnail.xml b/quickstep/res/layout/keyboard_quick_switch_taskview_thumbnail.xml
similarity index 100%
rename from quickstep/res/layout/keyboard_quick_switch_thumbnail.xml
rename to quickstep/res/layout/keyboard_quick_switch_taskview_thumbnail.xml
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index a393857..48aec13 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Deel"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skermkiekie"</string>
<string name="action_split" msgid="2098009717623550676">"Verdeel"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Stoor app-paar"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tik op ’n ander app om verdeelde skerm te gebruik"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Kies ’n ander app as jy verdeelde skerm wil gebruik"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Kanselleer"</b></string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 7948346..1942a74 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"አጋራ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ቅጽበታዊ ገፅ ዕይታ"</string>
<string name="action_split" msgid="2098009717623550676">"ክፈል"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"የመተግበሪያ ጥምረትን አስቀምጥ"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"የተከፈለ ማያ ገጽን ለመጠቀም ሌላ መተግበሪያ መታ ያድርጉ"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"የተከፈለ ማያ ገጽን ለመጠቀም ሌላ መተግበሪያ ይምረጡ"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ይቅር"</b></string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index af8327c..9b68f49 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"مشاركة"</string>
<string name="action_screenshot" msgid="8171125848358142917">"لقطة شاشة"</string>
<string name="action_split" msgid="2098009717623550676">"تقسيم"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"حفظ إعدادات الميزة"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"انقر على تطبيق آخر لاستخدام وضع تقسيم الشاشة."</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"اختَر تطبيقًا آخر لاستخدام \"وضع تقسيم الشاشة\"."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"إلغاء"</b></string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index e33f326..51068d9 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"শ্বেয়াৰ কৰক"</string>
<string name="action_screenshot" msgid="8171125848358142917">"স্ক্ৰীনশ্বট"</string>
<string name="action_split" msgid="2098009717623550676">"বিভাজন কৰক"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"এপৰ পেয়াৰ ছেভ কৰক"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপত টিপক"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"বিভাজিত স্ক্ৰীন ব্যৱহাৰ কৰিবলৈ অন্য এটা এপ্ বাছনি কৰক"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"বাতিল কৰক"</b></string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index d62881c..4b52f0b 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Paylaşın"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skrinşot"</string>
<string name="action_split" msgid="2098009717623550676">"Ayırın"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Tətbiq cütünü saxla"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Bölünmüş ekran üçün başqa tətbiqə toxunun"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Bölünmüş ekrandan istifadə üçün başqa tətbiq seçin"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Ləğv edin"</b></string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 2b06953..8d874fd 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Абагуліць"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Здымак экрана"</string>
<string name="action_split" msgid="2098009717623550676">"Падзелены экран"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Захаваць спалучэнне"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Каб падзяліць экран, націсніце на іншую праграму"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Каб карыстацца рэжымам падзеленага экрана, выберыце другую праграму"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Скасаваць"</b></string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index cf1b470..be66004 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Споделяне"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Екранна снимка"</string>
<string name="action_split" msgid="2098009717623550676">"Разделяне на екрана"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Двойка прил.: Запис"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Докоснете друго прил., за да ползвате разд. екран"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"За разделен екран изберете още едно приложение"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Отказ"</b></string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 1549f30..7ffbb64 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"শেয়ার করুন"</string>
<string name="action_screenshot" msgid="8171125848358142917">"স্ক্রিনশট নিন"</string>
<string name="action_split" msgid="2098009717623550676">"স্প্লিট"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"অ্যাপ পেয়ার সেভ করুন"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"স্প্লিট স্ক্রিন ব্যবহারের জন্য অ্যাপে ট্যাপ করুন"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"স্প্লিট স্ক্রিন ব্যবহার করতে অন্য অ্যাপ বেছে নিন"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"বাতিল করুন"</b></string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 0d2442c..ccf6c36 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -95,7 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Dijeli"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
<string name="action_split" msgid="2098009717623550676">"Podijeli"</string>
- <string name="action_save_app_pair" msgid="5974823919237645229">"Spremi par apl."</string>
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Sačuvaj par aplikacija"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu apl. da koristite podijeljeni ekran"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Odaberite drugu aplikaciju da koristite podijeljeni ekran"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Otkaži"</b></string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index bf95d5f..1cffbdf 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Comparteix"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
<string name="action_split" msgid="2098009717623550676">"Divideix"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Desa la parella d\'apps"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Toca una altra app per utilitzar pantalla dividida"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Tria una altra aplicació per utilitzar la pantalla dividida"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancel·la"</b></string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index f8672b9..f3f5777 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Sdílet"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snímek obrazovky"</string>
<string name="action_split" msgid="2098009717623550676">"Rozdělit"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Uložit dvojici aplikací"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Obrazovku rozdělíte klepnutím na jinou aplikaci"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Výběrem další aplikace rozdělíte obrazovku"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Zrušit"</b></string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 522170e..623a0b7 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Del"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Opdel"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Gem appsammenknytning"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tryk på en anden app for at bruge opdelt skærm"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Vælg en anden app for at bruge opdelt skærm"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuller"</b></string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 9f9c068..499a3d5 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Teilen"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Teilen"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"App-Paar speichern"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Für Splitscreen auf weitere App tippen"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Für Splitscreen andere App auswählen"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Abbrechen"</b></string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 4fa6d66..69f1718 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Κοινοποίηση"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Στιγμιότυπο οθόνης"</string>
<string name="action_split" msgid="2098009717623550676">"Διαχωρισμός"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Αποθήκ. ζεύγ. εφαρμ."</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Πατήστε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Επιλέξτε άλλη εφαρμογή για διαχωρισμό οθόνης"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Ακύρωση"</b></string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 442e5d7..580a8df 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Compartir"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Captura de pantalla"</string>
<string name="action_split" msgid="2098009717623550676">"Pantalla dividida"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Guardar vinculación"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Presiona otra app para usar la pantalla dividida"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Elige otra app para usar la pantalla dividida"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 51c85b9..0900f78 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Compartir"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Hacer captura"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Guardar apps emparejadas"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Toca otra aplicación para usar la pantalla dividida"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Elige otra app para usar la pantalla dividida."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index eef802a..f8e2ecd 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Jaga"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
<string name="action_split" msgid="2098009717623550676">"Eralda"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Salv. rakendusepaar"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Jagatud ekraanikuva kasutamiseks puudutage muud rakendust"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Tühista"</b></string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index e93458b..3247785 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Partekatu"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Atera pantaila-argazki bat"</string>
<string name="action_split" msgid="2098009717623550676">"Zatitu"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Gorde aplikazio parea"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Sakatu beste aplikazio bat pantaila zatitzeko"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Pantaila zatitua erabiltzeko, aukeratu beste aplikazio bat"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Utzi"</b></string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 915003a..e8d0a00 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"همرسانی"</string>
<string name="action_screenshot" msgid="8171125848358142917">"نماگرفت"</string>
<string name="action_split" msgid="2098009717623550676">"دونیمه"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"ذخیره جفت برنامه"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"زدن روی برنامهای دیگر برای استفاده از صفحه دونیمه"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"انتخاب برنامهای دیگر برای استفاده از صفحه دونیمه"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"لغو کردن"</b></string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 747561e..e913f85 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Jaa"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Kuvakaappaus"</string>
<string name="action_split" msgid="2098009717623550676">"Jaa"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Tallenna pari"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Avaa jaettu näyttö napauttamalla toista sovellusta"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Käytä jaettua näyttöä valitsemalla toinen sovellus"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Peruuta"</b></string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index e0f894e..6173bee 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Partager"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Capture d\'écran"</string>
<string name="action_split" msgid="2098009717623550676">"Partager"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Enr. paire d\'applis"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Toucher une autre appli pour partager l\'écran"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choisir une autre application pour utiliser l\'Écran divisé"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuler"</b></string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 5901457..b266263 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Compartir"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Gardar empar. apps"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Para usar a pantalla dividida, toca outra app"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolle outra aplicación para usar a pantalla dividida."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index 2ab585e..0e6f237 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"શેર કરો"</string>
<string name="action_screenshot" msgid="8171125848358142917">"સ્ક્રીનશૉટ"</string>
<string name="action_split" msgid="2098009717623550676">"વિભાજિત કરો"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"ઍપની જોડી સાચવો"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"વિભાજિત સ્ક્રીન વાપરવા, કોઈ અન્ય ઍપ પર ટૅપ કરો"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"વિભાજિત સ્ક્રીનની સુવિધાનો ઉપયોગ કરવા કોઈ અન્ય ઍપ પસંદ કરો"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"રદ કરો"</b></string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index f1f9132..017c5f6 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Megosztás"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Képernyőkép"</string>
<string name="action_split" msgid="2098009717623550676">"Felosztás"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"App-pár mentése"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Koppintson másik appra az osztott képernyőhöz"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Válasszon másik appot a képernyő felosztásához"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Mégse"</b></string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 5344fef..c09ceba 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Կիսվել"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Սքրինշոթ անել"</string>
<string name="action_split" msgid="2098009717623550676">"Տրոհել"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Պահել հավելվ․ զույգը"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Հպեք այլ հավելվածի՝ տրոհված էկրանից օգտվելու համար"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Ընտրեք այլ հավելված՝ կիսված էկրանից օգտվելու համար"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Չեղարկել"</b></string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index bb063d2..fc07b94 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Condividi"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Dividi"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Salva coppia di app"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tocca un\'altra app per usare lo schermo diviso"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Scegli un\'altra app per usare lo schermo diviso"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annulla"</b></string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index cad9a18..c599ccf 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"ចែករំលែក"</string>
<string name="action_screenshot" msgid="8171125848358142917">"រូបថតអេក្រង់"</string>
<string name="action_split" msgid="2098009717623550676">"បំបែក"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"រក្សាទុកគូកម្មវិធី"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"ចុចកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"ជ្រើសរើសកម្មវិធីផ្សេងទៀត ដើម្បីប្រើមុខងារបំបែកអេក្រង់"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"បោះបង់"</b></string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 78f798c..903534a 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"ಹಂಚಿಕೊಳ್ಳಿ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string>
<string name="action_split" msgid="2098009717623550676">"ವಿಭಜಿಸಿ"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"ಆ್ಯಪ್ ಪೇರ್ ಸೇವ್ ಮಾಡಿ"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಇನ್ನೊಂದು ಆ್ಯಪ್ ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ರದ್ದುಮಾಡಿ"</b></string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 280bbcd..9a885c1 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"공유"</string>
<string name="action_screenshot" msgid="8171125848358142917">"스크린샷"</string>
<string name="action_split" msgid="2098009717623550676">"분할"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"앱 페어링 저장"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"다른 앱을 탭하여 화면 분할 사용"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"화면 분할을 사용하려면 다른 앱을 선택하세요."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"취소"</b></string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index 01707d6..cb211c0 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Kopīgot"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Veikt ekrānuzņēmumu"</string>
<string name="action_split" msgid="2098009717623550676">"Sadalīt"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Saglabāt pāri"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Lai sadalītu ekrānu, pieskarieties citai lietotnei"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Izvēlieties citu lietotni, lai sadalītu ekrānu"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Atcelt"</b></string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 38e61d4..b4c9569 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Сподели"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Слика од екранот"</string>
<string name="action_split" msgid="2098009717623550676">"Раздели"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Зачувај пар аплик."</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Допрете друга аплик. за да користите поделен екран"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Изберете друга апликација за да користите поделен екран"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Откажи"</b></string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index ad7cc6a..d4f7537 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Хуваалцах"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Дэлгэцийн агшин дарах"</string>
<string name="action_split" msgid="2098009717623550676">"Хуваах"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Апп хослуулалт хадгал"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Дэлгэцийг хуваахыг ашиглахын тулд өөр аппыг товш"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Дэлгэц хуваахыг ашиглахын тулд өөр апп сонгоно уу"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Цуцлах"</b></string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index c077aa7..c8f147a 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"शेअर करा"</string>
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट"</string>
<string name="action_split" msgid="2098009717623550676">"स्प्लिट"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"ॲपची जोडी सेव्ह करा"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिट स्क्रीन वापरण्यासाठी दुसऱ्या ॲपवर टॅप करा"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"स्प्लिट स्क्रीन वापरण्यासाठी दुसरे ॲप निवडा"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"रद्द करा"</b></string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 5fc2883..2383000 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Del"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skjermdump"</string>
<string name="action_split" msgid="2098009717623550676">"Del opp"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Lagre apptilkobling"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Trykk på en annen app for å bruke delt skjerm"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Velg en annen app for å bruke delt skjerm"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Avbryt"</b></string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 2462138..03abd4d 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"सेयर गर्नुहोस्"</string>
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रिनसट"</string>
<string name="action_split" msgid="2098009717623550676">"स्प्लिट गर्नुहोस्"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"एपको पेयर सेभ गर्नुहोस्"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिटस्क्रिन प्रयोग गर्न अर्को एपमा ट्याप गर्नु…"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"स्प्लिट स्क्रिन प्रयोग गर्न अर्को एप रोज्नुहोस्"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"रद्द गर्नुहोस्"</b></string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index dec3a5d..1ddcdf2 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"ସେୟାର୍ କରନ୍ତୁ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ସ୍କ୍ରିନସଟ୍"</string>
<string name="action_split" msgid="2098009717623550676">"ସ୍ପ୍ଲିଟ୍"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"ଆପ ପେୟାର ସେଭ କରନ୍ତୁ"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"ସ୍ପ୍ଲିଟସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପରେ ଟାପ କର"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"ସ୍ପ୍ଲିଟ ସ୍କ୍ରିନ ବ୍ୟବହାର କରିବାକୁ ଅନ୍ୟ ଏକ ଆପ ବାଛନ୍ତୁ"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ବାତିଲ କରନ୍ତୁ"</b></string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index db0aafa..4b80a2e 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"ਸਾਂਝਾ ਕਰੋ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
<string name="action_split" msgid="2098009717623550676">"ਸਪਲਿਟ"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"ਐਪ ਜੋੜਾਬੱਧ ਰੱਖਿਅਤ ਕਰੋ"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨੂੰ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਵਰਤਣ ਲਈ ਕਿਸੇ ਹੋਰ ਐਪ ਨੂੰ ਚੁਣੋ"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ਰੱਦ ਕਰੋ"</b></string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index eae0bfb..b7af90d 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Partilhar"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Fazer captura de ecrã"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Guardar par de apps"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Toque noutra app para usar o ecrã dividido"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolha outra app para usar o ecrã dividido"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 80a1af2..25307b0 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Distribuie"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Captură de ecran"</string>
<string name="action_split" msgid="2098009717623550676">"Împărțit"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Salvează perechea de aplicații"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Atinge altă aplicație pentru ecranul împărțit"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Alege altă aplicație pentru a folosi ecranul împărțit"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Anulează"</b></string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 2ffee8f..c4ea90d 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Поделиться"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="action_split" msgid="2098009717623550676">"Разделить"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Сохр. одновр. исп."</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Для разделения экрана выберите другое приложение."</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Чтобы использовать разделенный экран, выберите другое приложение."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Отмена"</b></string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index bb38e97..2e2151d 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"බෙදා ගන්න"</string>
<string name="action_screenshot" msgid="8171125848358142917">"තිර රුව"</string>
<string name="action_split" msgid="2098009717623550676">"බෙදන්න"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"යෙදුම් යුගල සුරකින්න"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"බෙදුම් තිරය භාවිතා කිරීමට තවත් යෙදුමක් තට්ටු කරන්න"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"බෙදුම් තිරය භාවිත කිරීමට වෙනත් යෙදුමක් තෝරා ගන්න"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"අවලංගු කරන්න"</b></string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index fe90a31..1865043 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Zdieľať"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snímka obrazovky"</string>
<string name="action_split" msgid="2098009717623550676">"Rozdeliť"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Uložiť pár aplikácií"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Obrazovku rozdelíte klepnutím na inú aplikáciu"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Na použitie rozdelenej obrazovky vyberte inú aplikáciu"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Zrušiť"</b></string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index feb6f7b..94e5c53 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Ndaj"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Pamja e ekranit"</string>
<string name="action_split" msgid="2098009717623550676">"Ndaj"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Ruaj çiftin e aplikacioneve"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Trokit një apl. tjetër; përdor ekranin e ndarë"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Zgjidh një aplikacion tjetër për të përdorur ekranin e ndarë"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Anulo"</b></string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 617ab5f..290ef9c 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Dela"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skärmbild"</string>
<string name="action_split" msgid="2098009717623550676">"Delat"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Spara par av appar"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tryck på en annan app för att använda delad skärm"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Välj en annan app för att använda delad skärm"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Avbryt"</b></string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 1e2a4dc..279e9f9 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"பகிர்"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ஸ்கிரீன்ஷாட்"</string>
<string name="action_split" msgid="2098009717623550676">"பிரி"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"ஆப்ஸ் ஜோடியைச் சேமி"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"திரைப் பிரிப்பைப் பயன்படுத்த வேறு ஆப்ஸைத் தட்டவும்"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"திரைப் பிரிப்பைப் பயன்படுத்த வேறு ஆப்ஸைத் தேர்வுசெய்யுங்கள்"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ரத்துசெய்"</b></string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index 0555bf7..9461d48 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"షేర్ చేయండి"</string>
<string name="action_screenshot" msgid="8171125848358142917">"స్క్రీన్షాట్"</string>
<string name="action_split" msgid="2098009717623550676">"స్ప్లిట్ చేయండి"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"యాప్ పెయిర్ను సేవ్ చేయండి"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"స్ప్లిట్ స్క్రీన్ కోసం మరొక యాప్ను ట్యాప్ చేయండి"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"స్ప్లిట్ స్క్రీన్ను ఉపయోగించడానికి మరొక యాప్ ఎంచుకోండి"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"రద్దు చేయండి"</b></string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 44bcfcc..4df24d7 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Поділитися"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Знімок екрана"</string>
<string name="action_split" msgid="2098009717623550676">"Розділити"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Зберегти пару"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Щоб розділити екран, виберіть ще один додаток."</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Щоб розділити екран, виберіть ще один додаток."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Скасувати"</b></string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index e09bad4..3c5d22d 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"اشتراک کریں"</string>
<string name="action_screenshot" msgid="8171125848358142917">"اسکرین شاٹ"</string>
<string name="action_split" msgid="2098009717623550676">"اسپلٹ"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"ایپس کے جوڑے کو محفوظ کریں"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"اسپلٹ اسکرین کا استعمال کرنے کیلئے دوسری ایپ پر تھپتھپائیں"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"اسپلٹ اسکرین کے استعمال کیلئے دوسری ایپ منتخب کریں"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"منسوخ کریں"</b></string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index fcceb7f..fb28736 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Chia sẻ"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Chụp ảnh màn hình"</string>
<string name="action_split" msgid="2098009717623550676">"Chia đôi màn hình"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Lưu cặp ứng dụng"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Nhấn vào ứng dụng khác để chia đôi màn hình"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Chọn một ứng dụng khác để dùng chế độ chia đôi màn hình"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Huỷ"</b></string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index fe8f11c..050c47c 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"分享"</string>
<string name="action_screenshot" msgid="8171125848358142917">"螢幕截圖"</string>
<string name="action_split" msgid="2098009717623550676">"分割"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"儲存應用程式配對"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"輕按其他應用程式以使用分割螢幕"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"選擇其他應用程式才能使用分割螢幕"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"取消"</b></string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index e68fa48..c7d79c1 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"分享"</string>
<string name="action_screenshot" msgid="8171125848358142917">"螢幕截圖"</string>
<string name="action_split" msgid="2098009717623550676">"分割"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"儲存應用程式配對"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"輕觸另一個應用程式即可使用分割畫面"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"選擇要在分割畫面中使用的另一個應用程式"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"取消"</b></string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index 4eb0df4..0688082 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -95,8 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Yabelana"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Isithombe-skrini"</string>
<string name="action_split" msgid="2098009717623550676">"Hlukanisa"</string>
- <!-- no translation found for action_save_app_pair (5974823919237645229) -->
- <skip />
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Londoloza ukubhangqa i-app"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Thepha enye i-app ukuze usebenzise isikrini sokuhlukanisa"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Khetha enye i-app ukuze usebenzise ukuhlukanisa isikrini"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Khansela"</b></string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 0e18fb4..fcc2eff 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -441,8 +441,7 @@
<dimen name="keyboard_quick_switch_border_width">4dp</dimen>
<dimen name="keyboard_quick_switch_taskview_width">104dp</dimen>
<dimen name="keyboard_quick_switch_taskview_height">134dp</dimen>
- <dimen name="keyboard_quick_switch_taskview_icon_size">28dp</dimen>
- <dimen name="keyboard_quick_switch_taskview_icon_margin">4dp</dimen>
+ <dimen name="keyboard_quick_switch_taskview_icon_size">52dp</dimen>
<dimen name="keyboard_quick_switch_recents_icon_size">20dp</dimen>
<dimen name="keyboard_quick_switch_margin_top">56dp</dimen>
<dimen name="keyboard_quick_switch_margin_ends">16dp</dimen>
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index 350c752..16fb6d2 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -315,5 +315,6 @@
<style name="WidgetPickerActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
<item name="widgetsTheme">@style/WidgetContainerTheme</item>
<item name="android:windowBackground">@android:color/transparent</item>
+ <item name="pageIndicatorDotColor">@color/page_indicator_dot_color_light</item>
</style>
</resources>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 569e95a..be532b4 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -43,6 +43,7 @@
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_APP_TRANSITIONS;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_PENDING_FLAGS;
import static com.android.launcher3.BaseActivity.PENDING_INVISIBLE_BY_WALLPAPER_ANIMATION;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY;
import static com.android.launcher3.LauncherAnimUtils.VIEW_BACKGROUND_COLOR;
import static com.android.launcher3.LauncherState.ALL_APPS;
@@ -215,7 +216,8 @@
public static final int TASKBAR_TO_APP_DURATION = 600;
// TODO(b/236145847): Tune TASKBAR_TO_HOME_DURATION to 383 after conflict with unlock animation
// is solved.
- public static final int TASKBAR_TO_HOME_DURATION = 300;
+ private static final int TASKBAR_TO_HOME_DURATION_FAST = 300;
+ private static final int TASKBAR_TO_HOME_DURATION_SLOW = 1000;
protected static final int CONTENT_SCALE_DURATION = 350;
protected static final int CONTENT_SCRIM_DURATION = 350;
@@ -1704,6 +1706,14 @@
return new Pair(rectFSpringAnim, anim);
}
+ public static int getTaskbarToHomeDuration() {
+ if (enableScalingRevealHomeAnimation()) {
+ return TASKBAR_TO_HOME_DURATION_SLOW;
+ } else {
+ return TASKBAR_TO_HOME_DURATION_FAST;
+ }
+ }
+
/**
* Remote animation runner for animation from the app to Launcher, including recents.
*/
diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
index e1443d0..b36fd66 100644
--- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java
@@ -138,9 +138,9 @@
int totalHeight = iconHeight + iconPadding + textHeight + mVerticalPadding * 2;
// Prediction row height will be 4dp bigger than the regular apps in A-Z list when two line
// is not enabled. Otherwise, the extra height will increase by just the textHeight.
- int extraHeight = (FeatureFlags.enableTwolineAllapps() && (!Flags.enableTwolineToggle()
- || (Flags.enableTwolineToggle() && LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(
- getContext())))) ? textHeight : mTopRowExtraHeight;
+ int extraHeight = (Flags.enableTwolineToggle() &&
+ LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(getContext()))
+ ? textHeight : mTopRowExtraHeight;
totalHeight += extraHeight;
return getVisibility() == GONE ? 0 : totalHeight + getPaddingTop() + getPaddingBottom();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/BlurredBitmapDrawable.kt b/quickstep/src/com/android/launcher3/taskbar/BlurredBitmapDrawable.kt
new file mode 100644
index 0000000..8aee1aa
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/BlurredBitmapDrawable.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.graphics.Bitmap
+import android.graphics.Canvas
+import android.graphics.PixelFormat
+import android.graphics.RenderEffect
+import android.graphics.RenderNode
+import android.graphics.Shader
+import android.graphics.drawable.BitmapDrawable
+import android.graphics.drawable.DrawableWrapper
+
+/* BitmapDrawable that can blur the given bitmap. */
+class BlurredBitmapDrawable(bitmap: Bitmap?, radiusX: Float, radiusY: Float) :
+ DrawableWrapper(BitmapDrawable(bitmap)) {
+ private val mBlurRenderNode: RenderNode = RenderNode("BlurredConstraintLayoutBlurNode")
+
+ constructor(bitmap: Bitmap?, radius: Float) : this(bitmap, radius, radius)
+
+ init {
+ mBlurRenderNode.setRenderEffect(
+ RenderEffect.createBlurEffect(radiusX, radiusY, Shader.TileMode.CLAMP)
+ )
+ }
+
+ override fun draw(canvas: Canvas) {
+ if (!canvas.isHardwareAccelerated) {
+ super.draw(canvas)
+ return
+ }
+ mBlurRenderNode.setPosition(bounds)
+ if (!mBlurRenderNode.hasDisplayList()) {
+ // Record render node if its display list is not recorded or discarded
+ // (which happens when it's no longer drawn by anything).
+ val recordingCanvas = mBlurRenderNode.beginRecording()
+ super.draw(recordingCanvas)
+ mBlurRenderNode.endRecording()
+ }
+ canvas.drawRenderNode(mBlurRenderNode)
+ }
+
+ override fun getOpacity(): Int {
+ return PixelFormat.OPAQUE
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index f15d12b..8566e20 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -193,10 +193,14 @@
}
void closeQuickSwitchView() {
+ closeQuickSwitchView(true);
+ }
+
+ void closeQuickSwitchView(boolean animate) {
if (mQuickSwitchViewController == null) {
return;
}
- mQuickSwitchViewController.closeQuickSwitchView(true);
+ mQuickSwitchViewController.closeQuickSwitchView(animate);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
index a9d50b9..5b407f0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchTaskView.java
@@ -23,6 +23,7 @@
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
@@ -47,6 +48,8 @@
*/
public class KeyboardQuickSwitchTaskView extends ConstraintLayout {
+ private static final float THUMBNAIL_BLUR_RADIUS = 1f;
+
@ColorInt private final int mBorderColor;
@Nullable private BorderAnimator mBorderAnimator;
@@ -89,10 +92,10 @@
@Override
protected void onFinishInflate() {
super.onFinishInflate();
- mThumbnailView1 = findViewById(R.id.thumbnail1);
- mThumbnailView2 = findViewById(R.id.thumbnail2);
- mIcon1 = findViewById(R.id.icon1);
- mIcon2 = findViewById(R.id.icon2);
+ mThumbnailView1 = findViewById(R.id.thumbnail_1);
+ mThumbnailView2 = findViewById(R.id.thumbnail_2);
+ mIcon1 = findViewById(R.id.icon_1);
+ mIcon2 = findViewById(R.id.icon_2);
mContent = findViewById(R.id.content);
Resources resources = mContext.getResources();
@@ -167,10 +170,7 @@
@Nullable ImageView thumbnailView,
@Nullable Task task,
@Nullable ThumbnailUpdateFunction updateFunction) {
- if (thumbnailView == null) {
- return;
- }
- if (task == null) {
+ if (thumbnailView == null || task == null) {
return;
}
if (updateFunction == null) {
@@ -182,19 +182,30 @@
}
private void applyThumbnail(
- @NonNull ImageView thumbnailView, ThumbnailData thumbnailData) {
+ @NonNull ImageView thumbnailView,
+ ThumbnailData thumbnailData) {
Bitmap bm = thumbnailData == null ? null : thumbnailData.thumbnail;
- thumbnailView.setVisibility(VISIBLE);
- thumbnailView.setImageBitmap(bm);
+ if (thumbnailView.getVisibility() != VISIBLE) {
+ thumbnailView.setVisibility(VISIBLE);
+ }
+ thumbnailView.setImageDrawable(new BlurredBitmapDrawable(bm, THUMBNAIL_BLUR_RADIUS));
}
private void applyIcon(@Nullable ImageView iconView, @Nullable Task task) {
- if (iconView == null || task == null) {
+ if (iconView == null || task == null || task.icon == null) {
return;
}
- iconView.setVisibility(VISIBLE);
- iconView.setImageDrawable(task.icon);
+ Drawable.ConstantState constantState = task.icon.getConstantState();
+ if (constantState == null) {
+ return;
+ }
+ if (iconView.getVisibility() != VISIBLE) {
+ iconView.setVisibility(VISIBLE);
+ }
+ // Use the bitmap directly since the drawable's scale can change
+ iconView.setImageDrawable(
+ constantState.newDrawable(getResources(), getContext().getTheme()));
}
protected interface ThumbnailUpdateFunction {
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index c830aa8..5134f3b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -238,8 +238,7 @@
}
void launchTaskAt(int index) {
- mCurrentFocusIndex = Utilities.boundToRange(
- index, 0, mKeyboardQuickSwitchView.getChildCount() - 1);
+ mCurrentFocusIndex = index;
mControllers.taskbarActivityContext.launchKeyboardFocusedTask();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 1e861d2..2710bd9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -191,7 +191,7 @@
? TRANSIENT_TASKBAR_TRANSITION_DURATION
: (!isVisible
? QuickstepTransitionManager.TASKBAR_TO_APP_DURATION
- : QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION));
+ : QuickstepTransitionManager.getTaskbarToHomeDuration()));
}
@Nullable
@@ -414,6 +414,13 @@
}
@Override
+ protected boolean canToggleHomeAllApps() {
+ return mLauncher.isResumed()
+ && !mTaskbarLauncherStateController.isInOverview()
+ && !mLauncher.areFreeformTasksVisible();
+ }
+
+ @Override
public RecentsView getRecentsView() {
return mLauncher.getOverviewPanel();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 5e325fb..9625789 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -17,6 +17,7 @@
import static android.content.pm.PackageManager.FEATURE_PC;
import static android.os.Trace.TRACE_TAG_APP;
+import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
@@ -529,52 +530,26 @@
/**
* Creates {@link WindowManager.LayoutParams} for Taskbar, and also sets LP.paramsForRotation
- * for taskbar showing as navigation bar
+ * for taskbar
*/
private WindowManager.LayoutParams createAllWindowParams() {
final int windowType =
ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL;
WindowManager.LayoutParams windowLayoutParams =
createDefaultWindowLayoutParams(windowType, TaskbarActivityContext.WINDOW_TITLE);
- if (!isPhoneButtonNavMode()) {
- return windowLayoutParams;
- }
- // Provide WM layout params for all rotations to cache, see NavigationBar#getBarLayoutParams
- int width = WindowManager.LayoutParams.MATCH_PARENT;
- int height = WindowManager.LayoutParams.MATCH_PARENT;
- int gravity = Gravity.BOTTOM;
windowLayoutParams.paramsForRotation = new WindowManager.LayoutParams[4];
for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
WindowManager.LayoutParams lp =
createDefaultWindowLayoutParams(windowType,
TaskbarActivityContext.WINDOW_TITLE);
- switch (rot) {
- case Surface.ROTATION_0, Surface.ROTATION_180 -> {
- // Defaults are fine
- width = WindowManager.LayoutParams.MATCH_PARENT;
- height = mLastRequestedNonFullscreenSize;
- gravity = Gravity.BOTTOM;
- }
- case Surface.ROTATION_90 -> {
- width = mLastRequestedNonFullscreenSize;
- height = WindowManager.LayoutParams.MATCH_PARENT;
- gravity = Gravity.END;
- }
- case Surface.ROTATION_270 -> {
- width = mLastRequestedNonFullscreenSize;
- height = WindowManager.LayoutParams.MATCH_PARENT;
- gravity = Gravity.START;
- }
-
+ if (isPhoneButtonNavMode()) {
+ populatePhoneButtonNavModeWindowLayoutParams(rot, lp);
}
- lp.width = width;
- lp.height = height;
- lp.gravity = gravity;
windowLayoutParams.paramsForRotation[rot] = lp;
}
- // Override current layout params
+ // Override with current layout params
WindowManager.LayoutParams currentParams =
windowLayoutParams.paramsForRotation[getDisplay().getRotation()];
windowLayoutParams.width = currentParams.width;
@@ -584,6 +559,32 @@
return windowLayoutParams;
}
+ /**
+ * Update {@link WindowManager.LayoutParams} with values specific to phone and 3 button
+ * navigation users
+ */
+ private void populatePhoneButtonNavModeWindowLayoutParams(int rot,
+ WindowManager.LayoutParams lp) {
+ lp.width = WindowManager.LayoutParams.MATCH_PARENT;
+ lp.height = WindowManager.LayoutParams.MATCH_PARENT;
+ lp.gravity = Gravity.BOTTOM;
+
+ // Override with per-rotation specific values
+ switch (rot) {
+ case Surface.ROTATION_0, Surface.ROTATION_180 -> {
+ lp.height = mLastRequestedNonFullscreenSize;
+ }
+ case Surface.ROTATION_90 -> {
+ lp.width = mLastRequestedNonFullscreenSize;
+ lp.gravity = Gravity.END;
+ }
+ case Surface.ROTATION_270 -> {
+ lp.width = mLastRequestedNonFullscreenSize;
+ lp.gravity = Gravity.START;
+ }
+ }
+ }
+
public void onConfigurationChanged(@Config int configChanges) {
mControllers.onConfigurationChanged(configChanges);
if (!mIsUserSetupComplete) {
@@ -944,8 +945,14 @@
}
if (landscapePhoneButtonNav) {
mWindowLayoutParams.width = size;
+ for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
+ mWindowLayoutParams.paramsForRotation[rot].width = size;
+ }
} else {
mWindowLayoutParams.height = size;
+ for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
+ mWindowLayoutParams.paramsForRotation[rot].height = size;
+ }
}
mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
notifyUpdateLayoutParams();
@@ -1208,7 +1215,7 @@
.handleAppPairLaunchInApp((AppPairIcon) launchingIconView, itemInfos);
} else {
// Tapped a single app, nothing complicated here.
- startItemInfoActivity(itemInfos.get(0));
+ startItemInfoActivity(itemInfos.get(0), null /*foundTask*/);
}
}
@@ -1249,19 +1256,37 @@
recents.getSplitSelectController().getAppPairsController().launchAppPair(
(AppPairIcon) launchingIconView);
} else {
- startItemInfoActivity(itemInfos.get(0));
+ startItemInfoActivity(itemInfos.get(0), foundTask);
}
}
);
}
- private void startItemInfoActivity(ItemInfo info) {
+ /**
+ * Starts an activity with the information provided by the "info" param. However, if
+ * taskInRecents is present, it will prioritize re-launching an existing instance via
+ * {@link ActivityManagerWrapper#startActivityFromRecents(int, ActivityOptions)}
+ */
+ private void startItemInfoActivity(ItemInfo info, @Nullable Task taskInRecents) {
Intent intent = new Intent(info.getIntent())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
if (info.user.equals(Process.myUserHandle())) {
// TODO(b/216683257): Use startActivityForResult for search results that require it.
+ if (taskInRecents != null) {
+ // Re launch instance from recents
+ ActivityOptionsWrapper opts = getActivityLaunchOptions(null, info);
+ opts.options.setLaunchDisplayId(
+ getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
+ if (ActivityManagerWrapper.getInstance()
+ .startActivityFromRecents(taskInRecents.key, opts.options)) {
+ mControllers.uiController.getRecentsView()
+ .addSideTaskLaunchCallback(opts.onEndCallback);
+ return;
+ }
+ }
+
startActivity(intent);
} else {
getSystemService(LauncherApps.class).startMainActivity(
@@ -1320,8 +1345,12 @@
* Called when we want to unstash taskbar when user performs swipes up gesture.
*/
public void onSwipeToUnstashTaskbar() {
- VibratorWrapper.INSTANCE.get(this).vibrateForTaskbarUnstash();
+ boolean wasStashed = mControllers.taskbarStashController.isStashed();
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(/* stash= */ false);
+ boolean isStashed = mControllers.taskbarStashController.isStashed();
+ if (isStashed != wasStashed) {
+ VibratorWrapper.INSTANCE.get(this).vibrateForTaskbarUnstash();
+ }
mControllers.taskbarEduTooltipController.hide();
}
@@ -1551,4 +1580,13 @@
public float getStashedTaskbarScale() {
return mControllers.stashedHandleViewController.getStashedHandleHintScale().value;
}
+
+ /** Closes the KeyboardQuickSwitchView without an animation if open. */
+ public void closeKeyboardQuickSwitchView() {
+ mControllers.keyboardQuickSwitchController.closeQuickSwitchView(false);
+ }
+
+ boolean canToggleHomeAllApps() {
+ return mControllers.uiController.canToggleHomeAllApps();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index aa457ca..567fad0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -118,11 +118,9 @@
getProvidedInsets(insetsRoundedCornerFlag)
}
- if (!context.isGestureNav) {
- if (windowLayoutParams.paramsForRotation != null) {
- for (layoutParams in windowLayoutParams.paramsForRotation) {
- layoutParams.providedInsets = getProvidedInsets(insetsRoundedCornerFlag)
- }
+ if (windowLayoutParams.paramsForRotation != null) {
+ for (layoutParams in windowLayoutParams.paramsForRotation) {
+ layoutParams.providedInsets = getProvidedInsets(insetsRoundedCornerFlag)
}
}
@@ -156,19 +154,12 @@
)
}
- val gravity = windowLayoutParams.gravity
-
// Pre-calculate insets for different providers across different rotations for this gravity
for (rotation in Surface.ROTATION_0..Surface.ROTATION_270) {
// Add insets for navbar rotated params
- if (windowLayoutParams.paramsForRotation != null) {
- val layoutParams = windowLayoutParams.paramsForRotation[rotation]
- for (provider in layoutParams.providedInsets) {
- setProviderInsets(provider, layoutParams.gravity, rotation)
- }
- }
- for (provider in windowLayoutParams.providedInsets) {
- setProviderInsets(provider, gravity, rotation)
+ val layoutParams = windowLayoutParams.paramsForRotation[rotation]
+ for (provider in layoutParams.providedInsets) {
+ setProviderInsets(provider, layoutParams.gravity, rotation)
}
}
context.notifyUpdateLayoutParams()
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 8d83716..a14e3fd 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -193,7 +193,7 @@
updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, true);
if (!mShouldDelayLauncherStateAnim) {
if (toState == LauncherState.NORMAL) {
- applyState(QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION);
+ applyState(QuickstepTransitionManager.getTaskbarToHomeDuration());
} else {
applyState();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index ff33ca9..ecbc7e7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -23,7 +23,6 @@
import static com.android.launcher3.BaseActivity.EVENT_DESTROYED;
import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
-import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
@@ -69,6 +68,7 @@
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SimpleBroadcastReceiver;
+import com.android.quickstep.AllAppsActionManager;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.TouchInteractionService;
@@ -158,6 +158,8 @@
private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver =
new SimpleBroadcastReceiver(this::showTaskbarFromBroadcast);
+ private final AllAppsActionManager mAllAppsActionManager;
+
private final Runnable mActivityOnDestroyCallback = new Runnable() {
@Override
public void run() {
@@ -212,12 +214,14 @@
private Boolean mFolded;
@SuppressLint("WrongConstant")
- public TaskbarManager(TouchInteractionService service) {
+ public TaskbarManager(
+ TouchInteractionService service, AllAppsActionManager allAppsActionManager) {
Display display =
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
mContext = service.createWindowContext(display,
ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL,
null);
+ mAllAppsActionManager = allAppsActionManager;
mNavigationBarPanelContext = ENABLE_TASKBAR_NAVBAR_UNIFICATION
? service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null)
: null;
@@ -291,10 +295,10 @@
recreateTaskbar();
} else {
// Config change might be handled without re-creating the taskbar
- if (dp != null && !isTaskbarPresent(dp)) {
+ if (dp != null && !isTaskbarEnabled(dp)) {
destroyExistingTaskbar();
} else {
- if (dp != null && isTaskbarPresent(dp)) {
+ if (dp != null && isTaskbarEnabled(dp)) {
if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
// Re-initialize for screen size change? Should this be done
// by looking at screen-size change flag in configDiff in the
@@ -349,7 +353,7 @@
}
DeviceProfile dp = mUserUnlocked ?
LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
- if (dp == null || !isTaskbarPresent(dp)) {
+ if (dp == null || !isTaskbarEnabled(dp)) {
removeTaskbarRootViewFromWindow();
}
}
@@ -369,20 +373,11 @@
* @param homeAllAppsIntent Intent used if Taskbar is not enabled or Launcher is resumed.
*/
public void toggleAllApps(Intent homeAllAppsIntent) {
- if (mTaskbarActivityContext == null) {
+ if (mTaskbarActivityContext == null || mTaskbarActivityContext.canToggleHomeAllApps()) {
mContext.startActivity(homeAllAppsIntent);
- return;
+ } else {
+ mTaskbarActivityContext.toggleAllAppsSearch();
}
-
- if (mActivity != null
- && mActivity.isResumed()
- && !mActivity.isInState(OVERVIEW)
- && !(mActivity instanceof QuickstepLauncher l && l.areFreeformTasksVisible())) {
- mContext.startActivity(homeAllAppsIntent);
- return;
- }
-
- mTaskbarActivityContext.toggleAllAppsSearch();
}
/**
@@ -477,9 +472,12 @@
DeviceProfile dp = mUserUnlocked ?
LauncherAppState.getIDP(mContext).getDeviceProfile(mContext) : null;
+ // All Apps action is unrelated to navbar unification, so we only need to check DP.
+ mAllAppsActionManager.setTaskbarPresent(dp != null && dp.isTaskbarPresent);
+
destroyExistingTaskbar();
- boolean isTaskbarEnabled = dp != null && isTaskbarPresent(dp);
+ boolean isTaskbarEnabled = dp != null && isTaskbarEnabled(dp);
debugWhyTaskbarNotDestroyed("recreateTaskbar: isTaskbarEnabled=" + isTaskbarEnabled
+ " [dp != null (i.e. mUserUnlocked)]=" + (dp != null)
+ " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION
@@ -544,7 +542,7 @@
}
}
- private static boolean isTaskbarPresent(DeviceProfile deviceProfile) {
+ private static boolean isTaskbarEnabled(DeviceProfile deviceProfile) {
return ENABLE_TASKBAR_NAVBAR_UNIFICATION || deviceProfile.isTaskbarPresent;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 629c951..3d58464 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -900,12 +900,12 @@
}
// Only update the following flags when system gesture is not in progress.
+ updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, false);
setStashedImeState();
}
private void setStashedImeState() {
boolean shouldStashForIme = shouldStashForIme();
- updateStateForFlag(FLAG_STASHED_IN_TASKBAR_ALL_APPS, false);
if (hasAnyFlag(FLAG_STASHED_IN_APP_IME) != shouldStashForIme) {
updateStateForFlag(FLAG_STASHED_IN_APP_IME, shouldStashForIme);
applyState(TASKBAR_STASH_DURATION_FOR_IME, getTaskbarStashStartDelayForIme());
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index efe1e39..109400e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -197,6 +197,11 @@
return false;
}
+ /** Returns {@code true} if Home All Apps available instead of Taskbar All Apps. */
+ protected boolean canToggleHomeAllApps() {
+ return false;
+ }
+
@CallSuper
protected void dumpLogs(String prefix, PrintWriter pw) {
pw.println(String.format(
diff --git a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
index dcc3b05..873dea8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -21,6 +21,7 @@
import android.app.Person;
import android.content.Context;
import android.content.Intent;
+import android.content.IntentSender;
import android.content.pm.ActivityInfo;
import android.content.pm.LauncherActivityInfo;
import android.content.pm.LauncherApps;
@@ -158,6 +159,28 @@
}
/**
+ * Returns an intent which can be used to open Private Space Settings.
+ */
+ public static Intent getPrivateSpaceSettingsIntent(Context context) {
+ if (android.os.Flags.allowPrivateProfile() && Flags.enablePrivateSpace()) {
+ LauncherApps launcherApps = context.getSystemService(LauncherApps.class);
+ IntentSender intentSender = launcherApps.getPrivateSpaceSettingsIntent();
+ if (intentSender == null) {
+ return null;
+ }
+ StartActivityParams params = new StartActivityParams((PendingIntent) null, 0);
+ params.intentSender = intentSender;
+ ActivityOptions options = ActivityOptions.makeBasic()
+ .setPendingIntentBackgroundActivityStartMode(ActivityOptions
+ .MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ params.options = options.toBundle();
+ params.requireActivityResult = false;
+ return ProxyActivityStarter.getLaunchIntent(context, params);
+ }
+ return null;
+ }
+
+ /**
* Checks if an activity is flagged as non-resizeable.
*/
public static boolean isNonResizeableActivity(LauncherActivityInfo lai) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 75dfe30..2b10bfd 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -39,8 +39,8 @@
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_HOME;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
@@ -105,6 +105,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Flags;
import com.android.launcher3.HomeTransitionController;
+import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.LauncherState;
@@ -666,6 +667,14 @@
}
@Override
+ protected boolean initDeviceProfile(InvariantDeviceProfile idp) {
+ final boolean ret = super.initDeviceProfile(idp);
+ mDeviceProfile.isPredictiveBackSwipe =
+ getApplicationInfo().isOnBackInvokedCallbackEnabled();
+ return ret;
+ }
+
+ @Override
public void startSplitSelection(SplitSelectSource splitSelectSource) {
RecentsView recentsView = getOverviewPanel();
// Check if there is already an instance of this app running, if so, initiate the split
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
index e3ff281..23e2622 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepWidgetHolder.java
@@ -26,10 +26,10 @@
import android.util.SparseArray;
import android.widget.RemoteViews;
+import androidx.annotation.AnyThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
-import androidx.annotation.WorkerThread;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.WidgetsModel;
@@ -265,6 +265,14 @@
}
}
+ /**
+ * Clears all the internal widget views excluding the update listeners
+ */
+ @Override
+ public void clearWidgetViews() {
+ mViews.clear();
+ }
+
private static class QuickstepWidgetHolderListener
implements AppWidgetHost.AppWidgetHostListener {
@@ -288,21 +296,21 @@
}
@Override
- @WorkerThread
+ @AnyThread
public void onUpdateProviderInfo(@Nullable AppWidgetProviderInfo info) {
mRemoteViews = null;
executeOnMainExecutor(KEY_PROVIDER_UPDATE, info);
}
@Override
- @WorkerThread
+ @AnyThread
public void updateAppWidget(@Nullable RemoteViews views) {
mRemoteViews = views;
executeOnMainExecutor(KEY_VIEWS_UPDATE, mRemoteViews);
}
@Override
- @WorkerThread
+ @AnyThread
public void onViewDataChanged(int viewId) {
executeOnMainExecutor(KEY_VIEW_DATA_CHANGED, viewId);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index e6a115a..6c1d4b1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -133,7 +133,7 @@
// Create transition animations to split select
RecentsPagedOrientationHandler orientationHandler =
((RecentsView) mLauncher.getOverviewPanel()).getPagedOrientationHandler();
- Pair<FloatProperty, FloatProperty> taskViewsFloat =
+ Pair<FloatProperty<RecentsView>, FloatProperty<RecentsView>> taskViewsFloat =
orientationHandler.getSplitSelectTaskOffset(
TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
mLauncher.getDeviceProfile());
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index 577eba6..b6002e8 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -16,6 +16,7 @@
package com.android.launcher3.uioverrides.states;
import static com.android.app.animation.Interpolators.DECELERATE_2;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_ALLAPPS;
import android.content.Context;
@@ -28,6 +29,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
+import com.android.quickstep.util.BaseDepthController;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
/**
@@ -105,8 +107,14 @@
return context.getDeviceProfile().bottomSheetDepth;
} else {
// The scrim fades in at approximately 50% of the swipe gesture.
- // This means that the depth should be greater than 1, in order to fully zoom out.
- return 2f;
+ if (enableScalingRevealHomeAnimation()) {
+ // This means that the depth should be twice of what we want, in order to fully zoom
+ // out during the visible portion of the animation.
+ return BaseDepthController.DEPTH_60_PERCENT;
+ } else {
+ // This means that the depth should be greater than 1, in order to fully zoom out.
+ return 2f;
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
index d11a08b..6a25c21 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/BackgroundAppState.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.uioverrides.states;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.quickstep.TaskAnimationManager.ENABLE_SHELL_TRANSITIONS;
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
@@ -26,6 +27,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.quickstep.util.BaseDepthController;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
@@ -90,13 +92,14 @@
@Override
protected float getDepthUnchecked(Context context) {
- if (isDesktopModeSupported()) {
- if (Launcher.getLauncher(context).areFreeformTasksVisible()) {
- // Don't blur the background while freeform tasks are visible
- return 0;
- }
+ if (isDesktopModeSupported() && Launcher.getLauncher(context).areFreeformTasksVisible()) {
+ // Don't blur the background while freeform tasks are visible
+ return BaseDepthController.DEPTH_0_PERCENT;
+ } else if (enableScalingRevealHomeAnimation()) {
+ return BaseDepthController.DEPTH_70_PERCENT;
+ } else {
+ return 1f;
}
- return 1;
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 7650235..8c2efc2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -16,6 +16,7 @@
package com.android.launcher3.uioverrides.states;
import static com.android.app.animation.Interpolators.DECELERATE_2;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import static com.android.wm.shell.Flags.enableSplitContextual;
@@ -29,6 +30,7 @@
import com.android.launcher3.R;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.Themes;
+import com.android.quickstep.util.BaseDepthController;
import com.android.quickstep.util.LayoutUtils;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
@@ -186,8 +188,14 @@
@Override
protected float getDepthUnchecked(Context context) {
- //TODO revert when b/178661709 is fixed
- return SystemProperties.getBoolean("ro.launcher.depth.overview", true) ? 1 : 0;
+ // TODO(178661709): revert to always scaled
+ if (enableScalingRevealHomeAnimation()) {
+ return SystemProperties.getBoolean("ro.launcher.depth.overview", true)
+ ? BaseDepthController.DEPTH_70_PERCENT
+ : BaseDepthController.DEPTH_0_PERCENT;
+ } else {
+ return SystemProperties.getBoolean("ro.launcher.depth.overview", true) ? 1 : 0;
+ }
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 72218bf..b401868 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -37,7 +37,6 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
-import static com.android.launcher3.QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION;
import static com.android.launcher3.WorkspaceStateTransitionAnimation.getWorkspaceSpringScaleAnimator;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE;
import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH;
@@ -59,6 +58,7 @@
import com.android.launcher3.CellLayout;
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.QuickstepTransitionManager;
import com.android.launcher3.Workspace;
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.touch.AllAppsSwipeController;
@@ -108,7 +108,8 @@
// We sync the scrim fade with the taskbar animation duration to avoid any flickers for
// taskbar icons disappearing before hotseat icons show up.
- float scrimUpperBoundFromSplit = TASKBAR_TO_HOME_DURATION / (float) config.duration;
+ float scrimUpperBoundFromSplit =
+ QuickstepTransitionManager.getTaskbarToHomeDuration() / (float) config.duration;
config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR, 0, 0.25f));
config.setInterpolator(ANIM_SCRIM_FADE,
fromState == OVERVIEW_SPLIT_SELECT
@@ -135,9 +136,9 @@
config.duration = Math.max(config.duration, scrollDuration);
// Sync scroll so that it ends before or at the same time as the taskbar animation.
- if (DisplayController.isTransientTaskbar(mActivity)
- && mActivity.getDeviceProfile().isTaskbarPresent) {
- config.duration = Math.min(config.duration, TASKBAR_TO_HOME_DURATION);
+ if (mActivity.getDeviceProfile().isTaskbarPresent) {
+ config.duration = Math.min(
+ config.duration, QuickstepTransitionManager.getTaskbarToHomeDuration());
}
overview.snapToPage(DEFAULT_PAGE, Math.toIntExact(config.duration));
} else {
diff --git a/quickstep/src/com/android/quickstep/AllAppsActionManager.kt b/quickstep/src/com/android/quickstep/AllAppsActionManager.kt
new file mode 100644
index 0000000..fd2ed3a
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/AllAppsActionManager.kt
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import android.accessibilityservice.AccessibilityService.GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS
+import android.app.PendingIntent
+import android.app.RemoteAction
+import android.content.Context
+import android.graphics.drawable.Icon
+import android.view.accessibility.AccessibilityManager
+import com.android.launcher3.R
+import java.util.concurrent.Executor
+
+/**
+ * Registers a [RemoteAction] for toggling All Apps if needed.
+ *
+ * We need this action when either [isHomeAndOverviewSame] or [isTaskbarPresent] is `true`. When
+ * home and overview are the same, we can control Launcher's or Taskbar's All Apps tray. If they are
+ * not the same, but Taskbar is present, we can only control Taskbar's tray.
+ */
+class AllAppsActionManager(
+ private val context: Context,
+ private val bgExecutor: Executor,
+ private val createAllAppsPendingIntent: () -> PendingIntent,
+) {
+
+ /** `true` if home and overview are the same Activity. */
+ var isHomeAndOverviewSame = false
+ set(value) {
+ field = value
+ updateSystemAction()
+ }
+
+ /** `true` if Taskbar is enabled. */
+ var isTaskbarPresent = false
+ set(value) {
+ field = value
+ updateSystemAction()
+ }
+
+ /** `true` if the action should be registered. */
+ var isActionRegistered = false
+ private set
+
+ private fun updateSystemAction() {
+ val shouldRegisterAction = isHomeAndOverviewSame || isTaskbarPresent
+ if (isActionRegistered == shouldRegisterAction) return
+ isActionRegistered = shouldRegisterAction
+
+ bgExecutor.execute {
+ val accessibilityManager =
+ context.getSystemService(AccessibilityManager::class.java) ?: return@execute
+ if (shouldRegisterAction) {
+ accessibilityManager.registerSystemAction(
+ RemoteAction(
+ Icon.createWithResource(context, R.drawable.ic_apps),
+ context.getString(R.string.all_apps_label),
+ context.getString(R.string.all_apps_label),
+ createAllAppsPendingIntent(),
+ ),
+ GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS,
+ )
+ } else {
+ accessibilityManager.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS)
+ }
+ }
+ }
+
+ fun onDestroy() {
+ context
+ .getSystemService(AccessibilityManager::class.java)
+ ?.unregisterSystemAction(
+ GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS,
+ )
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 2341e4c..59302b7 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -380,13 +380,6 @@
}
/**
- * Calculates the task size for the desktop task
- */
- public final void calculateDesktopTaskSize(Context context, DeviceProfile dp, Rect outRect) {
- calculateFocusTaskSize(context, dp, outRect);
- }
-
- /**
* Calculates the modal taskView size for the provided device configuration
*/
public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect,
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index a9d8afc..f678bea 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -17,6 +17,7 @@
import static com.android.app.animation.Interpolators.EXAGGERATED_EASE;
import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.Utilities.mapBoundToRange;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
@@ -46,6 +47,7 @@
import com.android.launcher3.views.FloatingView;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.quickstep.util.RectFSpringAnim;
+import com.android.quickstep.util.ScalingWorkspaceRevealAnim;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.util.TaskViewSimulator;
import com.android.quickstep.views.FloatingWidgetView;
@@ -296,9 +298,15 @@
@Override
public void playAtomicAnimation(float velocity) {
- new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
- getViewIgnoredInWorkspaceRevealAnimation())
- .start();
+ if (enableScalingRevealHomeAnimation()) {
+ if (mActivity != null) {
+ new ScalingWorkspaceRevealAnim(mActivity).start();
+ }
+ } else {
+ new StaggeredWorkspaceAnim(mActivity, velocity, true /* animateOverviewScrim */,
+ getViewIgnoredInWorkspaceRevealAnimation())
+ .start();
+ }
}
}
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 65b5397..56c9a00 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -248,7 +248,15 @@
case TYPE_SHOW:
// already visible
return true;
+ case TYPE_KEYBOARD_INPUT: {
+ if (visibleRecentsView.isHandlingTouch()) {
+ return true;
+ }
+ }
case TYPE_HIDE: {
+ if (visibleRecentsView.isHandlingTouch()) {
+ return true;
+ }
mKeyboardTaskFocusIndex = INVALID_PAGE;
int currentPage = visibleRecentsView.getNextPage();
TaskView tv = (currentPage >= 0
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 36bdad4..62ce341 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -328,11 +328,15 @@
// No "save app pair" menu item if:
// - app pairs feature is not enabled
+ // - we are in 3p launcher
// - the task in question is a single task
// - at least one app in app pair is unpinnable
// - the Overview Actions Button should be visible
- if (!FeatureFlags.enableAppPairs() || !taskView.containsMultipleTasks()
- || hasUnpinnableApp || shouldShowActionsButtonInstead) {
+ if (!FeatureFlags.enableAppPairs()
+ || !recentsView.supportsAppPairs()
+ || !taskView.containsMultipleTasks()
+ || hasUnpinnableApp
+ || shouldShowActionsButtonInstead) {
return null;
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 415f73f..b43c520 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -31,6 +31,7 @@
import static com.android.launcher3.MotionEventsUtils.isTrackpadMultiFingerSwipe;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TRACKPAD_GESTURE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.OnboardingPrefs.HOME_BOUNCE_SEEN;
import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH;
import static com.android.quickstep.GestureState.DEFAULT_STATE;
@@ -40,7 +41,6 @@
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_DOWN;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_MOVE;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.MOTION_UP;
-import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.RECENTS_ANIMATION_START_PENDING;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
@@ -60,14 +60,12 @@
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_STARTING_WINDOW;
import android.app.PendingIntent;
-import android.app.RemoteAction;
import android.app.Service;
import android.content.IIntentReceiver;
import android.content.IIntentSender;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Region;
-import android.graphics.drawable.Icon;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
@@ -78,7 +76,6 @@
import android.view.InputDevice;
import android.view.InputEvent;
import android.view.MotionEvent;
-import android.view.accessibility.AccessibilityManager;
import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
@@ -89,7 +86,6 @@
import com.android.launcher3.ConstantItem;
import com.android.launcher3.EncryptionType;
import com.android.launcher3.LauncherPrefs;
-import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.provider.RestoreDbTask;
@@ -102,7 +98,6 @@
import com.android.launcher3.uioverrides.flags.FlagsFactory;
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
import com.android.launcher3.util.DisplayController;
-import com.android.launcher3.util.Executors;
import com.android.launcher3.util.LockedUserState;
import com.android.launcher3.util.SafeCloseable;
import com.android.launcher3.util.ScreenOnTracker;
@@ -489,6 +484,7 @@
private TaskbarManager mTaskbarManager;
private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null;
+ private AllAppsActionManager mAllAppsActionManager;
@Override
public void onCreate() {
@@ -498,7 +494,9 @@
mMainChoreographer = Choreographer.getInstance();
mAM = ActivityManagerWrapper.getInstance();
mDeviceState = new RecentsAnimationDeviceState(this, true);
- mTaskbarManager = new TaskbarManager(this);
+ mAllAppsActionManager = new AllAppsActionManager(
+ this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent);
+ mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager);
mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
BootAwarePreloader.start(this);
@@ -591,16 +589,7 @@
}
private void onOverviewTargetChange(boolean isHomeAndOverviewSame) {
- Executors.UI_HELPER_EXECUTOR.execute(() -> {
- AccessibilityManager am = getSystemService(AccessibilityManager.class);
-
- if (isHomeAndOverviewSame) {
- am.registerSystemAction(
- createAllAppsAction(), GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
- } else {
- am.unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
- }
- });
+ mAllAppsActionManager.setHomeAndOverviewSame(isHomeAndOverviewSame);
StatefulActivity newOverviewActivity = mOverviewComponentObserver.getActivityInterface()
.getCreatedActivity();
@@ -610,13 +599,12 @@
mTISBinder.onOverviewTargetChange();
}
- private RemoteAction createAllAppsAction() {
+ private PendingIntent createAllAppsPendingIntent() {
final Intent homeIntent = new Intent(mOverviewComponentObserver.getHomeIntent())
.setAction(INTENT_ACTION_ALL_APPS_TOGGLE);
- final PendingIntent actionPendingIntent;
if (FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
- actionPendingIntent = new PendingIntent(new IIntentSender.Stub() {
+ return new PendingIntent(new IIntentSender.Stub() {
@Override
public void send(int code, Intent intent, String resolvedType,
IBinder allowlistToken, IIntentReceiver finishedReceiver,
@@ -625,18 +613,12 @@
}
});
} else {
- actionPendingIntent = PendingIntent.getActivity(
+ return PendingIntent.getActivity(
this,
GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS,
homeIntent,
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
}
-
- return new RemoteAction(
- Icon.createWithResource(this, R.drawable.ic_apps),
- getString(R.string.all_apps_label),
- getString(R.string.all_apps_label),
- actionPendingIntent);
}
@UiThread
@@ -679,8 +661,7 @@
mDeviceState.destroy();
SystemUiProxy.INSTANCE.get(this).clearProxy();
- getSystemService(AccessibilityManager.class)
- .unregisterSystemAction(GLOBAL_ACTION_ACCESSIBILITY_ALL_APPS);
+ mAllAppsActionManager.onDestroy();
mTaskbarManager.destroy();
sConnected = false;
@@ -734,15 +715,17 @@
// an ACTION_HOVER_ENTER will fire as well.
boolean isHoverActionWithoutConsumer = enableCursorHoverStates()
&& isHoverActionWithoutConsumer(event);
- if (mTaskAnimationManager.isRecentsAnimationStartPending()
- && (action == ACTION_DOWN || isHoverActionWithoutConsumer)) {
- ActiveGestureLog.INSTANCE.addLog(
- new CompoundString("TIS.onInputEvent: ")
- .append("Cannot process input event: a recents animation has been ")
- .append("requested, but hasn't started."),
- RECENTS_ANIMATION_START_PENDING);
- return;
- }
+
+ // TODO(b/285636175): Uncomment this once WM can properly guarantee all animation callbacks
+// if (mTaskAnimationManager.isRecentsAnimationStartPending()
+// && (action == ACTION_DOWN || isHoverActionWithoutConsumer)) {
+// ActiveGestureLog.INSTANCE.addLog(
+// new CompoundString("TIS.onInputEvent: ")
+// .append("Cannot process input event: a recents animation has been ")
+// .append("requested, but hasn't started."),
+// RECENTS_ANIMATION_START_PENDING);
+// return;
+// }
SafeCloseable traceToken = TraceHelper.INSTANCE.allowIpcs("TIS.onInputEvent");
@@ -753,6 +736,10 @@
boolean isOneHandedModeActive = mDeviceState.isOneHandedModeActive();
boolean isInSwipeUpTouchRegion = mRotationTouchHelper.isInSwipeUpTouchRegion(event);
+ TaskbarActivityContext tac = mTaskbarManager.getCurrentActivityContext();
+ if (isInSwipeUpTouchRegion && tac != null) {
+ tac.closeKeyboardQuickSwitchView();
+ }
if ((!isOneHandedModeActive && isInSwipeUpTouchRegion)
|| isHoverActionWithoutConsumer) {
reasonString.append(!isOneHandedModeActive && isInSwipeUpTouchRegion
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
index 8a87f63..69de3b0 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackNavBarTouchController.java
@@ -45,8 +45,7 @@
NavBarPosition navBarPosition = new NavBarPosition(sysUINavigationMode,
DisplayController.INSTANCE.get(mActivity).getInfo());
mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(mActivity,
- true /* disableHorizontalSwipe */, navBarPosition,
- null /* onInterceptTouch */, this);
+ true /* disableHorizontalSwipe */, navBarPosition, this);
} else {
mTriggerSwipeUpTracker = null;
}
@@ -78,7 +77,4 @@
public void onSwipeUp(boolean wasFling, PointF finalVelocity) {
mActivity.<FallbackRecentsView>getOverviewPanel().startHome();
}
-
- @Override
- public void onSwipeUpCancelled() {}
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
index 3e731e5..69eaf6a 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsStateController.java
@@ -49,6 +49,7 @@
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.quickstep.RecentsActivity;
import com.android.quickstep.views.ClearAllButton;
+import com.android.quickstep.views.RecentsView;
/**
* State controller for fallback recents activity
@@ -125,7 +126,7 @@
setter.add(pa.buildAnim());
}
- Pair<FloatProperty, FloatProperty> taskViewsFloat =
+ Pair<FloatProperty<RecentsView>, FloatProperty<RecentsView>> taskViewsFloat =
mRecentsView.getPagedOrientationHandler().getSplitSelectTaskOffset(
TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
mActivity.getDeviceProfile());
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 0ee50a4..32d8be9 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -302,4 +302,10 @@
protected boolean canLaunchFullscreenTask() {
return !mActivity.isInState(OVERVIEW_SPLIT_SELECT);
}
+
+ /** Returns if app pairs are supported in this launcher. */
+ @Override
+ public boolean supportsAppPairs() {
+ return false;
+ }
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
index 41730bb..42e8694 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OverviewWithoutFocusInputConsumer.java
@@ -51,7 +51,7 @@
mGestureState = gestureState;
mInputMonitor = inputMonitor;
mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(context, disableHorizontalSwipe,
- deviceState.getNavBarPosition(), this::onInterceptTouch, this);
+ deviceState.getNavBarPosition(), this);
}
@Override
@@ -69,7 +69,8 @@
mTriggerSwipeUpTracker.onMotionEvent(ev);
}
- private void onInterceptTouch() {
+ @Override
+ public void onSwipeUpTouchIntercepted() {
if (mInputMonitor != null) {
TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
mInputMonitor.pilferPointers();
@@ -93,7 +94,4 @@
.build())
.log(LAUNCHER_HOME_GESTURE);
}
-
- @Override
- public void onSwipeUpCancelled() {}
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
index 4806ac1..871d075 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/SysUiOverlayInputConsumer.java
@@ -54,7 +54,7 @@
mContext = context;
mInputMonitor = inputMonitor;
mTriggerSwipeUpTracker = new TriggerSwipeUpTouchTracker(context, true,
- deviceState.getNavBarPosition(), this::onInterceptTouch, this);
+ deviceState.getNavBarPosition(), this);
}
@Override
@@ -72,7 +72,8 @@
mTriggerSwipeUpTracker.onMotionEvent(ev);
}
- private void onInterceptTouch() {
+ @Override
+ public void onSwipeUpTouchIntercepted() {
if (mInputMonitor != null) {
TestLogging.recordEvent(TestProtocol.SEQUENCE_PILFER, "pilferPointers");
mInputMonitor.pilferPointers();
@@ -88,9 +89,4 @@
Log.e(TAG, "Exception calling closeSystemDialogs " + e.getMessage());
}
}
-
- @Override
- public void onSwipeUpCancelled() {
-
- }
}
diff --git a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
index c4a2216..c00f508 100644
--- a/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
+++ b/quickstep/src/com/android/quickstep/interaction/NavBarGestureHandler.java
@@ -65,7 +65,7 @@
mSwipeUpTouchTracker =
new TriggerSwipeUpTouchTracker(context, true /*disableHorizontalSwipe*/,
new NavBarPosition(NavigationMode.NO_BUTTON, displayInfo),
- null /*onInterceptTouch*/, this);
+ this);
mMotionPauseDetector = new MotionPauseDetector(context);
final Resources resources = context.getResources();
diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.java
deleted file mode 100644
index 8648b56..0000000
--- a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.java
+++ /dev/null
@@ -1,698 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep.orientation;
-
-import static android.view.Gravity.BOTTOM;
-import static android.view.Gravity.CENTER_VERTICAL;
-import static android.view.Gravity.END;
-import static android.view.Gravity.LEFT;
-import static android.view.Gravity.START;
-import static android.view.Gravity.TOP;
-import static android.view.View.LAYOUT_DIRECTION_RTL;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
-
-import static com.android.launcher3.Flags.enableOverviewIconMenu;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
-import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
-import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
-
-import android.content.res.Resources;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.ShapeDrawable;
-import android.util.FloatProperty;
-import android.util.Pair;
-import android.view.Gravity;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.VelocityTracker;
-import android.view.View;
-import android.view.accessibility.AccessibilityEvent;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.touch.SingleAxisSwipeDetector;
-import com.android.launcher3.util.SplitConfigurationOptions;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
-import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
-import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.views.IconAppChipView;
-
-import java.util.Collections;
-import java.util.List;
-
-public class LandscapePagedViewHandler implements RecentsPagedOrientationHandler {
-
- @Override
- public <T> T getPrimaryValue(T x, T y) {
- return y;
- }
-
- @Override
- public <T> T getSecondaryValue(T x, T y) {
- return x;
- }
-
- @Override
- public int getPrimaryValue(int x, int y) {
- return y;
- }
-
- @Override
- public int getSecondaryValue(int x, int y) {
- return x;
- }
-
- @Override
- public float getPrimaryValue(float x, float y) {
- return y;
- }
-
- @Override
- public float getSecondaryValue(float x, float y) {
- return x;
- }
-
- @Override
- public boolean isLayoutNaturalToLauncher() {
- return false;
- }
-
- @Override
- public void adjustFloatingIconStartVelocity(PointF velocity) {
- float oldX = velocity.x;
- float oldY = velocity.y;
- velocity.set(-oldY, oldX);
- }
-
- @Override
- public void fixBoundsForHomeAnimStartRect(RectF outStartRect, DeviceProfile deviceProfile) {
- // We don't need to check the "top" value here because the startRect is in the orientation
- // of the app, not of the fixed portrait launcher.
- if (outStartRect.left > deviceProfile.heightPx) {
- outStartRect.offsetTo(0, outStartRect.top);
- } else if (outStartRect.left < -deviceProfile.heightPx) {
- outStartRect.offsetTo(0, outStartRect.top);
- }
- }
-
- @Override
- public <T> void setPrimary(T target, Int2DAction<T> action, int param) {
- action.call(target, 0, param);
- }
-
- @Override
- public <T> void setPrimary(T target, Float2DAction<T> action, float param) {
- action.call(target, 0, param);
- }
-
- @Override
- public <T> void setSecondary(T target, Float2DAction<T> action, float param) {
- action.call(target, param, 0);
- }
-
- @Override
- public <T> void set(T target, Int2DAction<T> action, int primaryParam,
- int secondaryParam) {
- action.call(target, secondaryParam, primaryParam);
- }
-
- @Override
- public float getPrimaryDirection(MotionEvent event, int pointerIndex) {
- return event.getY(pointerIndex);
- }
-
- @Override
- public float getPrimaryVelocity(VelocityTracker velocityTracker, int pointerId) {
- return velocityTracker.getYVelocity(pointerId);
- }
-
- @Override
- public int getMeasuredSize(View view) {
- return view.getMeasuredHeight();
- }
-
- @Override
- public int getPrimarySize(View view) {
- return view.getHeight();
- }
-
- @Override
- public float getPrimarySize(RectF rect) {
- return rect.height();
- }
-
- @Override
- public float getStart(RectF rect) {
- return rect.top;
- }
-
- @Override
- public float getEnd(RectF rect) {
- return rect.bottom;
- }
-
- @Override
- public int getClearAllSidePadding(View view, boolean isRtl) {
- return (isRtl ? view.getPaddingBottom() : - view.getPaddingTop()) / 2;
- }
-
- @Override
- public int getSecondaryDimension(View view) {
- return view.getWidth();
- }
-
- @Override
- public FloatProperty<View> getPrimaryViewTranslate() {
- return VIEW_TRANSLATE_Y;
- }
-
- @Override
- public FloatProperty<View> getSecondaryViewTranslate() {
- return VIEW_TRANSLATE_X;
- }
-
- @Override
- public int getPrimaryScroll(View view) {
- return view.getScrollY();
- }
-
- @Override
- public float getPrimaryScale(View view) {
- return view.getScaleY();
- }
-
- @Override
- public void setMaxScroll(AccessibilityEvent event, int maxScroll) {
- event.setMaxScrollY(maxScroll);
- }
-
- @Override
- public boolean getRecentsRtlSetting(Resources resources) {
- return !Utilities.isRtl(resources);
- }
-
- @Override
- public float getDegreesRotated() {
- return 90;
- }
-
- @Override
- public int getRotation() {
- return Surface.ROTATION_90;
- }
-
- @Override
- public void setPrimaryScale(View view, float scale) {
- view.setScaleY(scale);
- }
-
- @Override
- public void setSecondaryScale(View view, float scale) {
- view.setScaleX(scale);
- }
-
- @Override
- public int getChildStart(View view) {
- return view.getTop();
- }
-
- @Override
- public int getCenterForPage(View view, Rect insets) {
- return (view.getPaddingLeft() + view.getMeasuredWidth() + insets.left
- - insets.right - view.getPaddingRight()) / 2;
- }
-
- @Override
- public int getScrollOffsetStart(View view, Rect insets) {
- return insets.top + view.getPaddingTop();
- }
-
- @Override
- public int getScrollOffsetEnd(View view, Rect insets) {
- return view.getHeight() - view.getPaddingBottom() - insets.bottom;
- }
-
- public int getSecondaryTranslationDirectionFactor() {
- return 1;
- }
-
- @Override
- public int getSplitTranslationDirectionFactor(int stagePosition, DeviceProfile deviceProfile) {
- if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
- return -1;
- } else {
- return 1;
- }
- }
-
- @Override
- public float getTaskMenuX(float x, View thumbnailView,
- DeviceProfile deviceProfile, float taskInsetMargin, View taskViewIcon) {
- return thumbnailView.getMeasuredWidth() + x - taskInsetMargin;
- }
-
- @Override
- public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
- View taskMenuView, float taskInsetMargin, View taskViewIcon) {
- BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams();
- int taskMenuWidth = lp.width;
- if (stagePosition == STAGE_POSITION_UNDEFINED) {
- return y + taskInsetMargin
- + (thumbnailView.getMeasuredHeight() - taskMenuWidth) / 2f;
- } else {
- return y + taskInsetMargin;
- }
- }
-
- @Override
- public int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
- @StagePosition int stagePosition) {
- if (enableOverviewIconMenu()) {
- return thumbnailView.getResources().getDimensionPixelSize(
- R.dimen.task_thumbnail_icon_menu_expanded_width);
- }
- if (stagePosition == SplitConfigurationOptions.STAGE_POSITION_UNDEFINED) {
- return thumbnailView.getMeasuredWidth();
- } else {
- return thumbnailView.getMeasuredHeight();
- }
- }
-
- @Override
- public void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
- LinearLayout taskMenuLayout, int dividerSpacing,
- ShapeDrawable dividerDrawable) {
- taskMenuLayout.setOrientation(LinearLayout.VERTICAL);
- dividerDrawable.setIntrinsicHeight(dividerSpacing);
- taskMenuLayout.setDividerDrawable(dividerDrawable);
- }
-
- @Override
- public void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp,
- LinearLayout viewGroup, DeviceProfile deviceProfile) {
- // Phone fake landscape
- viewGroup.setOrientation(LinearLayout.HORIZONTAL);
- lp.width = MATCH_PARENT;
- lp.height = WRAP_CONTENT;
- }
-
- @Override
- public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
- int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
- View[] thumbnailViews, int desiredTaskId, View banner) {
- boolean isRtl = banner.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
- float translationX = 0;
- float translationY = 0;
- FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams();
- banner.setPivotX(0);
- banner.setPivotY(0);
- banner.setRotation(getDegreesRotated());
- translationX = banner.getHeight();
- FrameLayout.LayoutParams snapshotParams =
- (FrameLayout.LayoutParams) thumbnailViews[0]
- .getLayoutParams();
- bannerParams.gravity = TOP | (isRtl ? END : START);
- if (splitBounds == null) {
- // Single, fullscreen case
- bannerParams.width = taskViewHeight - snapshotParams.topMargin;
- return new Pair<>(translationX, Integer.valueOf(snapshotParams.topMargin).floatValue());
- }
-
- // Set correct width
- if (desiredTaskId == splitBounds.leftTopTaskId) {
- bannerParams.width = thumbnailViews[0].getMeasuredHeight();
- } else {
- bannerParams.width = thumbnailViews[1].getMeasuredHeight();
- }
-
- // Set translations
- if (desiredTaskId == splitBounds.rightBottomTaskId) {
- float topLeftTaskPlusDividerPercent = splitBounds.appsStackedVertically
- ? (splitBounds.topTaskPercent + splitBounds.dividerHeightPercent)
- : (splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent);
- translationY = snapshotParams.topMargin
- + ((taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent);
- }
- if (desiredTaskId == splitBounds.leftTopTaskId) {
- translationY = snapshotParams.topMargin;
- }
- return new Pair<>(translationX, translationY);
- }
-
- /* ---------- The following are only used by TaskViewTouchHandler. ---------- */
-
- @Override
- public SingleAxisSwipeDetector.Direction getUpDownSwipeDirection() {
- return HORIZONTAL;
- }
-
- @Override
- public int getUpDirection(boolean isRtl) {
- return isRtl ? SingleAxisSwipeDetector.DIRECTION_NEGATIVE
- : SingleAxisSwipeDetector.DIRECTION_POSITIVE;
- }
-
- @Override
- public boolean isGoingUp(float displacement, boolean isRtl) {
- return isRtl ? displacement < 0 : displacement > 0;
- }
-
- @Override
- public int getTaskDragDisplacementFactor(boolean isRtl) {
- return isRtl ? 1 : -1;
- }
-
- /* -------------------- */
-
- @Override
- public ChildBounds getChildBounds(View child, int childStart, int pageCenter,
- boolean layoutChild) {
- final int childHeight = child.getMeasuredHeight();
- final int childBottom = childStart + childHeight;
- final int childWidth = child.getMeasuredWidth();
- final int childLeft = pageCenter - childWidth/ 2;
- if (layoutChild) {
- child.layout(childLeft, childStart, childLeft + childWidth, childBottom);
- }
- return new ChildBounds(childHeight, childWidth, childBottom, childLeft);
- }
-
- @SuppressWarnings("SuspiciousNameCombination")
- @Override
- public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
- return rect.left;
- }
-
- @Override
- public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
- // Add "left" side of phone which is actually the top
- return Collections.singletonList(new SplitPositionOption(
- R.drawable.ic_split_horizontal, R.string.recent_task_option_split_screen,
- STAGE_POSITION_TOP_OR_LEFT, STAGE_TYPE_MAIN));
- }
-
- @Override
- public void getInitialSplitPlaceholderBounds(int placeholderHeight, int placeholderInset,
- DeviceProfile dp, @StagePosition int stagePosition, Rect out) {
- // In fake land/seascape, the placeholder always needs to go to the "top" of the device,
- // which is the same bounds as 0 rotation.
- int width = dp.widthPx;
- int insetSizeAdjustment = getPlaceholderSizeAdjustment(dp);
- out.set(0, 0, width, placeholderHeight + insetSizeAdjustment);
- out.inset(placeholderInset, 0);
-
- // Adjust the top to account for content off screen. This will help to animate the view in
- // with rounded corners.
- int screenWidth = dp.widthPx;
- int screenHeight = dp.heightPx;
- int totalHeight = (int) (1.0f * screenHeight / 2 * (screenWidth - 2 * placeholderInset)
- / screenWidth);
- out.top -= (totalHeight - placeholderHeight);
- }
-
- @Override
- public void updateSplitIconParams(View out, float onScreenRectCenterX,
- float onScreenRectCenterY, float fullscreenScaleX, float fullscreenScaleY,
- int drawableWidth, int drawableHeight, DeviceProfile dp,
- @StagePosition int stagePosition) {
- float insetAdjustment = getPlaceholderSizeAdjustment(dp) / 2f;
- out.setX(onScreenRectCenterX / fullscreenScaleX
- - 1.0f * drawableWidth / 2);
- out.setY((onScreenRectCenterY + insetAdjustment) / fullscreenScaleY
- - 1.0f * drawableHeight / 2);
- }
-
- /**
- * The split placeholder comes with a default inset to buffer the icon from the top of the
- * screen. But if the device already has a large inset (from cutouts etc), use that instead.
- */
- private int getPlaceholderSizeAdjustment(DeviceProfile dp) {
- return Math.max(dp.getInsets().top - dp.splitPlaceholderInset, 0);
- }
-
- @Override
- public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
- int splitInstructionsWidth) {
- out.setPivotX(0);
- out.setPivotY(splitInstructionsHeight);
- out.setRotation(getDegreesRotated());
- int distanceToEdge = out.getResources().getDimensionPixelSize(
- R.dimen.split_instructions_bottom_margin_phone_landscape);
- // Adjust for any insets on the left edge
- int insetCorrectionX = dp.getInsets().left;
- // Center the view in case of unbalanced insets on top or bottom of screen
- int insetCorrectionY = (dp.getInsets().bottom - dp.getInsets().top) / 2;
- out.setTranslationX(distanceToEdge - insetCorrectionX);
- out.setTranslationY(((-splitInstructionsHeight - splitInstructionsWidth) / 2f)
- + insetCorrectionY);
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams();
- // Setting gravity to LEFT instead of the lint-recommended START because we always want this
- // view to be screen-left when phone is in landscape, regardless of the RtL setting.
- lp.gravity = LEFT | CENTER_VERTICAL;
- out.setLayoutParams(lp);
- }
-
- @Override
- public void getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp,
- @StagePosition int stagePosition, Rect out1, Rect out2) {
- // In fake land/seascape, the window bounds are always top and bottom half
- int screenHeight = dp.heightPx;
- int screenWidth = dp.widthPx;
- out1.set(0, 0, screenWidth, screenHeight / 2 - splitDividerSize);
- out2.set(0, screenHeight / 2 + splitDividerSize, screenWidth, screenHeight);
- }
-
- @Override
- public void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect,
- SplitBounds splitInfo, int desiredStagePosition) {
- float topLeftTaskPercent = splitInfo.appsStackedVertically
- ? splitInfo.topTaskPercent
- : splitInfo.leftTaskPercent;
- float dividerBarPercent = splitInfo.appsStackedVertically
- ? splitInfo.dividerHeightPercent
- : splitInfo.dividerWidthPercent;
-
- if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) {
- outRect.bottom = outRect.top + (int) (outRect.height() * topLeftTaskPercent);
- } else {
- outRect.top += (int) (outRect.height() * (topLeftTaskPercent + dividerBarPercent));
- }
- }
-
- @Override
- public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
- int parentWidth, int parentHeight, SplitBounds splitBoundsConfig, DeviceProfile dp,
- boolean isRtl) {
- FrameLayout.LayoutParams primaryParams =
- (FrameLayout.LayoutParams) primarySnapshot.getLayoutParams();
- FrameLayout.LayoutParams secondaryParams =
- (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams();
-
- // Swap the margins that are set in TaskView#setRecentsOrientedState()
- secondaryParams.topMargin = dp.overviewTaskThumbnailTopMarginPx;
- primaryParams.topMargin = 0;
-
- // Measure and layout the thumbnails bottom up, since the primary is on the visual left
- // (portrait bottom) and secondary is on the right (portrait top)
- int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
- int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
- int dividerBar = Math.round(totalThumbnailHeight * (splitBoundsConfig.appsStackedVertically
- ? splitBoundsConfig.dividerHeightPercent
- : splitBoundsConfig.dividerWidthPercent));
-
- Pair<Point, Point> taskViewSizes =
- getGroupedTaskViewSizes(dp, splitBoundsConfig, parentWidth, parentHeight);
-
- int translationY = taskViewSizes.first.y + spaceAboveSnapshot + dividerBar;
- primarySnapshot.setTranslationY(spaceAboveSnapshot);
- secondarySnapshot.setTranslationY(translationY - spaceAboveSnapshot);
-
- primarySnapshot.measure(
- View.MeasureSpec.makeMeasureSpec(taskViewSizes.first.x, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(taskViewSizes.first.y, View.MeasureSpec.EXACTLY)
- );
- secondarySnapshot.measure(
- View.MeasureSpec.makeMeasureSpec(taskViewSizes.second.x, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(taskViewSizes.second.y, View.MeasureSpec.EXACTLY)
- );
- }
-
- @Override
- public Pair<Point, Point> getGroupedTaskViewSizes(
- DeviceProfile dp,
- SplitBounds splitBoundsConfig,
- int parentWidth,
- int parentHeight) {
- int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
- int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
- int dividerBar = Math.round(totalThumbnailHeight * (splitBoundsConfig.appsStackedVertically
- ? splitBoundsConfig.dividerHeightPercent
- : splitBoundsConfig.dividerWidthPercent));
- float taskPercent = splitBoundsConfig.appsStackedVertically
- ? splitBoundsConfig.topTaskPercent
- : splitBoundsConfig.leftTaskPercent;
-
- Point firstTaskViewSize = new Point(
- parentWidth,
- (int) (totalThumbnailHeight * taskPercent)
- );
- Point secondTaskViewSize = new Point(
- parentWidth,
- totalThumbnailHeight - firstTaskViewSize.y - dividerBar
- );
-
- return new Pair<>(firstTaskViewSize, secondTaskViewSize);
- }
-
- @Override
- public void setTaskIconParams(FrameLayout.LayoutParams iconParams, int taskIconMargin,
- int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
- iconParams.gravity = (isRtl ? START : END) | CENTER_VERTICAL;
- iconParams.rightMargin = -taskIconHeight - taskIconMargin / 2;
- iconParams.leftMargin = 0;
- iconParams.topMargin = thumbnailTopMargin / 2;
- iconParams.bottomMargin = 0;
- }
-
- @Override
- public void setIconAppChipChildrenParams(FrameLayout.LayoutParams iconParams,
- int chipChildMarginStart) {
- iconParams.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
- iconParams.setMarginStart(chipChildMarginStart);
- iconParams.topMargin = 0;
- }
-
- @Override
- public void setIconAppChipMenuParams(IconAppChipView iconAppChipView,
- FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin, int thumbnailTopMargin) {
- boolean isRtl = iconAppChipView.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
- iconMenuParams.gravity = (isRtl ? START : END) | (isRtl ? BOTTOM : TOP);
- iconMenuParams.setMarginStart(isRtl ? iconMenuMargin : 0);
- iconMenuParams.topMargin = iconMenuMargin;
- iconMenuParams.bottomMargin = isRtl ? iconMenuMargin : 0;
- iconMenuParams.setMarginEnd(iconMenuMargin);
-
- iconAppChipView.setPivotX(isRtl ? iconMenuParams.width - (iconMenuParams.height / 2f)
- : iconMenuParams.width / 2f);
- iconAppChipView.setPivotY(
- isRtl ? (iconMenuParams.height / 2f) : iconMenuParams.width / 2f);
- iconAppChipView.setSplitTranslationY(0);
- iconAppChipView.setRotation(getDegreesRotated());
- }
-
- @Override
- public void setSplitIconParams(View primaryIconView, View secondaryIconView,
- int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
- int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
- DeviceProfile deviceProfile, SplitBounds splitConfig) {
- FrameLayout.LayoutParams primaryIconParams =
- (FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
- FrameLayout.LayoutParams secondaryIconParams = enableOverviewIconMenu()
- ? (FrameLayout.LayoutParams) secondaryIconView.getLayoutParams()
- : new FrameLayout.LayoutParams(primaryIconParams);
-
- // We calculate the "midpoint" of the thumbnail area, and place the icons there.
- // This is the place where the thumbnail area splits by default, in a near-50/50 split.
- // It is usually not exactly 50/50, due to insets/screen cutouts.
- int fullscreenInsetThickness = deviceProfile.getInsets().top
- - deviceProfile.getInsets().bottom;
- int fullscreenMidpointFromBottom = ((deviceProfile.heightPx - fullscreenInsetThickness)
- / 2);
- float midpointFromBottomPct = (float) fullscreenMidpointFromBottom / deviceProfile.heightPx;
- float insetPct = (float) fullscreenInsetThickness / deviceProfile.heightPx;
- int spaceAboveSnapshots = deviceProfile.overviewTaskThumbnailTopMarginPx;
- int overviewThumbnailAreaThickness = groupedTaskViewHeight - spaceAboveSnapshots;
- int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness * midpointFromBottomPct);
- int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
-
- if (enableOverviewIconMenu()) {
- primaryIconParams.gravity = isRtl ? BOTTOM | START : TOP | END;
- secondaryIconParams.gravity = isRtl ? BOTTOM | START : TOP | END;
- } else {
- primaryIconParams.gravity = BOTTOM | (isRtl ? START : END);
- secondaryIconParams.gravity = BOTTOM | (isRtl ? START : END);
- }
- primaryIconView.setTranslationX(0);
- secondaryIconView.setTranslationX(0);
- if (enableOverviewIconMenu()) {
- IconAppChipView primaryAppChipView = (IconAppChipView) primaryIconView;
- IconAppChipView secondaryAppChipView = (IconAppChipView) secondaryIconView;
- if (primaryIconView.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
- secondaryAppChipView.setSplitTranslationY(-primarySnapshotHeight);
- primaryAppChipView.setSplitTranslationY(0);
- } else {
- int secondarySnapshotHeight = groupedTaskViewHeight - primarySnapshotHeight;
- primaryAppChipView.setSplitTranslationY(secondarySnapshotHeight);
- }
- } else if (splitConfig.initiatedFromSeascape) {
- // if the split was initiated from seascape,
- // the task on the right (secondary) is slightly larger
- primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
- secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
- + taskIconHeight);
- } else {
- // if not,
- // the task on the left (primary) is slightly larger
- primaryIconView.setTranslationY(-bottomToMidpointOffset);
- secondaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight);
- }
-
- primaryIconView.setLayoutParams(primaryIconParams);
- secondaryIconView.setLayoutParams(secondaryIconParams);
- }
-
- @Override
- public int getDefaultSplitPosition(DeviceProfile deviceProfile) {
- throw new IllegalStateException("Default position not available in fake landscape");
- }
-
- @Override
- public Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
- FloatProperty secondary, DeviceProfile deviceProfile) {
- return new Pair<>(primary, secondary);
- }
-
- @Override
- public float getFloatingTaskOffscreenTranslationTarget(View floatingTask, RectF onScreenRect,
- @StagePosition int stagePosition, DeviceProfile dp) {
- float currentTranslationY = floatingTask.getTranslationY();
- return currentTranslationY - onScreenRect.height();
- }
-
- @Override
- public void setFloatingTaskPrimaryTranslation(View floatingTask, float translation,
- DeviceProfile dp) {
- floatingTask.setTranslationY(translation);
- }
-
- @Override
- public Float getFloatingTaskPrimaryTranslation(View floatingTask, DeviceProfile dp) {
- return floatingTask.getTranslationY();
- }
-}
diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
new file mode 100644
index 0000000..1640104
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
@@ -0,0 +1,700 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.orientation
+
+import android.annotation.SuppressLint
+import android.content.res.Resources
+import android.graphics.Point
+import android.graphics.PointF
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.ShapeDrawable
+import android.util.FloatProperty
+import android.util.Pair
+import android.view.Gravity
+import android.view.MotionEvent
+import android.view.Surface
+import android.view.VelocityTracker
+import android.view.View
+import android.view.View.MeasureSpec
+import android.view.ViewGroup
+import android.view.accessibility.AccessibilityEvent
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+import androidx.annotation.VisibleForTesting
+import androidx.core.util.component1
+import androidx.core.util.component2
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.Flags
+import com.android.launcher3.LauncherAnimUtils
+import com.android.launcher3.R
+import com.android.launcher3.Utilities
+import com.android.launcher3.touch.PagedOrientationHandler.ChildBounds
+import com.android.launcher3.touch.PagedOrientationHandler.Float2DAction
+import com.android.launcher3.touch.PagedOrientationHandler.Int2DAction
+import com.android.launcher3.touch.SingleAxisSwipeDetector
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN
+import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds
+import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition
+import com.android.launcher3.views.BaseDragLayer
+import com.android.quickstep.views.IconAppChipView
+import kotlin.math.max
+
+open class LandscapePagedViewHandler : RecentsPagedOrientationHandler {
+ override fun <T> getPrimaryValue(x: T, y: T): T = y
+
+ override fun <T> getSecondaryValue(x: T, y: T): T = x
+
+ override fun getPrimaryValue(x: Int, y: Int): Int = y
+
+ override fun getSecondaryValue(x: Int, y: Int): Int = x
+
+ override fun getPrimaryValue(x: Float, y: Float): Float = y
+
+ override fun getSecondaryValue(x: Float, y: Float): Float = x
+
+ override val isLayoutNaturalToLauncher: Boolean = false
+
+ override fun adjustFloatingIconStartVelocity(velocity: PointF) {
+ val oldX = velocity.x
+ val oldY = velocity.y
+ velocity.set(-oldY, oldX)
+ }
+
+ override fun fixBoundsForHomeAnimStartRect(outStartRect: RectF, deviceProfile: DeviceProfile) {
+ // We don't need to check the "top" value here because the startRect is in the orientation
+ // of the app, not of the fixed portrait launcher.
+ if (outStartRect.left > deviceProfile.heightPx) {
+ outStartRect.offsetTo(0f, outStartRect.top)
+ } else if (outStartRect.left < -deviceProfile.heightPx) {
+ outStartRect.offsetTo(0f, outStartRect.top)
+ }
+ }
+
+ override fun <T> setPrimary(target: T, action: Int2DAction<T>, param: Int) =
+ action.call(target, 0, param)
+
+ override fun <T> setPrimary(target: T, action: Float2DAction<T>, param: Float) =
+ action.call(target, 0f, param)
+
+ override fun <T> setSecondary(target: T, action: Float2DAction<T>, param: Float) =
+ action.call(target, param, 0f)
+
+ override fun <T> set(
+ target: T,
+ action: Int2DAction<T>,
+ primaryParam: Int,
+ secondaryParam: Int
+ ) = action.call(target, secondaryParam, primaryParam)
+
+ override fun getPrimaryDirection(event: MotionEvent, pointerIndex: Int): Float =
+ event.getY(pointerIndex)
+
+ override fun getPrimaryVelocity(velocityTracker: VelocityTracker, pointerId: Int): Float =
+ velocityTracker.getYVelocity(pointerId)
+
+ override fun getMeasuredSize(view: View): Int = view.measuredHeight
+
+ override fun getPrimarySize(view: View): Int = view.height
+
+ override fun getPrimarySize(rect: RectF): Float = rect.height()
+
+ override fun getStart(rect: RectF): Float = rect.top
+
+ override fun getEnd(rect: RectF): Float = rect.bottom
+
+ override fun getClearAllSidePadding(view: View, isRtl: Boolean): Int =
+ if (isRtl) view.paddingBottom / 2 else -view.paddingTop / 2
+
+ override fun getSecondaryDimension(view: View): Int = view.width
+
+ override val primaryViewTranslate: FloatProperty<View> = LauncherAnimUtils.VIEW_TRANSLATE_Y
+
+ override val secondaryViewTranslate: FloatProperty<View> = LauncherAnimUtils.VIEW_TRANSLATE_X
+
+ override fun getPrimaryScroll(view: View): Int = view.scrollY
+
+ override fun getPrimaryScale(view: View): Float = view.scaleY
+
+ override fun setMaxScroll(event: AccessibilityEvent, maxScroll: Int) {
+ event.maxScrollY = maxScroll
+ }
+
+ override fun getRecentsRtlSetting(resources: Resources): Boolean = !Utilities.isRtl(resources)
+
+ override val degreesRotated: Float = 90f
+
+ override val rotation: Int = Surface.ROTATION_90
+
+ override fun setPrimaryScale(view: View, scale: Float) {
+ view.scaleY = scale
+ }
+
+ override fun setSecondaryScale(view: View, scale: Float) {
+ view.scaleX = scale
+ }
+
+ override fun getChildStart(view: View): Int = view.top
+
+ override fun getCenterForPage(view: View, insets: Rect): Int =
+ (view.paddingLeft + view.measuredWidth + insets.left - insets.right - view.paddingRight) / 2
+
+ override fun getScrollOffsetStart(view: View, insets: Rect): Int = insets.top + view.paddingTop
+
+ override fun getScrollOffsetEnd(view: View, insets: Rect): Int =
+ view.height - view.paddingBottom - insets.bottom
+
+ override val secondaryTranslationDirectionFactor: Int = 1
+
+ override fun getSplitTranslationDirectionFactor(
+ stagePosition: Int,
+ deviceProfile: DeviceProfile
+ ): Int = if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) -1 else 1
+
+ override fun getTaskMenuX(
+ x: Float,
+ thumbnailView: View,
+ deviceProfile: DeviceProfile,
+ taskInsetMargin: Float,
+ taskViewIcon: View
+ ): Float = thumbnailView.measuredWidth + x - taskInsetMargin
+
+ override fun getTaskMenuY(
+ y: Float,
+ thumbnailView: View,
+ stagePosition: Int,
+ taskMenuView: View,
+ taskInsetMargin: Float,
+ taskViewIcon: View
+ ): Float {
+ val layoutParams = taskMenuView.layoutParams as BaseDragLayer.LayoutParams
+ var taskMenuY = y + taskInsetMargin
+
+ if (stagePosition == STAGE_POSITION_UNDEFINED) {
+ taskMenuY += (thumbnailView.measuredHeight - layoutParams.width) / 2f
+ }
+
+ return taskMenuY
+ }
+
+ override fun getTaskMenuWidth(
+ thumbnailView: View,
+ deviceProfile: DeviceProfile,
+ @StagePosition stagePosition: Int
+ ): Int =
+ when {
+ Flags.enableOverviewIconMenu() ->
+ thumbnailView.resources.getDimensionPixelSize(
+ R.dimen.task_thumbnail_icon_menu_expanded_width
+ )
+ stagePosition == STAGE_POSITION_UNDEFINED -> thumbnailView.measuredWidth
+ else -> thumbnailView.measuredHeight
+ }
+
+ override fun getTaskMenuHeight(
+ taskInsetMargin: Float,
+ deviceProfile: DeviceProfile,
+ taskMenuX: Float,
+ taskMenuY: Float
+ ): Int = (taskMenuX - taskInsetMargin).toInt()
+
+ override fun setTaskOptionsMenuLayoutOrientation(
+ deviceProfile: DeviceProfile,
+ taskMenuLayout: LinearLayout,
+ dividerSpacing: Int,
+ dividerDrawable: ShapeDrawable
+ ) {
+ taskMenuLayout.orientation = LinearLayout.VERTICAL
+ dividerDrawable.intrinsicHeight = dividerSpacing
+ taskMenuLayout.dividerDrawable = dividerDrawable
+ }
+
+ override fun setLayoutParamsForTaskMenuOptionItem(
+ lp: LinearLayout.LayoutParams,
+ viewGroup: LinearLayout,
+ deviceProfile: DeviceProfile
+ ) {
+ // Phone fake landscape
+ viewGroup.orientation = LinearLayout.HORIZONTAL
+ lp.width = ViewGroup.LayoutParams.MATCH_PARENT
+ lp.height = ViewGroup.LayoutParams.WRAP_CONTENT
+ }
+
+ override fun getDwbLayoutTranslations(
+ taskViewWidth: Int,
+ taskViewHeight: Int,
+ splitBounds: SplitBounds?,
+ deviceProfile: DeviceProfile,
+ thumbnailViews: Array<View>,
+ desiredTaskId: Int,
+ banner: View
+ ): Pair<Float, Float> {
+ val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams
+ val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL
+ val translationX = banner.height.toFloat()
+
+ val bannerParams = banner.layoutParams as FrameLayout.LayoutParams
+ bannerParams.gravity = Gravity.TOP or if (isRtl) Gravity.END else Gravity.START
+ banner.pivotX = 0f
+ banner.pivotY = 0f
+ banner.rotation = degreesRotated
+
+ if (splitBounds == null) {
+ // Single, fullscreen case
+ bannerParams.width = taskViewHeight - snapshotParams.topMargin
+ return Pair(translationX, snapshotParams.topMargin.toFloat())
+ }
+
+ // Set correct width and translations
+ val translationY: Float
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ bannerParams.width = thumbnailViews[0].measuredHeight
+ translationY = snapshotParams.topMargin.toFloat()
+ } else {
+ bannerParams.width = thumbnailViews[1].measuredHeight
+ val topLeftTaskPlusDividerPercent =
+ if (splitBounds.appsStackedVertically) {
+ splitBounds.topTaskPercent + splitBounds.dividerHeightPercent
+ } else {
+ splitBounds.leftTaskPercent + splitBounds.dividerWidthPercent
+ }
+ translationY =
+ snapshotParams.topMargin +
+ (taskViewHeight - snapshotParams.topMargin) * topLeftTaskPlusDividerPercent
+ }
+
+ return Pair(translationX, translationY)
+ }
+
+ /* ---------- The following are only used by TaskViewTouchHandler. ---------- */
+ override val upDownSwipeDirection: SingleAxisSwipeDetector.Direction =
+ SingleAxisSwipeDetector.HORIZONTAL
+
+ override fun getUpDirection(isRtl: Boolean): Int =
+ if (isRtl) SingleAxisSwipeDetector.DIRECTION_NEGATIVE
+ else SingleAxisSwipeDetector.DIRECTION_POSITIVE
+
+ override fun isGoingUp(displacement: Float, isRtl: Boolean): Boolean =
+ if (isRtl) displacement < 0 else displacement > 0
+
+ override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) 1 else -1
+ /* -------------------- */
+
+ override fun getChildBounds(
+ child: View,
+ childStart: Int,
+ pageCenter: Int,
+ layoutChild: Boolean
+ ): ChildBounds {
+ val childHeight = child.measuredHeight
+ val childWidth = child.measuredWidth
+ val childBottom = childStart + childHeight
+ val childLeft = pageCenter - childWidth / 2
+ if (layoutChild) {
+ child.layout(childLeft, childStart, childLeft + childWidth, childBottom)
+ }
+ return ChildBounds(childHeight, childWidth, childBottom, childLeft)
+ }
+
+ override fun getDistanceToBottomOfRect(dp: DeviceProfile, rect: Rect): Int = rect.left
+
+ override fun getSplitPositionOptions(dp: DeviceProfile): List<SplitPositionOption> =
+ // Add "left" side of phone which is actually the top
+ listOf(
+ SplitPositionOption(
+ R.drawable.ic_split_horizontal,
+ R.string.recent_task_option_split_screen,
+ STAGE_POSITION_TOP_OR_LEFT,
+ STAGE_TYPE_MAIN
+ )
+ )
+
+ override fun getInitialSplitPlaceholderBounds(
+ placeholderHeight: Int,
+ placeholderInset: Int,
+ dp: DeviceProfile,
+ @StagePosition stagePosition: Int,
+ out: Rect
+ ) {
+ // In fake land/seascape, the placeholder always needs to go to the "top" of the device,
+ // which is the same bounds as 0 rotation.
+ val width = dp.widthPx
+ val insetSizeAdjustment = getPlaceholderSizeAdjustment(dp)
+ out.set(0, 0, width, placeholderHeight + insetSizeAdjustment)
+ out.inset(placeholderInset, 0)
+
+ // Adjust the top to account for content off screen. This will help to animate the view in
+ // with rounded corners.
+ val screenWidth = dp.widthPx
+ val screenHeight = dp.heightPx
+ val totalHeight =
+ (1.0f * screenHeight / 2 * (screenWidth - 2 * placeholderInset) / screenWidth).toInt()
+ out.top -= totalHeight - placeholderHeight
+ }
+
+ override fun updateSplitIconParams(
+ out: View,
+ onScreenRectCenterX: Float,
+ onScreenRectCenterY: Float,
+ fullscreenScaleX: Float,
+ fullscreenScaleY: Float,
+ drawableWidth: Int,
+ drawableHeight: Int,
+ dp: DeviceProfile,
+ @StagePosition stagePosition: Int
+ ) {
+ val insetAdjustment = getPlaceholderSizeAdjustment(dp) / 2f
+ out.x = (onScreenRectCenterX / fullscreenScaleX - 1.0f * drawableWidth / 2)
+ out.y =
+ ((onScreenRectCenterY + insetAdjustment) / fullscreenScaleY - 1.0f * drawableHeight / 2)
+ }
+
+ /**
+ * The split placeholder comes with a default inset to buffer the icon from the top of the
+ * screen. But if the device already has a large inset (from cutouts etc), use that instead.
+ */
+ private fun getPlaceholderSizeAdjustment(dp: DeviceProfile?): Int =
+ max((dp!!.insets.top - dp.splitPlaceholderInset).toDouble(), 0.0).toInt()
+
+ override fun setSplitInstructionsParams(
+ out: View,
+ dp: DeviceProfile,
+ splitInstructionsHeight: Int,
+ splitInstructionsWidth: Int
+ ) {
+ out.pivotX = 0f
+ out.pivotY = splitInstructionsHeight.toFloat()
+ out.rotation = degreesRotated
+ val distanceToEdge =
+ out.resources.getDimensionPixelSize(
+ R.dimen.split_instructions_bottom_margin_phone_landscape
+ )
+ // Adjust for any insets on the left edge
+ val insetCorrectionX = dp.insets.left
+ // Center the view in case of unbalanced insets on top or bottom of screen
+ val insetCorrectionY = (dp.insets.bottom - dp.insets.top) / 2
+ out.translationX = (distanceToEdge - insetCorrectionX).toFloat()
+ out.translationY =
+ (-splitInstructionsHeight - splitInstructionsWidth) / 2f + insetCorrectionY
+ // Setting gravity to LEFT instead of the lint-recommended START because we always want this
+ // view to be screen-left when phone is in landscape, regardless of the RtL setting.
+ val lp = out.layoutParams as FrameLayout.LayoutParams
+ lp.gravity = Gravity.LEFT or Gravity.CENTER_VERTICAL
+ out.layoutParams = lp
+ }
+
+ override fun getFinalSplitPlaceholderBounds(
+ splitDividerSize: Int,
+ dp: DeviceProfile,
+ @StagePosition stagePosition: Int,
+ out1: Rect,
+ out2: Rect
+ ) {
+ // In fake land/seascape, the window bounds are always top and bottom half
+ val screenHeight = dp.heightPx
+ val screenWidth = dp.widthPx
+ out1.set(0, 0, screenWidth, screenHeight / 2 - splitDividerSize)
+ out2.set(0, screenHeight / 2 + splitDividerSize, screenWidth, screenHeight)
+ }
+
+ override fun setSplitTaskSwipeRect(
+ dp: DeviceProfile,
+ outRect: Rect,
+ splitInfo: SplitBounds,
+ desiredStagePosition: Int
+ ) {
+ val topLeftTaskPercent: Float
+ val dividerBarPercent: Float
+ if (splitInfo.appsStackedVertically) {
+ topLeftTaskPercent = splitInfo.topTaskPercent
+ dividerBarPercent = splitInfo.dividerHeightPercent
+ } else {
+ topLeftTaskPercent = splitInfo.leftTaskPercent
+ dividerBarPercent = splitInfo.dividerWidthPercent
+ }
+
+ if (desiredStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+ outRect.bottom = outRect.top + (outRect.height() * topLeftTaskPercent).toInt()
+ } else {
+ outRect.top += (outRect.height() * (topLeftTaskPercent + dividerBarPercent)).toInt()
+ }
+ }
+
+ override fun measureGroupedTaskViewThumbnailBounds(
+ primarySnapshot: View,
+ secondarySnapshot: View,
+ parentWidth: Int,
+ parentHeight: Int,
+ splitBoundsConfig: SplitBounds,
+ dp: DeviceProfile,
+ isRtl: Boolean
+ ) {
+ val primaryParams = primarySnapshot.layoutParams as FrameLayout.LayoutParams
+ val secondaryParams = secondarySnapshot.layoutParams as FrameLayout.LayoutParams
+
+ // Swap the margins that are set in TaskView#setRecentsOrientedState()
+ secondaryParams.topMargin = dp.overviewTaskThumbnailTopMarginPx
+ primaryParams.topMargin = 0
+
+ // Measure and layout the thumbnails bottom up, since the primary is on the visual left
+ // (portrait bottom) and secondary is on the right (portrait top)
+ val spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx
+ val totalThumbnailHeight = parentHeight - spaceAboveSnapshot
+ val dividerBar = getDividerBarSize(totalThumbnailHeight, splitBoundsConfig)
+
+ val (taskViewFirst, taskViewSecond) =
+ getGroupedTaskViewSizes(dp, splitBoundsConfig, parentWidth, parentHeight)
+
+ primarySnapshot.translationY = spaceAboveSnapshot.toFloat()
+ primarySnapshot.measure(
+ MeasureSpec.makeMeasureSpec(taskViewFirst.x, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(taskViewFirst.y, MeasureSpec.EXACTLY)
+ )
+ val translationY = taskViewFirst.y + spaceAboveSnapshot + dividerBar
+ secondarySnapshot.translationY = (translationY - spaceAboveSnapshot).toFloat()
+ secondarySnapshot.measure(
+ MeasureSpec.makeMeasureSpec(taskViewSecond.x, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(taskViewSecond.y, MeasureSpec.EXACTLY)
+ )
+ }
+
+ override fun getGroupedTaskViewSizes(
+ dp: DeviceProfile,
+ splitBoundsConfig: SplitBounds,
+ parentWidth: Int,
+ parentHeight: Int
+ ): Pair<Point, Point> {
+ val spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx
+ val totalThumbnailHeight = parentHeight - spaceAboveSnapshot
+ val dividerBar = getDividerBarSize(totalThumbnailHeight, splitBoundsConfig)
+
+ val taskPercent =
+ if (splitBoundsConfig.appsStackedVertically) {
+ splitBoundsConfig.topTaskPercent
+ } else {
+ splitBoundsConfig.leftTaskPercent
+ }
+ val firstTaskViewSize = Point(parentWidth, (totalThumbnailHeight * taskPercent).toInt())
+ val secondTaskViewSize =
+ Point(parentWidth, totalThumbnailHeight - firstTaskViewSize.y - dividerBar)
+ return Pair(firstTaskViewSize, secondTaskViewSize)
+ }
+
+ override fun setTaskIconParams(
+ iconParams: FrameLayout.LayoutParams,
+ taskIconMargin: Int,
+ taskIconHeight: Int,
+ thumbnailTopMargin: Int,
+ isRtl: Boolean
+ ) {
+ iconParams.gravity =
+ if (isRtl) {
+ Gravity.START or Gravity.CENTER_VERTICAL
+ } else {
+ Gravity.END or Gravity.CENTER_VERTICAL
+ }
+ iconParams.rightMargin = -taskIconHeight - taskIconMargin / 2
+ iconParams.leftMargin = 0
+ iconParams.topMargin = thumbnailTopMargin / 2
+ iconParams.bottomMargin = 0
+ }
+
+ override fun setIconAppChipChildrenParams(
+ iconParams: FrameLayout.LayoutParams,
+ chipChildMarginStart: Int
+ ) {
+ iconParams.gravity = Gravity.START or Gravity.CENTER_VERTICAL
+ iconParams.marginStart = chipChildMarginStart
+ iconParams.topMargin = 0
+ }
+
+ override fun setIconAppChipMenuParams(
+ iconAppChipView: IconAppChipView,
+ iconMenuParams: FrameLayout.LayoutParams,
+ iconMenuMargin: Int,
+ thumbnailTopMargin: Int
+ ) {
+ val isRtl = iconAppChipView.layoutDirection == View.LAYOUT_DIRECTION_RTL
+
+ if (isRtl) {
+ iconMenuParams.gravity = Gravity.START or Gravity.BOTTOM
+ iconMenuParams.marginStart = iconMenuMargin
+ iconMenuParams.bottomMargin = iconMenuMargin
+ iconAppChipView.pivotX = iconMenuParams.width - iconMenuParams.height / 2f
+ iconAppChipView.pivotY = iconMenuParams.height / 2f
+ } else {
+ iconMenuParams.gravity = Gravity.END or Gravity.TOP
+ iconMenuParams.marginStart = 0
+ iconMenuParams.bottomMargin = 0
+ iconAppChipView.pivotX = iconMenuParams.width / 2f
+ iconAppChipView.pivotY = iconMenuParams.width / 2f
+ }
+
+ iconMenuParams.topMargin = iconMenuMargin
+ iconMenuParams.marginEnd = iconMenuMargin
+ iconAppChipView.setSplitTranslationY(0f)
+ iconAppChipView.setRotation(degreesRotated)
+ }
+
+ override fun setSplitIconParams(
+ primaryIconView: View,
+ secondaryIconView: View,
+ taskIconHeight: Int,
+ primarySnapshotWidth: Int,
+ primarySnapshotHeight: Int,
+ groupedTaskViewHeight: Int,
+ groupedTaskViewWidth: Int,
+ isRtl: Boolean,
+ deviceProfile: DeviceProfile,
+ splitConfig: SplitBounds
+ ) {
+ val spaceAboveSnapshot = deviceProfile.overviewTaskThumbnailTopMarginPx
+ val totalThumbnailHeight = groupedTaskViewHeight - spaceAboveSnapshot
+ val dividerBar: Int = getDividerBarSize(totalThumbnailHeight, splitConfig)
+
+ val (topLeftY, bottomRightY) =
+ getSplitIconsPosition(
+ taskIconHeight,
+ primarySnapshotHeight,
+ totalThumbnailHeight,
+ isRtl,
+ deviceProfile.overviewTaskMarginPx,
+ dividerBar
+ )
+
+ updateSplitIconsPosition(primaryIconView, topLeftY, isRtl)
+ updateSplitIconsPosition(secondaryIconView, bottomRightY, isRtl)
+ }
+
+ override fun getDefaultSplitPosition(deviceProfile: DeviceProfile): Int {
+ throw IllegalStateException("Default position not available in fake landscape")
+ }
+
+ override fun <T> getSplitSelectTaskOffset(
+ primary: FloatProperty<T>,
+ secondary: FloatProperty<T>,
+ deviceProfile: DeviceProfile
+ ): Pair<FloatProperty<T>, FloatProperty<T>> = Pair(primary, secondary)
+
+ override fun getFloatingTaskOffscreenTranslationTarget(
+ floatingTask: View,
+ onScreenRect: RectF,
+ @StagePosition stagePosition: Int,
+ dp: DeviceProfile
+ ): Float = floatingTask.translationY - onScreenRect.height()
+
+ override fun setFloatingTaskPrimaryTranslation(
+ floatingTask: View,
+ translation: Float,
+ dp: DeviceProfile
+ ) {
+ floatingTask.translationY = translation
+ }
+
+ override fun getFloatingTaskPrimaryTranslation(floatingTask: View, dp: DeviceProfile): Float =
+ floatingTask.translationY
+
+ /**
+ * Retrieves split icons position
+ *
+ * @param taskIconHeight The height of the task icon.
+ * @param primarySnapshotHeight The height for the primary snapshot (i.e., top-left snapshot).
+ * @param totalThumbnailHeight The total height for the group task view.
+ * @param isRtl Whether the layout direction is RTL (or false for LTR).
+ * @param overviewTaskMarginPx The space under the focused task icon provided by Device Profile.
+ * @param dividerSize The size of the divider for the group task view.
+ * @return The top-left and right-bottom positions for the icon views.
+ */
+ @VisibleForTesting
+ open fun getSplitIconsPosition(
+ taskIconHeight: Int,
+ primarySnapshotHeight: Int,
+ totalThumbnailHeight: Int,
+ isRtl: Boolean,
+ overviewTaskMarginPx: Int,
+ dividerSize: Int,
+ ): SplitIconPositions {
+ return if (Flags.enableOverviewIconMenu()) {
+ if (isRtl) {
+ SplitIconPositions(0, -(totalThumbnailHeight - primarySnapshotHeight))
+ } else {
+ SplitIconPositions(0, primarySnapshotHeight + dividerSize)
+ }
+ } else {
+ val topLeftY = primarySnapshotHeight + overviewTaskMarginPx
+ SplitIconPositions(
+ topLeftY = topLeftY,
+ bottomRightY = topLeftY + dividerSize + taskIconHeight
+ )
+ }
+ }
+
+ /**
+ * Updates icon view gravity and translation for split tasks
+ *
+ * @param iconView View to be updated
+ * @param translationY the translationY that should be applied
+ * @param isRtl Whether the layout direction is RTL (or false for LTR).
+ */
+ @SuppressLint("RtlHardcoded")
+ @VisibleForTesting
+ open fun updateSplitIconsPosition(iconView: View, translationY: Int, isRtl: Boolean) {
+ val layoutParams = iconView.layoutParams as FrameLayout.LayoutParams
+
+ if (Flags.enableOverviewIconMenu()) {
+ val appChipView = iconView as IconAppChipView
+ layoutParams.gravity =
+ if (isRtl) Gravity.BOTTOM or Gravity.START else Gravity.TOP or Gravity.END
+ appChipView.layoutParams = layoutParams
+ appChipView.setSplitTranslationX(0f)
+ appChipView.setSplitTranslationY(translationY.toFloat())
+ } else {
+ layoutParams.gravity = Gravity.TOP or Gravity.RIGHT
+ layoutParams.topMargin = translationY
+ iconView.translationX = 0f
+ iconView.translationY = 0f
+ iconView.layoutParams = layoutParams
+ }
+ }
+
+ /**
+ * It calculates the divider's size in the group task view.
+ *
+ * @param totalThumbnailHeight The total height for the group task view
+ * @param splitConfig Contains information about sizes and proportions for split task.
+ * @return The divider size for the group task view.
+ */
+ protected fun getDividerBarSize(totalThumbnailHeight: Int, splitConfig: SplitBounds): Int {
+ return Math.round(
+ totalThumbnailHeight *
+ if (splitConfig.appsStackedVertically) splitConfig.dividerHeightPercent
+ else splitConfig.dividerWidthPercent
+ )
+ }
+
+ /**
+ * Data structure to keep the y position to be used for the split task icon views translation.
+ *
+ * @param topLeftY The y-axis position for the task view position on the Top or Left side.
+ * @param bottomRightY The y-axis position for the task view position on the Bottom or Right
+ * side.
+ */
+ data class SplitIconPositions(val topLeftY: Int, val bottomRightY: Int)
+}
diff --git a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
index 60e6a25..0476fe8 100644
--- a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
+++ b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
@@ -75,6 +75,7 @@
public <T> T getSecondaryValue(T x, T y) {
return y;
}
+
@Override
public boolean isLayoutNaturalToLauncher() {
return true;
@@ -210,6 +211,12 @@
}
@Override
+ public int getTaskMenuHeight(float taskInsetMargin, DeviceProfile deviceProfile,
+ float taskMenuX, float taskMenuY) {
+ return (int) (deviceProfile.availableHeightPx - taskInsetMargin - taskMenuY);
+ }
+
+ @Override
public void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
LinearLayout taskMenuLayout, int dividerSpacing,
ShapeDrawable dividerDrawable) {
@@ -789,7 +796,7 @@
}
@Override
- public Float getFloatingTaskPrimaryTranslation(View floatingTask, DeviceProfile dp) {
+ public float getFloatingTaskPrimaryTranslation(View floatingTask, DeviceProfile dp) {
return dp.isLeftRightSplit
? floatingTask.getTranslationX()
: floatingTask.getTranslationY();
diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.java b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.java
deleted file mode 100644
index 01c1225..0000000
--- a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.java
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep.orientation;
-
-
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.drawable.ShapeDrawable;
-import android.util.FloatProperty;
-import android.util.Pair;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.LinearLayout;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.touch.PagedOrientationHandler;
-import com.android.launcher3.touch.SingleAxisSwipeDetector;
-import com.android.launcher3.util.SplitConfigurationOptions;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
-import com.android.launcher3.util.SplitConfigurationOptions.StagePosition;
-import com.android.quickstep.views.IconAppChipView;
-
-import java.util.List;
-
-/**
- * Abstraction layer to separate horizontal and vertical specific implementations
- * for {@link com.android.quickstep.views.RecentsView}. Majority of these implementations are
- * (should be) as simple as choosing the correct X and Y analogous methods.
- */
-public interface RecentsPagedOrientationHandler extends PagedOrientationHandler {
-
- RecentsPagedOrientationHandler PORTRAIT = new PortraitPagedViewHandler();
- RecentsPagedOrientationHandler LANDSCAPE = new LandscapePagedViewHandler();
- RecentsPagedOrientationHandler SEASCAPE = new SeascapePagedViewHandler();
-
- <T> void setSecondary(T target, Float2DAction<T> action, float param);
- <T> void set(T target, Int2DAction<T> action, int primaryParam, int secondaryParam);
- int getPrimarySize(View view);
- float getPrimarySize(RectF rect);
- int getSecondaryTranslationDirectionFactor();
- float getDegreesRotated();
- int getRotation();
- boolean isLayoutNaturalToLauncher();
-
- <T> T getPrimaryValue(T x, T y);
- <T> T getSecondaryValue(T x, T y);
- void setPrimaryScale(View view, float scale);
- void setSecondaryScale(View view, float scale);
- float getStart(RectF rect);
- float getEnd(RectF rect);
- int getClearAllSidePadding(View view, boolean isRtl);
- int getSecondaryDimension(View view);
- FloatProperty<View> getPrimaryViewTranslate();
- FloatProperty<View> getSecondaryViewTranslate();
- int getSplitTranslationDirectionFactor(@StagePosition int stagePosition,
- DeviceProfile deviceProfile);
- Pair<FloatProperty, FloatProperty> getSplitSelectTaskOffset(FloatProperty primary,
- FloatProperty secondary, DeviceProfile deviceProfile);
- int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect);
- List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp);
- /**
- * @param placeholderHeight height of placeholder view in portrait, width in landscape
- */
- void getInitialSplitPlaceholderBounds(int placeholderHeight, int placeholderInset,
- DeviceProfile dp, @StagePosition int stagePosition, Rect out);
-
- /**
- * Centers an icon in the split staging area, accounting for insets.
- * @param out The icon that needs to be centered.
- * @param onScreenRectCenterX The x-center of the on-screen staging area (most of the Rect is
- * offscreen).
- * @param onScreenRectCenterY The y-center of the on-screen staging area (most of the Rect is
- * offscreen).
- * @param fullscreenScaleX A x-scaling factor used to convert coordinates back into pixels.
- * @param fullscreenScaleY A y-scaling factor used to convert coordinates back into pixels.
- * @param drawableWidth The icon's drawable (final) width.
- * @param drawableHeight The icon's drawable (final) height.
- * @param dp The device profile, used to report rotation and hardware insets.
- * @param stagePosition 0 if the staging area is pinned to top/left, 1 for bottom/right.
- */
- void updateSplitIconParams(View out, float onScreenRectCenterX,
- float onScreenRectCenterY, float fullscreenScaleX, float fullscreenScaleY,
- int drawableWidth, int drawableHeight, DeviceProfile dp,
- @StagePosition int stagePosition);
-
- /**
- * Sets positioning and rotation for a SplitInstructionsView.
- * @param out The SplitInstructionsView that needs to be positioned.
- * @param dp The device profile, used to report rotation and device type.
- * @param splitInstructionsHeight The SplitInstructionView's height.
- * @param splitInstructionsWidth The SplitInstructionView's width.
- */
- void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
- int splitInstructionsWidth);
-
- /**
- * @param splitDividerSize height of split screen drag handle in portrait, width in landscape
- * @param stagePosition the split position option (top/left, bottom/right) of the first
- * task selected for entering split
- * @param out1 the bounds for where the first selected app will be
- * @param out2 the bounds for where the second selected app will be, complimentary to
- * {@param out1} based on {@param initialSplitOption}
- */
- void getFinalSplitPlaceholderBounds(int splitDividerSize, DeviceProfile dp,
- @StagePosition int stagePosition, Rect out1, Rect out2);
-
- int getDefaultSplitPosition(DeviceProfile deviceProfile);
-
- /**
- * @param outRect This is expected to be the rect that has the dimensions for a non-split,
- * fullscreen task in overview. This will directly be modified.
- * @param desiredStagePosition Which stage position (topLeft/rightBottom) we want to resize
- * outRect for
- */
- void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect, SplitBounds splitInfo,
- @SplitConfigurationOptions.StagePosition int desiredStagePosition);
-
- void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
- int parentWidth, int parentHeight,
- SplitBounds splitBoundsConfig, DeviceProfile dp, boolean isRtl);
-
- /**
- * Creates two Points representing the dimensions of the two tasks in a GroupedTaskView
- *
- * @return first -> primary task snapshot, second -> secondary task snapshot.
- * x -> width, y -> height
- */
- Pair<Point, Point> getGroupedTaskViewSizes(DeviceProfile dp, SplitBounds splitBoundsConfig,
- int parentWidth, int parentHeight);
-
- // Overview TaskMenuView methods
- /** Sets layout params on a task's app icon. Only use this when app chip is disabled. */
- void setTaskIconParams(FrameLayout.LayoutParams iconParams,
- int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl);
-
- /**
- * Sets layout params on the children of an app chip. Only use this when app chip is enabled.
- */
- void setIconAppChipChildrenParams(
- FrameLayout.LayoutParams iconParams, int chipChildMarginStart);
-
- void setIconAppChipMenuParams(IconAppChipView iconAppChipView,
- FrameLayout.LayoutParams iconMenuParams,
- int iconMenuMargin, int thumbnailTopMargin);
- void setSplitIconParams(View primaryIconView, View secondaryIconView,
- int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
- int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
- DeviceProfile deviceProfile, SplitBounds splitConfig);
-
- /*
- * The following two methods try to center the TaskMenuView in landscape by finding the center
- * of the thumbnail view and then subtracting half of the taskMenu width. In this case, the
- * taskMenu width is the same size as the thumbnail width (what got set below in
- * getTaskMenuWidth()), so we directly use that in the calculations.
- */
- float getTaskMenuX(float x, View thumbnailView, DeviceProfile deviceProfile,
- float taskInsetMargin, View taskViewIcon);
- float getTaskMenuY(float y, View thumbnailView, int stagePosition,
- View taskMenuView, float taskInsetMargin, View taskViewIcon);
- int getTaskMenuWidth(View thumbnailView, DeviceProfile deviceProfile,
- @StagePosition int stagePosition);
- /**
- * Sets linear layout orientation for {@link com.android.launcher3.popup.SystemShortcut} items
- * inside task menu view.
- */
- void setTaskOptionsMenuLayoutOrientation(DeviceProfile deviceProfile,
- LinearLayout taskMenuLayout, int dividerSpacing,
- ShapeDrawable dividerDrawable);
- /**
- * Sets layout param attributes for {@link com.android.launcher3.popup.SystemShortcut} child
- * views inside task menu view.
- */
- void setLayoutParamsForTaskMenuOptionItem(LinearLayout.LayoutParams lp,
- LinearLayout viewGroup, DeviceProfile deviceProfile);
-
- /**
- * Calculates the position where a Digital Wellbeing Banner should be placed on its parent
- * TaskView.
- * @return A Pair of Floats representing the proper x and y translations.
- */
- Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
- int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
- View[] thumbnailViews, int desiredTaskId, View banner);
-
- // The following are only used by TaskViewTouchHandler.
- /** @return Either VERTICAL or HORIZONTAL. */
- SingleAxisSwipeDetector.Direction getUpDownSwipeDirection();
- /** @return Given {@link #getUpDownSwipeDirection()}, whether POSITIVE or NEGATIVE is up. */
- int getUpDirection(boolean isRtl);
- /** @return Whether the displacement is going towards the top of the screen. */
- boolean isGoingUp(float displacement, boolean isRtl);
- /** @return Either 1 or -1, a factor to multiply by so the animation goes the correct way. */
- int getTaskDragDisplacementFactor(boolean isRtl);
-
- /**
- * Maps the velocity from the coordinate plane of the foreground app to that
- * of Launcher's (which now will always be portrait)
- */
- void adjustFloatingIconStartVelocity(PointF velocity);
-
- /**
- * Ensures that outStartRect left bound is within the DeviceProfile's visual boundaries
- * @param outStartRect The start rect that will directly be modified
- */
- void fixBoundsForHomeAnimStartRect(RectF outStartRect, DeviceProfile deviceProfile);
-
- /**
- * Determine the target translation for animating the FloatingTaskView out. This value could
- * either be an x-coordinate or a y-coordinate, depending on which way the FloatingTaskView was
- * docked.
- *
- * @param floatingTask The FloatingTaskView.
- * @param onScreenRect The current on-screen dimensions of the FloatingTaskView.
- * @param stagePosition STAGE_POSITION_TOP_OR_LEFT or STAGE_POSITION_BOTTOM_OR_RIGHT.
- * @param dp The device profile.
- * @return A float. When an animation translates the FloatingTaskView to this position, it will
- * appear to tuck away off the edge of the screen.
- */
- float getFloatingTaskOffscreenTranslationTarget(View floatingTask, RectF onScreenRect,
- @StagePosition int stagePosition, DeviceProfile dp);
-
- /**
- * Sets the translation of a FloatingTaskView along its "slide-in/slide-out" axis (could be
- * either x or y), depending on how the view is oriented.
- *
- * @param floatingTask The FloatingTaskView to be translated.
- * @param translation The target translation value.
- * @param dp The current device profile.
- */
- void setFloatingTaskPrimaryTranslation(View floatingTask, float translation, DeviceProfile dp);
-
- /**
- * Gets the translation of a FloatingTaskView along its "slide-in/slide-out" axis (could be
- * either x or y), depending on how the view is oriented.
- *
- * @param floatingTask The FloatingTaskView in question.
- * @param dp The current device profile.
- * @return The current translation value.
- */
- Float getFloatingTaskPrimaryTranslation(View floatingTask, DeviceProfile dp);
-}
diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
new file mode 100644
index 0000000..6c82890
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
@@ -0,0 +1,379 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.orientation
+
+import android.graphics.Point
+import android.graphics.PointF
+import android.graphics.Rect
+import android.graphics.RectF
+import android.graphics.drawable.ShapeDrawable
+import android.util.FloatProperty
+import android.util.Pair
+import android.view.View
+import android.widget.FrameLayout
+import android.widget.LinearLayout
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.touch.PagedOrientationHandler
+import com.android.launcher3.touch.PagedOrientationHandler.Float2DAction
+import com.android.launcher3.touch.PagedOrientationHandler.Int2DAction
+import com.android.launcher3.touch.SingleAxisSwipeDetector
+import com.android.launcher3.util.SplitConfigurationOptions
+import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption
+import com.android.launcher3.util.SplitConfigurationOptions.StagePosition
+import com.android.quickstep.views.IconAppChipView
+
+/**
+ * Abstraction layer to separate horizontal and vertical specific implementations for
+ * [com.android.quickstep.views.RecentsView]. Majority of these implementations are (should be) as
+ * simple as choosing the correct X and Y analogous methods.
+ */
+interface RecentsPagedOrientationHandler : PagedOrientationHandler {
+ fun <T> setSecondary(target: T, action: Float2DAction<T>, param: Float)
+
+ operator fun <T> set(target: T, action: Int2DAction<T>, primaryParam: Int, secondaryParam: Int)
+
+ fun getPrimarySize(view: View): Int
+
+ fun getPrimarySize(rect: RectF): Float
+
+ val secondaryTranslationDirectionFactor: Int
+
+ val degreesRotated: Float
+
+ val rotation: Int
+
+ val isLayoutNaturalToLauncher: Boolean
+
+ fun <T> getPrimaryValue(x: T, y: T): T
+
+ fun <T> getSecondaryValue(x: T, y: T): T
+
+ fun setPrimaryScale(view: View, scale: Float)
+
+ fun setSecondaryScale(view: View, scale: Float)
+
+ fun getStart(rect: RectF): Float
+
+ fun getEnd(rect: RectF): Float
+
+ fun getClearAllSidePadding(view: View, isRtl: Boolean): Int
+
+ fun getSecondaryDimension(view: View): Int
+
+ val primaryViewTranslate: FloatProperty<View>
+ val secondaryViewTranslate: FloatProperty<View>
+
+ fun getSplitTranslationDirectionFactor(
+ @StagePosition stagePosition: Int,
+ deviceProfile: DeviceProfile
+ ): Int
+
+ fun <T> getSplitSelectTaskOffset(
+ primary: FloatProperty<T>,
+ secondary: FloatProperty<T>,
+ deviceProfile: DeviceProfile
+ ): Pair<FloatProperty<T>, FloatProperty<T>>
+
+ fun getDistanceToBottomOfRect(dp: DeviceProfile, rect: Rect): Int
+
+ fun getSplitPositionOptions(dp: DeviceProfile): List<SplitPositionOption>
+
+ /** @param placeholderHeight height of placeholder view in portrait, width in landscape */
+ fun getInitialSplitPlaceholderBounds(
+ placeholderHeight: Int,
+ placeholderInset: Int,
+ dp: DeviceProfile,
+ @StagePosition stagePosition: Int,
+ out: Rect
+ )
+
+ /**
+ * Centers an icon in the split staging area, accounting for insets.
+ *
+ * @param out The icon that needs to be centered.
+ * @param onScreenRectCenterX The x-center of the on-screen staging area (most of the Rect is
+ * offscreen).
+ * @param onScreenRectCenterY The y-center of the on-screen staging area (most of the Rect is
+ * offscreen).
+ * @param fullscreenScaleX A x-scaling factor used to convert coordinates back into pixels.
+ * @param fullscreenScaleY A y-scaling factor used to convert coordinates back into pixels.
+ * @param drawableWidth The icon's drawable (final) width.
+ * @param drawableHeight The icon's drawable (final) height.
+ * @param dp The device profile, used to report rotation and hardware insets.
+ * @param stagePosition 0 if the staging area is pinned to top/left, 1 for bottom/right.
+ */
+ fun updateSplitIconParams(
+ out: View,
+ onScreenRectCenterX: Float,
+ onScreenRectCenterY: Float,
+ fullscreenScaleX: Float,
+ fullscreenScaleY: Float,
+ drawableWidth: Int,
+ drawableHeight: Int,
+ dp: DeviceProfile,
+ @StagePosition stagePosition: Int
+ )
+
+ /**
+ * Sets positioning and rotation for a SplitInstructionsView.
+ *
+ * @param out The SplitInstructionsView that needs to be positioned.
+ * @param dp The device profile, used to report rotation and device type.
+ * @param splitInstructionsHeight The SplitInstructionView's height.
+ * @param splitInstructionsWidth The SplitInstructionView's width.
+ */
+ fun setSplitInstructionsParams(
+ out: View,
+ dp: DeviceProfile,
+ splitInstructionsHeight: Int,
+ splitInstructionsWidth: Int
+ )
+
+ /**
+ * @param splitDividerSize height of split screen drag handle in portrait, width in landscape
+ * @param stagePosition the split position option (top/left, bottom/right) of the first task
+ * selected for entering split
+ * @param out1 the bounds for where the first selected app will be
+ * @param out2 the bounds for where the second selected app will be, complimentary to {@param
+ * out1} based on {@param initialSplitOption}
+ */
+ fun getFinalSplitPlaceholderBounds(
+ splitDividerSize: Int,
+ dp: DeviceProfile,
+ @StagePosition stagePosition: Int,
+ out1: Rect,
+ out2: Rect
+ )
+
+ fun getDefaultSplitPosition(deviceProfile: DeviceProfile): Int
+
+ /**
+ * @param outRect This is expected to be the rect that has the dimensions for a non-split,
+ * fullscreen task in overview. This will directly be modified.
+ * @param desiredStagePosition Which stage position (topLeft/rightBottom) we want to resize
+ * outRect for
+ */
+ fun setSplitTaskSwipeRect(
+ dp: DeviceProfile,
+ outRect: Rect,
+ splitInfo: SplitConfigurationOptions.SplitBounds,
+ @StagePosition desiredStagePosition: Int
+ )
+
+ fun measureGroupedTaskViewThumbnailBounds(
+ primarySnapshot: View,
+ secondarySnapshot: View,
+ parentWidth: Int,
+ parentHeight: Int,
+ splitBoundsConfig: SplitConfigurationOptions.SplitBounds,
+ dp: DeviceProfile,
+ isRtl: Boolean
+ )
+
+ /**
+ * Creates two Points representing the dimensions of the two tasks in a GroupedTaskView
+ *
+ * @return first -> primary task snapshot, second -> secondary task snapshot. x -> width, y ->
+ * height
+ */
+ fun getGroupedTaskViewSizes(
+ dp: DeviceProfile,
+ splitBoundsConfig: SplitConfigurationOptions.SplitBounds,
+ parentWidth: Int,
+ parentHeight: Int
+ ): Pair<Point, Point>
+ // Overview TaskMenuView methods
+ /** Sets layout params on a task's app icon. Only use this when app chip is disabled. */
+ fun setTaskIconParams(
+ iconParams: FrameLayout.LayoutParams,
+ taskIconMargin: Int,
+ taskIconHeight: Int,
+ thumbnailTopMargin: Int,
+ isRtl: Boolean
+ )
+
+ /**
+ * Sets layout params on the children of an app chip. Only use this when app chip is enabled.
+ */
+ fun setIconAppChipChildrenParams(
+ iconParams: FrameLayout.LayoutParams,
+ chipChildMarginStart: Int
+ )
+
+ fun setIconAppChipMenuParams(
+ iconAppChipView: IconAppChipView,
+ iconMenuParams: FrameLayout.LayoutParams,
+ iconMenuMargin: Int,
+ thumbnailTopMargin: Int
+ )
+
+ fun setSplitIconParams(
+ primaryIconView: View,
+ secondaryIconView: View,
+ taskIconHeight: Int,
+ primarySnapshotWidth: Int,
+ primarySnapshotHeight: Int,
+ groupedTaskViewHeight: Int,
+ groupedTaskViewWidth: Int,
+ isRtl: Boolean,
+ deviceProfile: DeviceProfile,
+ splitConfig: SplitConfigurationOptions.SplitBounds
+ )
+
+ /*
+ * The following two methods try to center the TaskMenuView in landscape by finding the center
+ * of the thumbnail view and then subtracting half of the taskMenu width. In this case, the
+ * taskMenu width is the same size as the thumbnail width (what got set below in
+ * getTaskMenuWidth()), so we directly use that in the calculations.
+ */
+ fun getTaskMenuX(
+ x: Float,
+ thumbnailView: View,
+ deviceProfile: DeviceProfile,
+ taskInsetMargin: Float,
+ taskViewIcon: View
+ ): Float
+
+ fun getTaskMenuY(
+ y: Float,
+ thumbnailView: View,
+ stagePosition: Int,
+ taskMenuView: View,
+ taskInsetMargin: Float,
+ taskViewIcon: View
+ ): Float
+
+ fun getTaskMenuWidth(
+ thumbnailView: View,
+ deviceProfile: DeviceProfile,
+ @StagePosition stagePosition: Int
+ ): Int
+
+ fun getTaskMenuHeight(
+ taskInsetMargin: Float,
+ deviceProfile: DeviceProfile,
+ taskMenuX: Float,
+ taskMenuY: Float
+ ): Int
+
+ /**
+ * Sets linear layout orientation for [com.android.launcher3.popup.SystemShortcut] items inside
+ * task menu view.
+ */
+ fun setTaskOptionsMenuLayoutOrientation(
+ deviceProfile: DeviceProfile,
+ taskMenuLayout: LinearLayout,
+ dividerSpacing: Int,
+ dividerDrawable: ShapeDrawable
+ )
+
+ /**
+ * Sets layout param attributes for [com.android.launcher3.popup.SystemShortcut] child views
+ * inside task menu view.
+ */
+ fun setLayoutParamsForTaskMenuOptionItem(
+ lp: LinearLayout.LayoutParams,
+ viewGroup: LinearLayout,
+ deviceProfile: DeviceProfile
+ )
+
+ /**
+ * Calculates the position where a Digital Wellbeing Banner should be placed on its parent
+ * TaskView.
+ *
+ * @return A Pair of Floats representing the proper x and y translations.
+ */
+ fun getDwbLayoutTranslations(
+ taskViewWidth: Int,
+ taskViewHeight: Int,
+ splitBounds: SplitConfigurationOptions.SplitBounds?,
+ deviceProfile: DeviceProfile,
+ thumbnailViews: Array<View>,
+ desiredTaskId: Int,
+ banner: View
+ ): Pair<Float, Float>
+ // The following are only used by TaskViewTouchHandler.
+
+ /** @return Either VERTICAL or HORIZONTAL. */
+ val upDownSwipeDirection: SingleAxisSwipeDetector.Direction
+
+ /** @return Given [.getUpDownSwipeDirection], whether POSITIVE or NEGATIVE is up. */
+ fun getUpDirection(isRtl: Boolean): Int
+
+ /** @return Whether the displacement is going towards the top of the screen. */
+ fun isGoingUp(displacement: Float, isRtl: Boolean): Boolean
+
+ /** @return Either 1 or -1, a factor to multiply by so the animation goes the correct way. */
+ fun getTaskDragDisplacementFactor(isRtl: Boolean): Int
+
+ /**
+ * Maps the velocity from the coordinate plane of the foreground app to that of Launcher's
+ * (which now will always be portrait)
+ */
+ fun adjustFloatingIconStartVelocity(velocity: PointF)
+
+ /**
+ * Ensures that outStartRect left bound is within the DeviceProfile's visual boundaries
+ *
+ * @param outStartRect The start rect that will directly be modified
+ */
+ fun fixBoundsForHomeAnimStartRect(outStartRect: RectF, deviceProfile: DeviceProfile)
+
+ /**
+ * Determine the target translation for animating the FloatingTaskView out. This value could
+ * either be an x-coordinate or a y-coordinate, depending on which way the FloatingTaskView was
+ * docked.
+ *
+ * @param floatingTask The FloatingTaskView.
+ * @param onScreenRect The current on-screen dimensions of the FloatingTaskView.
+ * @param stagePosition STAGE_POSITION_TOP_OR_LEFT or STAGE_POSITION_BOTTOM_OR_RIGHT.
+ * @param dp The device profile.
+ * @return A float. When an animation translates the FloatingTaskView to this position, it will
+ * appear to tuck away off the edge of the screen.
+ */
+ fun getFloatingTaskOffscreenTranslationTarget(
+ floatingTask: View,
+ onScreenRect: RectF,
+ @StagePosition stagePosition: Int,
+ dp: DeviceProfile
+ ): Float
+
+ /**
+ * Sets the translation of a FloatingTaskView along its "slide-in/slide-out" axis (could be
+ * either x or y), depending on how the view is oriented.
+ *
+ * @param floatingTask The FloatingTaskView to be translated.
+ * @param translation The target translation value.
+ * @param dp The current device profile.
+ */
+ fun setFloatingTaskPrimaryTranslation(floatingTask: View, translation: Float, dp: DeviceProfile)
+
+ /**
+ * Gets the translation of a FloatingTaskView along its "slide-in/slide-out" axis (could be
+ * either x or y), depending on how the view is oriented.
+ *
+ * @param floatingTask The FloatingTaskView in question.
+ * @param dp The current device profile.
+ * @return The current translation value.
+ */
+ fun getFloatingTaskPrimaryTranslation(floatingTask: View, dp: DeviceProfile): Float
+
+ companion object {
+ @JvmField val PORTRAIT: RecentsPagedOrientationHandler = PortraitPagedViewHandler()
+ @JvmField val LANDSCAPE: RecentsPagedOrientationHandler = LandscapePagedViewHandler()
+ @JvmField val SEASCAPE: RecentsPagedOrientationHandler = SeascapePagedViewHandler()
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.java
deleted file mode 100644
index a964639..0000000
--- a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.java
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.quickstep.orientation;
-
-import static android.view.Gravity.BOTTOM;
-import static android.view.Gravity.CENTER_VERTICAL;
-import static android.view.Gravity.END;
-import static android.view.Gravity.RIGHT;
-import static android.view.Gravity.START;
-import static android.view.Gravity.TOP;
-import static android.view.View.LAYOUT_DIRECTION_RTL;
-
-import static com.android.launcher3.Flags.enableOverviewIconMenu;
-import static com.android.launcher3.touch.SingleAxisSwipeDetector.HORIZONTAL;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
-import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN;
-
-import android.content.res.Resources;
-import android.graphics.Point;
-import android.graphics.PointF;
-import android.graphics.Rect;
-import android.util.Pair;
-import android.view.Gravity;
-import android.view.Surface;
-import android.view.View;
-import android.widget.FrameLayout;
-
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
-import com.android.launcher3.touch.SingleAxisSwipeDetector;
-import com.android.launcher3.util.SplitConfigurationOptions;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
-import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption;
-import com.android.launcher3.views.BaseDragLayer;
-import com.android.quickstep.views.IconAppChipView;
-
-import java.util.Collections;
-import java.util.List;
-
-public class SeascapePagedViewHandler extends LandscapePagedViewHandler {
-
- @Override
- public int getSecondaryTranslationDirectionFactor() {
- return -1;
- }
-
- @Override
- public int getSplitTranslationDirectionFactor(int stagePosition, DeviceProfile deviceProfile) {
- if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) {
- return -1;
- } else {
- return 1;
- }
- }
-
- @Override
- public boolean getRecentsRtlSetting(Resources resources) {
- return Utilities.isRtl(resources);
- }
-
- @Override
- public float getDegreesRotated() {
- return 270;
- }
-
- @Override
- public int getRotation() {
- return Surface.ROTATION_270;
- }
-
- @Override
- public void adjustFloatingIconStartVelocity(PointF velocity) {
- float oldX = velocity.x;
- float oldY = velocity.y;
- velocity.set(oldY, -oldX);
- }
-
- @Override
- public float getTaskMenuX(float x, View thumbnailView,
- DeviceProfile deviceProfile, float taskInsetMargin, View taskViewIcon) {
- return x + taskInsetMargin;
- }
-
- @Override
- public float getTaskMenuY(float y, View thumbnailView, int stagePosition,
- View taskMenuView, float taskInsetMargin, View taskViewIcon) {
- if (enableOverviewIconMenu()) {
- return y;
- }
- BaseDragLayer.LayoutParams lp = (BaseDragLayer.LayoutParams) taskMenuView.getLayoutParams();
- int taskMenuWidth = lp.width;
- if (stagePosition == STAGE_POSITION_UNDEFINED) {
- return y + taskInsetMargin
- + (thumbnailView.getMeasuredHeight() + taskMenuWidth) / 2f;
- } else {
- return y + taskMenuWidth + taskInsetMargin;
- }
- }
-
- @Override
- public void setSplitTaskSwipeRect(DeviceProfile dp, Rect outRect, SplitBounds splitInfo,
- int desiredStagePosition) {
- float topLeftTaskPercent = splitInfo.appsStackedVertically
- ? splitInfo.topTaskPercent
- : splitInfo.leftTaskPercent;
- float dividerBarPercent = splitInfo.appsStackedVertically
- ? splitInfo.dividerHeightPercent
- : splitInfo.dividerWidthPercent;
-
- // In seascape, the primary thumbnail is counterintuitively placed at the physical bottom of
- // the screen. This is to preserve consistency when the user rotates: From the user's POV,
- // the primary should always be on the left.
- if (desiredStagePosition == SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT) {
- outRect.top += (int) (outRect.height() * ((1 - topLeftTaskPercent)));
- } else {
- outRect.bottom -= (int) (outRect.height() * (topLeftTaskPercent + dividerBarPercent));
- }
- }
-
- @Override
- public Pair<Float, Float> getDwbLayoutTranslations(int taskViewWidth,
- int taskViewHeight, SplitBounds splitBounds, DeviceProfile deviceProfile,
- View[] thumbnailViews, int desiredTaskId, View banner) {
- boolean isRtl = banner.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
- float translationX = 0;
- float translationY = 0;
- FrameLayout.LayoutParams bannerParams = (FrameLayout.LayoutParams) banner.getLayoutParams();
- banner.setPivotX(0);
- banner.setPivotY(0);
- banner.setRotation(getDegreesRotated());
- translationX = taskViewWidth - banner.getHeight();
- FrameLayout.LayoutParams snapshotParams =
- (FrameLayout.LayoutParams) thumbnailViews[0]
- .getLayoutParams();
- bannerParams.gravity = BOTTOM | (isRtl ? END : START);
-
- if (splitBounds == null) {
- // Single, fullscreen case
- bannerParams.width = taskViewHeight - snapshotParams.topMargin;
- translationY = banner.getHeight();
- return new Pair<>(translationX, translationY);
- }
-
- // Set correct width
- if (desiredTaskId == splitBounds.leftTopTaskId) {
- bannerParams.width = thumbnailViews[0].getMeasuredHeight();
- } else {
- bannerParams.width = thumbnailViews[1].getMeasuredHeight();
- }
-
- // Set translations
- if (desiredTaskId == splitBounds.rightBottomTaskId) {
- translationY = banner.getHeight();
- }
- if (desiredTaskId == splitBounds.leftTopTaskId) {
- float bottomRightTaskPlusDividerPercent = splitBounds.appsStackedVertically
- ? (1f - splitBounds.topTaskPercent)
- : (1f - splitBounds.leftTaskPercent);
- translationY = banner.getHeight()
- - ((taskViewHeight - snapshotParams.topMargin)
- * bottomRightTaskPlusDividerPercent);
- }
- return new Pair<>(translationX, translationY);
- }
-
- @Override
- public int getDistanceToBottomOfRect(DeviceProfile dp, Rect rect) {
- return dp.widthPx - rect.right;
- }
-
- @Override
- public List<SplitPositionOption> getSplitPositionOptions(DeviceProfile dp) {
- // Add "right" option which is actually the top
- return Collections.singletonList(new SplitPositionOption(
- R.drawable.ic_split_horizontal, R.string.recent_task_option_split_screen,
- STAGE_POSITION_BOTTOM_OR_RIGHT, STAGE_TYPE_MAIN));
- }
-
- @Override
- public void setSplitInstructionsParams(View out, DeviceProfile dp, int splitInstructionsHeight,
- int splitInstructionsWidth) {
- out.setPivotX(0);
- out.setPivotY(splitInstructionsHeight);
- out.setRotation(getDegreesRotated());
- int distanceToEdge = out.getResources().getDimensionPixelSize(
- R.dimen.split_instructions_bottom_margin_phone_landscape);
- // Adjust for any insets on the right edge
- int insetCorrectionX = dp.getInsets().right;
- // Center the view in case of unbalanced insets on top or bottom of screen
- int insetCorrectionY = (dp.getInsets().bottom - dp.getInsets().top) / 2;
- out.setTranslationX(splitInstructionsWidth - distanceToEdge + insetCorrectionX);
- out.setTranslationY(((-splitInstructionsHeight + splitInstructionsWidth) / 2f)
- + insetCorrectionY);
- FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) out.getLayoutParams();
- // Setting gravity to RIGHT instead of the lint-recommended END because we always want this
- // view to be screen-right when phone is in seascape, regardless of the RtL setting.
- lp.gravity = RIGHT | CENTER_VERTICAL;
- out.setLayoutParams(lp);
- }
-
- @Override
- public void setTaskIconParams(FrameLayout.LayoutParams iconParams,
- int taskIconMargin, int taskIconHeight, int thumbnailTopMargin, boolean isRtl) {
- iconParams.gravity = (isRtl ? END : START) | CENTER_VERTICAL;
- iconParams.setMargins(-taskIconHeight - taskIconMargin / 2, thumbnailTopMargin / 2, 0, 0);
- }
-
- @Override
- public void setIconAppChipChildrenParams(FrameLayout.LayoutParams iconParams,
- int chipChildMarginStart) {
- iconParams.setMargins(0, 0, 0, 0);
- iconParams.setMarginStart(chipChildMarginStart);
- iconParams.gravity = Gravity.START | Gravity.CENTER_VERTICAL;
- }
-
- @Override
- public void setIconAppChipMenuParams(IconAppChipView iconAppChipView,
- FrameLayout.LayoutParams iconMenuParams, int iconMenuMargin, int thumbnailTopMargin) {
- boolean isRtl = iconAppChipView.getLayoutDirection() == LAYOUT_DIRECTION_RTL;
- iconMenuParams.gravity = (isRtl ? TOP : BOTTOM) | (isRtl ? END : START);
- iconMenuParams.setMarginStart(0);
- iconMenuParams.topMargin = isRtl ? iconMenuMargin : 0;
- iconMenuParams.bottomMargin = 0;
- iconMenuParams.setMarginEnd(isRtl ? thumbnailTopMargin : 0);
-
- // Use half menu height to place the pivot within the X/Y center of icon in the menu.
- float iconCenter = iconAppChipView.getHeight() / 2f;
- iconAppChipView.setPivotX(isRtl ? iconMenuParams.width / 2f : iconCenter);
- iconAppChipView.setPivotY(
- isRtl ? iconMenuParams.width / 2f : iconCenter - iconMenuMargin);
- iconAppChipView.setSplitTranslationY(0);
- iconAppChipView.setRotation(getDegreesRotated());
- }
-
- @Override
- public void setSplitIconParams(View primaryIconView, View secondaryIconView,
- int taskIconHeight, int primarySnapshotWidth, int primarySnapshotHeight,
- int groupedTaskViewHeight, int groupedTaskViewWidth, boolean isRtl,
- DeviceProfile deviceProfile, SplitBounds splitConfig) {
- super.setSplitIconParams(primaryIconView, secondaryIconView, taskIconHeight,
- primarySnapshotWidth, primarySnapshotHeight, groupedTaskViewHeight,
- groupedTaskViewWidth, isRtl, deviceProfile, splitConfig);
- FrameLayout.LayoutParams primaryIconParams =
- (FrameLayout.LayoutParams) primaryIconView.getLayoutParams();
- FrameLayout.LayoutParams secondaryIconParams =
- (FrameLayout.LayoutParams) secondaryIconView.getLayoutParams();
-
- // We calculate the "midpoint" of the thumbnail area, and place the icons there.
- // This is the place where the thumbnail area splits by default, in a near-50/50 split.
- // It is usually not exactly 50/50, due to insets/screen cutouts.
- int fullscreenInsetThickness = deviceProfile.getInsets().top
- - deviceProfile.getInsets().bottom;
- int fullscreenMidpointFromBottom = ((deviceProfile.heightPx
- - fullscreenInsetThickness) / 2);
- float midpointFromBottomPct = (float) fullscreenMidpointFromBottom / deviceProfile.heightPx;
- float insetPct = (float) fullscreenInsetThickness / deviceProfile.heightPx;
- int spaceAboveSnapshots = deviceProfile.overviewTaskThumbnailTopMarginPx;
- int overviewThumbnailAreaThickness = groupedTaskViewHeight - spaceAboveSnapshots;
- int bottomToMidpointOffset = (int) (overviewThumbnailAreaThickness * midpointFromBottomPct);
- int insetOffset = (int) (overviewThumbnailAreaThickness * insetPct);
-
- int gravity = (isRtl ? TOP : BOTTOM) | (isRtl ? END : START);
- primaryIconParams.gravity = gravity;
- secondaryIconParams.gravity = gravity;
- primaryIconView.setTranslationX(0);
- secondaryIconView.setTranslationX(0);
- if (enableOverviewIconMenu()) {
- IconAppChipView primaryAppChipView = (IconAppChipView) primaryIconView;
- IconAppChipView secondaryAppChipView = (IconAppChipView) secondaryIconView;
- if (isRtl) {
- primaryAppChipView.setSplitTranslationY(
- groupedTaskViewHeight - primarySnapshotHeight);
- secondaryAppChipView.setSplitTranslationY(0);
- } else {
- secondaryAppChipView.setSplitTranslationY(-primarySnapshotHeight);
- primaryAppChipView.setSplitTranslationY(0);
- }
- } else if (splitConfig.initiatedFromSeascape) {
- // if the split was initiated from seascape,
- // the task on the right (secondary) is slightly larger
- if (isRtl) {
- primaryIconView.setTranslationY(bottomToMidpointOffset - insetOffset
- + taskIconHeight);
- secondaryIconView.setTranslationY(bottomToMidpointOffset - insetOffset);
- } else {
- primaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset
- + taskIconHeight);
- secondaryIconView.setTranslationY(-bottomToMidpointOffset - insetOffset);
- }
- } else {
- // if not,
- // the task on the left (primary) is slightly larger
- if (isRtl) {
- primaryIconView.setTranslationY(bottomToMidpointOffset + taskIconHeight);
- secondaryIconView.setTranslationY(bottomToMidpointOffset);
- } else {
- primaryIconView.setTranslationY(-bottomToMidpointOffset + taskIconHeight);
- secondaryIconView.setTranslationY(-bottomToMidpointOffset);
- }
- }
-
- primaryIconView.setLayoutParams(primaryIconParams);
- secondaryIconView.setLayoutParams(secondaryIconParams);
- }
-
- @Override
- public void measureGroupedTaskViewThumbnailBounds(View primarySnapshot, View secondarySnapshot,
- int parentWidth, int parentHeight, SplitBounds splitBoundsConfig, DeviceProfile dp,
- boolean isRtl) {
- FrameLayout.LayoutParams primaryParams =
- (FrameLayout.LayoutParams) primarySnapshot.getLayoutParams();
- FrameLayout.LayoutParams secondaryParams =
- (FrameLayout.LayoutParams) secondarySnapshot.getLayoutParams();
-
- // Swap the margins that are set in TaskView#setRecentsOrientedState()
- secondaryParams.topMargin = dp.overviewTaskThumbnailTopMarginPx;
- primaryParams.topMargin = 0;
-
- // Measure and layout the thumbnails bottom up, since the primary is on the visual left
- // (portrait bottom) and secondary is on the right (portrait top)
- int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
- int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
- int dividerBar = Math.round(totalThumbnailHeight * (splitBoundsConfig.appsStackedVertically
- ? splitBoundsConfig.dividerHeightPercent
- : splitBoundsConfig.dividerWidthPercent));
-
- Pair<Point, Point> taskViewSizes =
- getGroupedTaskViewSizes(dp, splitBoundsConfig, parentWidth, parentHeight);
-
- secondarySnapshot.setTranslationY(0);
- primarySnapshot.setTranslationY(taskViewSizes.second.y + spaceAboveSnapshot + dividerBar);
-
- primarySnapshot.measure(
- View.MeasureSpec.makeMeasureSpec(taskViewSizes.first.x, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(taskViewSizes.first.y, View.MeasureSpec.EXACTLY)
- );
- secondarySnapshot.measure(
- View.MeasureSpec.makeMeasureSpec(taskViewSizes.second.x, View.MeasureSpec.EXACTLY),
- View.MeasureSpec.makeMeasureSpec(taskViewSizes.second.y, View.MeasureSpec.EXACTLY)
- );
- }
-
- @Override
- public Pair<Point, Point> getGroupedTaskViewSizes(
- DeviceProfile dp,
- SplitBounds splitBoundsConfig,
- int parentWidth,
- int parentHeight) {
- // Measure and layout the thumbnails bottom up, since the primary is on the visual left
- // (portrait bottom) and secondary is on the right (portrait top)
- int spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx;
- int totalThumbnailHeight = parentHeight - spaceAboveSnapshot;
- int dividerBar = Math.round(totalThumbnailHeight * (splitBoundsConfig.appsStackedVertically
- ? splitBoundsConfig.dividerHeightPercent
- : splitBoundsConfig.dividerWidthPercent));
- float taskPercent = splitBoundsConfig.appsStackedVertically
- ? splitBoundsConfig.topTaskPercent
- : splitBoundsConfig.leftTaskPercent;
-
- Point firstTaskViewSize = new Point(
- parentWidth,
- (int) (totalThumbnailHeight * taskPercent)
- );
- Point secondTaskViewSize = new Point(
- parentWidth,
- totalThumbnailHeight - firstTaskViewSize.y - dividerBar
- );
-
- return new Pair<>(firstTaskViewSize, secondTaskViewSize);
- }
-
- /* ---------- The following are only used by TaskViewTouchHandler. ---------- */
-
- @Override
- public SingleAxisSwipeDetector.Direction getUpDownSwipeDirection() {
- return HORIZONTAL;
- }
-
- @Override
- public int getUpDirection(boolean isRtl) {
- return isRtl ? SingleAxisSwipeDetector.DIRECTION_POSITIVE
- : SingleAxisSwipeDetector.DIRECTION_NEGATIVE;
- }
-
- @Override
- public boolean isGoingUp(float displacement, boolean isRtl) {
- return isRtl ? displacement > 0 : displacement < 0;
- }
-
- @Override
- public int getTaskDragDisplacementFactor(boolean isRtl) {
- return isRtl ? -1 : 1;
- }
-
- /* -------------------- */
-}
diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
new file mode 100644
index 0000000..5bebf8c
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
@@ -0,0 +1,398 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.orientation
+
+import android.annotation.SuppressLint
+import android.content.res.Resources
+import android.graphics.Point
+import android.graphics.PointF
+import android.graphics.Rect
+import android.util.Pair
+import android.view.Gravity
+import android.view.Surface
+import android.view.View
+import android.view.View.MeasureSpec
+import android.widget.FrameLayout
+import androidx.core.util.component1
+import androidx.core.util.component2
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.Flags
+import com.android.launcher3.R
+import com.android.launcher3.Utilities
+import com.android.launcher3.touch.SingleAxisSwipeDetector
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
+import com.android.launcher3.util.SplitConfigurationOptions.STAGE_TYPE_MAIN
+import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds
+import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption
+import com.android.launcher3.views.BaseDragLayer
+import com.android.quickstep.views.IconAppChipView
+
+class SeascapePagedViewHandler : LandscapePagedViewHandler() {
+ override val secondaryTranslationDirectionFactor: Int = -1
+
+ override fun getSplitTranslationDirectionFactor(
+ stagePosition: Int,
+ deviceProfile: DeviceProfile
+ ): Int = if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) -1 else 1
+
+ override fun getRecentsRtlSetting(resources: Resources): Boolean = Utilities.isRtl(resources)
+
+ override val degreesRotated: Float = 270f
+
+ override val rotation: Int = Surface.ROTATION_270
+
+ override fun adjustFloatingIconStartVelocity(velocity: PointF) =
+ velocity.set(velocity.y, -velocity.x)
+
+ override fun getTaskMenuX(
+ x: Float,
+ thumbnailView: View,
+ deviceProfile: DeviceProfile,
+ taskInsetMargin: Float,
+ taskViewIcon: View
+ ): Float = x + taskInsetMargin
+
+ override fun getTaskMenuY(
+ y: Float,
+ thumbnailView: View,
+ stagePosition: Int,
+ taskMenuView: View,
+ taskInsetMargin: Float,
+ taskViewIcon: View
+ ): Float {
+ if (Flags.enableOverviewIconMenu()) {
+ return y
+ }
+ val lp = taskMenuView.layoutParams as BaseDragLayer.LayoutParams
+ val taskMenuWidth = lp.width
+ return if (stagePosition == STAGE_POSITION_UNDEFINED) {
+ y + taskInsetMargin + (thumbnailView.measuredHeight + taskMenuWidth) / 2f
+ } else {
+ y + taskMenuWidth + taskInsetMargin
+ }
+ }
+
+ override fun getTaskMenuHeight(
+ taskInsetMargin: Float,
+ deviceProfile: DeviceProfile,
+ taskMenuX: Float,
+ taskMenuY: Float
+ ): Int = (deviceProfile.availableWidthPx - taskInsetMargin - taskMenuX).toInt()
+
+ override fun setSplitTaskSwipeRect(
+ dp: DeviceProfile,
+ outRect: Rect,
+ splitInfo: SplitBounds,
+ desiredStagePosition: Int
+ ) {
+ val topLeftTaskPercent: Float
+ val dividerBarPercent: Float
+ if (splitInfo.appsStackedVertically) {
+ topLeftTaskPercent = splitInfo.topTaskPercent
+ dividerBarPercent = splitInfo.dividerHeightPercent
+ } else {
+ topLeftTaskPercent = splitInfo.leftTaskPercent
+ dividerBarPercent = splitInfo.dividerWidthPercent
+ }
+
+ // In seascape, the primary thumbnail is counterintuitively placed at the physical bottom of
+ // the screen. This is to preserve consistency when the user rotates: From the user's POV,
+ // the primary should always be on the left.
+ if (desiredStagePosition == STAGE_POSITION_TOP_OR_LEFT) {
+ outRect.top += (outRect.height() * (1 - topLeftTaskPercent)).toInt()
+ } else {
+ outRect.bottom -= (outRect.height() * (topLeftTaskPercent + dividerBarPercent)).toInt()
+ }
+ }
+
+ override fun getDwbLayoutTranslations(
+ taskViewWidth: Int,
+ taskViewHeight: Int,
+ splitBounds: SplitBounds?,
+ deviceProfile: DeviceProfile,
+ thumbnailViews: Array<View>,
+ desiredTaskId: Int,
+ banner: View
+ ): Pair<Float, Float> {
+ val snapshotParams = thumbnailViews[0].layoutParams as FrameLayout.LayoutParams
+ val isRtl = banner.layoutDirection == View.LAYOUT_DIRECTION_RTL
+
+ val bannerParams = banner.layoutParams as FrameLayout.LayoutParams
+ bannerParams.gravity = Gravity.BOTTOM or if (isRtl) Gravity.END else Gravity.START
+ banner.pivotX = 0f
+ banner.pivotY = 0f
+ banner.rotation = degreesRotated
+
+ val translationX: Float = (taskViewWidth - banner.height).toFloat()
+ if (splitBounds == null) {
+ // Single, fullscreen case
+ bannerParams.width = taskViewHeight - snapshotParams.topMargin
+ return Pair(translationX, banner.height.toFloat())
+ }
+
+ // Set correct width and translations
+ val translationY: Float
+ if (desiredTaskId == splitBounds.leftTopTaskId) {
+ bannerParams.width = thumbnailViews[0].measuredHeight
+ val bottomRightTaskPlusDividerPercent =
+ if (splitBounds.appsStackedVertically) {
+ 1f - splitBounds.topTaskPercent
+ } else {
+ 1f - splitBounds.leftTaskPercent
+ }
+ translationY =
+ banner.height -
+ (taskViewHeight - snapshotParams.topMargin) * bottomRightTaskPlusDividerPercent
+ } else {
+ bannerParams.width = thumbnailViews[1].measuredHeight
+ translationY = banner.height.toFloat()
+ }
+
+ return Pair(translationX, translationY)
+ }
+
+ override fun getDistanceToBottomOfRect(dp: DeviceProfile, rect: Rect): Int =
+ dp.widthPx - rect.right
+
+ override fun getSplitPositionOptions(dp: DeviceProfile): List<SplitPositionOption> =
+ // Add "right" option which is actually the top
+ listOf(
+ SplitPositionOption(
+ R.drawable.ic_split_horizontal,
+ R.string.recent_task_option_split_screen,
+ STAGE_POSITION_BOTTOM_OR_RIGHT,
+ STAGE_TYPE_MAIN
+ )
+ )
+
+ override fun setSplitInstructionsParams(
+ out: View,
+ dp: DeviceProfile,
+ splitInstructionsHeight: Int,
+ splitInstructionsWidth: Int
+ ) {
+ out.pivotX = 0f
+ out.pivotY = splitInstructionsHeight.toFloat()
+ out.rotation = degreesRotated
+ val distanceToEdge =
+ out.resources.getDimensionPixelSize(
+ R.dimen.split_instructions_bottom_margin_phone_landscape
+ )
+ // Adjust for any insets on the right edge
+ val insetCorrectionX = dp.insets.right
+ // Center the view in case of unbalanced insets on top or bottom of screen
+ val insetCorrectionY = (dp.insets.bottom - dp.insets.top) / 2
+ out.translationX = (splitInstructionsWidth - distanceToEdge + insetCorrectionX).toFloat()
+ out.translationY =
+ (-splitInstructionsHeight + splitInstructionsWidth) / 2f + insetCorrectionY
+ // Setting gravity to RIGHT instead of the lint-recommended END because we always want this
+ // view to be screen-right when phone is in seascape, regardless of the RtL setting.
+ val lp = out.layoutParams as FrameLayout.LayoutParams
+ lp.gravity = Gravity.RIGHT or Gravity.CENTER_VERTICAL
+ out.layoutParams = lp
+ }
+
+ override fun setTaskIconParams(
+ iconParams: FrameLayout.LayoutParams,
+ taskIconMargin: Int,
+ taskIconHeight: Int,
+ thumbnailTopMargin: Int,
+ isRtl: Boolean
+ ) {
+ iconParams.gravity =
+ if (isRtl) {
+ Gravity.END or Gravity.CENTER_VERTICAL
+ } else {
+ Gravity.START or Gravity.CENTER_VERTICAL
+ }
+ iconParams.setMargins(-taskIconHeight - taskIconMargin / 2, thumbnailTopMargin / 2, 0, 0)
+ }
+
+ override fun setIconAppChipChildrenParams(
+ iconParams: FrameLayout.LayoutParams,
+ chipChildMarginStart: Int
+ ) {
+ iconParams.setMargins(0, 0, 0, 0)
+ iconParams.marginStart = chipChildMarginStart
+ iconParams.gravity = Gravity.START or Gravity.CENTER_VERTICAL
+ }
+
+ override fun setIconAppChipMenuParams(
+ iconAppChipView: IconAppChipView,
+ iconMenuParams: FrameLayout.LayoutParams,
+ iconMenuMargin: Int,
+ thumbnailTopMargin: Int
+ ) {
+ val isRtl = iconAppChipView.layoutDirection == View.LAYOUT_DIRECTION_RTL
+ val iconCenter = iconAppChipView.getHeight() / 2f
+
+ if (isRtl) {
+ iconMenuParams.gravity = Gravity.TOP or Gravity.END
+ iconMenuParams.topMargin = iconMenuMargin
+ iconMenuParams.marginEnd = thumbnailTopMargin
+ // Use half menu height to place the pivot within the X/Y center of icon in the menu.
+ iconAppChipView.pivotX = iconMenuParams.width / 2f
+ iconAppChipView.pivotY = iconMenuParams.width / 2f
+ } else {
+ iconMenuParams.gravity = Gravity.BOTTOM or Gravity.START
+ iconMenuParams.topMargin = 0
+ iconMenuParams.marginEnd = 0
+ iconAppChipView.pivotX = iconCenter
+ iconAppChipView.pivotY = iconCenter - iconMenuMargin
+ }
+ iconMenuParams.marginStart = 0
+ iconMenuParams.bottomMargin = 0
+ iconAppChipView.setSplitTranslationY(0f)
+ iconAppChipView.setRotation(degreesRotated)
+ }
+
+ override fun measureGroupedTaskViewThumbnailBounds(
+ primarySnapshot: View,
+ secondarySnapshot: View,
+ parentWidth: Int,
+ parentHeight: Int,
+ splitBoundsConfig: SplitBounds,
+ dp: DeviceProfile,
+ isRtl: Boolean
+ ) {
+ val primaryParams = primarySnapshot.layoutParams as FrameLayout.LayoutParams
+ val secondaryParams = secondarySnapshot.layoutParams as FrameLayout.LayoutParams
+
+ // Swap the margins that are set in TaskView#setRecentsOrientedState()
+ secondaryParams.topMargin = dp.overviewTaskThumbnailTopMarginPx
+ primaryParams.topMargin = 0
+
+ // Measure and layout the thumbnails bottom up, since the primary is on the visual left
+ // (portrait bottom) and secondary is on the right (portrait top)
+ val spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx
+ val totalThumbnailHeight = parentHeight - spaceAboveSnapshot
+ val dividerBar = getDividerBarSize(totalThumbnailHeight, splitBoundsConfig)
+
+ val (taskViewFirst, taskViewSecond) =
+ getGroupedTaskViewSizes(dp, splitBoundsConfig, parentWidth, parentHeight)
+ secondarySnapshot.translationY = 0f
+ primarySnapshot.translationY =
+ (taskViewSecond.y + spaceAboveSnapshot + dividerBar).toFloat()
+ primarySnapshot.measure(
+ MeasureSpec.makeMeasureSpec(taskViewFirst.x, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(taskViewFirst.y, MeasureSpec.EXACTLY)
+ )
+ secondarySnapshot.measure(
+ MeasureSpec.makeMeasureSpec(taskViewSecond.x, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(taskViewSecond.y, MeasureSpec.EXACTLY)
+ )
+ }
+
+ override fun getGroupedTaskViewSizes(
+ dp: DeviceProfile,
+ splitBoundsConfig: SplitBounds,
+ parentWidth: Int,
+ parentHeight: Int
+ ): Pair<Point, Point> {
+ // Measure and layout the thumbnails bottom up, since the primary is on the visual left
+ // (portrait bottom) and secondary is on the right (portrait top)
+ val spaceAboveSnapshot = dp.overviewTaskThumbnailTopMarginPx
+ val totalThumbnailHeight = parentHeight - spaceAboveSnapshot
+ val dividerBar = getDividerBarSize(totalThumbnailHeight, splitBoundsConfig)
+
+ val taskPercent =
+ if (splitBoundsConfig.appsStackedVertically) {
+ splitBoundsConfig.topTaskPercent
+ } else {
+ splitBoundsConfig.leftTaskPercent
+ }
+ val firstTaskViewSize = Point(parentWidth, (totalThumbnailHeight * taskPercent).toInt())
+ val secondTaskViewSize =
+ Point(parentWidth, totalThumbnailHeight - firstTaskViewSize.y - dividerBar)
+ return Pair(firstTaskViewSize, secondTaskViewSize)
+ }
+
+ /* ---------- The following are only used by TaskViewTouchHandler. ---------- */
+ override val upDownSwipeDirection: SingleAxisSwipeDetector.Direction =
+ SingleAxisSwipeDetector.HORIZONTAL
+
+ override fun getUpDirection(isRtl: Boolean): Int =
+ if (isRtl) SingleAxisSwipeDetector.DIRECTION_POSITIVE
+ else SingleAxisSwipeDetector.DIRECTION_NEGATIVE
+
+ override fun isGoingUp(displacement: Float, isRtl: Boolean): Boolean =
+ if (isRtl) displacement > 0 else displacement < 0
+
+ override fun getTaskDragDisplacementFactor(isRtl: Boolean): Int = if (isRtl) -1 else 1
+ /* -------------------- */
+
+ override fun getSplitIconsPosition(
+ taskIconHeight: Int,
+ primarySnapshotHeight: Int,
+ totalThumbnailHeight: Int,
+ isRtl: Boolean,
+ overviewTaskMarginPx: Int,
+ dividerSize: Int,
+ ): SplitIconPositions {
+ return if (Flags.enableOverviewIconMenu()) {
+ if (isRtl) {
+ SplitIconPositions(
+ topLeftY = totalThumbnailHeight - primarySnapshotHeight,
+ bottomRightY = 0
+ )
+ } else {
+ SplitIconPositions(
+ topLeftY = 0,
+ bottomRightY = -(primarySnapshotHeight + dividerSize)
+ )
+ }
+ } else {
+ // In seascape, the icons are initially placed at the bottom start of the
+ // display (portrait locked). The values defined here are used to translate the icons
+ // from the bottom to the almost-center of the screen using the bottom margin.
+ // The primary snapshot is placed at the bottom, thus we translate the icons using
+ // the size of the primary snapshot minus the icon size for the top-left icon.
+ SplitIconPositions(
+ topLeftY = primarySnapshotHeight - taskIconHeight,
+ bottomRightY = primarySnapshotHeight + dividerSize
+ )
+ }
+ }
+
+ /**
+ * Updates icon view gravity and translation for split tasks
+ *
+ * @param iconView View to be updated
+ * @param translationY the translationY that should be applied
+ * @param isRtl Whether the layout direction is RTL (or false for LTR).
+ */
+ @SuppressLint("RtlHardcoded")
+ override fun updateSplitIconsPosition(iconView: View, translationY: Int, isRtl: Boolean) {
+ val layoutParams = iconView.layoutParams as FrameLayout.LayoutParams
+
+ if (Flags.enableOverviewIconMenu()) {
+ val appChipView = iconView as IconAppChipView
+ layoutParams.gravity =
+ if (isRtl) Gravity.TOP or Gravity.END else Gravity.BOTTOM or Gravity.START
+ appChipView.layoutParams = layoutParams
+ appChipView.setSplitTranslationX(0f)
+ appChipView.setSplitTranslationY(translationY.toFloat())
+ } else {
+ layoutParams.gravity = Gravity.BOTTOM or Gravity.LEFT
+ iconView.translationX = 0f
+ iconView.translationY = 0f
+ layoutParams.bottomMargin = translationY
+ iconView.layoutParams = layoutParams
+ }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/AssistStateManager.java b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
index e9a06f7..660fc22 100644
--- a/quickstep/src/com/android/quickstep/util/AssistStateManager.java
+++ b/quickstep/src/com/android/quickstep/util/AssistStateManager.java
@@ -52,11 +52,6 @@
return Optional.empty();
}
- /** Whether search recovery is available. */
- public boolean isVisRecoveryEnabled() {
- return false;
- }
-
/** Return {@code true} if the Settings toggle is enabled. */
public boolean isSettingsNavHandleEnabled() {
return false;
diff --git a/quickstep/src/com/android/quickstep/util/BaseDepthController.java b/quickstep/src/com/android/quickstep/util/BaseDepthController.java
index 99f564c..5d6bb1d 100644
--- a/quickstep/src/com/android/quickstep/util/BaseDepthController.java
+++ b/quickstep/src/com/android/quickstep/util/BaseDepthController.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep.util;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
+
import android.app.WallpaperManager;
import android.os.IBinder;
import android.util.FloatProperty;
@@ -33,6 +35,9 @@
* Utility class for applying depth effect
*/
public class BaseDepthController {
+ public static final float DEPTH_0_PERCENT = 0f;
+ public static final float DEPTH_60_PERCENT = 0.6f;
+ public static final float DEPTH_70_PERCENT = 0.7f;
private static final FloatProperty<BaseDepthController> DEPTH =
new FloatProperty<BaseDepthController>("depth") {
@@ -127,10 +132,14 @@
float depth = mDepth;
IBinder windowToken = mLauncher.getRootView().getWindowToken();
if (windowToken != null) {
- // The API's full zoom-out is three times larger than the zoom-out we apply to the
- // icons. To keep the two consistent throughout the animation while keeping Launcher's
- // concept of full depth unchanged, we divide the depth by 3 here.
- mWallpaperManager.setWallpaperZoomOut(windowToken, depth / 3);
+ if (enableScalingRevealHomeAnimation()) {
+ mWallpaperManager.setWallpaperZoomOut(windowToken, depth);
+ } else {
+ // The API's full zoom-out is three times larger than the zoom-out we apply to the
+ // icons. To keep the two consistent throughout the animation while keeping
+ // Launcher's concept of full depth unchanged, we divide the depth by 3 here.
+ mWallpaperManager.setWallpaperZoomOut(windowToken, depth / 3);
+ }
}
if (!BlurUtils.supportsBlursOnWindows()) {
@@ -150,8 +159,15 @@
boolean hasOpaqueBg = mLauncher.getScrimView().isFullyOpaque();
boolean isSurfaceOpaque = !mHasContentBehindLauncher && hasOpaqueBg && !mPauseBlurs;
+ float blurAmount;
+ if (enableScalingRevealHomeAnimation()) {
+ blurAmount = mapDepthToBlur(depth);
+ } else {
+ blurAmount = depth;
+ }
mCurrentBlur = !mCrossWindowBlursEnabled || hasOpaqueBg || mPauseBlurs
- ? 0 : (int) (depth * mMaxBlurRadius);
+ ? 0 : (int) (blurAmount * mMaxBlurRadius);
+
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction()
.setBackgroundBlurRadius(mSurface, mCurrentBlur)
.setOpaque(mSurface, isSurfaceOpaque);
@@ -197,4 +213,12 @@
applyDepthAndBlur();
}
}
+
+ /**
+ * Maps depth values to blur amounts as a percentage of the max blur.
+ * The blur percentage grows linearly with depth, and maxes out at 30% depth.
+ */
+ private static float mapDepthToBlur(float depth) {
+ return Math.min(3 * depth, 1f);
+ }
}
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
index 245dde2..c39056d 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -15,6 +15,8 @@
*/
package com.android.quickstep.util;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
+
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.animation.Animator;
@@ -104,6 +106,8 @@
private float mCurrentScaleProgress;
private FlingSpringAnim mRectXAnim;
private FlingSpringAnim mRectYAnim;
+ private SpringAnimation mRectXSpring;
+ private SpringAnimation mRectYSpring;
private SpringAnimation mRectScaleAnim;
private boolean mAnimsStarted;
private boolean mRectXAnimEnded;
@@ -166,27 +170,47 @@
}
public void onTargetPositionChanged() {
- if (mRectXAnim != null && mRectXAnim.getTargetPosition() != mTargetRect.centerX()) {
- mRectXAnim.updatePosition(mCurrentCenterX, mTargetRect.centerX());
- }
+ if (enableScalingRevealHomeAnimation()) {
+ if (mRectXSpring != null) {
+ mRectXSpring.animateToFinalPosition(mTargetRect.centerX());
+ }
- if (mRectYAnim != null) {
- switch (mTracking) {
- case TRACKING_TOP:
- if (mRectYAnim.getTargetPosition() != mTargetRect.top) {
- mRectYAnim.updatePosition(mCurrentY, mTargetRect.top);
- }
- break;
- case TRACKING_BOTTOM:
- if (mRectYAnim.getTargetPosition() != mTargetRect.bottom) {
- mRectYAnim.updatePosition(mCurrentY, mTargetRect.bottom);
- }
- break;
- case TRACKING_CENTER:
- if (mRectYAnim.getTargetPosition() != mTargetRect.centerY()) {
- mRectYAnim.updatePosition(mCurrentY, mTargetRect.centerY());
- }
- break;
+ if (mRectYSpring != null) {
+ switch (mTracking) {
+ case TRACKING_TOP:
+ mRectYSpring.animateToFinalPosition(mTargetRect.top);
+ break;
+ case TRACKING_BOTTOM:
+ mRectYSpring.animateToFinalPosition(mTargetRect.bottom);
+ break;
+ case TRACKING_CENTER:
+ mRectYSpring.animateToFinalPosition(mTargetRect.centerY());
+ break;
+ }
+ }
+ } else {
+ if (mRectXAnim != null && mRectXAnim.getTargetPosition() != mTargetRect.centerX()) {
+ mRectXAnim.updatePosition(mCurrentCenterX, mTargetRect.centerX());
+ }
+
+ if (mRectYAnim != null) {
+ switch (mTracking) {
+ case TRACKING_TOP:
+ if (mRectYAnim.getTargetPosition() != mTargetRect.top) {
+ mRectYAnim.updatePosition(mCurrentY, mTargetRect.top);
+ }
+ break;
+ case TRACKING_BOTTOM:
+ if (mRectYAnim.getTargetPosition() != mTargetRect.bottom) {
+ mRectYAnim.updatePosition(mCurrentY, mTargetRect.bottom);
+ }
+ break;
+ case TRACKING_CENTER:
+ if (mRectYAnim.getTargetPosition() != mTargetRect.centerY()) {
+ mRectYAnim.updatePosition(mCurrentY, mTargetRect.centerY());
+ }
+ break;
+ }
}
}
}
@@ -215,59 +239,126 @@
maybeOnEnd();
});
- // We dampen the user velocity here to keep the natural feeling and to prevent the
- // rect from straying too from a linear path.
- final float xVelocityPxPerS = velocityPxPerMs.x * 1000;
- final float yVelocityPxPerS = velocityPxPerMs.y * 1000;
- final float dampedXVelocityPxPerS = OverScroll.dampedScroll(
- Math.abs(xVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(xVelocityPxPerS);
- final float dampedYVelocityPxPerS = OverScroll.dampedScroll(
- Math.abs(yVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(yVelocityPxPerS);
-
+ float xVelocityPxPerS = velocityPxPerMs.x * 1000;
+ float yVelocityPxPerS = velocityPxPerMs.y * 1000;
float startX = mCurrentCenterX;
float endX = mTargetRect.centerX();
- float minXValue = Math.min(startX, endX);
- float maxXValue = Math.max(startX, endX);
-
- mRectXAnim = new FlingSpringAnim(this, context, RECT_CENTER_X, startX, endX,
- dampedXVelocityPxPerS, mMinVisChange, minXValue, maxXValue, mDampingX, mStiffnessX,
- onXEndListener);
-
float startY = mCurrentY;
float endY = getTrackedYFromRect(mTargetRect);
- float minYValue = Math.min(startY, endY);
- float maxYValue = Math.max(startY, endY);
- mRectYAnim = new FlingSpringAnim(this, context, RECT_Y, startY, endY, dampedYVelocityPxPerS,
- mMinVisChange, minYValue, maxYValue, mDampingY, mStiffnessY, onYEndListener);
-
float minVisibleChange = Math.abs(1f / mStartRect.height());
- ResourceProvider rp = DynamicResource.provider(context);
- float damping = rp.getFloat(R.dimen.swipe_up_rect_scale_damping_ratio);
- // Increase the stiffness for devices where we want the window size to transform quicker.
- boolean shouldUseHigherStiffness = profile != null
- && (profile.isLandscape || profile.isTablet);
- float stiffness = shouldUseHigherStiffness
- ? rp.getFloat(R.dimen.swipe_up_rect_scale_higher_stiffness)
- : rp.getFloat(R.dimen.swipe_up_rect_scale_stiffness);
+ if (enableScalingRevealHomeAnimation()) {
+ ResourceProvider rp = DynamicResource.provider(context);
+ long minVelocityXPxPerS = rp.getInt(R.dimen.swipe_up_min_velocity_x_px_per_s);
+ long maxVelocityXPxPerS = rp.getInt(R.dimen.swipe_up_max_velocity_x_px_per_s);
+ long minVelocityYPxPerS = rp.getInt(R.dimen.swipe_up_min_velocity_y_px_per_s);
+ long maxVelocityYPxPerS = rp.getInt(R.dimen.swipe_up_max_velocity_y_px_per_s);
+ float fallOffFactor = rp.getFloat(R.dimen.swipe_up_max_velocity_fall_off_factor);
- mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
- .setSpring(new SpringForce(1f)
- .setDampingRatio(damping)
- .setStiffness(stiffness))
- .setStartVelocity(velocityPxPerMs.y * minVisibleChange)
- .setMaxValue(1f)
- .setMinimumVisibleChange(minVisibleChange)
- .addEndListener((animation, canceled, value, velocity) -> {
- mRectScaleAnimEnded = true;
- maybeOnEnd();
- });
+ // We want the actual initial velocity to never dip below the minimum, and to taper off
+ // once it's above the soft cap so that we can prevent the window from flying off
+ // screen, while maintaining a natural feel.
+ xVelocityPxPerS = adjustVelocity(
+ xVelocityPxPerS, minVelocityXPxPerS, maxVelocityXPxPerS, fallOffFactor);
+ yVelocityPxPerS = adjustVelocity(
+ yVelocityPxPerS, minVelocityYPxPerS, maxVelocityYPxPerS, fallOffFactor);
- setCanRelease(false);
- mAnimsStarted = true;
+ float stiffnessX = rp.getFloat(R.dimen.swipe_up_rect_x_stiffness);
+ float dampingX = rp.getFloat(R.dimen.swipe_up_rect_x_damping_ratio);
+ mRectXSpring =
+ new SpringAnimation(this, RECT_CENTER_X)
+ .setSpring(
+ new SpringForce(endX)
+ .setStiffness(stiffnessX)
+ .setDampingRatio(dampingX)
+ ).setStartValue(startX)
+ .setStartVelocity(xVelocityPxPerS)
+ .addEndListener(onXEndListener);
- mRectXAnim.start();
- mRectYAnim.start();
+ float stiffnessY = rp.getFloat(R.dimen.swipe_up_rect_y_stiffness);
+ float dampingY = rp.getFloat(R.dimen.swipe_up_rect_y_damping_ratio);
+ mRectYSpring =
+ new SpringAnimation(this, RECT_Y)
+ .setSpring(
+ new SpringForce(endY)
+ .setStiffness(stiffnessY)
+ .setDampingRatio(dampingY)
+ )
+ .setStartValue(startY)
+ .setStartVelocity(yVelocityPxPerS)
+ .addEndListener(onYEndListener);
+
+ float stiffnessZ = rp.getFloat(R.dimen.swipe_up_rect_scale_stiffness_v2);
+ float dampingZ = rp.getFloat(R.dimen.swipe_up_rect_scale_damping_ratio_v2);
+ mRectScaleAnim =
+ new SpringAnimation(this, RECT_SCALE_PROGRESS)
+ .setSpring(
+ new SpringForce(1f)
+ .setStiffness(stiffnessZ)
+ .setDampingRatio(dampingZ))
+ .setStartVelocity(velocityPxPerMs.y * minVisibleChange)
+ .setMinimumVisibleChange(minVisibleChange)
+ .addEndListener((animation, canceled, value, velocity) -> {
+ mRectScaleAnimEnded = true;
+ maybeOnEnd();
+ });
+
+ setCanRelease(false);
+ mAnimsStarted = true;
+
+ mRectXSpring.start();
+ mRectYSpring.start();
+ } else {
+ // We dampen the user velocity here to keep the natural feeling and to prevent the
+ // rect from straying too from a linear path.
+ final float dampedXVelocityPxPerS = OverScroll.dampedScroll(
+ Math.abs(xVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(xVelocityPxPerS);
+ final float dampedYVelocityPxPerS = OverScroll.dampedScroll(
+ Math.abs(yVelocityPxPerS), mMaxVelocityPxPerS) * Math.signum(yVelocityPxPerS);
+
+ float minXValue = Math.min(startX, endX);
+ float maxXValue = Math.max(startX, endX);
+
+ mRectXAnim = new FlingSpringAnim(this, context, RECT_CENTER_X, startX, endX,
+ dampedXVelocityPxPerS, mMinVisChange, minXValue, maxXValue, mDampingX,
+ mStiffnessX, onXEndListener);
+
+ float minYValue = Math.min(startY, endY);
+ float maxYValue = Math.max(startY, endY);
+ mRectYAnim = new FlingSpringAnim(this, context, RECT_Y, startY, endY,
+ dampedYVelocityPxPerS, mMinVisChange, minYValue, maxYValue, mDampingY,
+ mStiffnessY, onYEndListener);
+
+ ResourceProvider rp = DynamicResource.provider(context);
+ float damping = rp.getFloat(R.dimen.swipe_up_rect_scale_damping_ratio);
+
+ // Increase the stiffness for devices where we want the window size to transform
+ // quicker.
+ boolean shouldUseHigherStiffness = profile != null
+ && (profile.isLandscape || profile.isTablet);
+ float stiffness = shouldUseHigherStiffness
+ ? rp.getFloat(R.dimen.swipe_up_rect_scale_higher_stiffness)
+ : rp.getFloat(R.dimen.swipe_up_rect_scale_stiffness);
+
+ mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS)
+ .setSpring(new SpringForce(1f)
+ .setDampingRatio(damping)
+ .setStiffness(stiffness))
+ .setStartVelocity(velocityPxPerMs.y * minVisibleChange)
+ .setMaxValue(1f)
+ .setMinimumVisibleChange(minVisibleChange)
+ .addEndListener((animation, canceled, value, velocity) -> {
+ mRectScaleAnimEnded = true;
+ maybeOnEnd();
+ });
+
+ setCanRelease(false);
+ mAnimsStarted = true;
+
+ mRectXAnim.start();
+ mRectYAnim.start();
+ }
+
mRectScaleAnim.start();
for (Animator.AnimatorListener animatorListener : mAnimatorListeners) {
animatorListener.onAnimationStart(null);
@@ -276,8 +367,17 @@
public void end() {
if (mAnimsStarted) {
- mRectXAnim.end();
- mRectYAnim.end();
+ if (enableScalingRevealHomeAnimation()) {
+ if (mRectXSpring.canSkipToEnd()) {
+ mRectXSpring.skipToEnd();
+ }
+ if (mRectYSpring.canSkipToEnd()) {
+ mRectYSpring.skipToEnd();
+ }
+ } else {
+ mRectXAnim.end();
+ mRectYAnim.end();
+ }
if (mRectScaleAnim.canSkipToEnd()) {
mRectScaleAnim.skipToEnd();
}
@@ -357,6 +457,32 @@
end();
}
+ /**
+ * Modify the given velocity so that it's never below the minimum value, and falls off by the
+ * given factor once it goes above the maximum value.
+ * In order for the max soft cap to be enforced, the fall-off factor must be >1.
+ */
+ private static float adjustVelocity(float velocity, long min, long max, float factor) {
+ float sign = Math.signum(velocity);
+ float magnitude = Math.abs(velocity);
+
+ // If the absolute velocity is less than the min, bump it up.
+ if (magnitude < min) {
+ return min * sign;
+ }
+
+ // If the absolute velocity falls between min and max, or the fall-off factor is invalid,
+ // do nothing.
+ if (magnitude <= max || factor <= 1) {
+ return velocity;
+ }
+
+ // Scale the excess velocity by the fall-off factor.
+ float excess = magnitude - max;
+ float scaled = (float) Math.pow(excess, 1f / factor);
+ return (max + scaled) * sign;
+ }
+
public interface OnUpdateListener {
/**
* Called when an update is made to the animation.
diff --git a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
new file mode 100644
index 0000000..33736ad
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.util
+
+import android.view.View
+import com.android.app.animation.Interpolators
+import com.android.app.animation.Interpolators.EMPHASIZED
+import com.android.app.animation.Interpolators.LINEAR
+import com.android.launcher3.Launcher
+import com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY
+import com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WORKSPACE_STATE
+import com.android.launcher3.LauncherAnimUtils.WORKSPACE_SCALE_PROPERTY_FACTORY
+import com.android.launcher3.LauncherState
+import com.android.launcher3.anim.AnimatorListeners
+import com.android.launcher3.anim.PendingAnimation
+import com.android.launcher3.anim.PropertySetter
+import com.android.launcher3.states.StateAnimationConfig
+import com.android.launcher3.states.StateAnimationConfig.SKIP_DEPTH_CONTROLLER
+import com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW
+import com.android.launcher3.states.StateAnimationConfig.SKIP_SCRIM
+import com.android.launcher3.uioverrides.QuickstepLauncher
+import com.android.quickstep.views.RecentsView
+
+/**
+ * Creates an animation where the workspace and hotseat fade in while revealing from the center of
+ * the screen outwards radially. This is used in conjunction with the swipe up to home animation.
+ */
+class ScalingWorkspaceRevealAnim(launcher: Launcher) {
+ companion object {
+ private const val FADE_DURATION_MS = 200L
+ private const val SCALE_DURATION_MS = 1000L
+ private const val MAX_ALPHA = 1f
+ private const val MIN_ALPHA = 0f
+ private const val MAX_SIZE = 1f
+ private const val MIN_SIZE = 0.85f
+ }
+
+ private val animation = PendingAnimation(SCALE_DURATION_MS)
+
+ init {
+ // Make sure the starting state is right for the animation.
+ val config = StateAnimationConfig()
+ config.animFlags = SKIP_OVERVIEW.or(SKIP_DEPTH_CONTROLLER).or(SKIP_SCRIM)
+ config.duration = 0
+ launcher.stateManager
+ .createAtomicAnimation(LauncherState.BACKGROUND_APP, LauncherState.NORMAL, config)
+ .start()
+ launcher
+ .getOverviewPanel<RecentsView<QuickstepLauncher, LauncherState>>()
+ .forceFinishScroller()
+ launcher.workspace.stateTransitionAnimation.setScrim(
+ PropertySetter.NO_ANIM_PROPERTY_SETTER,
+ LauncherState.BACKGROUND_APP,
+ config
+ )
+
+ val workspace = launcher.workspace
+ val hotseat = launcher.hotseat
+
+ // Scale the Workspace and Hotseat around the same pivot.
+ animation.addFloat(
+ workspace,
+ WORKSPACE_SCALE_PROPERTY_FACTORY[SCALE_INDEX_WORKSPACE_STATE],
+ MIN_SIZE,
+ MAX_SIZE,
+ EMPHASIZED,
+ )
+ workspace.setPivotToScaleWithSelf(hotseat)
+ animation.addFloat(
+ hotseat,
+ HOTSEAT_SCALE_PROPERTY_FACTORY[SCALE_INDEX_WORKSPACE_STATE],
+ MIN_SIZE,
+ MAX_SIZE,
+ EMPHASIZED,
+ )
+
+ // Fade in quickly at the beginning of the animation, so the content doesn't look like it's
+ // popping into existence out of nowhere.
+ val fadeClamp = FADE_DURATION_MS.toFloat() / SCALE_DURATION_MS
+ workspace.alpha = MIN_ALPHA
+ animation.setViewAlpha(
+ workspace,
+ MAX_ALPHA,
+ Interpolators.clampToProgress(LINEAR, 0f, fadeClamp)
+ )
+ hotseat.alpha = MIN_ALPHA
+ animation.setViewAlpha(
+ hotseat,
+ MAX_ALPHA,
+ Interpolators.clampToProgress(LINEAR, 0f, fadeClamp)
+ )
+
+ // Match the Wallpaper animation to the rest of the content.
+ val depthController = (launcher as? QuickstepLauncher)?.depthController
+ val depthConfig = StateAnimationConfig()
+ depthConfig.setInterpolator(StateAnimationConfig.ANIM_DEPTH, EMPHASIZED)
+ depthController?.setStateWithAnimation(LauncherState.NORMAL, depthConfig, animation)
+
+ // Needed to avoid text artefacts during the scale animation.
+ workspace.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+ hotseat.setLayerType(View.LAYER_TYPE_HARDWARE, null)
+ animation.addListener(
+ AnimatorListeners.forEndCallback(
+ Runnable {
+ workspace.setLayerType(View.LAYER_TYPE_NONE, null)
+ hotseat.setLayerType(View.LAYER_TYPE_NONE, null)
+ }
+ )
+ )
+ }
+
+ fun start() {
+ animation.buildAnim().start()
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 6b3199f..d6d6a11 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -65,7 +65,7 @@
// Should be used for animations running alongside this StaggeredWorkspaceAnim.
public static final int DURATION_MS = 250;
public static final int DURATION_TASKBAR_MS =
- QuickstepTransitionManager.TASKBAR_TO_HOME_DURATION;
+ QuickstepTransitionManager.getTaskbarToHomeDuration();
private static final float MAX_VELOCITY_PX_PER_S = 22f;
diff --git a/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java b/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
index 7bbde30..c63a58e 100644
--- a/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
+++ b/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
@@ -28,6 +28,8 @@
import android.view.MotionEvent;
import android.view.VelocityTracker;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -41,21 +43,20 @@
private final float mMinFlingVelocity;
private final boolean mDisableHorizontalSwipe;
private final NavBarPosition mNavBarPosition;
- private final Runnable mOnInterceptTouch;
+
+ @NonNull
private final OnSwipeUpListener mOnSwipeUp;
private boolean mInterceptedTouch;
private VelocityTracker mVelocityTracker;
public TriggerSwipeUpTouchTracker(Context context, boolean disableHorizontalSwipe,
- NavBarPosition navBarPosition, Runnable onInterceptTouch,
- OnSwipeUpListener onSwipeUp) {
+ NavBarPosition navBarPosition, @NonNull OnSwipeUpListener onSwipeUp) {
mSquaredTouchSlop = Utilities.squaredTouchSlop(context);
mMinFlingVelocity = context.getResources().getDimension(
R.dimen.quickstep_fling_threshold_speed);
mNavBarPosition = navBarPosition;
mDisableHorizontalSwipe = disableHorizontalSwipe;
- mOnInterceptTouch = onInterceptTouch;
mOnSwipeUp = onSwipeUp;
init();
@@ -103,10 +104,7 @@
}
mInterceptedTouch = true;
-
- if (mOnInterceptTouch != null) {
- mOnInterceptTouch.run();
- }
+ mOnSwipeUp.onSwipeUpTouchIntercepted();
}
}
break;
@@ -124,7 +122,8 @@
}
}
- private void endTouchTracking() {
+ /** Finishes the tracking. All events after this call are ignored */
+ public void endTouchTracking() {
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
@@ -151,12 +150,10 @@
isSwipeUp = squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop;
}
- if (mOnSwipeUp != null) {
- if (isSwipeUp) {
- mOnSwipeUp.onSwipeUp(wasFling, new PointF(velocityX, velocityY));
- } else {
- mOnSwipeUp.onSwipeUpCancelled();
- }
+ if (isSwipeUp) {
+ mOnSwipeUp.onSwipeUp(wasFling, new PointF(velocityX, velocityY));
+ } else {
+ mOnSwipeUp.onSwipeUpCancelled();
}
}
@@ -172,6 +169,9 @@
void onSwipeUp(boolean wasFling, PointF finalVelocity);
/** Called on touch up if a swipe up was not detected. */
- void onSwipeUpCancelled();
+ default void onSwipeUpCancelled() { }
+
+ /** Called when the touch for swipe up is intercepted. */
+ default void onSwipeUpTouchIntercepted() { }
}
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 7a1c49a..e0091a5 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -106,6 +106,7 @@
public @interface AppPairButtonHiddenFlags { }
public static final int FLAG_SINGLE_TASK_HIDE_APP_PAIR = 1 << 0;
public static final int FLAG_SMALL_SCREEN_HIDE_APP_PAIR = 1 << 1;
+ public static final int FLAG_3P_LAUNCHER_HIDE_APP_PAIR = 1 << 2;
private MultiValueAlpha mMultiValueAlpha;
@@ -255,6 +256,13 @@
}
/**
+ * Updates flags to hide and show actions buttons for 1p/3p launchers.
+ */
+ public void updateFor3pLauncher(boolean is3pLauncher) {
+ updateAppPairButtonHiddenFlags(FLAG_3P_LAUNCHER_HIDE_APP_PAIR, is3pLauncher);
+ }
+
+ /**
* Updates the proper flags to indicate whether the "Screenshot" button should be hidden.
*
* @param flag The flag to update.
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 2cbeb31..af1dd3a 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -463,7 +463,6 @@
protected final Rect mLastComputedTaskSize = new Rect();
protected final Rect mLastComputedGridSize = new Rect();
protected final Rect mLastComputedGridTaskSize = new Rect();
- protected final Rect mLastComputedDesktopTaskSize = new Rect();
private TaskView mSelectedTask = null;
// How much a task that is directly offscreen will be pushed out due to RecentsView scale/pivot.
@Nullable
@@ -1271,6 +1270,8 @@
final SurfaceTransaction showTransaction = new SurfaceTransaction();
for (int i = apps.length - 1; i >= 0; --i) {
showTransaction.getTransaction().show(apps[i].leash);
+ showTransaction.forSurface(apps[i].leash).setLayer(
+ Integer.MAX_VALUE - 1000 + apps[i].prefixOrderIndex);
}
surfaceApplier.scheduleApply(showTransaction);
}
@@ -1658,15 +1659,8 @@
removeView(runningTaskView);
mMovingTaskView = null;
runningTaskView.resetPersistentViewTransforms();
- int frontTaskIndex = 0;
- if (isDesktopModeSupported() && mDesktopTaskView != null
- && !runningTaskView.isDesktopTask()) {
- // If desktop mode is enabled, desktop task view is pinned at first position if present.
- // Move running task to position 1.
- frontTaskIndex = 1;
- }
- addView(runningTaskView, frontTaskIndex);
- setCurrentPage(frontTaskIndex);
+ addView(runningTaskView, 0);
+ setCurrentPage(0);
updateTaskSize();
}
@@ -1743,7 +1737,6 @@
// Clear out desktop view if it is set
mDesktopTaskView = null;
- DesktopTask desktopTask = null;
// Add views as children based on whether it's grouped or single task. Looping through
// taskGroups backwards populates the thumbnail grid from least recent to most recent.
@@ -1752,12 +1745,6 @@
boolean isRemovalNeeded = stagedTaskIdToBeRemovedFromGrid != INVALID_TASK_ID
&& groupTask.containsTask(stagedTaskIdToBeRemovedFromGrid);
- if (groupTask instanceof DesktopTask) {
- desktopTask = (DesktopTask) groupTask;
- // Desktop task will be added separately in the end
- continue;
- }
-
TaskView taskView;
if (isRemovalNeeded && groupTask.hasMultipleTasks()) {
// If we need to remove half of a pair of tasks, force a TaskView with Type.SINGLE
@@ -1788,6 +1775,10 @@
((GroupedTaskView) taskView).bind(leftTopTask, rightBottomTask, mOrientationState,
groupTask.mSplitBounds);
+ } else if (taskView instanceof DesktopTaskView) {
+ ((DesktopTaskView) taskView).bind(((DesktopTask) groupTask).tasks,
+ mOrientationState);
+ mDesktopTaskView = (DesktopTaskView) taskView;
} else {
taskView.bind(groupTask.task1, mOrientationState);
}
@@ -1800,19 +1791,6 @@
if (!taskGroups.isEmpty()) {
addView(mClearAllButton);
- if (isDesktopModeSupported()) {
- // Check if we have apps on the desktop
- if (desktopTask != null && !desktopTask.tasks.isEmpty()) {
- // If we are actively choosing apps for split, skip the desktop tile
- if (!getSplitSelectController().isSplitSelectActive()) {
- mDesktopTaskView = (DesktopTaskView) getTaskViewFromPool(
- TaskView.Type.DESKTOP);
- // Always add a desktop task to the first position
- addView(mDesktopTaskView, 0);
- mDesktopTaskView.bind(desktopTask.tasks, mOrientationState);
- }
- }
- }
}
// Keep same previous focused task
@@ -1820,12 +1798,6 @@
// If the list changed, maybe the focused task doesn't exist anymore
if (newFocusedTaskView == null && getTaskViewCount() > 0) {
newFocusedTaskView = getTaskViewAt(0);
- // Check if the first task is the desktop.
- // If first task is desktop, try to find another task to set as the focused task
- if (newFocusedTaskView != null && newFocusedTaskView.isDesktopTask()
- && getTaskViewCount() > 1) {
- newFocusedTaskView = getTaskViewAt(1);
- }
}
mFocusedTaskViewId = newFocusedTaskView != null && !enableGridOnlyOverview()
? newFocusedTaskView.getTaskViewId() : INVALID_TASK_ID;
@@ -1869,12 +1841,7 @@
if (hasAnyValidTaskIds(runningTaskId)) {
targetPage = indexOfChild(newRunningTaskView);
} else if (getTaskViewCount() > 0) {
- TaskView taskView = requireTaskViewAt(0);
- // If first task id desktop, try to find another task to set the target page
- if (taskView.isDesktopTask() && getTaskViewCount() > 1) {
- taskView = requireTaskViewAt(1);
- }
- targetPage = indexOfChild(taskView);
+ targetPage = indexOfChild(requireTaskViewAt(0));
}
}
if (targetPage != -1 && mCurrentPage != targetPage) {
@@ -2119,9 +2086,6 @@
mSizeStrategy.calculateGridSize(dp, mActivity, mLastComputedGridSize);
mSizeStrategy.calculateGridTaskSize(mActivity, dp, mLastComputedGridTaskSize,
getPagedOrientationHandler());
- if (isDesktopModeSupported()) {
- mSizeStrategy.calculateDesktopTaskSize(mActivity, dp, mLastComputedDesktopTaskSize);
- }
if (enableGridOnlyOverview()) {
mSizeStrategy.calculateCarouselTaskSize(mActivity, dp, mLastComputedCarouselTaskSize,
getPagedOrientationHandler());
@@ -2222,11 +2186,6 @@
return mLastComputedGridTaskSize;
}
- /** Gets the last computed desktop task size */
- public Rect getLastComputedDesktopTaskSize() {
- return mLastComputedDesktopTaskSize;
- }
-
public Rect getLastComputedCarouselTaskSize() {
return mLastComputedCarouselTaskSize;
}
@@ -2977,8 +2936,6 @@
TaskView homeTaskView = getHomeTaskView();
TaskView nextFocusedTaskView = null;
- int desktopTaskIndex = Integer.MAX_VALUE;
-
if (!isTaskDismissal) {
mTopRowIdSet.clear();
}
@@ -3005,21 +2962,6 @@
// If focused task is snapped, the row width is just task width and spacing.
snappedTaskRowWidth = taskWidthAndSpacing;
}
- } else if (taskView.isDesktopTask()) {
- // Desktop task was not focused. Pin it to the right of focused
- desktopTaskIndex = i;
- if (taskView.getVisibility() == View.GONE) {
- // Desktop task view is hidden, skip it from grid calculations
- continue;
- }
- if (!enableGridOnlyOverview()) {
- // Only apply x-translation when using legacy overview grid
- gridTranslations[i] += mIsRtl ? taskWidthAndSpacing : -taskWidthAndSpacing;
- }
-
- // Center view vertically in case it's from different orientation.
- taskView.setGridTranslationY((mLastComputedDesktopTaskSize.height() + taskTopMargin
- - taskView.getLayoutParams().height) / 2f);
} else {
if (i > focusedTaskIndex) {
// For tasks after the focused task, shift by focused task's width and spacing.
@@ -3060,7 +3002,7 @@
// Move horizontally into empty space.
float widthOffset = 0;
for (int j = i - 1; !topSet.contains(j) && j >= 0; j--) {
- if (j == focusedTaskIndex || j == desktopTaskIndex) {
+ if (j == focusedTaskIndex) {
continue;
}
widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
@@ -3079,7 +3021,7 @@
// Move horizontally into empty space.
float widthOffset = 0;
for (int j = i - 1; !bottomSet.contains(j) && j >= 0; j--) {
- if (j == focusedTaskIndex || j == desktopTaskIndex) {
+ if (j == focusedTaskIndex) {
continue;
}
widthOffset += requireTaskViewAt(j).getLayoutParams().width + mPageSpacing;
@@ -4022,6 +3964,8 @@
mActionsView.updateForGroupedTask(isCurrentSplit);
// Update flags to see if actions bar should show buttons for tablets or phones.
mActionsView.updateForSmallScreen(!mActivity.getDeviceProfile().isTablet);
+ // Update flags for 1p/3p launchers
+ mActionsView.updateFor3pLauncher(!supportsAppPairs());
if (isDesktopModeSupported()) {
boolean isCurrentDesktop = getCurrentPageTaskView() instanceof DesktopTaskView;
@@ -4029,6 +3973,11 @@
}
}
+ /** Returns if app pairs are supported in this launcher. Overridden in subclasses. */
+ public boolean supportsAppPairs() {
+ return true;
+ }
+
/**
* Returns all the tasks in the top row, without the focused task
*/
@@ -4140,10 +4089,10 @@
private boolean snapToPageRelative(int delta, boolean cycle,
@TaskGridNavHelper.TASK_NAV_DIRECTION int direction) {
- // Ignore grid page snap events while scroll animations are running, otherwise the next
- // page gets set before the animation finishes and can cause jumps.
+ // Set next page if scroll animation is still running, otherwise cannot snap to the
+ // next page on successive key presses. Setting the current page aborts the scroll.
if (!mScroller.isFinished()) {
- return true;
+ setCurrentPage(getNextPage());
}
int pageCount = getPageCount();
if (pageCount == 0) {
@@ -4224,30 +4173,31 @@
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getAction() == KeyEvent.ACTION_DOWN) {
- switch (event.getKeyCode()) {
- case KeyEvent.KEYCODE_TAB:
- return snapToPageRelative(event.isShiftPressed() ? -1 : 1, true /* cycle */,
- DIRECTION_TAB);
- case KeyEvent.KEYCODE_DPAD_RIGHT:
- return snapToPageRelative(mIsRtl ? -1 : 1, true /* cycle */, DIRECTION_RIGHT);
- case KeyEvent.KEYCODE_DPAD_LEFT:
- return snapToPageRelative(mIsRtl ? 1 : -1, true /* cycle */, DIRECTION_LEFT);
- case KeyEvent.KEYCODE_DPAD_UP:
- return snapToPageRelative(1, false /* cycle */, DIRECTION_UP);
- case KeyEvent.KEYCODE_DPAD_DOWN:
- return snapToPageRelative(1, false /* cycle */, DIRECTION_DOWN);
- case KeyEvent.KEYCODE_DEL:
- case KeyEvent.KEYCODE_FORWARD_DEL:
+ if (isHandlingTouch() || event.getAction() != KeyEvent.ACTION_DOWN) {
+ return super.dispatchKeyEvent(event);
+ }
+ switch (event.getKeyCode()) {
+ case KeyEvent.KEYCODE_TAB:
+ return snapToPageRelative(event.isShiftPressed() ? -1 : 1, true /* cycle */,
+ DIRECTION_TAB);
+ case KeyEvent.KEYCODE_DPAD_RIGHT:
+ return snapToPageRelative(mIsRtl ? -1 : 1, true /* cycle */, DIRECTION_RIGHT);
+ case KeyEvent.KEYCODE_DPAD_LEFT:
+ return snapToPageRelative(mIsRtl ? 1 : -1, true /* cycle */, DIRECTION_LEFT);
+ case KeyEvent.KEYCODE_DPAD_UP:
+ return snapToPageRelative(1, false /* cycle */, DIRECTION_UP);
+ case KeyEvent.KEYCODE_DPAD_DOWN:
+ return snapToPageRelative(1, false /* cycle */, DIRECTION_DOWN);
+ case KeyEvent.KEYCODE_DEL:
+ case KeyEvent.KEYCODE_FORWARD_DEL:
+ dismissCurrentTask();
+ return true;
+ case KeyEvent.KEYCODE_NUMPAD_DOT:
+ if (event.isAltPressed()) {
+ // Numpad DEL pressed while holding Alt.
dismissCurrentTask();
return true;
- case KeyEvent.KEYCODE_NUMPAD_DOT:
- if (event.isAltPressed()) {
- // Numpad DEL pressed while holding Alt.
- dismissCurrentTask();
- return true;
- }
- }
+ }
}
return super.dispatchKeyEvent(event);
}
@@ -5024,7 +4974,7 @@
firstFloatingTaskView.update(mTempRectF, /*progress=*/1f);
RecentsPagedOrientationHandler orientationHandler = getPagedOrientationHandler();
- Pair<FloatProperty, FloatProperty> taskViewsFloat =
+ Pair<FloatProperty<RecentsView>, FloatProperty<RecentsView>> taskViewsFloat =
orientationHandler.getSplitSelectTaskOffset(
TASK_PRIMARY_SPLIT_TRANSLATION, TASK_SECONDARY_SPLIT_TRANSLATION,
mActivity.getDeviceProfile());
@@ -5162,9 +5112,13 @@
public float getMaxScaleForFullScreen() {
if (enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet
&& !mOverviewGridEnabled) {
+ if (mLastComputedCarouselTaskSize.isEmpty()) {
+ mSizeStrategy.calculateCarouselTaskSize(mActivity, mActivity.getDeviceProfile(),
+ mLastComputedCarouselTaskSize, getPagedOrientationHandler());
+ }
mTempRect.set(mLastComputedCarouselTaskSize);
} else {
- if (mLastComputedTaskSize.height() == 0 || mLastComputedTaskSize.width() == 0) {
+ if (mLastComputedTaskSize.isEmpty()) {
getTaskSize(mLastComputedTaskSize);
}
mTempRect.set(mLastComputedTaskSize);
@@ -5533,10 +5487,6 @@
}
private int getFirstViewIndex() {
- if (isDesktopModeSupported() && mDesktopTaskView != null) {
- // Desktop task is at position 0, that is the first view
- return 0;
- }
TaskView focusedTaskView = mShowAsGridLastOnLayout ? getFocusedTaskView() : null;
return focusedTaskView != null ? indexOfChild(focusedTaskView) : 0;
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 137455e..c9aad1a 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -140,11 +140,9 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- if (!enableOverviewIconMenu()) {
- int maxMenuHeight = calculateMaxHeight();
- if (MeasureSpec.getSize(heightMeasureSpec) > maxMenuHeight) {
- heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxMenuHeight, MeasureSpec.AT_MOST);
- }
+ int maxMenuHeight = calculateMaxHeight();
+ if (MeasureSpec.getSize(heightMeasureSpec) > maxMenuHeight) {
+ heightMeasureSpec = MeasureSpec.makeMeasureSpec(maxMenuHeight, MeasureSpec.AT_MOST);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@@ -416,10 +414,9 @@
* with a margin on the top and bottom.
*/
private int calculateMaxHeight() {
- float taskBottom = mTaskView.getHeight() + mTaskView.getPersistentTranslationY();
float taskInsetMargin = getResources().getDimension(R.dimen.task_card_margin);
-
- return (int) (taskBottom - taskInsetMargin - getTranslationY());
+ return mTaskView.getPagedOrientationHandler().getTaskMenuHeight(taskInsetMargin,
+ mActivity.getDeviceProfile(), getTranslationX(), getTranslationY());
}
private void setOnClosingStartCallback(Runnable onClosingStartCallback) {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 9b48082..5123364 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -30,6 +30,8 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_ICON_TAP_OR_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_TAP;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
+import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
+import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
@@ -861,6 +863,7 @@
@Nullable
public RunnableList launchTaskAnimated() {
if (mTask != null) {
+ testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "TaskView.launchTaskAnimated");
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
ActivityOptionsWrapper opts = mActivity.getActivityLaunchOptions(this, null);
@@ -909,6 +912,7 @@
*/
public void launchTask(@NonNull Consumer<Boolean> callback, boolean isQuickswitch) {
if (mTask != null) {
+ testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "TaskView.launchTaskAnimated");
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "startActivityFromRecentsAsync", mTask);
@@ -1733,12 +1737,7 @@
int boxWidth;
int boxHeight;
boolean isFocusedTask = isFocusedTask();
- if (isDesktopTask()) {
- Rect lastComputedDesktopTaskSize =
- getRecentsView().getLastComputedDesktopTaskSize();
- boxWidth = lastComputedDesktopTaskSize.width();
- boxHeight = lastComputedDesktopTaskSize.height();
- } else if (isFocusedTask) {
+ if (isFocusedTask) {
// Task will be focused and should use focused task size. Use focusTaskRatio
// that is associated with the original orientation of the focused task.
boxWidth = taskWidth;
diff --git a/quickstep/tests/src/com/android/launcher3/model/AppEventProducerTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/model/AppEventProducerTest.java
similarity index 100%
rename from quickstep/tests/src/com/android/launcher3/model/AppEventProducerTest.java
rename to quickstep/tests/multivalentTests/src/com/android/launcher3/model/AppEventProducerTest.java
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java
similarity index 100%
rename from quickstep/tests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java
rename to quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/RecentsHitboxExtenderTest.java
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
similarity index 100%
rename from quickstep/tests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
rename to quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt
new file mode 100644
index 0000000..73b35e8
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AllAppsActionManagerTest.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep
+
+import android.app.PendingIntent
+import android.content.IIntentSender
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
+import com.android.launcher3.util.TestUtil
+import com.google.common.truth.Truth.assertThat
+import java.util.concurrent.Semaphore
+import java.util.concurrent.TimeUnit.SECONDS
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val TIMEOUT = 5L
+
+@RunWith(AndroidJUnit4::class)
+class AllAppsActionManagerTest {
+ private val callbackSemaphore = Semaphore(0)
+ private val bgExecutor = UI_HELPER_EXECUTOR
+
+ private val allAppsActionManager =
+ AllAppsActionManager(
+ InstrumentationRegistry.getInstrumentation().targetContext,
+ bgExecutor,
+ ) {
+ callbackSemaphore.release()
+ PendingIntent(IIntentSender.Default())
+ }
+
+ @Test
+ fun taskbarPresent_actionRegistered() {
+ allAppsActionManager.isTaskbarPresent = true
+ assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+ assertThat(allAppsActionManager.isActionRegistered).isTrue()
+ }
+
+ @Test
+ fun homeAndOverviewSame_actionRegistered() {
+ allAppsActionManager.isHomeAndOverviewSame = true
+ assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+ assertThat(allAppsActionManager.isActionRegistered).isTrue()
+ }
+
+ @Test
+ fun toggleTaskbar_destroyedAfterActionRegistered_actionUnregistered() {
+ allAppsActionManager.isTaskbarPresent = true
+ assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+
+ allAppsActionManager.isTaskbarPresent = false
+ TestUtil.runOnExecutorSync(bgExecutor) {} // Force system action to unregister.
+ assertThat(allAppsActionManager.isActionRegistered).isFalse()
+ }
+
+ @Test
+ fun toggleTaskbar_destroyedBeforeActionRegistered_pendingActionUnregistered() {
+ allAppsActionManager.isTaskbarPresent = true
+ allAppsActionManager.isTaskbarPresent = false
+
+ TestUtil.runOnExecutorSync(bgExecutor) {} // Force system action to unregister.
+ assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+ assertThat(allAppsActionManager.isActionRegistered).isFalse()
+ }
+
+ @Test
+ fun changeHome_sameAsOverviewBeforeActionUnregistered_actionRegisteredAgain() {
+ allAppsActionManager.isHomeAndOverviewSame = true // Initialize to same.
+ assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+
+ allAppsActionManager.isHomeAndOverviewSame = false
+ allAppsActionManager.isHomeAndOverviewSame = true
+ assertThat(callbackSemaphore.tryAcquire(TIMEOUT, SECONDS)).isTrue()
+ assertThat(allAppsActionManager.isActionRegistered).isTrue()
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationBarRotationContextTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/NavigationBarRotationContextTest.java
similarity index 100%
rename from quickstep/tests/src/com/android/quickstep/NavigationBarRotationContextTest.java
rename to quickstep/tests/multivalentTests/src/com/android/quickstep/NavigationBarRotationContextTest.java
diff --git a/quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
similarity index 100%
rename from quickstep/tests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
rename to quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
diff --git a/quickstep/tests/src/com/android/quickstep/util/TaskGridNavHelperTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.java
similarity index 100%
rename from quickstep/tests/src/com/android/quickstep/util/TaskGridNavHelperTest.java
rename to quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskGridNavHelperTest.java
diff --git a/quickstep/tests/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCacheTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCacheTest.java
similarity index 100%
rename from quickstep/tests/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCacheTest.java
rename to quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCacheTest.java
diff --git a/quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
similarity index 100%
rename from quickstep/tests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
rename to quickstep/tests/multivalentTests/src/com/android/quickstep/util/TaskViewSimulatorTest.java
diff --git a/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java b/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
index 37dde10..8702f70 100644
--- a/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
+++ b/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.model;
+import static android.content.pm.ApplicationInfo.CATEGORY_PRODUCTIVITY;
+import static android.content.pm.ApplicationInfo.FLAG_INSTALLED;
import static android.os.Process.myUserHandle;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
@@ -37,6 +39,8 @@
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ComponentName;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.LauncherApps;
import android.os.UserHandle;
import android.platform.test.flag.junit.SetFlagsRule;
import android.text.TextUtils;
@@ -81,6 +85,8 @@
private FakeBgDataModelCallback mCallback = new FakeBgDataModelCallback();
private LauncherModelHelper mModelHelper;
private UserHandle mUserHandle;
+ private LauncherApps mLauncherApps;
+
@Before
public void setup() throws Exception {
@@ -103,12 +109,18 @@
allWidgets = Arrays.asList(mApp1Provider1, mApp1Provider2, mApp2Provider1,
mApp4Provider1, mApp4Provider2, mApp5Provider1);
+ mLauncherApps = mModelHelper.sandboxContext.spyService(LauncherApps.class);
doAnswer(i -> {
String pkg = i.getArgument(0);
- return ApplicationInfoBuilder.newBuilder().setPackageName(pkg).setName(
- "App " + pkg).build();
- }).when(mModelHelper.sandboxContext.getPackageManager())
- .getApplicationInfo(anyString(), anyInt());
+ ApplicationInfo applicationInfo = ApplicationInfoBuilder.newBuilder()
+ .setPackageName(pkg)
+ .setName("App " + pkg)
+ .build();
+ applicationInfo.category = CATEGORY_PRODUCTIVITY;
+ applicationInfo.flags = FLAG_INSTALLED;
+ return applicationInfo;
+ }).when(mLauncherApps).getApplicationInfo(anyString(), anyInt(), any());
+
AppWidgetManager manager = mModelHelper.sandboxContext.spyService(AppWidgetManager.class);
doReturn(allWidgets).when(manager).getInstalledProviders();
doReturn(allWidgets).when(manager).getInstalledProvidersForProfile(eq(myUserHandle()));
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 213f58f..077ca60 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -76,17 +76,21 @@
import org.junit.runner.RunWith;
import org.junit.runners.model.Statement;
+import java.io.IOException;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
@LargeTest
@RunWith(AndroidJUnit4.class)
public class FallbackRecentsTest {
private static final String FALLBACK_LAUNCHER_TITLE = "Test launcher";
+ private static final Pattern COMPONENT_INFO_REGEX = Pattern.compile("ComponentInfo\\{(.*)\\}");
private final UiDevice mDevice;
private final LauncherInstrumentation mLauncher;
@@ -253,7 +257,7 @@
//@NavigationModeSwitch
@Test
@ScreenRecordRule.ScreenRecord // b/321775748
- public void testOverview() {
+ public void testOverview() throws IOException {
startAppFast(getAppPackageName());
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
startTestActivity(2);
@@ -261,7 +265,10 @@
Wait.atMost("Expected three apps in the task list",
() -> mLauncher.getRecentTasks().size() >= 3, DEFAULT_ACTIVITY_TIMEOUT, mLauncher);
+ checkTestLauncher();
BaseOverview overview = mLauncher.getLaunchedAppState().switchToOverview();
+ checkTestLauncher();
+
executeOnRecents(recents -> {
assertTrue("Don't have at least 3 tasks", getTaskCount(recents) >= 3);
});
@@ -303,6 +310,17 @@
mOtherLauncherActivity.packageName).text(FALLBACK_LAUNCHER_TITLE)), WAIT_TIME_MS));
}
+ private void checkTestLauncher() throws IOException {
+ final Matcher matcher = COMPONENT_INFO_REGEX.matcher(
+ mDevice.executeShellCommand("cmd shortcut get-default-launcher"));
+ assertTrue("Incorrect output from get-default-launcher", matcher.find());
+ assertEquals("Current Launcher activity is incorrect",
+ "com.google.android.apps.nexuslauncher.tests/com.android"
+ + ".launcher3.testcomponent.TestLauncherActivity",
+ matcher.group(1)
+ );
+ }
+
private int getCurrentOverviewPage(RecentsActivity recents) {
return recents.<RecentsView>getOverviewPanel().getCurrentPage();
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 45a9527..a53bb4e 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -35,7 +35,6 @@
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.Until;
-import com.android.launcher3.Flags;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.tapl.LaunchedAppState;
@@ -421,7 +420,6 @@
READ_DEVICE_CONFIG_PERMISSION);
// Debug if we need to goHome to prevent wrong previous state b/315525621
mLauncher.goHome();
- assumeFalse(Flags.enablePredictiveBackGesture());
mLauncher.getWorkspace().switchToAllApps().pressBackToWorkspace();
waitForState("Launcher internal state didn't switch to Home", () -> LauncherState.NORMAL);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
index aa8c7b5..374722e 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -19,7 +19,6 @@
import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import android.app.Instrumentation;
@@ -28,7 +27,6 @@
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
-import com.android.launcher3.Flags;
import com.android.launcher3.tapl.LauncherInstrumentation.TrackpadGestureType;
import com.android.launcher3.tapl.Workspace;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
@@ -69,7 +67,6 @@
@NavigationModeSwitch(mode = ZERO_BUTTON)
public void pressBack() throws Exception {
assumeTrue(mLauncher.isTablet());
- assumeFalse(Flags.enablePredictiveBackGesture());
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
try {
diff --git a/quickstep/tests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt b/quickstep/tests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt
new file mode 100644
index 0000000..ea52842
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/orientation/LandscapePagedViewHandlerTest.kt
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.orientation
+
+import android.platform.test.flag.junit.SetFlagsRule
+import android.view.Gravity
+import android.view.View
+import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.Flags
+import com.android.quickstep.orientation.LandscapePagedViewHandler.SplitIconPositions
+import com.android.quickstep.views.IconAppChipView
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.`when`
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+
+@RunWith(AndroidJUnit4::class)
+class LandscapePagedViewHandlerTest {
+
+ @get:Rule val setFlagsRule = SetFlagsRule()
+
+ private val sut = LandscapePagedViewHandler()
+
+ private fun enableGridOnlyOverview(isEnabled: Boolean) {
+ if (isEnabled) {
+ setFlagsRule.enableFlags(
+ Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW,
+ Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU
+ )
+ } else {
+ setFlagsRule.disableFlags(
+ Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW,
+ Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU
+ )
+ }
+ }
+
+ /** [ Test getSplitIconsPosition ] */
+ private fun getSplitIconsPosition(isRTL: Boolean): SplitIconPositions {
+ return sut.getSplitIconsPosition(
+ TASK_ICON_HEIGHT_PX,
+ PRIMARY_SNAPSHOT,
+ TOTAL_THUMBNAIL_HEIGHT,
+ isRTL,
+ OVERVIEW_TASK_MARGIN_PX,
+ DIVIDER_SIZE_PX,
+ )
+ }
+
+ @Test
+ fun testIcon_getSplitIconsPositions() {
+ enableGridOnlyOverview(false)
+
+ val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = false)
+
+ // Top-Left icon should be at the end of the primary snapshot height
+ assertThat(topLeftY).isEqualTo(250)
+ // Bottom-Right icon should be at the end of the primary height + divider + icon size
+ assertThat(bottomRightY).isEqualTo(374)
+ }
+
+ @Test
+ fun testIcon_getSplitIconsPositions_isRTL() {
+ enableGridOnlyOverview(false)
+
+ val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = true)
+
+ // Top-Left icon should be at the end of the primary snapshot height
+ assertThat(topLeftY).isEqualTo(250)
+ // Bottom-Right icon should be at the end of the primary height + divider + icon size
+ assertThat(bottomRightY).isEqualTo(374)
+ }
+
+ @Test
+ fun testChip_getSplitIconsPositions() {
+ enableGridOnlyOverview(true)
+
+ val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = false)
+
+ // Top-Left app chip should always be at the initial position of the first snapshot
+ assertThat(topLeftY).isEqualTo(0)
+ // Bottom-Right app chip should be at the end of the primary height + divider
+ assertThat(bottomRightY).isEqualTo(266)
+ }
+
+ @Test
+ fun testChip_getSplitIconsPositions_isRTL() {
+ enableGridOnlyOverview(true)
+
+ val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = true)
+
+ // TODO(b/326377497): When started in fake seascape and rotated to landscape,
+ // the icon chips are in RTL and wrongly positioned at the right side of the snapshot.
+ // Top-Left app chip should be placed at the top left of the first snapshot, but because
+ // this issue, it's displayed at the top-right of the second snapshot.
+ // The Bottom-Right app chip is displayed at the top-right of the first snapshot because
+ // of this issue.
+ assertThat(topLeftY).isEqualTo(0)
+ assertThat(bottomRightY).isEqualTo(-316)
+ }
+
+ /** Test updateSplitIconsPosition */
+ @Test
+ fun testIcon_updateSplitIconsPosition() {
+ enableGridOnlyOverview(false)
+
+ val expectedTranslationY = 250
+ val expectedGravity = Gravity.TOP or Gravity.RIGHT
+
+ val iconView = mock<View>()
+ val frameLayout = FrameLayout.LayoutParams(100, 100)
+ `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+ sut.updateSplitIconsPosition(iconView, expectedTranslationY, false)
+ assertThat(frameLayout.gravity).isEqualTo(expectedGravity)
+ assertThat(frameLayout.topMargin).isEqualTo(expectedTranslationY)
+ verify(iconView).translationX = 0f
+ verify(iconView).translationY = 0f
+ }
+
+ @Test
+ fun testIcon_updateSplitIconsPosition_isRTL() {
+ enableGridOnlyOverview(false)
+
+ val expectedTranslationY = 250
+ val expectedGravity = Gravity.TOP or Gravity.RIGHT
+
+ val iconView = mock<View>()
+ val frameLayout = FrameLayout.LayoutParams(100, 100)
+ `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+ sut.updateSplitIconsPosition(iconView, expectedTranslationY, true)
+ assertThat(frameLayout.gravity).isEqualTo(expectedGravity)
+ assertThat(frameLayout.topMargin).isEqualTo(expectedTranslationY)
+ verify(iconView).translationX = 0f
+ verify(iconView).translationY = 0f
+ }
+
+ @Test
+ fun testChip_updateSplitIconsPosition() {
+ enableGridOnlyOverview(true)
+
+ val expectedTranslationY = 250
+ val frameLayout = FrameLayout.LayoutParams(100, 100)
+ val iconView = mock<IconAppChipView>()
+ `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+ sut.updateSplitIconsPosition(iconView, expectedTranslationY, false)
+ assertThat(frameLayout.gravity).isEqualTo(Gravity.TOP or Gravity.END)
+ verify(iconView).setSplitTranslationX(0f)
+ verify(iconView).setSplitTranslationY(expectedTranslationY.toFloat())
+ }
+
+ @Test
+ fun testChip_updateSplitIconsPosition_isRTL() {
+ enableGridOnlyOverview(true)
+
+ val expectedTranslationY = 250
+ val frameLayout = FrameLayout.LayoutParams(100, 100)
+ val iconView = mock<IconAppChipView>()
+ `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+ sut.updateSplitIconsPosition(iconView, expectedTranslationY, true)
+ assertThat(frameLayout.gravity).isEqualTo(Gravity.BOTTOM or Gravity.START)
+ verify(iconView).setSplitTranslationX(0f)
+ verify(iconView).setSplitTranslationY(expectedTranslationY.toFloat())
+ }
+
+ private companion object {
+ const val TASK_ICON_HEIGHT_PX = 108
+ const val OVERVIEW_TASK_MARGIN_PX = 0
+ const val DIVIDER_SIZE_PX = 16
+ const val PRIMARY_SNAPSHOT = 250
+ const val SECONDARY_SNAPSHOT = 300
+ const val TOTAL_THUMBNAIL_HEIGHT = PRIMARY_SNAPSHOT + SECONDARY_SNAPSHOT + DIVIDER_SIZE_PX
+ }
+}
diff --git a/quickstep/tests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt b/quickstep/tests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt
new file mode 100644
index 0000000..2bc182c
--- /dev/null
+++ b/quickstep/tests/src/com/android/quickstep/orientation/SeascapePagedViewHandlerTest.kt
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.orientation
+
+import android.platform.test.flag.junit.SetFlagsRule
+import android.view.Gravity
+import android.view.View
+import android.widget.FrameLayout
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.Flags
+import com.android.quickstep.orientation.LandscapePagedViewHandler.SplitIconPositions
+import com.android.quickstep.views.IconAppChipView
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.`when`
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+
+@RunWith(AndroidJUnit4::class)
+class SeascapePagedViewHandlerTest {
+
+ @get:Rule val setFlagsRule = SetFlagsRule()
+
+ private val sut = SeascapePagedViewHandler()
+
+ private fun enableGridOnlyOverview(isEnabled: Boolean) {
+ if (isEnabled) {
+ setFlagsRule.enableFlags(
+ Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW,
+ Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU
+ )
+ } else {
+ setFlagsRule.disableFlags(
+ Flags.FLAG_ENABLE_GRID_ONLY_OVERVIEW,
+ Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU
+ )
+ }
+ }
+
+ /** [ Test getSplitIconsPosition ] */
+ private fun getSplitIconsPosition(isRTL: Boolean): SplitIconPositions {
+ return sut.getSplitIconsPosition(
+ TASK_ICON_HEIGHT_PX,
+ PRIMARY_SNAPSHOT,
+ TOTAL_THUMBNAIL_HEIGHT,
+ isRTL,
+ OVERVIEW_TASK_MARGIN_PX,
+ DIVIDER_SIZE_PX,
+ )
+ }
+
+ @Test
+ fun testIcon_getSplitIconsPositions() {
+ enableGridOnlyOverview(false)
+
+ val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = false)
+
+ // The top-left icon is translated from the bottom of the screen to the end of
+ // the primary snapshot minus the icon size.
+ assertThat(topLeftY).isEqualTo(142)
+ // The bottom-right icon is placed at the end of the primary snapshot plus the divider.
+ assertThat(bottomRightY).isEqualTo(266)
+ }
+
+ @Test
+ fun testIcon_getSplitIconsPositions_isRTL() {
+ enableGridOnlyOverview(false)
+
+ val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = true)
+
+ // The top-left icon is translated from the bottom of the screen to the end of
+ // the primary snapshot minus the icon size.
+ assertThat(topLeftY).isEqualTo(142)
+ // The bottom-right icon is placed at the end of the primary snapshot plus the divider.
+ assertThat(bottomRightY).isEqualTo(266)
+ }
+
+ @Test
+ fun testChip_getSplitIconsPositions() {
+ enableGridOnlyOverview(true)
+
+ val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = false)
+
+ // Top-Left app chip should always be at the initial position of the first snapshot
+ assertThat(topLeftY).isEqualTo(0)
+ // Bottom-Right app chip should be at the end of the primary height + divider
+ assertThat(bottomRightY).isEqualTo(-266)
+ }
+
+ @Test
+ fun testChip_getSplitIconsPositions_isRTL() {
+ enableGridOnlyOverview(true)
+
+ val (topLeftY, bottomRightY) = getSplitIconsPosition(isRTL = true)
+
+ // TODO(b/326377497): When started in fake seascape and rotated to landscape,
+ // the icon chips are in RTL and wrongly positioned at the right side of the snapshot.
+ // Top-Left app chip should be placed at the top left of the first snapshot, but because
+ // this issue, it's displayed at the top-right of the second snapshot.
+ // The Bottom-Right app chip is displayed at the top-right of the first snapshot because
+ // of this issue.
+ assertThat(topLeftY).isEqualTo(316)
+ assertThat(bottomRightY).isEqualTo(0)
+ }
+
+ /** Test updateSplitIconsPosition */
+ @Test
+ fun testIcon_updateSplitIconsPosition() {
+ enableGridOnlyOverview(false)
+
+ val expectedTranslationY = 250
+ val expectedGravity = Gravity.BOTTOM or Gravity.LEFT
+
+ val iconView = mock<View>()
+ val frameLayout = FrameLayout.LayoutParams(100, 100)
+ `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+ sut.updateSplitIconsPosition(iconView, expectedTranslationY, false)
+ assertThat(frameLayout.gravity).isEqualTo(expectedGravity)
+ assertThat(frameLayout.bottomMargin).isEqualTo(expectedTranslationY)
+ verify(iconView).translationX = 0f
+ verify(iconView).translationY = 0f
+ }
+
+ @Test
+ fun testIcon_updateSplitIconsPosition_isRTL() {
+ enableGridOnlyOverview(false)
+
+ val expectedTranslationY = 250
+ val expectedGravity = Gravity.BOTTOM or Gravity.LEFT
+
+ val iconView = mock<View>()
+ val frameLayout = FrameLayout.LayoutParams(100, 100)
+ `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+ sut.updateSplitIconsPosition(iconView, expectedTranslationY, true)
+ assertThat(frameLayout.gravity).isEqualTo(expectedGravity)
+ assertThat(frameLayout.bottomMargin).isEqualTo(expectedTranslationY)
+ verify(iconView).translationX = 0f
+ verify(iconView).translationY = 0f
+ }
+
+ @Test
+ fun testChip_updateSplitIconsPosition() {
+ enableGridOnlyOverview(true)
+
+ val expectedTranslationY = 250
+ val frameLayout = FrameLayout.LayoutParams(100, 100)
+ val iconView = mock<IconAppChipView>()
+ `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+ sut.updateSplitIconsPosition(iconView, expectedTranslationY, false)
+ assertThat(frameLayout.gravity).isEqualTo(Gravity.BOTTOM or Gravity.START)
+ verify(iconView).setSplitTranslationX(0f)
+ verify(iconView).setSplitTranslationY(expectedTranslationY.toFloat())
+ }
+
+ @Test
+ fun testChip_updateSplitIconsPosition_isRTL() {
+ enableGridOnlyOverview(true)
+
+ val expectedTranslationY = 250
+ val frameLayout = FrameLayout.LayoutParams(100, 100)
+ val iconView = mock<IconAppChipView>()
+ `when`(iconView.layoutParams).thenReturn(frameLayout)
+
+ sut.updateSplitIconsPosition(iconView, expectedTranslationY, true)
+ assertThat(frameLayout.gravity).isEqualTo(Gravity.TOP or Gravity.END)
+ verify(iconView).setSplitTranslationX(0f)
+ verify(iconView).setSplitTranslationY(expectedTranslationY.toFloat())
+ }
+
+ private companion object {
+ const val TASK_ICON_HEIGHT_PX = 108
+ const val OVERVIEW_TASK_MARGIN_PX = 0
+ const val DIVIDER_SIZE_PX = 16
+ const val PRIMARY_SNAPSHOT = 250
+ const val SECONDARY_SNAPSHOT = 300
+ const val TOTAL_THUMBNAIL_HEIGHT = PRIMARY_SNAPSHOT + SECONDARY_SNAPSHOT + DIVIDER_SIZE_PX
+ }
+}
diff --git a/res/drawable/ic_plus.xml b/res/drawable/ic_plus.xml
new file mode 100644
index 0000000..3ab926a
--- /dev/null
+++ b/res/drawable/ic_plus.xml
@@ -0,0 +1,24 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="19dp"
+ android:height="18dp"
+ android:viewportWidth="19"
+ android:viewportHeight="18">
+ <path
+ android:pathData="M15.5,9.75H10.25V15H8.75V9.75H3.5V8.25H8.75V3H10.25V8.25H15.5V9.75Z"
+ android:fillColor="#ffffff"/>
+</vector>
diff --git a/res/drawable/page_indicator.xml b/res/drawable/page_indicator.xml
index c0ccc49..d4cb13f 100644
--- a/res/drawable/page_indicator.xml
+++ b/res/drawable/page_indicator.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
- <solid android:color="?attr/folderPaginationColor"/>
+ <solid android:color="?attr/pageIndicatorDotColor"/>
<size android:width="@dimen/page_indicator_size" android:height="@dimen/page_indicator_size"/>
</shape>
\ No newline at end of file
diff --git a/res/drawable/widget_cell_add_button_background.xml b/res/drawable/widget_cell_add_button_background.xml
new file mode 100644
index 0000000..860d1cd
--- /dev/null
+++ b/res/drawable/widget_cell_add_button_background.xml
@@ -0,0 +1,28 @@
+<?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.
+-->
+<inset
+ xmlns:android="http://schemas.android.com/apk/res/android">
+ <ripple
+ android:color="?android:attr/colorControlHighlight">
+ <item>
+ <shape android:shape="rectangle">
+ <corners
+ android:radius="50dp"/>
+ <solid android:color="?attr/widgetPickerAddButtonBackgroundColor" />
+ </shape>
+ </item>
+ </ripple>
+</inset>
\ No newline at end of file
diff --git a/res/layout/widget_cell.xml b/res/layout/widget_cell.xml
index 55dd1de..4533873 100644
--- a/res/layout/widget_cell.xml
+++ b/res/layout/widget_cell.xml
@@ -17,7 +17,8 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="0dp"
android:layout_height="wrap_content"
- android:paddingHorizontal="@dimen/widget_cell_horizontal_padding"
+ android:layout_marginStart="@dimen/widget_cell_horizontal_padding"
+ android:layout_marginEnd="@dimen/widget_cell_horizontal_padding"
android:paddingVertical="@dimen/widget_cell_vertical_padding"
android:layout_weight="1"
android:orientation="vertical"
diff --git a/res/layout/widget_cell_content.xml b/res/layout/widget_cell_content.xml
index 0c606f6..106c5b7 100644
--- a/res/layout/widget_cell_content.xml
+++ b/res/layout/widget_cell_content.xml
@@ -45,40 +45,70 @@
android:layout_margin="@dimen/profile_badge_margin"/>
</com.android.launcher3.widget.WidgetCellPreview>
- <!-- The name of the widget. -->
- <TextView
- android:id="@+id/widget_name"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:ellipsize="end"
- android:fadingEdge="horizontal"
- android:gravity="center_horizontal|center_vertical"
- android:singleLine="true"
- android:maxLines="1"
- android:textColor="?android:attr/textColorPrimary"
- android:drawablePadding="@dimen/widget_cell_app_icon_padding"
- android:textSize="@dimen/widget_cell_font_size" />
-
- <!-- The original dimensions of the widget -->
- <TextView
- android:id="@+id/widget_dims"
+ <FrameLayout
android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:textColor="?android:attr/textColorSecondary"
- android:textSize="@dimen/widget_cell_font_size"
- android:alpha="0.7" />
+ android:layout_height="wrap_content">
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:id="@+id/widget_text_container"
+ android:orientation="vertical">
+ <!-- The name of the widget. -->
+ <TextView
+ android:id="@+id/widget_name"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:layout_gravity="center_horizontal"
+ android:gravity="center_horizontal|center_vertical"
+ android:singleLine="true"
+ android:maxLines="1"
+ android:textColor="?android:attr/textColorPrimary"
+ android:drawablePadding="@dimen/widget_cell_app_icon_padding"
+ android:textSize="@dimen/widget_cell_font_size" />
- <TextView
- android:id="@+id/widget_description"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:gravity="center_horizontal"
- android:textSize="@dimen/widget_cell_font_size"
- android:textColor="?android:attr/textColorSecondary"
- android:maxLines="2"
- android:ellipsize="end"
- android:fadingEdge="horizontal"
- android:alpha="0.7" />
+ <!-- The original dimensions of the widget -->
+ <TextView
+ android:id="@+id/widget_dims"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textColor="?android:attr/textColorSecondary"
+ android:textSize="@dimen/widget_cell_font_size"
+ android:alpha="0.7" />
-</merge>
\ No newline at end of file
+ <TextView
+ android:id="@+id/widget_description"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:gravity="center_horizontal"
+ android:textSize="@dimen/widget_cell_font_size"
+ android:textColor="?android:attr/textColorSecondary"
+ android:maxLines="2"
+ android:ellipsize="end"
+ android:fadingEdge="horizontal"
+ android:alpha="0.7" />
+ </LinearLayout>
+
+ <Button
+ android:id="@+id/widget_add_button"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/widget_cell_add_button_height"
+ android:layout_gravity="center"
+ android:minWidth="0dp"
+ android:paddingTop="@dimen/widget_cell_add_button_vertical_padding"
+ android:paddingBottom="@dimen/widget_cell_add_button_vertical_padding"
+ android:paddingStart="@dimen/widget_cell_add_button_start_padding"
+ android:paddingEnd="@dimen/widget_cell_add_button_end_padding"
+ android:text="@string/widget_add_button_label"
+ android:textColor="?attr/widgetPickerAddButtonTextColor"
+ android:textSize="@dimen/widget_cell_font_size"
+ android:gravity="center"
+ android:visibility="gone"
+ android:drawableLeft="@drawable/ic_plus"
+ android:drawablePadding="8dp"
+ android:drawableTint="?attr/widgetPickerAddButtonTextColor"
+ android:background="@drawable/widget_cell_add_button_background" />
+ </FrameLayout>
+</merge>
diff --git a/res/layout/widget_recommendations_table.xml b/res/layout/widget_recommendations_table.xml
index e3f0562..b53d2d5 100644
--- a/res/layout/widget_recommendations_table.xml
+++ b/res/layout/widget_recommendations_table.xml
@@ -17,5 +17,4 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingHorizontal="@dimen/widget_recommendations_table_horizontal_padding"
android:paddingVertical="@dimen/widget_recommendations_table_vertical_padding" />
diff --git a/res/layout/widgets_full_sheet_paged_view.xml b/res/layout/widgets_full_sheet_paged_view.xml
index 1d37043..8dc785a 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -79,6 +79,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
android:background="@drawable/widgets_surface_background"
android:orientation="vertical"
android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
@@ -92,7 +93,7 @@
android:layout_height="64dp"
android:gravity="center_horizontal"
android:orientation="horizontal"
- android:paddingVertical="8dp"
+ android:paddingBottom="8dp"
android:paddingHorizontal="@dimen/widget_list_horizontal_margin"
android:background="?attr/widgetPickerPrimarySurfaceColor"
style="@style/TextHeadline"
diff --git a/res/layout/widgets_full_sheet_recyclerview.xml b/res/layout/widgets_full_sheet_recyclerview.xml
index dca08ff..5427732 100644
--- a/res/layout/widgets_full_sheet_recyclerview.xml
+++ b/res/layout/widgets_full_sheet_recyclerview.xml
@@ -29,7 +29,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/collapse_handle"
- android:paddingBottom="16dp"
+ android:paddingBottom="8dp"
android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:clipToOutline="true"
android:orientation="vertical">
@@ -62,6 +62,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
+ android:layout_marginBottom="8dp"
android:background="@drawable/widgets_surface_background"
android:orientation="vertical"
android:visibility="gone">
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 4387399..1358c70 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Voeg by tuisskerm"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-legstuk by tuisskerm gevoeg"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Voorstelle"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Jou daaglikse noodsaaklikhede"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Nuus vir jou"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Jou ontspansone"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Bereik jou fiksheiddoelwitte"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Spring die weer voor"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Jy hou dalk ook van"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-legstukke aan die regterkant, soektog en opsies aan die linkerkant"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# legstuk}other{# legstukke}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# kortpad}other{# kortpaaie}}"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index e404506..bcdb9b7 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"ወደ መነሻ ማያ ገፅ አክል"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ምግብር ወደ መነሻ ማያ ገፅ ታክሏል"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"የአስተያየት ጥቆማዎች"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"የእርስዎ ዕለታዊ መሠረታዊ ነገሮች"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"ዜና ለእርስዎ"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"የሚያርፉበት ቦታዎ"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"የአካል ብቃት ግቦችዎን ያሳኩ"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"ለአየር ሁኔታው አስቀድመው ያቅዱ"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"ይህንንም ሊወዱት ይችላሉ"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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-ar/strings.xml b/res/values-ar/strings.xml
index e1b98fb..4ff688b 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"إضافة إلى الشاشة الرئيسية"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"تمت إضافة الأداة <xliff:g id="WIDGET_NAME">%1$s</xliff:g> إلى الشاشة الرئيسية."</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"اقتراحات"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"تطبيقات أساسية للحياة اليومية"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"أخبار مقترَحة لك"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"محتوى ترفيهي مقترَح"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"تحقيق أهداف اللياقة البدنية"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"معرفة حالة الطقس أولاً بأول"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"محتوى قد يعجبك أيضًا"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{تطبيق مصغّر واحد}zero{# تطبيق مصغّر}two{تطبيقان مصغّران}few{# تطبيقات مصغّرة}many{# تطبيقًا مصغّرًا}other{# تطبيق مصغّر}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{اختصار واحد}zero{# اختصار}two{اختصاران}few{# اختصارات}many{# اختصارًا}other{# اختصار}}"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 7913fca..396790b 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"গৃহ স্ক্ৰীনত যোগ কৰক"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ৱিজেটটো গৃহ স্ক্ৰীনত যোগ দিয়া হৈছে"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"পৰামৰ্শ"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"আপোনাৰ দৈনিক অত্যাৱশ্যকীয় সামগ্ৰী"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"আপোনাৰ বাবে বাতৰি"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"আপোনাৰ পচন্দৰ স্থান"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"আপোনাৰ সুস্থতাৰ লক্ষ্যত উপনীত হওক"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"বতৰৰ বিষয়ে আগতীয়াকৈ জানক"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"আপুনি হয়তো এইটোও পচন্দ কৰিব"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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-az/strings.xml b/res/values-az/strings.xml
index d11c4a7..0c21e27 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Əsas ekrana əlavə edin"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidceti əsas ekrana əlavə edildi"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Təkliflər"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Gündəlik vacib vidcetlər"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Sizin üçün xəbərlər"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"İstirahət zonası"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Fitnes hədəflərinə nail olun"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Hava barədə məlumatlı olun"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Tövsiyələr"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> vidcetləri sağda, axtarış və seçimlər solda"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidcet}other{# vidcet}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# qısayol}other{# qısayol}}"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index b99ec65..6fb5758 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Dodali ste vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> na početni ekran"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Predlozi"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Osnovni vidžeti za svaki dan"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Vesti za vas"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona za opuštanje"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Ostvarite fitnes ciljeve"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Budite u toku sa vremenskim prilikama"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Možda će vam se dopasti i"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Vidžeti <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> sa desne strane, pretraga i opcije sa leve strane"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidžet}one{# vidžet}few{# vidžeta}other{# vidžeta}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečica}one{# prečica}few{# prečice}other{# prečica}}"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index c978425..d51abda 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Дадаць на галоўны экран"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Віджэт \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\" дададзены на галоўны экран"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Прапановы"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Праграмы першай неабходнасці"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Навіны для вас"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Зона адпачынку"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Вашы фітнэс-мэты"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Прагноз надвор\'я"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Іншыя рэкамендацыі"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# віджэт}few{# віджэты}many{# віджэтаў}other{# віджэта}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ярлык}one{# ярлык}few{# ярлыкі}many{# ярлыкоў}other{# ярлыка}}"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 769c538..edf3cf4 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -42,12 +42,14 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Добавяне към началния екран"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Приспособлението <xliff:g id="WIDGET_NAME">%1$s</xliff:g> е добавено към началния екран"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Предложения"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Основните за деня ви"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Новини за вас"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Приспособления, които трябва да изпробвате"</string>
+ <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Новини и списания"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Зоната ви за разпускане"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Постигнете фитнес целите си"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Бъдете една крачка напред с прогнозата за времето"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Може също да харесате"</string>
+ <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Развлечения"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Социални мрежи"</string>
+ <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Здраве и фитнес"</string>
+ <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Времето"</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{# приспособление}other{# приспособления}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# пряк път}other{# преки пътя}}"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 12fabd3..84cf504 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"হোম স্ক্রিনে যোগ করুন"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> উইজেট হোম স্ক্রিনে যোগ করা হয়েছে"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"সাজেশন"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"আপনার নিত্য প্রয়োজনীয় জিনিস"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"আপনার জন্য খবর"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"আপনার চিল জোন"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"আপনার ফিটনেস সংক্রান্ত লক্ষ্যে পৌঁছান"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"আবহাওয়া সম্পর্কে আগেই খবর পান"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"আপনার এগুলিও পছন্দ হতে পারে"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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-bs/strings.xml b/res/values-bs/strings.xml
index 0c43561..d5f848d 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> je dodan na početni ekran"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Prijedlozi"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Svakodnevni osnovni vidžeti"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Vijesti za vas"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaša zona opuštanja"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Postignite svoje ciljeve fitnesa"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Ne dajte da vas uhvati oluja"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Možda vam se svidi i ovo"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Vidžeti aplikacije <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> su na desnoj, a pretraživanje i opcije na lijevoj strani"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidžet}one{# vidžet}few{# vidžeta}other{# vidžeta}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečica}one{# prečica}few{# prečice}other{# prečica}}"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 37d8626..2072155 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Afegeix a la pantalla d\'inici"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"El widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> s\'ha afegit a la pantalla d\'inici"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggeriments"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Els teus essencials per al dia a dia"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Notícies per a tu"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"La teva zona de relax"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Assoleix els teus objectius de fitnes"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Que no et sorprengui el temps"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"També et pot agradar"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> a la dreta, cerca i opcions a l\'esquerra"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# drecera}other{# dreceres}}"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 2def07c..34b3dcb 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Přidat na plochu"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> byl přidán na plochu"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Návrhy"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Vaše každodenní nezbytnosti"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Zprávy pro vás"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaše klidová zóna"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Dosažení kondičních cílů"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Mějte přehled o počasí"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Také by se vám mohlo líbit"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgety <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> vpravo, vyhledávání a možnosti vlevo"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ # widget}few{# widgety}many{# widgetu}other{# widgetů}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# zkratka}few{# zkratky}many{# zkratky}other{# zkratek}}"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 57053e6..d08cf01 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Føj til startskærm"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widgetten <xliff:g id="WIDGET_NAME">%1$s</xliff:g> blev føjet til startskærmen"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Forslag"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Dine vigtige apps"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Nyheder til dig"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Dit afslapningshjørne"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Nå dine fitnessmål"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Vær på forkant med vejret"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Du kan måske også lide"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-widgets til højre, søgning og valgmuligheder til venstre"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# genvej}one{# genvej}other{# genveje}}"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 5eff0b0..47c8063 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Zum Startbildschirm hinzufügen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-Widget zum Startbildschirm hinzugefügt"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Vorschläge"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Deine täglichen Essentials"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Neuigkeiten für dich"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zum Entspannen"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Erreiche deine Fitnessziele"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Dem Wetter einen Schritt voraus"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Das könnte dir auch gefallen"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-Widgets rechts, Suche und Optionen links"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# Widget}other{# Widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# Verknüpfung}other{# Verknüpfungen}}"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index d868040..d5d6d4d 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Προσθήκη στην αρχική οθόνη"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Το γραφικό στοιχείο <xliff:g id="WIDGET_NAME">%1$s</xliff:g> προστέθηκε στην αρχική οθόνη."</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Προτάσεις"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Τα καθημερινά απαραίτητα"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Ειδήσεις για εσάς"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ο δικός σας τρόπος χαλάρωσης"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Επιτύχετε τους στόχους που έχετε θέσει για τη φυσική σας κατάσταση"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Ετοιμαστείτε για κάθε καιρό"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Μπορεί να σας αρέσουν επίσης"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# γραφικό στοιχείο}other{# γραφικά στοιχεία}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# συντόμευση}other{# συντομεύσεις}}"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index cee4d2a..576b603 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Your daily essentials"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"News for you"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Your chill zone"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Reach your fitness goals"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Stay ahead of the weather"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"You might also like"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widgets on right, search and options on left"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 87cd9eb..5baace2 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -42,12 +42,14 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Your Daily Essentials"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"News For You"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essentials"</string>
+ <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"News & magazines"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Your Chill Zone"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Reach Your Fitness Goals"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Stay Ahead of the Weather"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"You Might Also Like"</string>
+ <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entertainment"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+ <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Health & fitness"</string>
+ <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Weather"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggested for you"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widgets on right, search and options on left"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index cee4d2a..576b603 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Your daily essentials"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"News for you"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Your chill zone"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Reach your fitness goals"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Stay ahead of the weather"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"You might also like"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widgets on right, search and options on left"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index cee4d2a..576b603 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Your daily essentials"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"News for you"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Your chill zone"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Reach your fitness goals"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Stay ahead of the weather"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"You might also like"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widgets on right, search and options on left"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index ae84841..511abb3 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -42,12 +42,14 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Add to home screen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget added to home screen"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Your Daily Essentials"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"News For You"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Essentials"</string>
+ <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"News & magazines"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Your Chill Zone"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Reach Your Fitness Goals"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Stay Ahead of the Weather"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"You Might Also Like"</string>
+ <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entertainment"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+ <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Health & fitness"</string>
+ <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Weather"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Suggested for you"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widgets on right, search and options on left"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}other{# shortcuts}}"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 8689105..a4e7c8a 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Agregar a pantalla principal"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Se agregó el widget de <xliff:g id="WIDGET_NAME">%1$s</xliff:g> a la pantalla principal"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugerencias"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Tus esenciales diarios"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Noticias para ti"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona de descanso"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Logra tus objetivos de fitness"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Mantente al tanto del clima"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Puede que también te guste"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> a la derecha, búsqueda y opciones a la izquierda"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# acceso directo}other{# accesos directos}}"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 5270050..d49b7cb 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Añadir a pantalla de inicio"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> añadido a la pantalla de inicio"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugerencias"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Lo esencial para el día a día"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Noticias para ti"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Tu zona de descanso"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Logra tus objetivos de actividad física"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Infórmate sobre el tiempo"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"También te puede interesar"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> a la derecha, búsqueda y opciones a la izquierda"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# acceso directo}other{# accesos directos}}"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 830abf0..4f1257a 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Lisa avakuvale"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Vidin <xliff:g id="WIDGET_NAME">%1$s</xliff:g> lisati avakuvale"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Soovitused"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Kasulikud vidinad"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Uudised teile"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Teie lõõgastumiskoht"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Saavutage oma treeningueesmärgid"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Olge ilmateatega kursis"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Teile võivad meeldida ka need"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Teenuse <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> vidinad paremal, otsing ja valikud vasakul"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# vidin}other{# vidinat}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# otsetee}other{# otseteed}}"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index e44a951..1a593a3 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Gehitu orri nagusian"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widgeta orri nagusian gehitu da"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Iradokizunak"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Eguneroko funtsezkoak"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Zuretzako albisteak"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Lasaitzeko gunea"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Erdietsi zure fitness-helburuak"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Hartu aurrea eguraldiari"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Gustatuko zaizkizulakoan"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> zerbitzuaren widgetak eskuinean, bilaketa eta aukerak ezkerrean"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# lasterbide}other{# lasterbide}}"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index feaf724..6f954a9 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"افزودن به صفحه اصلی"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g> به صفحه اصلی اضافه شد"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"پیشنهادها"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"ملزومات روزانه"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"اخبار برای شما"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"منطقه آرامش شما"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"دستیابی به اهداف تناسب اندام"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"آبوهوا را پیشبینی کنید"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"شاید این را هم بپسندید"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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-fi/strings.xml b/res/values-fi/strings.xml
index 3198a03..27b9d2e 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Lisää aloitusnäytölle"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget lisätty aloitusnäytölle: <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Ehdotukset"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Tärkeät asiat päivään"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Uutisia sinulle"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ota rennosti"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Saavuta kuntoilutavoitteet"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Pysy ajan tasalla säästä"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Saatat pitää myös näistä"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pikakuvake}other{# pikakuvaketta}}"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 3919c1e..0843a44 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Ajouter à l\'écran d\'accueil"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Le widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> a été ajouté à l\'écran d\'accueil"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Vos indispensables au quotidien"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Actualités personnalisées"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zone de divertissement"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Objectifs de mise en forme"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"À l\'affût de la météo"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Autres recommandations"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> à droite, recherche et options à gauche"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# raccourci}one{# raccourci}other{# raccourcis}}"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index fdeae1c..bece20b 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Ajouter à l\'écran d\'accueil"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ajouté à l\'écran d\'accueil"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Vos indispensables du jour"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Actualités personnalisées"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Votre espace détente"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Atteignez vos objectifs forme"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Soyez au fait de la météo"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Découvrez également"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> à droite, recherche et options à gauche"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# raccourci}one{# raccourci}other{# raccourcis}}"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 9388948..d67c396 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Engadir á pantalla de inicio"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Engadiuse o widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> á pantalla de inicio"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suxestións"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Indispensables para o día a día"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Novidades para ti"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Reláxate"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Acada os teus obxectivos para estar en forma"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Adiántate á meteoroloxía"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Tamén che pode interesar…"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> á dereita, busca e opcións á esquerda"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atallo}other{# atallos}}"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index ec6d994..ab10e8d 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"હોમ સ્ક્રીનમાં ઉમેરો"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"હોમ સ્ક્રીન પર <xliff:g id="WIDGET_NAME">%1$s</xliff:g> વિજેટ ઉમેર્યુ"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"સૂચનો"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"તમારી દૈનિક આવશ્યકતાઓ"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"તમારા માટે સમાચાર"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"તમારો આરામદાયક ઝોન"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"તમારા ફિટનેસ લક્ષ્યો પૂરા કરો"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"હવામાન વિશે અપ ટૂ ડેટ રહો"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"કદાચ તમને આ પણ પસંદ હોય"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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-hi/strings.xml b/res/values-hi/strings.xml
index f043149..0568dd3 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"होम स्क्रीन पर जोड़ें"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट को होम स्क्रीन पर जोड़ा गया"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"सुझाव"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"रोज़ाना इस्तेमाल होने वाले ज़रूरी ऐप्लिकेशन"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"आपके लिए खबरें"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"आपके मनोरंजन के लिए"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"फ़िटनेस के लक्ष्य हासिल करें"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"मौसम की अप-टू-डेट जानकारी पाएं"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"शायद आपको ये भी पसंद आएं"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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-hr/strings.xml b/res/values-hr/strings.xml
index f40252b..f2b9a4b 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni zaslon"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> dodan je na početni zaslon"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Prijedlozi"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Vaše dnevne potrepštine"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Vijesti za vas"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaša zona za opuštanje"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Postignite svoje ciljeve u fitnesu"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Budite korak ispred vremenskih prilika"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Možda će vam se svidjeti i ovo"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> –widgeti zdesna, pretraživanje i opcije slijeva"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}few{# widgeta}other{# widgeta}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# prečac}one{# prečac}few{# prečaca}other{# prečaca}}"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 6fc5f28..72b9258 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Hozzáadás a kezdőképernyőhöz"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> modul hozzáadva a kezdőképernyőhöz"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Javaslatok"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Legfontosabb napi dolgok"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Hírek Önnek"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Az Ön relaxáló zónája"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Elérheti kitűzött erőnléti céljait"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Mindig friss időjárás-információk"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Lehet, hogy ez is tetszeni fog"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"A <xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-modulok a jobb, a kereső és a beállítások pedig a bal oldalon találhatók"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# modul}other{# modul}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# gyorsparancs}other{# gyorsparancs}}"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 83a4559..f348da6 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Ավելացնել հիմնական էկրանին"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> վիջեթն ավելացվել է հիմնական էկրանին"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Առաջարկներ"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Ամենաանհրաժեշտը յուրաքանչյուր օրվա համար"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Նորություններ ձեզ համար"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ձեր հանգստի գոտին"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Հասեք ձեր ֆիթնես նպատակներին"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Եղեք տեղեկացված եղանակի մասին"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Ձեզ կարող է դուր գալ"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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-in/strings.xml b/res/values-in/strings.xml
index d2cbca6..d6129af 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -31,10 +31,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Info aplikasi untuk %1$s"</string>
<string name="save_app_pair" msgid="5647523853662686243">"Simpan pasangan aplikasi"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
- <!-- no translation found for app_pair_unlaunchable_at_screen_size (3446551575502685376) -->
- <skip />
- <!-- no translation found for app_pair_needs_unfold (4588897528143807002) -->
- <skip />
+ <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Pasangan aplikasi ini tidak didukung di perangkat ini"</string>
+ <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Buka perangkat untuk menggunakan pasangan aplikasi ini"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Sentuh lama untuk memindahkan widget."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Ketuk dua kali & tahan untuk memindahkan widget atau gunakan tindakan khusus."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -44,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Tambahkan ke layar utama"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ditambahkan ke layar utama"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Saran"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Kebutuhan Harian Anda"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Berita untuk Anda"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona Nyaman Anda"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Capai Target Kebugaran Anda"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Tetap Waspada Menghadapi Cuaca"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Anda Mungkin Juga Suka"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widget <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> di bagian kanan, penelusuran dan opsi di bagian kiri"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pintasan}other{# pintasan}}"</string>
@@ -137,8 +144,7 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> sedang diinstal, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> sedang didownload, <xliff:g id="PROGRESS">%2$s</xliff:g> selesai"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> menunggu dipasang"</string>
- <!-- no translation found for app_archived_title (9124290918876665128) -->
- <skip />
+ <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g> diarsipkan. Ketuk untuk mendownload."</string>
<string name="dialog_update_title" msgid="114234265740994042">"Aplikasi perlu diupdate"</string>
<string name="dialog_update_message" msgid="4176784553982226114">"Aplikasi untuk ikon ini belum diupdate. Anda dapat mengupdate secara manual untuk mengaktifkan kembali pintasan ini, atau hapus ikon."</string>
<string name="dialog_update" msgid="2178028071796141234">"Update"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index b75f61f..b1e9638 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Bæta á heimaskjá"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> græju bætt við heimaskjá"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Tillögur"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Daglegar nauðsynjar"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Fréttir fyrir þig"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Slakaðu á"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Náðu hreyfingarmarkmiðunum þínum"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Vertu einu skrefi á undan veðrinu"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Þú gætir einnig haft áhuga á"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-græjur til hægri, leit og valkostir til vinstri"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# græja}one{# græja}other{# græjur}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# flýtileið}one{# flýtileið}other{# flýtileiðir}}"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 0c76ba9..fa32208 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Aggiungi alla schermata Home"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> aggiunto alla schermata Home"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggerimenti"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"L\'essenziale ogni giorno"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Notizie per te"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Il tuo angolo di tranquillità"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Raggiungi i tuoi obiettivi di fitness"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Non perderti le previsioni meteo"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Ti potrebbero anche piacere"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widget di <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> a destra, ricerca e opzioni a sinistra"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# scorciatoia}other{# scorciatoie}}"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 68173cc..6905682 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"הוספה למסך הבית"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"הווידג\'ט <xliff:g id="WIDGET_NAME">%1$s</xliff:g> נוסף למסך הבית"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"הצעות"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"הפריטים היומיומיים שלך"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"חדשות בשבילך"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"המקום שלך לרגיעה"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"השגת יעדי הכושר שלך"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"התעדכנות במזג האוויר"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"אולי יעניין אותך גם"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# ווידג\'טים}two{# ווידג\'טים}other{# ווידג\'טים}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{קיצור דרך אחד}one{# קיצורי דרך}two{# קיצורי דרך}other{# קיצורי דרך}}"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 7f6846c..85936c8 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -42,12 +42,14 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"ホーム画面に追加"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」ウィジェットをホーム画面に追加しました"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"候補"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"生活必需品"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"あなたへのおすすめニュース"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"基本"</string>
+ <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"ニュース&雑誌"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"休憩エリア"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"フィットネスの目標を達成"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"天気予報"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"あなたへのおすすめ"</string>
+ <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"エンタメ"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"ソーシャル"</string>
+ <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"健康&フィットネス"</string>
+ <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"天気"</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{# 件のウィジェット}other{# 件のウィジェット}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 件のショートカット}other{# 件のショートカット}}"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index ae3b1e6..696aafb 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"მთავარ ეკრანზე დამატება"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ვიჯეტი დამატებულია მთავარ ეკრანზე"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"შეთავაზებები"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"თქვენი ყოველდღიური საჭირო აპები"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"News თქვენთვის"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"განტვირთვის ადგილი"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"მიაღწიეთ ფიტნეს-მიზნებს"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"მიიღეთ ინფორმაცია წინასწარ ამინდის შესახებ"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"ასევე შეიძლება მოგეწონოთ"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# ვიჯეტი}other{# ვიჯეტი}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# მალსახმობი}other{# მალსახმობი}}"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 7038483..d1b968c 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Негізгі экранға қосу"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджеті негізгі экранға енгізілді."</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Ұсыныстар"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Күнделікті маңызды виджеттеріңіз"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Сізге арналған жаңалықтар"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Жанға жайлы жер"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Денені шынықтыру бойынша қойған мақсаттарыңызға жетіңіз"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Ауа райын алдын ала біліп отырыңыз"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Сізге мыналар да ұнауы мүмкін"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# виджет}other{# виджет}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# таңбаша}other{# таңбаша}}"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 1297dee..f0a15a6 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"បញ្ចូលទៅក្នុងអេក្រង់ដើម"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"បានបញ្ចូលធាតុក្រាហ្វិក <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ទៅអេក្រង់ដើម"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"ការណែនាំ"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"វត្ថុចាំបាច់ប្រចាំថ្ងៃរបស់អ្នក"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"ព័ត៌មានសម្រាប់អ្នក"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"តំបន់បន្ធូរអារម្មណ៍របស់អ្នក"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"សម្រេចគោលដៅហាត់ប្រាណរបស់អ្នក"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"ទទួលបានដំណឹងជាមុនអំពីអាកាសធាតុ"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"អ្នកក៏អាចនឹងចូលចិត្ត"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{ធាតុក្រាហ្វិក #}other{ធាតុក្រាហ្វិក #}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ផ្លូវកាត់ #}other{ផ្លូវកាត់ #}}"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 2832941..a5329bd 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"ಹೋಮ್ ಸ್ಕ್ರೀನ್ಗೆ ಸೇರಿಸಿ"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"ಹೋಮ್ಸ್ಕ್ರೀನ್ಗೆ <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ವಿಜೆಟ್ ಅನ್ನು ಸೇರಿಸಲಾಗಿದೆ"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"ಸಲಹೆಗಳು"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"ನಿಮ್ಮ ದೈನಂದಿನ ಎಸೆನ್ಶಿಯಲ್ಗಳು"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"ನಿಮಗಾಗಿ ಸುದ್ದಿ"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"ನೀವು ವಿಶ್ರಾಂತಿ ಪಡೆಯುವ ಸ್ಥಳ"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"ನಿಮ್ಮ ಫಿಟ್ನೆಸ್ ಗುರಿಗಳನ್ನು ಸಾಧಿಸಿ"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"ಹವಾಮಾನದ ಕುರಿತು ಮುಂಚೆಯೇ ಅಪ್ಡೇಟ್ ಆಗಿರಿ"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"ನಿಮಗೆ ಇವು ಕೂಡ ಇಷ್ಟವಾಗಬಹುದು"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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-ko/strings.xml b/res/values-ko/strings.xml
index 5c1e854..bd4e9dd 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"홈 화면에 추가"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> 위젯이 홈 화면에 추가됨"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"추천"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"매일 사용하는 항목"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"추천 뉴스"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"휴식 공간"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"피트니스 목표 달성"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"사전에 날씨 확인"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"좋아할 만한 항목"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{위젯 #개}other{위젯 #개}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{바로가기 #개}other{바로가기 #개}}"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 7c32fe6..ae5a6c7 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Башкы экранга кошуу"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджети башкы экранга кошулду"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Сунуштар"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Күнүмдүк керектелүүчү нерселер"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Сиз үчүн жаңылыктар"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Чер жазуу"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Фитнес максаттарыңызга жетиңиз"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Аба ырайы тууралуу маалымат"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Төмөнкүлөр да жагышы мүмкүн"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# виджет}other{# виджет}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ыкчам баскыч}other{# ыкчам баскыч}}"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 0ff2d4e..6a37221 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"ເພີ່ມໃສ່ໂຮມສະກຣີນ"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"ເພີ່ມວິດເຈັດ <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ໃສ່ໂຮມສະກຣີນແລ້ວ"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"ການແນະນຳ"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"ສິ່ງຈຳເປັນໃນຊີວິດປະຈຳວັນຂອງທ່ານ"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"ຂ່າວສຳລັບທ່ານ"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"ພື້ນທີ່ພັກຜ່ອນຂອງທ່ານ"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"ບັນລຸເປົ້າໝາຍການອອກກຳລັງກາຍຂອງທ່ານ"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"ຮູ້ສະພາບອາກາດລ່ວງໜ້າ"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"ທ່ານອາດຈະມັກ"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# ວິດເຈັດ}other{# ວິດເຈັດ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ທາງລັດ}other{# ທາງລັດ}}"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index ef81b96..3c6db14 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Pridėti prie pagrindinio ekrano"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Valdiklis „<xliff:g id="WIDGET_NAME">%1$s</xliff:g>“ pridėtas prie pagrindinio ekrano"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Pasiūlymai"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Tai, ko jums reikia kasdien"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Naujienos jums"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Jūsų atsipalaidavimo zona"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Pasiekite mankštos tikslus"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Visada žinokite, kokie bus orai"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Jums taip pat gali patikti"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> valdikliai dešinėje, paieška ir parinktys kairėje"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# valdiklis}one{# valdiklis}few{# valdikliai}many{# valdiklio}other{# valdiklių}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# spartusis klavišas}one{# spartusis klavišas}few{# spartieji klavišai}many{# sparčiojo klavišo}other{# sparčiųjų klavišų}}"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 86f7603..6b5c72c 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Pievienot sākuma ekrānam"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Logrīks “<xliff:g id="WIDGET_NAME">%1$s</xliff:g>” ir pievienots sākuma ekrānam"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Ieteikumi"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Jums ikdienā vajadzīgais"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Ziņas jums"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Jūsu atpūtas stūrītis"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Sasniedziet fitnesa mērķus"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Neļaujiet laikapstākļiem jūs pārsteigt"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Jums varētu patikt arī…"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Pa labi logrīki <xliff:g id="SELECTED_HEADER">%1$s</xliff:g>, pa kreisi meklēšana un iespējas"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# logrīks}zero{# logrīku}one{# logrīks}other{# logrīki}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# saīsne}zero{# saīšņu}one{# saīsne}other{# saīsnes}}"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 184d7cc..1029c2c 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Додај на почетниот екран"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Виџетот <xliff:g id="WIDGET_NAME">%1$s</xliff:g> е додаден на почетниот екран"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Предлози"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Вашите секојдневни неопходности"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Вести за вас"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Вашата зона за релаксација"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Достигнете ги целите за фитнес"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Бидете во тек со временската прогноза"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Можеби ќе ви се допадне и"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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-ml/strings.xml b/res/values-ml/strings.xml
index 3952b22..5d8f4ae 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"ഹോം സ്ക്രീനിലേക്ക് ചേർക്കുക"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> വിജറ്റ് ഹോം സ്ക്രീനിലേക്ക് ചേർത്തു"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"നിർദ്ദേശങ്ങൾ"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"ഓരോ ദിവസവും ആവശ്യമായവ"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"നിങ്ങൾക്കായുള്ള വാർത്ത"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"നിങ്ങൾക്ക് സുഖപ്രദമായ സ്ഥലം"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"ശാരീരികക്ഷമതയുമായി ബന്ധപ്പെട്ട ലക്ഷ്യങ്ങൾ കൈവരിക്കൂ"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"കാലാവസ്ഥ മുൻകൂട്ടി മനസ്സിലാക്കുക"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"നിങ്ങൾക്ക് ഇനിപ്പറയുന്നവ ഇഷ്ടമായേക്കാം"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# വിജറ്റ്}other{# വിജറ്റുകൾ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# കുറുക്കുവഴി}other{# കുറുക്കുവഴികൾ}}"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 7a73041..72cf6bf 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Үндсэн нүүрэнд нэмэх"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> виджетийг үндсэн нүүрэнд нэмсэн"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Зөвлөмжүүд"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Таны өдөр тутмын хэрэгцээт зүйлс"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Танд зориулсан мэдээ"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Таны амралтын бүс"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Фитнесийн зорилгодоо хүрээрэй"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Цаг агаарын урьдчилсан мэдээлэлтэй байгаарай"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Танд таалагдаж магадгүй"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# виджет}other{# виджет}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# товчлол}other{# товчлол}}"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index c54f614..62a3a04 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"होम स्क्रीनवर जोडा"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> हे विजेट तुमच्या होम स्क्रीनवर जोडले आहे"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"सूचना"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"तुमच्या दररोजच्या आवश्यक गोष्टी"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"तुमच्यासाठी बातम्या"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"तुमचा आरामदायक झोन"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"तुमची फिटनेस ध्येये गाठा"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"हवामानासंबंधित बातम्या आगामी मिळवा"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"तुम्हाला हेदेखील आवडू शकते"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# विजेट}other{# विजेट}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# शॉर्टकट}other{# शॉर्टकट}}"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index ac7f8ed..5da5ae8 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Tambahkan pada skrin utama"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ditambahkan pada skrin utama"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Cadangan"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Keperluan Harian Anda"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Berita Untuk Anda"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zon Santai Anda"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Capai Matlamat Kecergasan Anda"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Ketahui Perkembangan Terkini Cuaca"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Anda Mungkin Turut Menyukai"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widget <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> pada sebelah kanan, carian dan pilihan pada sebelah kiri"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# pintasan}other{# pintasan}}"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index c3067bb..637b6e8 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"ပင်မစာမျက်နှာတွင် ထည့်ရန်"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်ကို ပင်မစာမျက်နှာတွင် ထည့်လိုက်ပြီ"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"အကြံပြုချက်"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"သင်၏ နေ့စဉ်မရှိမဖြစ်များ"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"သင့်အတွက် သတင်းများ"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"သင်အနားယူသောနေရာ"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"သင့်ကြံ့ခိုင်ရေးပန်းတိုင်ဆီ သွားရန်"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"မိုးလေဝသကို ကြိုတင်ကာကွယ်ရန်"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"သင်နှစ်သက်နိုင်သောအရာများ"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{ဝိဂျက် # ခု}other{ဝိဂျက် # ခု}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ဖြတ်လမ်းလင့်ခ် # ခု}other{ဖြတ်လမ်းလင့်ခ် # ခု}}"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 72ac454..e70983d 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Legg til på startskjermen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>-modulen er lagt til på startskjermen"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Forslag"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Viktige apper for dagliglivet"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Nyheter for deg"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Avslappingssonen din"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Nå treningsmålene dine"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Hold deg i forkant av været"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Kanskje du også liker"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> moduler til høyre, søk og alternativer til venstre"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# modul}other{# moduler}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# snarvei}other{# snarveier}}"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index bf5a214..db15495 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"होम स्क्रिनमा राख्नुहोस्"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"होम स्क्रिनमा <xliff:g id="WIDGET_NAME">%1$s</xliff:g> विजेट हालियो"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"सुझावहरू"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"तपाईंलाई दैनिक आवश्यक पर्ने एपहरू"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"तपाईंका निम्ति सिफारिस गरिएका समाचार"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"तपाईंको Chill Zone"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"आफूले तय गरेको तन्दुरुस्तीको लक्ष्यमा पुग्नुहोस्"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"मौसमको पूर्वानुमान प्राप्त गर्नुहोस्"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"तपाईंलाई निम्न कुराहरू पनि मन पर्न सक्छन्"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# विजेट}other{# वटा विजेट}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# सर्टकट}other{# वटा सर्टकट}}"</string>
diff --git a/res/values-night-v31/colors.xml b/res/values-night-v31/colors.xml
index e462ae0..d23f4d1 100644
--- a/res/values-night-v31/colors.xml
+++ b/res/values-night-v31/colors.xml
@@ -46,6 +46,10 @@
@android:color/system_neutral2_200</color>
<color name="widget_picker_collapse_handle_color_dark">
@android:color/system_neutral2_700</color>
+ <color name="widget_picker_add_button_background_color_dark">
+ @android:color/system_accent1_200</color>
+ <color name="widget_picker_add_button_text_color_dark">
+ @android:color/system_accent1_800</color>
<color name="work_fab_bg_color">
@android:color/system_accent1_200</color>
diff --git a/res/values-night/styles.xml b/res/values-night/styles.xml
index d41eb7e..613c2e9 100644
--- a/res/values-night/styles.xml
+++ b/res/values-night/styles.xml
@@ -22,4 +22,10 @@
<item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
<item name="android:windowTranslucentStatus">true</item>
</style>
+
+ <style name="WidgetPickerActivityTheme" parent="@android:style/Theme.Translucent.NoTitleBar">
+ <item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
+ <item name="android:windowBackground">@android:color/transparent</item>
+ <item name="pageIndicatorDotColor">@color/page_indicator_dot_color_dark</item>
+ </style>
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index d639fdc..e350aaf 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Toevoegen aan startscherm"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> toegevoegd aan startscherm"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggesties"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Je dagelijkse essentials"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Nieuws voor jou"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Je chillzone"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Behaal je fitnessdoelen"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Blijf het weer een stap voor"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Misschien ook interessant"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>-widgets aan de rechterkant, zoeken en opties aan de linkerkant"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# snelkoppeling}other{# snelkoppelingen}}"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 181e010..6df47e8 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -31,10 +31,8 @@
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ପାଇଁ ଆପ ସୂଚନା"</string>
<string name="save_app_pair" msgid="5647523853662686243">"ଆପ ପେୟାର ସେଭ କରନ୍ତୁ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
- <!-- no translation found for app_pair_unlaunchable_at_screen_size (3446551575502685376) -->
- <skip />
- <!-- no translation found for app_pair_needs_unfold (4588897528143807002) -->
- <skip />
+ <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ଏହି ଆପ ପେୟାର ଏ ଡିଭାଇସରେ ସମର୍ଥିତ ନୁହେଁ"</string>
+ <string name="app_pair_needs_unfold" msgid="4588897528143807002">"ଏହି ଆପ ପେୟାରକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଡିଭାଇସକୁ ଅନଫୋଲ୍ଡ କରନ୍ତୁ"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"ଏକ ୱିଜେଟକୁ ମୁଭ୍ କରିବା ପାଇଁ ସ୍ପର୍ଶ କରି ଧରି ରଖନ୍ତୁ।"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"ଏକ ୱିଜେଟକୁ ମୁଭ୍ କରିବା ପାଇଁ ଦୁଇଥର-ଟାପ୍ କରି ଧରି ରଖନ୍ତୁ କିମ୍ବା କଷ୍ଟମ୍ କାର୍ଯ୍ୟଗୁଡ଼ିକୁ ବ୍ୟବହାର କରନ୍ତୁ।"</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -44,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"ହୋମ ସ୍କ୍ରିନରେ ଯୋଗ କରନ୍ତୁ"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>ର ୱିଜେଟ ହୋମ ସ୍କ୍ରିନରେ ଯୋଡ଼ାଗଲା"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"ପରାମର୍ଶଗୁଡ଼ିକ"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"ଆପଣଙ୍କ ଦୈନନ୍ଦିନ ଅତ୍ୟାବଶ୍ୟକୀୟ"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"ଆପଣଙ୍କ ପାଇଁ ନ୍ୟୁଜ"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"ଆପଣଙ୍କ ଚିଲ ଜୋନ"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"ଆପଣଙ୍କ ଫିଟନେସ ଲକ୍ଷ୍ୟରେ ପହଞ୍ଚନ୍ତୁ"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"ପାଣିପାଗ ବିଷୟରେ ଆଗୁଆ ସୂଚନା ପାଆନ୍ତୁ"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"ଆପଣ ମଧ୍ୟ ପସନ୍ଦ କରିପାରନ୍ତି"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# ୱିଜେଟ}other{# ୱିଜେଟ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{#ଟି ସର୍ଟକଟ୍}other{#ଟି ସର୍ଟକଟ୍}}"</string>
@@ -137,8 +144,7 @@
<string name="app_installing_title" msgid="5864044122733792085">"<xliff:g id="NAME">%1$s</xliff:g> ଇନଷ୍ଟଲ୍ କରାଯାଉଛି, <xliff:g id="PROGRESS">%2$s</xliff:g> ସମ୍ପୂର୍ଣ୍ଣ ହୋଇଛି"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"<xliff:g id="NAME">%1$s</xliff:g> ଡାଉନଲୋଡ୍ ହେଉଛି, <xliff:g id="PROGRESS">%2$s</xliff:g> ସମ୍ପୂର୍ଣ୍ଣ"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> ଇନଷ୍ଟଲ୍ ହେବାକୁ ଅପେକ୍ଷା କରିଛି"</string>
- <!-- no translation found for app_archived_title (9124290918876665128) -->
- <skip />
+ <string name="app_archived_title" msgid="9124290918876665128">"<xliff:g id="NAME">%1$s</xliff:g>କୁ ଆର୍କାଇଭ କରାଯାଇଛି। ଡାଉନଲୋଡ୍ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ।"</string>
<string name="dialog_update_title" msgid="114234265740994042">"ଆପକୁ ଅପଡେଟ କରିବା ଆବଶ୍ୟକ"</string>
<string name="dialog_update_message" msgid="4176784553982226114">"ଏହି ଆଇକନ ପାଇଁ ଆପକୁ ଅପଡେଟ କରାଯାଇନାହିଁ। ଏହି ସର୍ଟକଟକୁ ପୁଣି-ସକ୍ଷମ କରିବା ପାଇଁ ଆପଣ ମାନୁଆଲୀ ଅପଡେଟ କରିପାରିବେ କିମ୍ବା ଆଇକନଟିକୁ କାଢ଼ି ଦେଇପାରିବେ।"</string>
<string name="dialog_update" msgid="2178028071796141234">"ଅପଡେଟ କରନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 7ed539f..48f6bba 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ਵਿਜੇਟ ਨੂੰ ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"ਸੁਝਾਅ"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"ਤੁਹਾਡੇ ਰੋਜ਼ਾਨਾ ਦੀਆਂ ਲੋੜੀਂਦੀਆਂ ਚੀਜ਼ਾਂ"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"ਤੁਹਾਡੇ ਲਈ ਖਬਰਾਂ"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"ਤੁਹਾਡੇ ਲਈ ਸਕੂਨਮਈ ਖੇਤਰ"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"ਆਪਣੇ ਫਿੱਟਨੈੱਸ ਸੰਬੰਧੀ ਟੀਚੇ ਹਾਸਲ ਕਰੋ"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"ਮੌਸਮ ਬਾਰੇ ਅੱਪ-ਟੂ-ਡੇਟ ਰਹੋ"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"ਸ਼ਾਇਦ ਤੁਸੀਂ ਇਹ ਵੀ ਪਸੰਦ ਕਰੋ"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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-pl/strings.xml b/res/values-pl/strings.xml
index e382ba9..38f04de 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -42,12 +42,14 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj do ekranu głównego"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> został dodany do ekranu głównego"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestie"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Niezbędne na co dzień"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Wiadomości dla Ciebie"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Niezbędne"</string>
+ <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Wiadomości i czasopisma"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Strefa relaksu"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Zadbaj o swoją formę"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Nie daj się zaskoczyć pogodzie"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"To też może Cię zainteresować"</string>
+ <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Rozrywka"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Społecznościowe"</string>
+ <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Zdrowie i fitness"</string>
+ <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Pogoda"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Proponowane dla Ciebie"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widżety (<xliff:g id="SELECTED_HEADER">%1$s</xliff:g>) po prawej, wyszukiwanie i opcje po lewej"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widżet}few{# widżety}many{# widżetów}other{# widżetu}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# skrót}few{# skróty}many{# skrótów}other{# skrótu}}"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 24f3b06..6130981 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Adicionar ao ecrã principal"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> adicionado ao ecrã principal"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestões"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Os seus essenciais do dia a dia"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Notícias para si"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"A sua zona de relaxamento"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Atingir os seus objetivos de fitness"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Ficar a par da meteorologia"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Também poderá gostar de"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets de <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> à direita, pesquisa e opções à esquerda"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atalho}other{# atalhos}}"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 4417174..f8ec2e8 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Adicionar à tela inicial"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> adicionado à tela inicial"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestões"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Seus itens diários essenciais"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Notícias para você"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Sua zona de relaxamento"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Alcance seus objetivos fitness"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Fique por dentro da previsão do tempo"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Você também pode gostar de"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgets da <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> à direita, pesquisa e opções à esquerda"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# widgets}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# atalho}one{# atalho}other{# atalhos}}"</string>
@@ -135,7 +144,7 @@
<string name="app_installing_title" msgid="5864044122733792085">"Instalando <xliff:g id="NAME">%1$s</xliff:g>. <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Fazendo download de <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="PROGRESS">%2$s</xliff:g> concluído"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"Aguardando instalação de <xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="app_archived_title" msgid="9124290918876665128">"O app <xliff:g id="NAME">%1$s</xliff:g> está arquivado. Toque para fazer o download."</string>
+ <string name="app_archived_title" msgid="9124290918876665128">"O app <xliff:g id="NAME">%1$s</xliff:g> está arquivado. Toque para baixar."</string>
<string name="dialog_update_title" msgid="114234265740994042">"Atualização obrigatória do app"</string>
<string name="dialog_update_message" msgid="4176784553982226114">"O app desse ícone não está atualizado. Você pode remover o ícone ou atualizar o app manualmente para reativar esse atalho."</string>
<string name="dialog_update" msgid="2178028071796141234">"Atualizar"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 9eab793..ffd14b9 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Adaugă pe ecranul de pornire"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widgetul <xliff:g id="WIDGET_NAME">%1$s</xliff:g> a fost adăugat pe ecranul de pornire"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestii"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Instrumente esențiale de zi cu zi"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Știri pentru tine"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona de relaxare"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Atinge-ți obiectivele de fitness"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Fii la curent cu prognoza meteo"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"S-ar putea să îți placă și"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgeturi pentru <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> în dreapta, căutare și opțiuni în stânga"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}few{# widgeturi}other{# de widgeturi}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# comandă rapidă}few{# comenzi rapide}other{# de comenzi rapide}}"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 1e8407a..6dbd0ac 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Добавить на главный экран"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Виджет \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\" добавлен на главный экран"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Подсказки"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Самое важное"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Новости для вас"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Развлечение и общение"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Ваши фитнес-цели"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Прогноз погоды"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Другие рекомендации"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# виджет}few{# виджета}many{# виджетов}other{# виджета}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ярлык}one{# ярлык}few{# ярлыка}many{# ярлыков}other{# ярлыка}}"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index ad5d158..fa55eb9 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"මුල් තිරය වෙත එක් කරන්න"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> විජට්ටුව මුල් පිටු තිරය වෙත එක් කරන ලදි"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"යෝජනා"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"ඔබේ දෛනික අත්යවශ්යාංග"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"ඔබ වෙනුවෙන් පුවත්"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"ඔබේ නිවුණු කලාපය"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"ඔබේ යෝග්යතා ඉලක්ක ළඟා කර ගන්න"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"කාලගුණයට ඉදිරියෙන් සිටින්න"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"ඔබ මේවාට ද කැමති විය හැක"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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-sk/strings.xml b/res/values-sk/strings.xml
index b4b67a1..6443af7 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Pridať na plochu"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Na plochu bola pridaná miniaplikácia <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Návrhy"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Vaše každodenné základné položky"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Vaše správy"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaša komfortná zóna"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Dosiahnite svoje kondičné ciele"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Získavajte informácie o počasí v predstihu"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Mohlo by sa vám páčiť"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Miniaplikácie <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> vpravo, vyhľadávanie a možnosti vľavo"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# miniaplikácia}few{# miniaplikácie}many{# widgets}other{# miniaplikácií}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# odkaz}few{# odkazy}many{# shortcuts}other{# odkazov}}"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 9472e44..5f1c7a1 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na začetni zaslon"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Pripomoček »<xliff:g id="WIDGET_NAME">%1$s</xliff:g>« je dodan na začetni zaslon."</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Predlogi"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Vaše dnevne potrebščine"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Novice za vas"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaš kotiček za sprostitev"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Dosegajte cilje glede telesne pripravljenosti"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Bodite na tekočem z vremenom"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Morda vam bo všeč tudi"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Pripomočki <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> na desni, iskanje in možnosti na levi"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# pripomoček}one{# pripomoček}two{# pripomočka}few{# pripomočki}other{# pripomočkov}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# bližnjica}one{# bližnjica}two{# bližnjici}few{# bližnjice}other{# bližnjic}}"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index bfc6fb3..c6a7740 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Shto në ekranin bazë"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Miniaplikacioni <xliff:g id="WIDGET_NAME">%1$s</xliff:g> u shtua në ekranin bazë"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugjerime"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Aplikacionet thelbësore të përditshme"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Lajme për ty"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona jote e qetësisë"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Realizo objektivat e stërvitjes"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Qëndro i informuar për motin"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Gjithashtu mund të të pëlqejë"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Miniaplikacionet e <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> në të djathtë, kërkimi dhe opsionet në të majtë"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# miniaplikacion}other{# miniaplikacione}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shkurtore}other{# shkurtore}}"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 270654d..0fbdc7f 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Додај на почетни екран"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Додали сте виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g> на почетни екран"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Предлози"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Основни виџети за сваки дан"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Вести за вас"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Зона за опуштање"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Остварите фитнес циљеве"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Будите у току са временским приликама"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Можда ће вам се допасти и"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# виџет}few{# виџета}other{# виџета}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# пречица}one{# пречица}few{# пречице}other{# пречица}}"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index bc72b3c..49ef90f 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Lägg till på startskärmen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget för <xliff:g id="WIDGET_NAME">%1$s</xliff:g> har lagts till på startskärmen"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Förslag"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Det viktigaste i vardagen"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Nyheter för dig"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Koppla av"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Nå dina träningsmål"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Håll koll på vädret"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Andra appar du kanske gillar"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Widgetar för <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> till höger, sökning och alternativ till vänster"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgetar}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# genväg}other{# genvägar}}"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 193c92e..d18466e 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Weka kwenye skrini ya kwanza"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Umeongeza wijeti ya <xliff:g id="WIDGET_NAME">%1$s</xliff:g> kwenye skrini ya kwanza"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Mapendekezo"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Hati Zako Muhimu za Kila Siku"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Habari Kwa Ajili Yako"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Mahali Pako pa Kupumzika"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Fikia Malengo Yako ya Siha"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Pata Taarifa kuhusu Hali ya Hewa"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Huenda Pia Ukapenda"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Wijeti za <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ziko upande wa kulia, utafutaji na chaguo ziko upande wa kushoto"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{Wijeti #}other{Wijeti #}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{Njia # ya mkato}other{Njia # za mkato}}"</string>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 3c79588..27aba6b 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -37,6 +37,7 @@
<!-- Widget picker-->
<dimen name="widget_list_horizontal_margin">30dp</dimen>
+ <dimen name="widget_cell_horizontal_padding">16dp</dimen>
<!-- Folder spaces -->
<dimen name="folder_footer_horiz_padding">24dp</dimen>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index aa65193..1e4e549 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"முகப்புத் திரையில் சேர்"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> விட்ஜெட் முகப்புத் திரையில் சேர்க்கப்பட்டது"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"பரிந்துரைகள்"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"உங்கள் தினசரி அத்தியாவசியத் தேவைகள்"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"உங்களுக்கான செய்திகள்"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"உங்கள் மனதுக்கு இதமானவை"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"உடற்பயிற்சி இலக்குகளை அடையுங்கள்"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"வானிலை குறித்து முன்கூட்டியே அறிந்திருங்கள்"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"நீங்கள் இவற்றையும் விரும்பக்கூடும்"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# விட்ஜெட்}other{# விட்ஜெட்டுகள்}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ஷார்ட்கட்}other{# ஷார்ட்கட்கள்}}"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 5f104e2..61d2bff 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"మొదటి స్క్రీన్కు జోడించండి"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"మొదటి స్క్రీన్కు <xliff:g id="WIDGET_NAME">%1$s</xliff:g> విడ్జెట్ జోడించబడింది"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"సూచనలు"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"మీ రోజువారీ అవసరాలు"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"మీ కోసం వార్తలు"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"మీరు ప్రశాంతంగా ఉండే ప్రదేశం"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"ఫిట్నెస్ లక్ష్యాలను చేరుకోండి"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"వాతావరణాన్ని ముందుగానే తెలుసుకోండి"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"మీరు వీటిని కూడా ఇష్టపడవచ్చు"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# విడ్జెట్}other{# విడ్జెట్లు}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# షార్ట్కట్}other{# షార్ట్కట్లు}}"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index c3c2c20..a2541b8 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"เพิ่มลงในหน้าจอหลัก"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"เพิ่มวิดเจ็ต <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ลงในหน้าจอหลักแล้ว"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"คำแนะนำ"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"สิ่งจำเป็นในชีวิตประจำวันของคุณ"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"ข่าวสารสำหรับคุณ"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"พื้นที่สบายๆ ของคุณ"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"บรรลุเป้าหมายการออกกำลังกาย"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"รู้สภาพอากาศล่วงหน้า"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"คุณอาจชอบ"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{วิดเจ็ต # รายการ}other{วิดเจ็ต # รายการ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ทางลัด # รายการ}other{ทางลัด # รายการ}}"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 8e4dc1d..a287044 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -42,12 +42,14 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Idagdag sa home screen"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Idinagdag sa home screen ang widget na <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Mga Suhestyon"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Ang Pang-araw-araw Mong Mga Essential"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Balita para sa Iyo"</string>
+ <string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Mga essential"</string>
+ <string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Balita at mga magazine"</string>
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ang Iyong Chill Zone"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Makamit ang Iyong Mga Layunin sa Fitness"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Manatiling Handa sa Lagay ng Panahon"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Baka Magustuhan Mo Rin"</string>
+ <string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entertainment"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
+ <string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Kalusugan at fitness"</string>
+ <string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Lagay ng panahon"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Iminumungkahi para sa iyo"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Mga widget ng <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> sa kanan, paghahanap at mga opsyon sa kaliwa"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}one{# widget}other{# na widget}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# shortcut}one{# shortcut}other{# na shortcut}}"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 7633940..8149063 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Ana ekrana ekle"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> widget\'ı ana ekrana eklendi"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Öneriler"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Günlük Gerekenler"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Size özel haberler"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Huzur alanınız"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Fitness hedeflerinize ulaşın"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Havanın durumu sizi şaşırtmasın"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Şunları da beğenebilirsiniz"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widget\'ları sağda, arama ve seçenekler solda"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widget}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# kısayol}other{# kısayol}}"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index f532da1..1167408 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Додати на головний екран"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Віджет <xliff:g id="WIDGET_NAME">%1$s</xliff:g> додано на головний екран"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Пропозиції"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Найнеобхідніше на кожен день"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Новини для вас"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Ваша зона розваг"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Досягайте своїх фітнес-цілей"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Завчасно дізнавайтеся про зміни погоди"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Вам також може сподобатися"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# віджет}few{# віджети}many{# віджетів}other{# віджета}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ярлик}one{# ярлик}few{# ярлики}many{# ярликів}other{# ярлика}}"</string>
@@ -111,7 +120,7 @@
<string name="folder_name_format_exact" msgid="8626242716117004803">"Папка \"<xliff:g id="NAME">%1$s</xliff:g>\", елементів: <xliff:g id="SIZE">%2$d</xliff:g>"</string>
<string name="folder_name_format_overflow" msgid="4270108890534995199">"Папка \"<xliff:g id="NAME">%1$s</xliff:g>\", елементів: <xliff:g id="SIZE">%2$d</xliff:g> або більше"</string>
<string name="app_pair_name_format" msgid="8134106404716224054">"Одночасне використання двох додатків: <xliff:g id="APP1">%1$s</xliff:g> і <xliff:g id="APP2">%2$s</xliff:g>"</string>
- <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Оформлення і стиль"</string>
+ <string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Оформлення й стиль"</string>
<string name="edit_home_screen" msgid="8947858375782098427">"Редагувати головний екран"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Налаштування головного екрана"</string>
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"Вимкнув адміністратор"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index c945bab..9555742 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"ہوم اسکرین میں شامل کریں"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ویجیٹ کو ہوم اسکرین میں شامل کیا گیا"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"تجاویز"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"آپ کے روز مرہ کے لوازمات"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"آپ کے لیے خبریں"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"آپ کا آرام دہ زون"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"اپنی تندرستی کے مقاصد حاصل کریں"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"موسم سے باخبر رہیں"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"آپ کو یہ بھی پسند آ سکتا ہے"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# ویجیٹ}other{# ویجیٹس}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# شارٹ کٹ}other{# شارٹ کٹس}}"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 4fbacb7..22ec767 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Bosh ekranga chiqarish"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> vidjeti bosh ekranga qoʻshildi"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Takliflar"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Kunlik muhim vazifalaringiz"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Siz uchun yangiliklar"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Sokin hududingiz"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Fitness maqsadlaringizga erishing"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Doim ob-havodan oldinda yuring"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Sizga yoqishi mumkin"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> vidjetlari oʻngda, qidiruv va sozlamalar chapda"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ta vidjet}other{# ta vidjet}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ta yorliq}other{# ta yorliq}}"</string>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index e2f610e..fa87221 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -47,8 +47,8 @@
<color name="wallpaper_popup_scrim">@android:color/system_neutral1_900</color>
- <color name="folder_pagination_color_light">@android:color/system_accent1_600</color>
- <color name="folder_pagination_color_dark">@android:color/system_accent1_200</color>
+ <color name="page_indicator_dot_color_light">@android:color/system_accent1_600</color>
+ <color name="page_indicator_dot_color_dark">@android:color/system_accent1_200</color>
<color name="home_settings_header_accent">@android:color/system_accent1_600</color>
<color name="home_settings_header_collapsed">@android:color/system_neutral1_100</color>
@@ -97,6 +97,10 @@
@android:color/system_neutral2_700</color>
<color name="widget_picker_collapse_handle_color_light">
@android:color/system_neutral2_200</color>
+ <color name="widget_picker_add_button_background_color_light">
+ @android:color/system_accent1_600</color>
+ <color name="widget_picker_add_button_text_color_light">
+ @android:color/system_accent1_0</color>
<color name="work_fab_bg_color">
@android:color/system_accent1_200</color>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 290adac..7e80c7a 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Thêm vào màn hình chính"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Đã thêm tiện ích <xliff:g id="WIDGET_NAME">%1$s</xliff:g> vào màn hình chính"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Nội dung đề xuất"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Các tiện ích thiết yếu hằng ngày của bạn"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Tin tức cho bạn"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Giai điệu thư giãn của bạn"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Đạt được mục tiêu tập thể dục"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Luôn nắm bắt tình hình thời tiết"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Có thể bạn cũng thích"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Tiện ích <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> ở bên phải, công cụ tìm kiếm và tuỳ chọn ở bên trái"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# tiện ích}other{# tiện ích}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# lối tắt}other{# lối tắt}}"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 26f42d8..469f3e0 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"添加到主屏幕"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已将“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件添加到主屏幕"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"建议"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"您的日常必需品"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"更多相关新闻"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"您的休闲区"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"达成您的健身目标"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"天气早知道"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"您可能还会喜欢"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# 个微件}other{# 个微件}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 个快捷方式}other{# 个快捷方式}}"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index ff71ad2..329ce31 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"加去主畫面"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已經將「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具加咗去主畫面"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"建議"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"你的日常必需品"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"你的專屬新聞"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"放鬆專區"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"向健身目標邁進"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"隨時掌握天氣資料"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"相關推薦"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# 個小工具}other{# 個小工具}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 個捷徑}other{# 個捷徑}}"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 1385fce..60629f5 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"新增至主畫面"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已將「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具新增到主畫面"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"建議"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"生活好幫手"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"你的專屬新聞"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"放鬆專區"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"達成健身目標"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"隨時掌握天氣資訊"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"你可能也會喜歡的內容"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<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{# 項小工具}other{# 項小工具}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 個捷徑}other{# 個捷徑}}"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 8388bb7..251078c 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -42,12 +42,21 @@
<string name="add_to_home_screen" msgid="9168649446635919791">"Faka kusikrini sasekhaya"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Iwijethi ye-<xliff:g id="WIDGET_NAME">%1$s</xliff:g> yengezwe kusikrini sasekhaya"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Iziphakamiso"</string>
- <string name="productivity_widget_recommendation_category_label" msgid="1722113555721820766">"Okusemqoka kwakho kwansuku zonke"</string>
- <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Izindaba Zakho"</string>
+ <!-- no translation found for productivity_widget_recommendation_category_label (3811812719618323750) -->
+ <skip />
+ <!-- no translation found for news_widget_recommendation_category_label (6756167867113741310) -->
+ <skip />
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Indawo Ozipholela Kuyo"</string>
- <string name="fitness_widget_recommendation_category_label" msgid="2657652999128882431">"Finyelela Imigomo Yakho Yokufaneleka"</string>
- <string name="weather_widget_recommendation_category_label" msgid="6712678763480668598">"Hlale Wazi Ngesimo Sezulu"</string>
- <string name="others_widget_recommendation_category_label" msgid="897876078077284733">"Ungase Futhi Uthande"</string>
+ <!-- no translation found for entertainment_widget_recommendation_category_label (3973107268630717874) -->
+ <skip />
+ <!-- no translation found for social_widget_recommendation_category_label (689147679536384717) -->
+ <skip />
+ <!-- no translation found for fitness_widget_recommendation_category_label (2756483898236585324) -->
+ <skip />
+ <!-- no translation found for weather_widget_recommendation_category_label (3059715991930798039) -->
+ <skip />
+ <!-- no translation found for others_widget_recommendation_category_label (5555987036267226245) -->
+ <skip />
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"Amawijethi okuthi <xliff:g id="SELECTED_HEADER">%1$s</xliff:g> kwesokudla, ukusesha nokukhethwayo kwesobunxele"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{iwijethi #}one{amawijethi #}other{amawijethi #}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{isinqamuleli #}one{izinqamuleli #}other{izinqamuleli #}}"</string>
diff --git a/res/values/attrs.xml b/res/values/attrs.xml
index 4a0b5e8..a1edbb9 100644
--- a/res/values/attrs.xml
+++ b/res/values/attrs.xml
@@ -44,7 +44,7 @@
<attr name="notificationDotColor" format="color" />
<attr name="focusOutlineColor" format="color" />
- <attr name="folderPaginationColor" format="color" />
+ <attr name="pageIndicatorDotColor" format="color" />
<attr name="folderPreviewColor" format="color" />
<attr name="folderBackgroundColor" format="color" />
<attr name="folderIconRadius" format="float" />
@@ -72,6 +72,8 @@
<attr name="widgetPickerSelectedTabTextColor" format="color"/>
<attr name="widgetPickerUnselectedTabTextColor" format="color"/>
<attr name="widgetPickerCollapseHandleColor" format="color"/>
+ <attr name="widgetPickerAddButtonBackgroundColor" format="color"/>
+ <attr name="widgetPickerAddButtonTextColor" format="color"/>
<!-- BubbleTextView specific attributes. -->
<declare-styleable name="BubbleTextView">
diff --git a/res/values/colors.xml b/res/values/colors.xml
index 6a484d7..a620eb0 100644
--- a/res/values/colors.xml
+++ b/res/values/colors.xml
@@ -73,8 +73,8 @@
<color name="folder_preview_light">#7FCFFF</color>
<color name="folder_preview_dark">#1E1F20</color>
- <color name="folder_pagination_color_light">#0B57D0</color>
- <color name="folder_pagination_color_dark">#A8C7FA</color>
+ <color name="pagination_indicator_dot_color_light">#0B57D0</color>
+ <color name="pagination_indicator_dot_color_dark">#A8C7FA</color>
<color name="text_color_primary_dark">#FFFFFFFF</color>
<color name="text_color_secondary_dark">#FFFFFFFF</color>
@@ -113,6 +113,8 @@
<color name="widget_picker_selected_tab_text_color_light">#FFFFFF</color>
<color name="widget_picker_unselected_tab_text_color_light">#444746</color>
<color name="widget_picker_collapse_handle_color_light">#C4C7C5</color>
+ <color name="widget_picker_add_button_background_color_light">#0B57D0</color>
+ <color name="widget_picker_add_button_text_color_light">#0B57D0</color>
<color name="widget_picker_primary_surface_color_dark">#1F2020</color>
<color name="widget_picker_secondary_surface_color_dark">#393939</color>
@@ -128,6 +130,8 @@
<color name="widget_picker_selected_tab_text_color_dark">#2D312F</color>
<color name="widget_picker_unselected_tab_text_color_dark">#C4C7C5</color>
<color name="widget_picker_collapse_handle_color_dark">#444746</color>
+ <color name="widget_picker_add_button_background_color_dark">#062E6F</color>
+ <color name="widget_picker_add_button_text_color_dark">#FFFFFF</color>
<color name="material_color_on_secondary_fixed_variant">#3F4759</color>
<color name="material_color_on_tertiary_fixed_variant">#583E5B</color>
diff --git a/res/values/config.xml b/res/values/config.xml
index 21d6024..048d6cc 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -159,6 +159,9 @@
<item name="swipe_up_rect_scale_damping_ratio" type="dimen" format="float">0.75</item>
<item name="swipe_up_rect_scale_stiffness" type="dimen" format="float">200</item>
<item name="swipe_up_rect_scale_higher_stiffness" type="dimen" format="float">400</item>
+ <!-- Flag: enableScalingRevealHomeAnimation() -->
+ <item name="swipe_up_rect_scale_damping_ratio_v2" type="dimen" format="float">0.8</item>
+ <item name="swipe_up_rect_scale_stiffness_v2" type="dimen" format="float">650</item>
<item name="swipe_up_rect_xy_fling_friction" type="dimen" format="float">1.5</item>
@@ -166,6 +169,11 @@
<item name="swipe_up_rect_xy_damping_ratio" type="dimen" format="float">0.8</item>
<item name="swipe_up_rect_xy_stiffness" type="dimen" format="float">200</item>
+ <!-- Flag: enableScalingRevealHomeAnimation() -->
+ <item name="swipe_up_rect_x_damping_ratio" type="dimen" format="float">0.965</item>
+ <item name="swipe_up_rect_x_stiffness" type="dimen" format="float">300</item>
+ <item name="swipe_up_rect_y_damping_ratio" type="dimen" format="float">0.95</item>
+ <item name="swipe_up_rect_y_stiffness" type="dimen" format="float">190</item>
<!-- Taskbar -->
<!-- This is a float because it is converted to dp later in DeviceProfile -->
@@ -190,6 +198,12 @@
<dimen name="swipe_up_fling_min_visible_change">18dp</dimen>
<dimen name="swipe_up_max_workspace_trans_y">-60dp</dimen>
<dimen name="swipe_up_max_velocity">7.619dp</dimen>
+ <!-- Flag: enableScalingRevealHomeAnimation() -->
+ <item name="swipe_up_min_velocity_x_px_per_s" type="dimen" format="integer">300</item>
+ <item name="swipe_up_max_velocity_x_px_per_s" type="dimen" format="integer">500</item>
+ <item name="swipe_up_min_velocity_y_px_per_s" type="dimen" format="integer">2000</item>
+ <item name="swipe_up_max_velocity_y_px_per_s" type="dimen" format="integer">5000</item>
+ <item name="swipe_up_max_velocity_fall_off_factor" type="dimen" format="float">1.4</item>
<array name="dynamic_resources">
<item>@dimen/swipe_up_scale_start</item>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index a912e2d..d265790 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -22,7 +22,7 @@
<dimen name="dynamic_grid_edge_margin">10.77dp</dimen>
<dimen name="dynamic_grid_left_right_margin">8dp</dimen>
<!-- Minimum amount of next page visible in spring loaded mode -->
- <dimen name="dynamic_grid_spring_loaded_min_next_space_visible">24dp</dimen>
+ <dimen name="dynamic_grid_spring_loaded_min_next_space_visible">48dp</dimen>
<dimen name="dynamic_grid_cell_border_spacing">16dp</dimen>
<dimen name="cell_layout_padding">10.77dp</dimen>
@@ -176,10 +176,14 @@
<!-- Widget tray -->
<dimen name="widget_cell_vertical_padding">8dp</dimen>
- <dimen name="widget_cell_horizontal_padding">16dp</dimen>
+ <dimen name="widget_cell_horizontal_padding">8dp</dimen>
<dimen name="widget_cell_font_size">14sp</dimen>
<dimen name="widget_cell_app_icon_size">24dp</dimen>
<dimen name="widget_cell_app_icon_padding">8dp</dimen>
+ <dimen name="widget_cell_add_button_height">48dp</dimen>
+ <dimen name="widget_cell_add_button_start_padding">8dp</dimen>
+ <dimen name="widget_cell_add_button_end_padding">16dp</dimen>
+ <dimen name="widget_cell_add_button_vertical_padding">10dp</dimen>
<dimen name="widget_tabs_button_horizontal_padding">4dp</dimen>
<dimen name="widget_tabs_horizontal_padding">16dp</dimen>
@@ -187,7 +191,6 @@
<dimen name="widget_picker_landscape_tablet_left_right_margin">117dp</dimen>
<dimen name="widget_picker_two_panels_left_right_margin">0dp</dimen>
<dimen name="widget_recommendations_table_vertical_padding">8dp</dimen>
- <dimen name="widget_recommendations_table_horizontal_padding">16dp</dimen>
<!-- Bottom margin for the search and recommended widgets container without work profile -->
<dimen name="search_and_recommended_widgets_container_bottom_margin">16dp</dimen>
<!-- Bottom margin for the search and recommended widgets container with work profile -->
@@ -198,7 +201,8 @@
<dimen name="widget_list_header_view_vertical_padding">20dp</dimen>
<dimen name="widget_list_entry_spacing">2dp</dimen>
- <dimen name="widget_list_horizontal_margin">16dp</dimen>
+ <!-- Less margin on sides to let widgets table width be close to the workspace width. -->
+ <dimen name="widget_list_horizontal_margin">11dp</dimen>
<!-- Margin applied to the recycler view with search bar & the list of widget apps below it. -->
<dimen name="widget_list_left_pane_horizontal_margin">0dp</dimen>
<dimen name="widget_list_horizontal_margin_two_pane">24dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index aaef15b..0fe9a9b 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -64,6 +64,12 @@
<!-- Spoken text for a screen reader. The placeholder text is the widget name.
[CHAR_LIMIT=none]-->
<string name="widget_preview_context_description"><xliff:g id="widget_name" example="Calendar month view">%1$s</xliff:g> widget</string>
+ <!-- Spoken text for a screen reader. The first placeholder text is the widget name, the
+ remaining placeholders are for the widget dimensions.
+ [CHAR_LIMIT=none]-->
+ <string name="widget_preview_name_and_dims_content_description">
+ <xliff:g id="widget_name" example="Calendar month view">%1$s</xliff:g> widget, %2$d wide by %3$d high
+ </string>
<!-- Message to tell the user to press and hold a widget/icon to add it to the home screen.
[CHAR LIMIT=NONE] -->
<string name="add_item_request_drag_hint">Touch & hold the widget to move it around the home screen</string>
@@ -75,12 +81,14 @@
<!-- Widget suggestions header title in the full widgets picker for large screen devices
in landscape mode. [CHAR_LIMIT=50] -->
<string name="suggested_widgets_header_title">Suggestions</string>
- <string name="productivity_widget_recommendation_category_label">Your Daily Essentials</string>
- <string name="news_widget_recommendation_category_label">News For You</string>
+ <string name="productivity_widget_recommendation_category_label">Essentials</string>
+ <string name="news_widget_recommendation_category_label">News & magazines</string>
<string name="social_and_entertainment_widget_recommendation_category_label">Your Chill Zone</string>
- <string name="fitness_widget_recommendation_category_label">Reach Your Fitness Goals</string>
- <string name="weather_widget_recommendation_category_label">Stay Ahead of the Weather</string>
- <string name="others_widget_recommendation_category_label">You Might Also Like</string>
+ <string name="entertainment_widget_recommendation_category_label">Entertainment</string>
+ <string name="social_widget_recommendation_category_label">Social</string>
+ <string name="fitness_widget_recommendation_category_label">Health & fitness</string>
+ <string name="weather_widget_recommendation_category_label">Weather</string>
+ <string name="others_widget_recommendation_category_label">Suggested for you</string>
<!-- accessibilityPaneTitle for the right pane when showing suggested widgets. -->
<string name="widget_picker_right_pane_accessibility_title"><xliff:g id="selected_header" example="Calendar">%1$s</xliff:g> widgets on right, search and options on left</string>
<!-- Label for showing the number of widgets an app has in the full widgets picker.
@@ -123,6 +131,12 @@
<!-- A widget category label for grouping widgets related to note taking. [CHAR_LIMIT=30] -->
<string name="widget_category_note_taking">Note-taking</string>
+ <!-- Text on the button that adds a widget to the home screen. [CHAR_LIMIT=15] -->
+ <string name="widget_add_button_label">Add</string>
+ <!-- Accessibility content description for the button that adds a widget to the home screen. The
+ placeholder text is the widget name. [CHAR_LIMIT=none] -->
+ <string name="widget_add_button_content_description">Add <xliff:g id="widget_name" example="Calendar month view">%1$s</xliff:g> widget</string>
+
<!-- Title of a dialog. This dialog lets a user know how they can use widgets on their phone.
[CHAR_LIMIT=NONE] -->
<string name="widget_education_header">Useful info at your fingertips</string>
diff --git a/res/values/styles.xml b/res/values/styles.xml
index 401155d..c2875d9 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -52,8 +52,8 @@
<item name="workspaceAmbientShadowColor">#40000000</item>
<item name="workspaceKeyShadowColor">#89000000</item>
<item name="widgetsTheme">@style/WidgetContainerTheme</item>
+ <item name="pageIndicatorDotColor">@color/page_indicator_dot_color_light</item>
<item name="focusOutlineColor">@color/material_color_on_secondary_container</item>
- <item name="folderPaginationColor">@color/folder_pagination_color_light</item>
<item name="folderPreviewColor">@color/folder_preview_light</item>
<item name="folderBackgroundColor">@color/folder_background_light</item>
<item name="folderIconBorderColor">?android:attr/colorPrimary</item>
@@ -164,7 +164,7 @@
<item name="popupShadeThird">@color/popup_shade_third_dark</item>
<item name="notificationDotColor">@color/notification_dot_color_dark</item>
<item name="widgetsTheme">@style/WidgetContainerTheme.Dark</item>
- <item name="folderPaginationColor">@color/folder_pagination_color_dark</item>
+ <item name="pageIndicatorDotColor">@color/page_indicator_dot_color_dark</item>
<item name="folderPreviewColor">@color/folder_preview_dark</item>
<item name="folderBackgroundColor">@color/folder_background_dark</item>
<item name="folderIconBorderColor">?android:attr/colorPrimary</item>
@@ -261,6 +261,10 @@
@color/widget_picker_unselected_tab_text_color_light</item>
<item name="widgetPickerCollapseHandleColor">
@color/widget_picker_collapse_handle_color_light</item>
+ <item name="widgetPickerAddButtonBackgroundColor">
+ @color/widget_picker_add_button_background_color_light</item>
+ <item name="widgetPickerAddButtonTextColor">
+ @color/widget_picker_add_button_text_color_light</item>
</style>
<style name="WidgetContainerTheme.Dark" parent="AppTheme.Dark">
<item name="android:colorEdgeEffect">?android:attr/textColorSecondary</item>
@@ -292,6 +296,10 @@
@color/widget_picker_unselected_tab_text_color_dark</item>
<item name="widgetPickerCollapseHandleColor">
@color/widget_picker_collapse_handle_color_dark</item>
+ <item name="widgetPickerAddButtonBackgroundColor">
+ @color/widget_picker_add_button_background_color_dark</item>
+ <item name="widgetPickerAddButtonTextColor">
+ @color/widget_picker_add_button_text_color_dark</item>
</style>
<style name="FastScrollerPopup" parent="@android:style/TextAppearance.DeviceDefault.DialogWindowTitle">
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index a9cf2ff..3ee1c61 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -285,9 +285,6 @@
mDotParams.scale = 0f;
mForceHideDot = false;
setBackground(null);
- if (FeatureFlags.enableTwolineAllapps() || FeatureFlags.ENABLE_TWOLINE_DEVICESEARCH.get()) {
- setMaxLines(1);
- }
setTag(null);
if (mIconLoadRequest != null) {
@@ -299,6 +296,7 @@
setAlpha(1);
setScaleY(1);
setTranslationY(0);
+ setMaxLines(1);
setVisibility(VISIBLE);
}
@@ -428,10 +426,9 @@
* Only if actual text can be displayed in two line, the {@code true} value will be effective.
*/
protected boolean shouldUseTwoLine() {
- return FeatureFlags.enableTwolineAllapps() && isCurrentLanguageEnglish()
- && (mDisplay == DISPLAY_ALL_APPS || mDisplay == DISPLAY_PREDICTION_ROW)
- && (!Flags.enableTwolineToggle() || (Flags.enableTwolineToggle()
- && LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(getContext())));
+ return isCurrentLanguageEnglish() && (mDisplay == DISPLAY_ALL_APPS
+ || mDisplay == DISPLAY_PREDICTION_ROW) && (Flags.enableTwolineToggle()
+ && LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(getContext()));
}
protected boolean isCurrentLanguageEnglish() {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 4b4bdc2..3ddc7aa 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -18,6 +18,7 @@
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.Flags.enableOverviewIconMenu;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.InvariantDeviceProfile.INDEX_DEFAULT;
import static com.android.launcher3.InvariantDeviceProfile.INDEX_LANDSCAPE;
import static com.android.launcher3.InvariantDeviceProfile.INDEX_TWO_PANEL_LANDSCAPE;
@@ -101,6 +102,7 @@
public final boolean transposeLayoutWithOrientation;
public final boolean isMultiDisplay;
public final boolean isTwoPanels;
+ public boolean isPredictiveBackSwipe;
public final boolean isQsbInline;
// Device properties in current orientation
@@ -436,7 +438,11 @@
if (isMultiDisplay && !ENABLE_MULTI_DISPLAY_PARTIAL_DEPTH.get()) {
// TODO(b/259893832): Revert to use maxWallpaperScale to calculate bottomSheetDepth
// when screen recorder bug is fixed.
- bottomSheetDepth = 1f;
+ if (enableScalingRevealHomeAnimation()) {
+ bottomSheetDepth = 0.3f;
+ } else {
+ bottomSheetDepth = 1f;
+ }
} else {
// The goal is to set wallpaper to zoom at workspaceContentScale when in AllApps.
// When depth is 0, wallpaper zoom is set to maxWallpaperScale.
@@ -1233,9 +1239,8 @@
if (isVerticalLayout && !mIsResponsiveGrid) {
hideWorkspaceLabelsIfNotEnoughSpace();
}
- if (FeatureFlags.enableTwolineAllapps()
- && (!Flags.enableTwolineToggle() || (Flags.enableTwolineToggle()
- && LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(context)))) {
+ if ((Flags.enableTwolineToggle()
+ && LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(context))) {
// Add extra textHeight to the existing allAppsCellHeight.
allAppsCellHeightPx += Utilities.calculateTextHeight(allAppsIconTextSizePx);
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 8277c3e..72977ee 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -2365,7 +2365,8 @@
* Similar to {@link #getFirstMatch} but optimized to finding a suitable view for the app close
* animation.
*
- * @param preferredItemId The id of the preferred item to match to if it exists.
+ * @param preferredItemId The id of the preferred item to match to if it exists,
+ * or ItemInfo#NO_MATCHING_ID if you want to not match by item id
* @param packageName The package name of the app to match.
* @param user The user of the app to match.
* @param supportsAllAppsState If true and we are in All Apps state, looks for view in All Apps.
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index 99fca62..be01d63 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -20,6 +20,7 @@
import static com.android.launcher3.LauncherAppState.ACTION_FORCE_ROLOAD;
import static com.android.launcher3.config.FeatureFlags.IS_STUDIO_BUILD;
+import static com.android.launcher3.icons.cache.BaseIconCache.EMPTY_CLASS_NAME;
import static com.android.launcher3.model.PackageUpdatedTask.OP_UPDATE;
import static com.android.launcher3.pm.UserCache.ACTION_PROFILE_AVAILABLE;
import static com.android.launcher3.pm.UserCache.ACTION_PROFILE_UNAVAILABLE;
@@ -27,6 +28,7 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInstaller;
@@ -70,6 +72,7 @@
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
+import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
@@ -443,9 +446,18 @@
@NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
IconCache iconCache = app.getIconCache();
final IntSet removedIds = new IntSet();
- HashSet<WorkspaceItemInfo> archivedItemsToCacheRefresh = new HashSet<>();
- HashSet<String> archivedPackagesToCacheRefresh = new HashSet<>();
+ HashSet<WorkspaceItemInfo> archivedWorkspaceItemsToCacheRefresh = new HashSet<>();
+ boolean isAppArchived = new PackageManagerHelper(
+ mApp.getContext()).isAppArchivedForUser(packageName, user);
synchronized (dataModel) {
+ if (isAppArchived) {
+ // Remove package icon cache entry for archived app in case of a session
+ // failure.
+ mApp.getIconCache().remove(
+ new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
+ user);
+ }
+
for (ItemInfo info : dataModel.itemsIdMap) {
if (info instanceof WorkspaceItemInfo
&& ((WorkspaceItemInfo) info).hasPromiseIconUi()
@@ -456,19 +468,16 @@
}
if (((WorkspaceItemInfo) info).isArchived()) {
WorkspaceItemInfo workspaceItem = (WorkspaceItemInfo) info;
- // Remove package cache icon for archived app in case of a session
- // failure.
- mApp.getIconCache().removeIconsForPkg(packageName, user);
// Refresh icons on the workspace for archived apps.
iconCache.getTitleAndIcon(workspaceItem,
workspaceItem.usingLowResIcon());
- archivedPackagesToCacheRefresh.add(packageName);
- archivedItemsToCacheRefresh.add(workspaceItem);
+ archivedWorkspaceItemsToCacheRefresh.add(workspaceItem);
}
}
}
- if (!archivedPackagesToCacheRefresh.isEmpty()) {
- apps.updateIconsAndLabels(archivedPackagesToCacheRefresh, user);
+
+ if (isAppArchived) {
+ apps.updateIconsAndLabels(new HashSet<>(List.of(packageName)), user);
}
}
@@ -477,8 +486,11 @@
ItemInfoMatcher.ofItemIds(removedIds),
"removed because install session failed");
}
- if (!archivedItemsToCacheRefresh.isEmpty()) {
- bindUpdatedWorkspaceItems(archivedItemsToCacheRefresh.stream().toList());
+ if (!archivedWorkspaceItemsToCacheRefresh.isEmpty()) {
+ bindUpdatedWorkspaceItems(
+ archivedWorkspaceItemsToCacheRefresh.stream().toList());
+ }
+ if (isAppArchived) {
bindApplicationsIfNeeded();
}
}
diff --git a/src/com/android/launcher3/LauncherSettings.java b/src/com/android/launcher3/LauncherSettings.java
index 34ebaf2..84b8ba1 100644
--- a/src/com/android/launcher3/LauncherSettings.java
+++ b/src/com/android/launcher3/LauncherSettings.java
@@ -139,6 +139,11 @@
public static final int ITEM_TYPE_SEARCH_ACTION = 9;
/**
+ * Private space install app button.
+ */
+ public static final int ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON = 11;
+
+ /**
* The custom icon bitmap.
* <P>Type: BLOB</P>
*/
@@ -206,6 +211,8 @@
case ITEM_TYPE_TASK: return "TASK";
case ITEM_TYPE_QSB: return "QSB";
case ITEM_TYPE_APP_PAIR: return "APP_PAIR";
+ case ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON:
+ return "PRIVATE_SPACE_INSTALL_APP_BUTTON";
default: return String.valueOf(type);
}
}
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index 9b65a31..f582be0 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -63,7 +63,8 @@
launcher.dragController.cancelDrag()
launcher.workspace.clearDropTargets()
launcher.workspace.removeAllWorkspaceScreens()
- launcher.appWidgetHolder.clearViews()
+ // Avoid clearing the widget update listeners for staying up-to-date with widget info
+ launcher.appWidgetHolder.clearWidgetViews()
launcher.hotseat?.resetLayout(launcher.deviceProfile.isVerticalBarLayout)
TraceHelper.INSTANCE.endSection()
}
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index e861d38..f130b89 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -405,7 +405,9 @@
} else if (item instanceof PendingAddItemInfo) {
PendingAddItemInfo info = (PendingAddItemInfo) item;
Workspace<?> workspace = mContext.getWorkspace();
- workspace.snapToPage(workspace.getPageIndexForScreenId(screenId));
+ workspace.post(
+ () -> workspace.snapToPage(workspace.getPageIndexForScreenId(screenId))
+ );
mContext.addPendingItem(info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
screenId, coordinates, info.spanX, info.spanY);
} else if (item instanceof WorkspaceItemInfo) {
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index 01ea9fb..fbeab4e 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -189,6 +189,7 @@
private float mBottomSheetAlpha = 1f;
private boolean mForceBottomSheetVisible;
private int mTabsProtectionAlpha;
+ private float mTotalHeaderProtectionHeight;
@Nullable private AllAppsTransitionController mAllAppsTransitionController;
private PrivateSpaceHeaderViewController mPrivateSpaceHeaderViewController;
@@ -1431,9 +1432,11 @@
mTmpPath.reset();
mTmpPath.addRoundRect(mTmpRectF, mBottomSheetCornerRadii, Direction.CW);
canvas.drawPath(mTmpPath, mHeaderPaint);
+ mTotalHeaderProtectionHeight = headerBottomWithScaleOnTablet;
}
} else {
canvas.drawRect(0, 0, canvas.getWidth(), headerBottomWithScaleOnPhone, mHeaderPaint);
+ mTotalHeaderProtectionHeight = headerBottomWithScaleOnPhone;
}
// If tab exist (such as work profile), extend header with tab height
@@ -1463,10 +1466,19 @@
right,
tabBottomWithScale,
mHeaderPaint);
+ mTotalHeaderProtectionHeight = tabBottomWithScale;
}
}
/**
+ * The height of the header protection is dynamically calculated during the time of drawing the
+ * header.
+ */
+ float getHeaderProtectionHeight() {
+ return mTotalHeaderProtectionHeight;
+ }
+
+ /**
* redraws header protection
*/
public void invalidateHeader() {
diff --git a/src/com/android/launcher3/allapps/AppInfoComparator.java b/src/com/android/launcher3/allapps/AppInfoComparator.java
index a0867db..bbf8e5a 100644
--- a/src/com/android/launcher3/allapps/AppInfoComparator.java
+++ b/src/com/android/launcher3/allapps/AppInfoComparator.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.os.Process;
import android.os.UserHandle;
+import android.text.TextUtils;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.pm.UserCache;
@@ -64,7 +65,7 @@
}
private String getSortingTitle(AppInfo info) {
- if (info.appTitle != null) {
+ if (!TextUtils.isEmpty(info.appTitle)) {
return info.appTitle.toString();
}
if (info.title != null) {
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index ca587c1..5e5795d 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -223,10 +223,9 @@
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch (viewType) {
case VIEW_TYPE_ICON:
- int layout = (FeatureFlags.enableTwolineAllapps() &&
- (!Flags.enableTwolineToggle() || (Flags.enableTwolineToggle()
- && LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(
- mActivityContext.getApplicationContext()))))
+ int layout = (Flags.enableTwolineToggle()
+ && LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE.get(
+ mActivityContext.getApplicationContext()))
? R.layout.all_apps_icon_twoline : R.layout.all_apps_icon;
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
layout, parent, false);
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 1ebd49e..e7bb1d0 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -23,15 +23,12 @@
import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
-import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_PRIVATE_SPACE_INSTALL_APP;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI;
import android.content.Context;
import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import android.os.UserManager;
@@ -43,6 +40,7 @@
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.PrivateSpaceInstallAppButtonInfo;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.Preconditions;
@@ -60,10 +58,6 @@
*/
public class PrivateProfileManager extends UserProfileManager {
- // TODO (b/324573634): Fix the intent string.
- public static final Intent PRIVATE_SPACE_INTENT = new
- Intent("com.android.settings.action.PRIVATE_SPACE_SETUP_FLOW");
-
private final ActivityAllAppsContainerView<?> mAllApps;
private final Predicate<UserHandle> mPrivateProfileMatcher;
private Set<String> mPreInstalledSystemPackages = new HashSet<>();
@@ -105,13 +99,13 @@
context, com.android.launcher3.R.drawable.private_space_install_app_icon);
BitmapInfo bitmapInfo = LauncherIcons.obtain(context).createIconBitmap(shortcut);
- AppInfo itemInfo = new AppInfo();
+ PrivateSpaceInstallAppButtonInfo itemInfo = new PrivateSpaceInstallAppButtonInfo();
itemInfo.title = context.getResources().getString(R.string.ps_add_button_label);
itemInfo.intent = mAppInstallerIntent;
itemInfo.bitmap = bitmapInfo;
itemInfo.contentDescription = context.getResources().getString(
com.android.launcher3.R.string.ps_add_button_content_description);
- itemInfo.runtimeStatusFlags |= FLAG_PRIVATE_SPACE_INSTALL_APP | FLAG_NOT_PINNABLE;
+ itemInfo.runtimeStatusFlags |= FLAG_NOT_PINNABLE;
BaseAllAppsAdapter.AdapterItem item = new BaseAllAppsAdapter.AdapterItem(VIEW_TYPE_ICON);
item.itemInfo = itemInfo;
@@ -162,7 +156,8 @@
/** Opens the Private Space Settings Page. */
public void openPrivateSpaceSettings() {
if (mPrivateSpaceSettingsAvailable) {
- mAllApps.getContext().startActivity(PRIVATE_SPACE_INTENT);
+ mAllApps.getContext()
+ .startActivity(ApiWrapper.getPrivateSpaceSettingsIntent(mAllApps.getContext()));
}
}
@@ -194,9 +189,8 @@
private void initializePrivateSpaceSettingsState() {
Preconditions.assertNonUiThread();
- ResolveInfo resolveInfo = mAllApps.getContext().getPackageManager()
- .resolveActivity(PRIVATE_SPACE_INTENT, PackageManager.MATCH_SYSTEM_ONLY);
- setPrivateSpaceSettingsAvailable(resolveInfo != null);
+ Intent psSettingsIntent = ApiWrapper.getPrivateSpaceSettingsIntent(mAllApps.getContext());
+ setPrivateSpaceSettingsAvailable(psSettingsIntent != null);
}
private void setPreInstalledSystemPackages() {
diff --git a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
index 6067454..fdc035e 100644
--- a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
+++ b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
@@ -41,15 +41,18 @@
import android.widget.RelativeLayout;
import android.widget.TextView;
+import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.LinearSmoothScroller;
import androidx.recyclerview.widget.RecyclerView;
import com.android.app.animation.Interpolators;
+import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Flags;
import com.android.launcher3.R;
import com.android.launcher3.allapps.UserProfileManager.UserProfileState;
import com.android.launcher3.anim.AnimatedPropertySetter;
import com.android.launcher3.anim.PropertySetter;
+import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.RecyclerViewFastScroller;
import java.util.List;
@@ -59,7 +62,6 @@
* {@link UserProfileState}
*/
public class PrivateSpaceHeaderViewController {
- private static final int EXPAND_SCROLL_DURATION = 2000;
private static final int EXPAND_COLLAPSE_DURATION = 800;
private static final int SETTINGS_OPACITY_DURATION = 160;
private final ActivityAllAppsContainerView mAllApps;
@@ -174,23 +176,24 @@
&& mAllApps.getActiveRecyclerView() == mainAdapterHolder.mRecyclerView) {
// Animate the text and settings icon.
updatePrivateStateAnimator(true, header);
- mAllApps.getActiveRecyclerView().scrollToBottomWithMotion(EXPAND_SCROLL_DURATION);
+ DeviceProfile deviceProfile =
+ ActivityContext.lookupContext(mAllApps.getContext()).getDeviceProfile();
+ AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
+ scrollForViewToBeVisibleInContainer(allAppsRecyclerView,
+ allAppsRecyclerView.getApps().getAdapterItems(),
+ header.getHeight(), deviceProfile.allAppsCellHeightPx);
}
}
/** Finds the private space header to scroll to and set the private space icons to GONE. */
private void collapse() {
AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
- for (int i = allAppsRecyclerView.getChildCount() - 1; i > 0; i--) {
- int adapterPosition = allAppsRecyclerView.getChildAdapterPosition(
- allAppsRecyclerView.getChildAt(i));
- List<BaseAllAppsAdapter.AdapterItem> allAppsAdapters = allAppsRecyclerView.getApps()
- .getAdapterItems();
- if (adapterPosition < 0 || adapterPosition >= allAppsAdapters.size()) {
- continue;
- }
+ List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems =
+ allAppsRecyclerView.getApps().getAdapterItems();
+ for (int i = appListAdapterItems.size() - 1; i > 0; i--) {
+ BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
// Scroll to the private space header.
- if (allAppsAdapters.get(adapterPosition).viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+ if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
// Note: SmoothScroller is meant to be used once.
RecyclerView.SmoothScroller smoothScroller =
new LinearSmoothScroller(mAllApps.getContext()) {
@@ -198,7 +201,7 @@
return LinearSmoothScroller.SNAP_TO_END;
}
};
- smoothScroller.setTargetPosition(adapterPosition);
+ smoothScroller.setTargetPosition(i);
RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
if (layoutManager != null) {
layoutManager.startSmoothScroll(smoothScroller);
@@ -206,12 +209,67 @@
break;
}
// Make the private space apps gone to "collapse".
- if (allAppsAdapters.get(adapterPosition).decorationInfo != null) {
- allAppsRecyclerView.getChildAt(i).setVisibility(GONE);
+ if (currentItem.decorationInfo != null) {
+ RecyclerView.ViewHolder viewHolder =
+ allAppsRecyclerView.findViewHolderForAdapterPosition(i);
+ if (viewHolder != null) {
+ viewHolder.itemView.setVisibility(GONE);
+ }
}
}
}
+ /**
+ * Upon expanding, only scroll to the item position in the adapter that allows the header to be
+ * visible.
+ */
+ @VisibleForTesting
+ public int scrollForViewToBeVisibleInContainer(
+ AllAppsRecyclerView allAppsRecyclerView,
+ List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems,
+ int psHeaderHeight,
+ int allAppsCellHeight) {
+ int rowToExpandToWithRespectToHeader = -1;
+ int itemToScrollTo = -1;
+ // Looks for the item in the app list to scroll to so that the header is visible.
+ for (int i = 0; i < appListAdapterItems.size(); i++) {
+ BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
+ if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+ itemToScrollTo = i;
+ continue;
+ }
+ if (itemToScrollTo != -1) {
+ if (rowToExpandToWithRespectToHeader == -1) {
+ rowToExpandToWithRespectToHeader = currentItem.rowIndex;
+ }
+ int rowToScrollTo =
+ (int) Math.floor((double) (mAllApps.getHeight() - psHeaderHeight
+ - mAllApps.getHeaderProtectionHeight()) / allAppsCellHeight);
+ int currentRowDistance = currentItem.rowIndex - rowToExpandToWithRespectToHeader;
+ // rowToScrollTo - 1 since the item to scroll to is 0 indexed.
+ if (currentRowDistance == rowToScrollTo - 1) {
+ itemToScrollTo = i;
+ break;
+ }
+ }
+ }
+ if (itemToScrollTo != -1) {
+ // Note: SmoothScroller is meant to be used once.
+ RecyclerView.SmoothScroller smoothScroller =
+ new LinearSmoothScroller(mAllApps.getContext()) {
+ @Override protected int getVerticalSnapPreference() {
+ return LinearSmoothScroller.SNAP_TO_ANY;
+ }
+ };
+ smoothScroller.setTargetPosition(itemToScrollTo);
+ RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
+ if (layoutManager != null) {
+ layoutManager.startSmoothScroll(smoothScroller);
+ }
+ }
+ return itemToScrollTo;
+ }
+
PrivateProfileManager getPrivateProfileManager() {
return mPrivateProfileManager;
}
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index a0e8571..6d64c22 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -165,7 +165,7 @@
// TODO(Block 5): Clean up flags
public static final BooleanFlag ENABLE_TWOLINE_DEVICESEARCH = getDebugFlag(201388851,
- "ENABLE_TWOLINE_DEVICESEARCH", ENABLED,
+ "ENABLE_TWOLINE_DEVICESEARCH", DISABLED,
"Enable two line label for icons with labels on device search.");
public static final BooleanFlag ENABLE_ICON_IN_TEXT_HEADER = getDebugFlag(270395143,
@@ -184,11 +184,6 @@
"SECONDARY_DRAG_N_DROP_TO_PIN", DISABLED,
"Enable dragging and dropping to pin apps within secondary display");
- // TODO(Block 7): Clean up flags
- public static final BooleanFlag ENABLE_FORCED_MONO_ICON = getDebugFlag(270396209,
- "ENABLE_FORCED_MONO_ICON", DISABLED,
- "Enable the ability to generate monochromatic icons, if it is not provided by the app");
-
// TODO(Block 8): Clean up flags
// TODO(Block 9): Clean up flags
@@ -281,10 +276,7 @@
// Aconfig migration complete for ENABLE_TWOLINE_ALLAPPS.
public static final BooleanFlag ENABLE_TWOLINE_ALLAPPS = getDebugFlag(270390937,
- "ENABLE_TWOLINE_ALLAPPS", ENABLED, "Enables two line label inside all apps.");
- public static boolean enableTwolineAllapps() {
- return ENABLE_TWOLINE_ALLAPPS.get() || Flags.enableTwolineAllapps();
- }
+ "ENABLE_TWOLINE_ALLAPPS", DISABLED, "Enables two line label inside all apps.");
public static final BooleanFlag IME_STICKY_SNACKBAR_EDU = getDebugFlag(270391693,
"IME_STICKY_SNACKBAR_EDU", ENABLED, "Show sticky IME edu in AllApps");
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index ac23868..c8c634a 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -1042,6 +1042,9 @@
public void onDropCompleted(final View target, final DragObject d,
final boolean success) {
if (success) {
+ if (getItemCount() <= 1) {
+ mDeleteFolderOnDropCompleted = true;
+ }
if (mDeleteFolderOnDropCompleted && !mItemAddedBackToSelfViaIcon && target != this) {
replaceFolderWithFinalItem();
}
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 8e73660..1633eba 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -222,6 +222,7 @@
* Updates {@param application} only if a valid entry is found.
*/
public synchronized void updateTitleAndIcon(AppInfo application) {
+ boolean preferPackageIcon = application.isArchived();
CacheEntry entry = cacheLocked(application.componentName,
application.user, () -> null, mLauncherActivityInfoCachingLogic,
false, application.usingLowResIcon());
@@ -229,13 +230,12 @@
return;
}
- boolean preferPackageIcon = application.isArchived();
if (preferPackageIcon) {
String packageName = application.getTargetPackage();
CacheEntry packageEntry =
cacheLocked(new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
application.user, () -> null, mLauncherActivityInfoCachingLogic,
- false, application.usingLowResIcon());
+ true, application.usingLowResIcon());
applyPackageEntry(packageEntry, application, entry);
} else {
applyCacheEntry(entry, application);
@@ -469,17 +469,22 @@
duplicateIconRequestsMap.get(cn);
if (cn != null) {
- CacheEntry entry = cacheLocked(
- cn,
- /* user = */ sectionKey.first,
- () -> duplicateIconRequests.get(0).launcherActivityInfo,
- mLauncherActivityInfoCachingLogic,
- c,
- /* usePackageIcon= */ false,
- /* useLowResIcons = */ sectionKey.second);
+ if (duplicateIconRequests != null) {
+ CacheEntry entry = cacheLocked(
+ cn,
+ /* user = */ sectionKey.first,
+ () -> duplicateIconRequests.get(0).launcherActivityInfo,
+ mLauncherActivityInfoCachingLogic,
+ c,
+ /* usePackageIcon= */ false,
+ /* useLowResIcons = */ sectionKey.second);
- for (IconRequestInfo<T> iconRequest : duplicateIconRequests) {
- applyCacheEntry(entry, iconRequest.itemInfo);
+ for (IconRequestInfo<T> iconRequest : duplicateIconRequests) {
+ applyCacheEntry(entry, iconRequest.itemInfo);
+ }
+ } else {
+ Log.e(TAG, "Found entry in icon database but no main activity "
+ + "entry for cn: " + cn);
}
}
}
diff --git a/src/com/android/launcher3/icons/LauncherIcons.java b/src/com/android/launcher3/icons/LauncherIcons.java
index a15348b..513377a 100644
--- a/src/com/android/launcher3/icons/LauncherIcons.java
+++ b/src/com/android/launcher3/icons/LauncherIcons.java
@@ -16,14 +16,13 @@
package com.android.launcher3.icons;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_FORCED_MONO_ICON;
-
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.os.UserHandle;
import androidx.annotation.NonNull;
+import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.graphics.LauncherPreviewRenderer;
@@ -103,7 +102,7 @@
@Override
protected Drawable getMonochromeDrawable(Drawable base) {
Drawable mono = super.getMonochromeDrawable(base);
- if (mono != null || !ENABLE_FORCED_MONO_ICON.get()) {
+ if (mono != null || !Flags.forceMonochromeAppIcons()) {
return mono;
}
if (mMonochromeIconFactory == null) {
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 5cb1540..3ede267 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -751,6 +751,9 @@
+ " metric.")
LAUNCHER_SPLIT_SELECTION_EXIT_INTERRUPTED(1612),
+ @UiEvent(doc = "User tapped add widget button in widget sheet.")
+ LAUNCHER_WIDGET_ADD_BUTTON_TAP(1622),
+
// ADD MORE
;
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index 30d2cfb..15190c7 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -40,6 +40,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
+import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings;
@@ -122,6 +123,16 @@
if (!needsToMigrate(srcDeviceState, destDeviceState)) {
return true;
}
+
+ if (Flags.enableGridMigrationFix()
+ && srcDeviceState.getColumns().equals(destDeviceState.getColumns())
+ && srcDeviceState.getRows() < destDeviceState.getRows()) {
+ // Only use this strategy when comparing the previous grid to the new grid and the
+ // columns are the same and the destination has more rows
+ copyTable(source, TABLE_NAME, target.getWritableDatabase(), TABLE_NAME, context);
+ destDeviceState.writeToPrefs(context);
+ return true;
+ }
copyTable(source, TABLE_NAME, target.getWritableDatabase(), TMP_TABLE, context);
HashSet<String> validPackages = getValidPackages(context);
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index 1dd58c3..3f88717 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -123,6 +123,7 @@
if (!Flags.enableGeneratedPreviews() || generatedPreviews == null) {
return false;
}
- return generatedPreviews.contains(widgetCategory);
+ return generatedPreviews.contains(widgetCategory)
+ && generatedPreviews.get(widgetCategory) != null;
}
}
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 55849c2..f7cff78 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -94,6 +94,10 @@
* {@link Favorites#ITEM_TYPE_APP_PAIR},
* {@link Favorites#ITEM_TYPE_APPWIDGET} or
* {@link Favorites#ITEM_TYPE_CUSTOM_APPWIDGET}.
+ * {@link Favorites#ITEM_TYPE_TASK}.
+ * {@link Favorites#ITEM_TYPE_QSB}.
+ * {@link Favorites#ITEM_TYPE_SEARCH_ACTION}.
+ * {@link Favorites#ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON}.
*/
public int itemType;
diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
index 70cad96..9fbc6bf 100644
--- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
+++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java
@@ -121,11 +121,6 @@
public static final int FLAG_ARCHIVED = 1 << 14;
/**
- * Flag indicating it's the Private Space Install App icon.
- */
- public static final int FLAG_PRIVATE_SPACE_INSTALL_APP = 1 << 15;
-
- /**
* Status associated with the system state of the underlying item. This is calculated every
* time a new info is created and not persisted on the disk.
*/
diff --git a/src/com/android/launcher3/model/data/PrivateSpaceInstallAppButtonInfo.java b/src/com/android/launcher3/model/data/PrivateSpaceInstallAppButtonInfo.java
new file mode 100644
index 0000000..1e7281d
--- /dev/null
+++ b/src/com/android/launcher3/model/data/PrivateSpaceInstallAppButtonInfo.java
@@ -0,0 +1,29 @@
+/*
+ * 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;
+
+import com.android.launcher3.LauncherSettings;
+
+/**
+ * Represents the Private Space Install App button in AllAppsView.
+ */
+public class PrivateSpaceInstallAppButtonInfo extends AppInfo {
+
+ public PrivateSpaceInstallAppButtonInfo() {
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON;
+ }
+}
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index 77effca..e44ea1d 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -153,7 +153,7 @@
mPaginationPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mPaginationPaint.setStyle(Style.FILL);
- mPaginationPaint.setColor(Themes.getAttrColor(context, R.attr.folderPaginationColor));
+ mPaginationPaint.setColor(Themes.getAttrColor(context, R.attr.pageIndicatorDotColor));
mDotRadius = getResources().getDimension(R.dimen.page_indicator_dot_size) / 2;
mCircleGap = DOT_GAP_FACTOR * mDotRadius;
setOutlineProvider(new MyOutlineProver());
diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java
index 1f15947..b992a92 100644
--- a/src/com/android/launcher3/provider/LauncherDbUtils.java
+++ b/src/com/android/launcher3/provider/LauncherDbUtils.java
@@ -152,7 +152,12 @@
}
ShortcutInfo info = infoBuilder.build();
- if (!PinRequestHelper.createRequestForShortcut(context, info).accept()) {
+ try {
+ if (!PinRequestHelper.createRequestForShortcut(context, info).accept()) {
+ deletedShortcuts.add(lc.id);
+ continue;
+ }
+ } catch (Exception e) {
deletedShortcuts.add(lc.id);
continue;
}
diff --git a/src/com/android/launcher3/provider/RestoreDbTask.java b/src/com/android/launcher3/provider/RestoreDbTask.java
index f2b7d18..99542f3 100644
--- a/src/com/android/launcher3/provider/RestoreDbTask.java
+++ b/src/com/android/launcher3/provider/RestoreDbTask.java
@@ -123,7 +123,7 @@
// executed again.
LauncherPrefs.get(context).removeSync(RESTORE_DEVICE);
- if (Flags.narrowGridRestore()) {
+ if (Flags.enableNarrowGridRestore()) {
String oldPhoneFileName = idp.dbFile;
removeOldDBs(context, oldPhoneFileName);
trySettingPreviousGidAsCurrent(context, idp, oldPhoneFileName);
diff --git a/src/com/android/launcher3/states/EditModeState.kt b/src/com/android/launcher3/states/EditModeState.kt
index aafaaa0..6ff47ae 100644
--- a/src/com/android/launcher3/states/EditModeState.kt
+++ b/src/com/android/launcher3/states/EditModeState.kt
@@ -16,6 +16,7 @@
package com.android.launcher3.states
import android.content.Context
+import com.android.launcher3.Flags.enableScalingRevealHomeAnimation
import com.android.launcher3.Launcher
import com.android.launcher3.LauncherState
import com.android.launcher3.logging.StatsLogManager
@@ -25,6 +26,8 @@
class EditModeState(id: Int) : LauncherState(id, StatsLogManager.LAUNCHER_STATE_HOME, STATE_FLAGS) {
companion object {
+ const val DEPTH_15_PERCENT = 0.15f
+
private val STATE_FLAGS =
(FLAG_MULTI_PAGE or
FLAG_WORKSPACE_INACCESSIBLE or
@@ -40,7 +43,11 @@
}
override fun <T> getDepthUnchecked(context: T): Float where T : Context?, T : ActivityContext? {
- return 0.5f
+ if (enableScalingRevealHomeAnimation()) {
+ return DEPTH_15_PERCENT
+ } else {
+ return 0.5f
+ }
}
override fun getWorkspaceScaleAndTranslation(launcher: Launcher): ScaleAndTranslation {
diff --git a/src/com/android/launcher3/states/HintState.java b/src/com/android/launcher3/states/HintState.java
index 4cfced8..bf2fb30 100644
--- a/src/com/android/launcher3/states/HintState.java
+++ b/src/com/android/launcher3/states/HintState.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.states;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import android.content.Context;
@@ -34,6 +35,8 @@
private static final int STATE_FLAGS = FLAG_WORKSPACE_INACCESSIBLE | FLAG_DISABLE_RESTORE
| FLAG_HAS_SYS_UI_SCRIM;
+ public static final float DEPTH_5_PERCENT = 0.05f;
+
public HintState(int id) {
this(id, LAUNCHER_STATE_HOME);
}
@@ -49,7 +52,11 @@
@Override
protected float getDepthUnchecked(Context context) {
- return 0.15f;
+ if (enableScalingRevealHomeAnimation()) {
+ return DEPTH_5_PERCENT;
+ } else {
+ return 0.15f;
+ }
}
@Override
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 3286afb..2e57ed8 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.states;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import android.content.Context;
@@ -33,6 +34,8 @@
| FLAG_WORKSPACE_INACCESSIBLE | FLAG_DISABLE_RESTORE
| FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED | FLAG_WORKSPACE_HAS_BACKGROUNDS;
+ public static final float DEPTH_15_PERCENT = 0.15f;
+
public SpringLoadedState(int id) {
super(id, LAUNCHER_STATE_HOME, STATE_FLAGS);
}
@@ -62,7 +65,11 @@
@Override
protected float getDepthUnchecked(Context context) {
- return 0.5f;
+ if (enableScalingRevealHomeAnimation()) {
+ return DEPTH_15_PERCENT;
+ } else {
+ return 0.5f;
+ }
}
@Override
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 07df7af..12cdd67 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -19,9 +19,9 @@
import static com.android.launcher3.allapps.AllAppsStore.DEFER_UPDATES_TEST;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.config.FeatureFlags.FOLDABLE_SINGLE_PAGE;
+import static com.android.launcher3.config.FeatureFlags.enableAppPairs;
import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
-import static com.android.launcher3.config.FeatureFlags.enableAppPairs;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import android.app.Activity;
@@ -183,7 +183,10 @@
case TestProtocol.REQUEST_IS_TABLET:
response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, mDeviceProfile.isTablet);
return response;
-
+ case TestProtocol.REQUEST_IS_PREDICTIVE_BACK_SWIPE_ENABLED:
+ response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+ mDeviceProfile.isPredictiveBackSwipe);
+ return response;
case TestProtocol.REQUEST_ENABLE_TASKBAR_NAVBAR_UNIFICATION:
response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
ENABLE_TASKBAR_NAVBAR_UNIFICATION);
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 111931e..911568c 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -369,8 +369,8 @@
intent = ApiWrapper.getAppMarketActivityIntent(launcher,
itemInfoWithIcon.getTargetComponent().getPackageName(),
Process.myUserHandle());
- } else if ((itemInfoWithIcon.runtimeStatusFlags
- & ItemInfoWithIcon.FLAG_PRIVATE_SPACE_INSTALL_APP) != 0) {
+ } else if (itemInfoWithIcon.itemType
+ == LauncherSettings.Favorites.ITEM_TYPE_PRIVATE_SPACE_INSTALL_APP_BUTTON) {
intent = ApiWrapper.getAppMarketActivityIntent(launcher,
BuildConfig.APPLICATION_ID,
launcher.getAppsView().getPrivateProfileManager().getProfileUser());
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 606918e..b66b96a 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -107,6 +107,7 @@
/**
* Returns whether the target app is archived for a given user
*/
+ @SuppressWarnings("NewApi")
public boolean isAppArchivedForUser(@NonNull final String packageName,
@NonNull final UserHandle user) {
if (!Utilities.enableSupportForArchiving()) {
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
index 30e0971..ddc3cbb 100644
--- a/src/com/android/launcher3/views/AbstractSlideInView.java
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -296,17 +296,13 @@
float scaleProgress = mSlideInViewScale.value;
SCALE_PROPERTY.set(this, scaleProgress);
setClipChildren(!mIsBackProgressing);
+ setClipToPadding(!mIsBackProgressing);
mContent.setClipChildren(!mIsBackProgressing);
+ mContent.setClipToPadding(!mIsBackProgressing);
invalidate();
}
@Override
- public void onBackInvoked() {
- super.onBackInvoked();
- animateSlideInViewToNoScale();
- }
-
- @Override
public void onBackCancelled() {
super.onBackCancelled();
animateSlideInViewToNoScale();
diff --git a/src/com/android/launcher3/views/FloatingSurfaceView.java b/src/com/android/launcher3/views/FloatingSurfaceView.java
index c60e1a4..cab7982 100644
--- a/src/com/android/launcher3/views/FloatingSurfaceView.java
+++ b/src/com/android/launcher3/views/FloatingSurfaceView.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.views;
+import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.views.FloatingIconView.getLocationBoundsForView;
import static com.android.launcher3.views.IconLabelDotView.setIconAndDotVisible;
@@ -159,7 +160,7 @@
if (mContract == null) {
return;
}
- View icon = mLauncher.getFirstMatchForAppClose(-1,
+ View icon = mLauncher.getFirstMatchForAppClose(NO_MATCHING_ID,
mContract.componentName.getPackageName(), mContract.user,
false /* supportsAllAppsState */);
diff --git a/src/com/android/launcher3/views/WidgetsEduView.java b/src/com/android/launcher3/views/WidgetsEduView.java
index 40c6115..45ff9de 100644
--- a/src/com/android/launcher3/views/WidgetsEduView.java
+++ b/src/com/android/launcher3/views/WidgetsEduView.java
@@ -59,6 +59,7 @@
mContent = findViewById(R.id.edu_view);
findViewById(R.id.edu_close_button)
.setOnClickListener(v -> close(/* animate= */ true));
+ setContentBackgroundWithParent(mContent.getBackground(), mContent);
}
@Override
@@ -68,6 +69,12 @@
mContent.getPaddingTop(), mContent.getPaddingEnd(), insets.bottom);
}
+ @Override
+ protected void onScaleProgressChanged() {
+ super.onScaleProgressChanged();
+ setTranslationY(getMeasuredHeight() * (1 - mSlideInViewScale.value) / 2);
+ }
+
private void show() {
attachToContainer();
animateOpen();
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 54ce973..0a5127b 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -18,6 +18,7 @@
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
+import static com.android.launcher3.Flags.enableWidgetTapToAdd;
import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_TIP_SEEN;
import android.content.Context;
@@ -41,8 +42,10 @@
import com.android.launcher3.Insettable;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherPrefs;
+import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -73,6 +76,8 @@
private boolean mDisableNavBarScrim = false;
+ @Nullable private WidgetCell mWidgetCellWithAddButton = null;
+
public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mContentHorizontalMargin = getWidgetListHorizontalMargin();
@@ -123,13 +128,49 @@
@Override
public final void onClick(View v) {
- if (v instanceof WidgetCell) {
- mActivityContext.getItemOnClickListener().onClick(v);
- } else if (v.getParent() instanceof WidgetCell wc) {
+ WidgetCell wc;
+ if (v instanceof WidgetCell view) {
+ wc = view;
+ } else if (v.getParent() instanceof WidgetCell parent) {
+ wc = parent;
+ } else {
+ return;
+ }
+
+ if (enableWidgetTapToAdd()) {
+ if (mWidgetCellWithAddButton != null) {
+ // If there is a add button currently showing, hide it.
+ mWidgetCellWithAddButton.hideAddButton(/* animate= */ true);
+ }
+
+ if (mWidgetCellWithAddButton != wc) {
+ // If click is on a cell not showing an add button, show it now.
+ final PendingAddItemInfo info = (PendingAddItemInfo) wc.getTag();
+ if (mActivityContext instanceof Launcher) {
+ wc.showAddButton((view) -> addWidget(info));
+ } else {
+ wc.showAddButton((view) -> mActivityContext.getItemOnClickListener()
+ .onClick(wc));
+ }
+ }
+
+ mWidgetCellWithAddButton = mWidgetCellWithAddButton != wc ? wc : null;
+ } else {
mActivityContext.getItemOnClickListener().onClick(wc);
}
}
+ /**
+ * Click handler for tap to add button.
+ */
+ public void addWidget(PendingAddItemInfo info) {
+ mActivityContext.getStatsLogManager().logger().withItemInfo(info).log(
+ StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_ADD_BUTTON_TAP);
+ handleClose(true);
+ Launcher.getLauncher(mActivityContext).getAccessibilityDelegate()
+ .addToWorkspace(info, /*accessibility=*/ false);
+ }
+
@Override
public boolean onLongClick(View v) {
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick");
diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
index 15bd6ed..0fb4e09 100644
--- a/src/com/android/launcher3/widget/LauncherWidgetHolder.java
+++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
@@ -103,7 +103,7 @@
if (WidgetsModel.GO_DISABLE_WIDGETS) {
return;
}
- setListeningFlag(true);
+
try {
mWidgetHost.startListening();
} catch (Exception e) {
@@ -115,6 +115,8 @@
// have been established by this point, and we will end up populating the
// widgets upon bind anyway. See issue 14255011 for more context.
}
+ // TODO: Investigate why widgetHost.startListening() always return non-empty updates
+ setListeningFlag(true);
updateDeferredView();
}
@@ -347,7 +349,13 @@
@NonNull
public final AppWidgetHostView attachViewToHostAndGetAttachedView(
@NonNull LauncherAppWidgetHostView view) {
- if (mViews.get(view.getAppWidgetId()) != view) {
+
+ // Binder can also inflate placeholder widgets in case of backup-restore. Skip
+ // attaching such widgets
+ boolean isRealWidget = ((view instanceof PendingAppWidgetHostView pw)
+ ? pw.isDeferredWidget() : true)
+ && view.getAppWidgetInfo() != null;
+ if (isRealWidget && mViews.get(view.getAppWidgetId()) != view) {
view = recycleExistingView(view);
mViews.put(view.getAppWidgetId(), view);
}
@@ -442,6 +450,13 @@
}
/**
+ * Clears all the internal widget views
+ */
+ public void clearWidgetViews() {
+ clearViews();
+ }
+
+ /**
* @return True if the host is listening to the updates, false otherwise
*/
public boolean isListening() {
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index f2f83c8..3dff555 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -18,6 +18,7 @@
import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
+import static com.android.launcher3.Flags.enableWidgetTapToAdd;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_TRAY;
import static com.android.launcher3.widget.LauncherAppWidgetProviderInfo.fromProviderInfo;
import static com.android.launcher3.widget.util.WidgetSizes.getWidgetItemSizePx;
@@ -36,6 +37,7 @@
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.accessibility.AccessibilityNodeInfo;
+import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -57,6 +59,8 @@
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.util.CancellableTask;
import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.widget.picker.util.WidgetPreviewContainerSize;
+import com.android.launcher3.widget.util.WidgetSizes;
import java.util.function.Consumer;
@@ -75,18 +79,21 @@
private static final boolean DEBUG = false;
private static final int FADE_IN_DURATION_MS = 90;
+ private static final int ADD_BUTTON_FADE_DURATION_MS = 300;
/**
* The requested scale of the preview container. It can be lower than this as well.
*/
private float mPreviewContainerScale = 1f;
-
+ private Size mPreviewContainerSize = new Size(0, 0);
private FrameLayout mWidgetImageContainer;
private WidgetImageView mWidgetImage;
private ImageView mWidgetBadge;
private TextView mWidgetName;
private TextView mWidgetDims;
private TextView mWidgetDescription;
+ private Button mWidgetAddButton;
+ private LinearLayout mWidgetTextContainer;
private WidgetItem mItem;
private Size mWidgetSize;
@@ -139,6 +146,11 @@
mWidgetName = findViewById(R.id.widget_name);
mWidgetDims = findViewById(R.id.widget_dims);
mWidgetDescription = findViewById(R.id.widget_description);
+ mWidgetTextContainer = findViewById(R.id.widget_text_container);
+ mWidgetAddButton = findViewById(R.id.widget_add_button);
+ if (enableWidgetTapToAdd()) {
+ mWidgetAddButton.setVisibility(INVISIBLE);
+ }
}
public void setRemoteViewsPreview(RemoteViews view) {
@@ -176,6 +188,12 @@
mWidgetDims.setText(null);
mWidgetDescription.setText(null);
mWidgetDescription.setVisibility(GONE);
+ showDescription(true);
+ showDimensions(true);
+
+ if (enableWidgetTapToAdd()) {
+ hideAddButton(/* animate= */ false);
+ }
if (mActiveRequest != null) {
mActiveRequest.cancel();
@@ -186,6 +204,7 @@
mWidgetImageContainer.removeView(mAppWidgetHostViewPreview);
}
mAppWidgetHostViewPreview = null;
+ mPreviewContainerSize = new Size(0, 0);
mAppWidgetHostViewScale = 1f;
mPreviewContainerScale = 1f;
mItem = null;
@@ -201,38 +220,25 @@
* Applies the item to this view
*/
public void applyFromCellItem(WidgetItem item) {
- applyFromCellItem(item, 1f);
- }
-
- /**
- * Applies the item to this view
- */
- public void applyFromCellItem(WidgetItem item, float previewScale) {
- applyFromCellItem(item, previewScale, this::applyPreview, null);
+ applyFromCellItem(item, this::applyPreview, /*cachedPreview=*/null);
}
/**
* Applies the item to this view
* @param item item to apply
- * @param previewScale factor to scale the preview
* @param callback callback when preview is loaded in case the preview is being loaded or cached
* @param cachedPreview previously cached preview bitmap is present
*/
- public void applyFromCellItem(WidgetItem item, float previewScale,
- @NonNull Consumer<Bitmap> callback, @Nullable Bitmap cachedPreview) {
- mPreviewContainerScale = previewScale;
-
+ public void applyFromCellItem(WidgetItem item, @NonNull Consumer<Bitmap> callback,
+ @Nullable Bitmap cachedPreview) {
Context context = getContext();
mItem = item;
mWidgetSize = getWidgetItemSizePx(getContext(), mActivity.getDeviceProfile(), mItem);
+ initPreviewContainerSizeAndScale();
mWidgetName.setText(mItem.label);
- mWidgetName.setContentDescription(
- context.getString(R.string.widget_preview_context_description, mItem.label));
mWidgetDims.setText(context.getString(R.string.widget_dims_format,
mItem.spanX, mItem.spanY));
- mWidgetDims.setContentDescription(context.getString(
- R.string.widget_accessible_dims_format, mItem.spanX, mItem.spanY));
if (!TextUtils.isEmpty(mItem.description)) {
mWidgetDescription.setText(mItem.description);
mWidgetDescription.setVisibility(VISIBLE);
@@ -240,6 +246,14 @@
mWidgetDescription.setVisibility(GONE);
}
+ // Setting the content description on the WidgetCell itself ensures that it remains
+ // screen reader focusable when the add button is showing and the text is hidden.
+ setContentDescription(createContentDescription(context));
+ if (mWidgetAddButton != null) {
+ mWidgetAddButton.setContentDescription(context.getString(
+ R.string.widget_add_button_content_description, mItem.label));
+ }
+
if (item.activityInfo != null) {
setTag(new PendingAddShortcutInfo(item.activityInfo));
} else {
@@ -278,6 +292,27 @@
}
}
+ private void initPreviewContainerSizeAndScale() {
+ WidgetPreviewContainerSize previewSize = WidgetPreviewContainerSize.Companion.forItem(mItem,
+ mActivity.getDeviceProfile());
+ mPreviewContainerSize = WidgetSizes.getWidgetSizePx(mActivity.getDeviceProfile(),
+ previewSize.spanX, previewSize.spanY);
+
+ float scaleX = (float) mPreviewContainerSize.getWidth() / mWidgetSize.getWidth();
+ float scaleY = (float) mPreviewContainerSize.getHeight() / mWidgetSize.getHeight();
+ mPreviewContainerScale = Math.min(scaleX, scaleY);
+ }
+
+ private String createContentDescription(Context context) {
+ String contentDescription =
+ context.getString(R.string.widget_preview_name_and_dims_content_description,
+ mItem.label, mItem.spanX, mItem.spanY);
+ if (!TextUtils.isEmpty(mItem.description)) {
+ contentDescription += " " + mItem.description;
+ }
+ return contentDescription;
+ }
+
private void setAppWidgetHostViewPreview(
NavigableAppWidgetHostView appWidgetHostViewPreview,
LauncherAppWidgetProviderInfo providerInfo,
@@ -384,6 +419,16 @@
}
/**
+ * Shows or hides the dimensions displayed below each widget.
+ *
+ * @param show a flag that shows the dimensions of the widget if {@code true}, hides it if
+ * {@code false}.
+ */
+ public void showDimensions(boolean show) {
+ mWidgetDims.setVisibility(show ? VISIBLE : GONE);
+ }
+
+ /**
* Set whether the app icon, for the app that provides the widget, should be shown next to the
* title text of the widget.
*
@@ -448,17 +493,22 @@
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
ViewGroup.LayoutParams containerLp = mWidgetImageContainer.getLayoutParams();
-
- mAppWidgetHostViewScale = mPreviewContainerScale;
int maxWidth = MeasureSpec.getSize(widthMeasureSpec);
- containerLp.width = Math.round(mWidgetSize.getWidth() * mAppWidgetHostViewScale);
+
+ // mPreviewContainerScale ensures the needed scaling with respect to original widget size.
+ mAppWidgetHostViewScale = mPreviewContainerScale;
+ containerLp.width = mPreviewContainerSize.getWidth();
+ containerLp.height = mPreviewContainerSize.getHeight();
+
+ // If we don't have enough available width, scale the preview container to fit.
if (containerLp.width > maxWidth) {
containerLp.width = maxWidth;
- mAppWidgetHostViewScale = (float) containerLp.width / mWidgetSize.getWidth();
+ mAppWidgetHostViewScale = (float) containerLp.width / mPreviewContainerSize.getWidth();
+ containerLp.height = Math.round(
+ mPreviewContainerSize.getHeight() * mAppWidgetHostViewScale);
}
- containerLp.height = Math.round(mWidgetSize.getHeight() * mAppWidgetHostViewScale);
- // No need to call mWidgetImageContainer.setLayoutParams as we are in measure pass
+ // No need to call mWidgetImageContainer.setLayoutParams as we are in measure pass
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
@@ -495,4 +545,55 @@
mIconLoadRequest = null;
}
}
+
+ /**
+ * Show tap to add button.
+ * @param callback Callback to be set on the button.
+ */
+ public void showAddButton(View.OnClickListener callback) {
+ mWidgetAddButton.setAlpha(0F);
+ mWidgetAddButton.setVisibility(VISIBLE);
+ mWidgetAddButton.setOnClickListener(callback);
+ mWidgetAddButton.animate().cancel();
+ mWidgetAddButton.animate()
+ .alpha(1F)
+ .setDuration(ADD_BUTTON_FADE_DURATION_MS);
+
+ mWidgetTextContainer.animate().cancel();
+ mWidgetTextContainer.animate()
+ .alpha(0F)
+ .setDuration(ADD_BUTTON_FADE_DURATION_MS)
+ .withEndAction(() -> {
+ mWidgetTextContainer.setVisibility(INVISIBLE);
+ });
+ }
+
+ /**
+ * Hide tap to add button.
+ */
+ public void hideAddButton(boolean animate) {
+ mWidgetAddButton.setOnClickListener(null);
+ mWidgetAddButton.animate().cancel();
+ mWidgetTextContainer.animate().cancel();
+
+ if (!animate) {
+ mWidgetAddButton.setVisibility(INVISIBLE);
+ mWidgetTextContainer.setVisibility(VISIBLE);
+ mWidgetTextContainer.setAlpha(1F);
+ return;
+ }
+
+ mWidgetAddButton.animate()
+ .alpha(0F)
+ .setDuration(ADD_BUTTON_FADE_DURATION_MS)
+ .withEndAction(() -> {
+ mWidgetAddButton.setVisibility(INVISIBLE);
+ });
+
+ mWidgetTextContainer.setAlpha(0F);
+ mWidgetTextContainer.setVisibility(VISIBLE);
+ mWidgetTextContainer.animate()
+ .alpha(1F)
+ .setDuration(ADD_BUTTON_FADE_DURATION_MS);
+ }
}
diff --git a/src/com/android/launcher3/widget/WidgetImageView.java b/src/com/android/launcher3/widget/WidgetImageView.java
index 11f4485..f0a23be 100644
--- a/src/com/android/launcher3/widget/WidgetImageView.java
+++ b/src/com/android/launcher3/widget/WidgetImageView.java
@@ -82,15 +82,27 @@
private void updateDstRectF() {
float myWidth = getWidth();
float myHeight = getHeight();
- float bitmapWidth = mDrawable.getIntrinsicWidth();
+ final float bitmapWidth = mDrawable.getIntrinsicWidth();
+ final float bitmapHeight = mDrawable.getIntrinsicHeight();
+ final float bitmapAspectRatio = bitmapWidth / bitmapHeight;
+ final float containerAspectRatio = myWidth / myHeight;
- final float scale = bitmapWidth > myWidth ? myWidth / bitmapWidth : 1;
- float scaledWidth = bitmapWidth * scale;
- float scaledHeight = mDrawable.getIntrinsicHeight() * scale;
+ // Scale by width if image has larger aspect ratio than the container else by height; and
+ // avoid cropping the previews
+ final float scale = bitmapAspectRatio > containerAspectRatio ? myWidth / bitmapWidth
+ : myHeight / bitmapHeight;
- mDstRectF.left = (myWidth - scaledWidth) / 2;
- mDstRectF.right = (myWidth + scaledWidth) / 2;
+ final float scaledWidth = bitmapWidth * scale;
+ final float scaledHeight = bitmapHeight * scale;
+ // Avoid cropping by checking bounds after scaling.
+ if (scaledWidth > myWidth) {
+ mDstRectF.left = 0;
+ mDstRectF.right = scaledWidth;
+ } else {
+ mDstRectF.left = (myWidth - scaledWidth) / 2;
+ mDstRectF.right = (myWidth + scaledWidth) / 2;
+ }
if (scaledHeight > myHeight) {
mDstRectF.top = 0;
mDstRectF.bottom = scaledHeight;
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index ceb0072..e6b9c9b 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -16,7 +16,6 @@
package com.android.launcher3.widget;
-import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_BOTTOM_WIDGETS_TRAY;
import android.content.Context;
@@ -119,6 +118,9 @@
mContent = findViewById(R.id.widgets_bottom_sheet);
setContentBackgroundWithParent(
getContext().getDrawable(R.drawable.bg_rounded_corner_bottom_sheet), mContent);
+ View scrollView = findViewById(R.id.widgets_table_scroll_view);
+ scrollView.setOutlineProvider(mViewOutlineProvider);
+ scrollView.setClipToOutline(true);
}
@Override
@@ -188,13 +190,7 @@
mWidgetCellHorizontalPadding)
.forEach(row -> {
TableRow tableRow = new TableRow(getContext());
- if (enableCategorizedWidgetSuggestions()) {
- // Vertically center align items, so that even if they don't fill bounds,
- // they can look organized when placed together in a row.
- tableRow.setGravity(Gravity.CENTER_VERTICAL);
- } else {
- tableRow.setGravity(Gravity.TOP);
- }
+ tableRow.setGravity(Gravity.TOP);
row.forEach(widgetItem -> {
WidgetCell widget = addItemCell(tableRow);
widget.applyFromCellItem(widgetItem);
diff --git a/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java b/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
index 68f18ae..0d775c3 100644
--- a/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
+++ b/src/com/android/launcher3/widget/model/WidgetsListHeaderEntry.java
@@ -36,41 +36,49 @@
(context, entry) -> entry.mWidgets.stream()
.map(item -> item.label).sorted().collect(Collectors.joining(", "));
- private static final BiFunction<Context, WidgetsListHeaderEntry, String> SUBTITLE_DEFAULT =
- (context, entry) -> {
- List<WidgetItem> items = entry.mWidgets;
- int wc = (int) items.stream().filter(item -> item.widgetInfo != null).count();
- int sc = Math.max(0, items.size() - wc);
+ @Nullable
+ private static String buildWidgetsCountString(Context context, int wc, int sc) {
+ Resources resources = context.getResources();
+ if (wc == 0 && sc == 0) {
+ return null;
+ }
- Resources resources = context.getResources();
- if (wc == 0 && sc == 0) {
- return null;
- }
-
- String subtitle;
- if (wc > 0 && sc > 0) {
- String widgetsCount = PluralMessageFormat.getIcuPluralString(context,
- R.string.widgets_count, wc);
- String shortcutsCount = PluralMessageFormat.getIcuPluralString(context,
- R.string.shortcuts_count, sc);
- subtitle = resources.getString(R.string.widgets_and_shortcuts_count,
- widgetsCount, shortcutsCount);
- } else if (wc > 0) {
- subtitle = PluralMessageFormat.getIcuPluralString(context,
- R.string.widgets_count, wc);
- } else {
- subtitle = PluralMessageFormat.getIcuPluralString(context,
- R.string.shortcuts_count, sc);
- }
- return subtitle;
- };
+ String subtitle;
+ if (wc > 0 && sc > 0) {
+ String widgetsCount = PluralMessageFormat.getIcuPluralString(context,
+ R.string.widgets_count, wc);
+ String shortcutsCount = PluralMessageFormat.getIcuPluralString(context,
+ R.string.shortcuts_count, sc);
+ subtitle = resources.getString(R.string.widgets_and_shortcuts_count,
+ widgetsCount, shortcutsCount);
+ } else if (wc > 0) {
+ subtitle = PluralMessageFormat.getIcuPluralString(context,
+ R.string.widgets_count, wc);
+ } else {
+ subtitle = PluralMessageFormat.getIcuPluralString(context,
+ R.string.shortcuts_count, sc);
+ }
+ return subtitle;
+ }
private final boolean mIsWidgetListShown;
+ /** Selected widgets displayed */
+ private final int mVisibleWidgetsCount;
private final boolean mIsSearchEntry;
private WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
+ List<WidgetItem> items, int visibleWidgetsCount,
+ boolean isSearchEntry, boolean isWidgetListShown) {
+ super(pkgItem, titleSectionName, items);
+ mVisibleWidgetsCount = visibleWidgetsCount;
+ mIsSearchEntry = isSearchEntry;
+ mIsWidgetListShown = isWidgetListShown;
+ }
+
+ private WidgetsListHeaderEntry(PackageItemInfo pkgItem, String titleSectionName,
List<WidgetItem> items, boolean isSearchEntry, boolean isWidgetListShown) {
super(pkgItem, titleSectionName, items);
+ mVisibleWidgetsCount = (int) items.stream().filter(w -> w.widgetInfo != null).count();
mIsSearchEntry = isSearchEntry;
mIsWidgetListShown = isWidgetListShown;
}
@@ -91,8 +99,13 @@
@Nullable
public String getSubtitle(Context context) {
- return mIsSearchEntry
- ? SUBTITLE_SEARCH.apply(context, this) : SUBTITLE_DEFAULT.apply(context, this);
+ if (mIsSearchEntry) {
+ return SUBTITLE_SEARCH.apply(context, this);
+ } else {
+ int shortcutsCount = Math.max(0,
+ (int) mWidgets.stream().filter(WidgetItem::isShortcut).count());
+ return buildWidgetsCountString(context, mVisibleWidgetsCount, shortcutsCount);
+ }
}
@Override
@@ -102,6 +115,7 @@
return mWidgets.equals(otherEntry.mWidgets) && mPkgItem.equals(otherEntry.mPkgItem)
&& mTitleSectionName.equals(otherEntry.mTitleSectionName)
&& mIsWidgetListShown == otherEntry.mIsWidgetListShown
+ && mVisibleWidgetsCount == otherEntry.mVisibleWidgetsCount
&& mIsSearchEntry == otherEntry.mIsSearchEntry;
}
@@ -112,6 +126,7 @@
mPkgItem,
mTitleSectionName,
mWidgets,
+ mVisibleWidgetsCount,
mIsSearchEntry,
/* isWidgetListShown= */ true);
}
@@ -122,7 +137,28 @@
pkgItem,
titleSectionName,
items,
- /* forSearch */ false,
+ /* isSearchEntry= */ false,
+ /* isWidgetListShown= */ false);
+ }
+
+ /**
+ * Creates a widget list holder for an header ("app" / "suggestions") which has widgets or/and
+ * shortcuts.
+ *
+ * @param pkgItem package item info for the header section
+ * @param titleSectionName title string for the header
+ * @param items all items for the given header
+ * @param visibleWidgetsCount widgets count when only selected widgets are shown due to
+ * limited space.
+ */
+ public static WidgetsListHeaderEntry create(PackageItemInfo pkgItem, String titleSectionName,
+ List<WidgetItem> items, int visibleWidgetsCount) {
+ return new WidgetsListHeaderEntry(
+ pkgItem,
+ titleSectionName,
+ items,
+ visibleWidgetsCount,
+ /* isSearchEntry= */ false,
/* isWidgetListShown= */ false);
}
@@ -132,7 +168,7 @@
pkgItem,
titleSectionName,
items,
- /* forSearch */ true,
+ /* isSearchEntry */ true,
/* isWidgetListShown= */ false);
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
index 801b1f6..c3906a6 100644
--- a/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProvider.java
@@ -18,13 +18,13 @@
import android.content.Context;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
-import android.util.Log;
+import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import com.android.launcher3.R;
import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.ResourceBasedOverride;
@@ -54,6 +54,7 @@
* to display the recommendation grouped by categories.
*/
@WorkerThread
+ @Nullable
public WidgetRecommendationCategory getWidgetRecommendationCategory(Context context,
WidgetItem item) {
// This is a default implementation that uses application category to derive the category to
@@ -61,17 +62,16 @@
// via the overridden WidgetRecommendationCategoryProvider resource.
Preconditions.assertWorkerThread();
- PackageManager pm = context.getPackageManager();
+ PackageManagerHelper pmHelper = new PackageManagerHelper(context);
if (item.widgetInfo != null && item.widgetInfo.getComponent() != null) {
String widgetComponentName = item.widgetInfo.getComponent().getClassName();
- try {
- int predictionCategory = pm.getApplicationInfo(
- item.widgetInfo.getComponent().getPackageName(), 0 /* flags */).category;
+ ApplicationInfo applicationInfo = pmHelper.getApplicationInfo(
+ item.widgetInfo.getComponent().getPackageName(), item.widgetInfo.getUser(),
+ 0 /* flags */);
+ if (applicationInfo != null) {
+ int predictionCategory = applicationInfo.category;
return getCategoryFromApplicationCategory(context, predictionCategory,
widgetComponentName);
- } catch (PackageManager.NameNotFoundException e) {
- Log.e(TAG, "Failed to retrieve application category when determining the "
- + "widget category for " + widgetComponentName, e);
}
}
return null;
@@ -112,17 +112,22 @@
R.string.news_widget_recommendation_category_label, /*order=*/1);
}
- if (applicationCategory == ApplicationInfo.CATEGORY_SOCIAL
- || applicationCategory == ApplicationInfo.CATEGORY_AUDIO
+ if (applicationCategory == ApplicationInfo.CATEGORY_SOCIAL) {
+ return new WidgetRecommendationCategory(
+ R.string.social_widget_recommendation_category_label,
+ /*order=*/5);
+ }
+
+ if (applicationCategory == ApplicationInfo.CATEGORY_AUDIO
|| applicationCategory == ApplicationInfo.CATEGORY_VIDEO
|| applicationCategory == ApplicationInfo.CATEGORY_IMAGE) {
return new WidgetRecommendationCategory(
- R.string.social_and_entertainment_widget_recommendation_category_label,
- /*order=*/4);
+ R.string.entertainment_widget_recommendation_category_label,
+ /*order=*/6);
}
return new WidgetRecommendationCategory(
- R.string.others_widget_recommendation_category_label, /*order=*/5);
+ R.string.others_widget_recommendation_category_label, /*order=*/4);
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
index 426a3ae..3b661d0 100644
--- a/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
@@ -93,18 +93,19 @@
* @param availableWidth width in px that the recommendations should display in
* @param cellPadding padding in px that should be applied to each widget in the
* recommendations
- * @return {@code false} if no recommendations could fit in the available space.
+ * @return number of recommendations that could fit in the available space.
*/
- public boolean setRecommendations(
+ public int setRecommendations(
List<WidgetItem> recommendedWidgets, DeviceProfile deviceProfile,
final @Px float availableHeight, final @Px int availableWidth,
final @Px int cellPadding) {
this.mAvailableHeight = availableHeight;
- removeAllViews();
+ clear();
- maybeDisplayInTable(recommendedWidgets, deviceProfile, availableWidth, cellPadding);
+ int displayedWidgets = maybeDisplayInTable(recommendedWidgets, deviceProfile,
+ availableWidth, cellPadding);
updateTitleAndIndicator();
- return getChildCount() > 0;
+ return displayedWidgets;
}
/**
@@ -118,9 +119,9 @@
* @param availableWidth width in px that the recommendations should display in
* @param cellPadding padding in px that should be applied to each widget in the
* recommendations
- * @return {@code false} if no recommendations could fit in the available space.
+ * @return number of recommendations that could fit in the available space.
*/
- public boolean setRecommendations(
+ public int setRecommendations(
Map<WidgetRecommendationCategory, List<WidgetItem>> recommendations,
DeviceProfile deviceProfile,
final @Px float availableHeight, final @Px int availableWidth,
@@ -128,19 +129,23 @@
this.mAvailableHeight = availableHeight;
Context context = getContext();
mPageIndicator.setPauseScroll(true, deviceProfile.isTwoPanels);
- removeAllViews();
+ clear();
int displayedCategories = 0;
+ int totalDisplayedWidgets = 0;
// Render top MAX_CATEGORIES in separate tables. Each table becomes a page.
for (Map.Entry<WidgetRecommendationCategory, List<WidgetItem>> entry :
new TreeMap<>(recommendations).entrySet()) {
// If none of the recommendations for the category could fit in the mAvailableHeight, we
// don't want to add that category; and we look for the next one.
- if (maybeDisplayInTable(entry.getValue(), deviceProfile, availableWidth, cellPadding)) {
+ int displayedCount = maybeDisplayInTable(entry.getValue(), deviceProfile,
+ availableWidth, cellPadding);
+ if (displayedCount > 0) {
mCategoryTitles.add(
context.getResources().getString(entry.getKey().categoryTitleRes));
displayedCategories++;
+ totalDisplayedWidgets += displayedCount;
}
if (displayedCategories == MAX_CATEGORIES) {
@@ -150,7 +155,12 @@
updateTitleAndIndicator();
mPageIndicator.setPauseScroll(false, deviceProfile.isTwoPanels);
- return getChildCount() > 0;
+ return totalDisplayedWidgets;
+ }
+
+ private void clear() {
+ mCategoryTitles.clear();
+ removeAllViews();
}
/** Displays the page title and paging indicator if there are multiple pages. */
@@ -172,7 +182,6 @@
// Since the title is outside the paging scroll, we update the title on page switch.
mRecommendationPageTitle.setText(mCategoryTitles.get(getNextPage()));
super.notifyPageSwitchListener(prevPage);
- requestLayout();
}
}
@@ -199,21 +208,8 @@
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
measureChild(child, widthMeasureSpec, heightMeasureSpec);
- if (mAvailableHeight == Float.MAX_VALUE) {
- // When we are not limited by height, use currentPage's height. This is the case
- // when the paged layout is placed in a scrollable container. We cannot use
- // height
- // of tallest child in such case, as it will display a scrollbar even for
- // smaller
- // pages that don't have more content.
- if (i == mCurrentPage) {
- int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
- desiredHeight = Math.max(parentHeight, child.getMeasuredHeight());
- }
- } else {
- // Use height of tallest child when we are limited to a certain height.
- desiredHeight = Math.max(desiredHeight, child.getMeasuredHeight());
- }
+ // Use height of tallest child as we have limited height.
+ desiredHeight = Math.max(desiredHeight, child.getMeasuredHeight());
}
int finalHeight = resolveSizeAndState(desiredHeight, heightMeasureSpec, 0);
@@ -228,12 +224,14 @@
* fits.
* <p>Returns false if none of the recommendations could fit.</p>
*/
- private boolean maybeDisplayInTable(List<WidgetItem> recommendedWidgets,
+ private int maybeDisplayInTable(List<WidgetItem> recommendedWidgets,
DeviceProfile deviceProfile,
final @Px int availableWidth, final @Px int cellPadding) {
Context context = getContext();
LayoutInflater inflater = LayoutInflater.from(context);
+ // Since we are limited by space, we don't sort recommendations - to show most relevant
+ // (if possible).
List<ArrayList<WidgetItem>> rows = groupWidgetItemsUsingRowPxWithoutReordering(
recommendedWidgets,
context,
@@ -249,13 +247,13 @@
recommendationsTable.setWidgetCellOnClickListener(mWidgetCellOnClickListener);
recommendationsTable.setWidgetCellLongClickListener(mWidgetCellOnLongClickListener);
- boolean displayedAtLeastOne = recommendationsTable.setRecommendedWidgets(rows,
+ int displayedCount = recommendationsTable.setRecommendedWidgets(rows,
deviceProfile, mAvailableHeight);
- if (displayedAtLeastOne) {
+ if (displayedCount > 0) {
addView(recommendationsTable);
}
- return displayedAtLeastOne;
+ return displayedCount;
}
/** Returns location of a widget cell for displaying the "touch and hold" education tip. */
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index c0f1070..848f6fa 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -107,7 +107,8 @@
entry -> mCurrentUser.equals(entry.mPkgItem.user);
private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter;
protected final boolean mHasWorkProfile;
- protected boolean mHasRecommendedWidgets;
+ // Number of recommendations displayed
+ protected int mRecommendedWidgetsCount;
protected final SparseArray<AdapterHolder> mAdapters = new SparseArray();
@Nullable private ArrowTipView mLatestEducationalTip;
private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
@@ -581,7 +582,7 @@
}
if (enableCategorizedWidgetSuggestions()) {
- mHasRecommendedWidgets = mWidgetRecommendationsView.setRecommendations(
+ mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations(
mActivityContext.getPopupDataProvider().getCategorizedRecommendedWidgets(),
mDeviceProfile,
/* availableHeight= */ getMaxAvailableHeightForRecommendations(),
@@ -589,7 +590,7 @@
/* cellPadding= */ mWidgetCellHorizontalPadding
);
} else {
- mHasRecommendedWidgets = mWidgetRecommendationsView.setRecommendations(
+ mRecommendedWidgetsCount = mWidgetRecommendationsView.setRecommendations(
mActivityContext.getPopupDataProvider().getRecommendedWidgets(),
mDeviceProfile,
/* availableHeight= */ getMaxAvailableHeightForRecommendations(),
@@ -597,7 +598,8 @@
/* cellPadding= */ mWidgetCellHorizontalPadding
);
}
- mWidgetRecommendationsContainer.setVisibility(mHasRecommendedWidgets ? VISIBLE : GONE);
+ mWidgetRecommendationsContainer.setVisibility(
+ mRecommendedWidgetsCount > 0 ? VISIBLE : GONE);
}
@Px
@@ -790,7 +792,7 @@
}
/** private the height, in pixel, + the vertical margins of a given view. */
- private static int measureHeightWithVerticalMargins(View view) {
+ protected static int measureHeightWithVerticalMargins(View view) {
if (view.getVisibility() != VISIBLE) {
return 0;
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index ef3ccf0..a7f7785 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -15,8 +15,6 @@
*/
package com.android.launcher3.widget.picker;
-import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
-
import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
@@ -121,7 +119,7 @@
widget.setVisibility(View.VISIBLE);
// When preview loads, notify adapter to rebind the item and possibly animate
- widget.applyFromCellItem(widgetItem, 1f,
+ widget.applyFromCellItem(widgetItem,
bitmap -> holder.onPreviewLoaded(Pair.create(widgetItem, bitmap)),
holder.previewCache.get(widgetItem));
widget.requestLayout();
@@ -150,13 +148,7 @@
tableRow = (TableRow) table.getChildAt(i);
} else {
tableRow = new TableRow(table.getContext());
- if (enableCategorizedWidgetSuggestions()) {
- // Vertically center align items, so that even if they don't fill bounds, they
- // can look organized when placed together in a row.
- tableRow.setGravity(Gravity.CENTER_VERTICAL);
- } else {
- tableRow.setGravity(Gravity.TOP);
- }
+ tableRow.setGravity(Gravity.TOP);
table.addView(tableRow);
}
if (tableRow.getChildCount() > widgetItems.size()) {
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
index 12564f4..7a2b4ef 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -17,11 +17,13 @@
import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
+import static com.android.launcher3.widget.util.WidgetSizes.getWidgetSizePx;
+import static com.android.launcher3.widget.util.WidgetsTableUtils.WIDGETS_TABLE_ROW_SIZE_COMPARATOR;
+
+import static java.lang.Math.max;
import android.content.Context;
import android.util.AttributeSet;
-import android.util.Log;
-import android.util.Size;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
@@ -30,26 +32,23 @@
import android.widget.TableRow;
import androidx.annotation.Nullable;
+import androidx.annotation.Px;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.widget.WidgetCell;
-import com.android.launcher3.widget.util.WidgetSizes;
+import com.android.launcher3.widget.picker.util.WidgetPreviewContainerSize;
import java.util.ArrayList;
import java.util.List;
/** A {@link TableLayout} for showing recommended widgets. */
public final class WidgetsRecommendationTableLayout extends TableLayout {
- private static final String TAG = "WidgetsRecommendationTableLayout";
- private static final float DOWN_SCALE_RATIO = 0.9f;
- private static final float MAX_DOWN_SCALE_RATIO = 0.5f;
private final float mWidgetsRecommendationTableVerticalPadding;
private final float mWidgetCellVerticalPadding;
private final float mWidgetCellTextViewsHeight;
- private float mRecommendationTableMaxHeight = Float.MAX_VALUE;
@Nullable private OnLongClickListener mWidgetCellOnLongClickListener;
@Nullable private OnClickListener mWidgetCellOnClickListener;
@@ -82,47 +81,38 @@
* desired {@code recommendationTableMaxHeight}.
*
* <p>If the content can't fit {@code recommendationTableMaxHeight}, this view will remove a
- * last row from the {@code recommendedWidgets} until it fits or only one row left. If the only
- * row still doesn't fit, we scale down the preview image.
+ * last row from the {@code recommendedWidgets} until it fits or only one row left.
*
* <p>Returns {@code false} if none of the widgets could fit</p>
*/
- public boolean setRecommendedWidgets(List<ArrayList<WidgetItem>> recommendedWidgets,
- DeviceProfile deviceProfile,
- float recommendationTableMaxHeight) {
- mRecommendationTableMaxHeight = recommendationTableMaxHeight;
- RecommendationTableData data = fitRecommendedWidgetsToTableSpace(/* previewScale= */ 1f,
- deviceProfile,
- recommendedWidgets);
- bindData(data);
- return !data.mRecommendationTable.isEmpty();
+ public int setRecommendedWidgets(List<ArrayList<WidgetItem>> recommendedWidgets,
+ DeviceProfile deviceProfile, float recommendationTableMaxHeight) {
+ List<ArrayList<WidgetItem>> rows = selectRowsThatFitInAvailableHeight(recommendedWidgets,
+ recommendationTableMaxHeight, deviceProfile);
+ bindData(rows);
+ return rows.stream().mapToInt(ArrayList::size).sum();
}
- private void bindData(RecommendationTableData data) {
- if (data.mRecommendationTable.isEmpty()) {
+ private void bindData(List<ArrayList<WidgetItem>> recommendationTable) {
+ if (recommendationTable.isEmpty()) {
setVisibility(GONE);
return;
}
removeAllViews();
- for (int i = 0; i < data.mRecommendationTable.size(); i++) {
- List<WidgetItem> widgetItems = data.mRecommendationTable.get(i);
+ for (int i = 0; i < recommendationTable.size(); i++) {
+ List<WidgetItem> widgetItems = recommendationTable.get(i);
TableRow tableRow = new TableRow(getContext());
- if (enableCategorizedWidgetSuggestions()) {
- // Vertically center align items, so that even if they don't fill bounds, they can
- // look organized when placed together in a row.
- tableRow.setGravity(Gravity.CENTER_VERTICAL);
- } else {
- tableRow.setGravity(Gravity.TOP);
- }
+ tableRow.setGravity(Gravity.TOP);
for (WidgetItem widgetItem : widgetItems) {
WidgetCell widgetCell = addItemCell(tableRow);
- widgetCell.applyFromCellItem(widgetItem, data.mPreviewScale);
+ widgetCell.applyFromCellItem(widgetItem);
widgetCell.showAppIconInWidgetTitle(true);
widgetCell.showBadge();
if (enableCategorizedWidgetSuggestions()) {
widgetCell.showDescription(false);
+ widgetCell.showDimensions(false);
}
}
addView(tableRow);
@@ -144,58 +134,32 @@
return widget;
}
- private RecommendationTableData fitRecommendedWidgetsToTableSpace(
- float previewScale,
- DeviceProfile deviceProfile,
- List<ArrayList<WidgetItem>> recommendedWidgetsInTable) {
- if (previewScale < MAX_DOWN_SCALE_RATIO) {
- Log.w(TAG, "Hide recommended widgets. Can't down scale previews to " + previewScale);
- return new RecommendationTableData(List.of(), previewScale);
- }
+ private List<ArrayList<WidgetItem>> selectRowsThatFitInAvailableHeight(
+ List<ArrayList<WidgetItem>> recommendedWidgets, @Px float recommendationTableMaxHeight,
+ DeviceProfile deviceProfile) {
+ List<ArrayList<WidgetItem>> filteredRows = new ArrayList<>();
// A naive estimation of the widgets recommendation table height without inflation.
float totalHeight = mWidgetsRecommendationTableVerticalPadding;
- for (int i = 0; i < recommendedWidgetsInTable.size(); i++) {
- List<WidgetItem> widgetItems = recommendedWidgetsInTable.get(i);
+
+ for (int i = 0; i < recommendedWidgets.size(); i++) {
+ List<WidgetItem> widgetItems = recommendedWidgets.get(i);
float rowHeight = 0;
for (int j = 0; j < widgetItems.size(); j++) {
WidgetItem widgetItem = widgetItems.get(j);
- Size widgetSize = WidgetSizes.getWidgetItemSizePx(getContext(), deviceProfile,
- widgetItem);
- float previewHeight = widgetSize.getHeight() * previewScale;
- rowHeight = Math.max(rowHeight,
- previewHeight + mWidgetCellTextViewsHeight + mWidgetCellVerticalPadding);
+ WidgetPreviewContainerSize previewContainerSize =
+ WidgetPreviewContainerSize.Companion.forItem(widgetItem, deviceProfile);
+ float widgetItemHeight = getWidgetSizePx(deviceProfile, previewContainerSize.spanX,
+ previewContainerSize.spanY).getHeight();
+ rowHeight = max(rowHeight,
+ widgetItemHeight + mWidgetCellTextViewsHeight + mWidgetCellVerticalPadding);
}
- totalHeight += rowHeight;
+ if (totalHeight + rowHeight <= recommendationTableMaxHeight) {
+ totalHeight += rowHeight;
+ filteredRows.add(new ArrayList<>(widgetItems));
+ }
}
- if (totalHeight < mRecommendationTableMaxHeight) {
- return new RecommendationTableData(recommendedWidgetsInTable, previewScale);
- }
-
- if (recommendedWidgetsInTable.size() > 1) {
- // We don't want to scale down widgets preview unless we really need to. Reduce the
- // num of row by 1 to see if it fits.
- return fitRecommendedWidgetsToTableSpace(
- previewScale,
- deviceProfile,
- recommendedWidgetsInTable.subList(/* fromIndex= */0,
- /* toIndex= */recommendedWidgetsInTable.size() - 1));
- }
-
- float nextPreviewScale = previewScale * DOWN_SCALE_RATIO;
- return fitRecommendedWidgetsToTableSpace(nextPreviewScale, deviceProfile,
- recommendedWidgetsInTable);
- }
-
- /** Data class for the widgets recommendation table and widgets preview scaling. */
- private class RecommendationTableData {
- private final List<ArrayList<WidgetItem>> mRecommendationTable;
- private final float mPreviewScale;
-
- RecommendationTableData(List<ArrayList<WidgetItem>> recommendationTable,
- float previewScale) {
- mRecommendationTable = recommendationTable;
- mPreviewScale = previewScale;
- }
+ // Perform re-ordering once we have filtered out recommendations that fit.
+ return filteredRows.stream().sorted(WIDGETS_TABLE_ROW_SIZE_COMPARATOR).toList();
}
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index 165b2fe..c3bb993 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -167,7 +167,7 @@
@Override
public void onWidgetsBound() {
super.onWidgetsBound();
- if (!mHasRecommendedWidgets && mSelectedHeader == null) {
+ if (mRecommendedWidgetsCount == 0 && mSelectedHeader == null) {
mAdapters.get(mActivePage).mWidgetsListAdapter.selectFirstHeaderEntry();
mAdapters.get(mActivePage).mWidgetsRecyclerView.scrollToTop();
}
@@ -177,7 +177,7 @@
public void onRecommendedWidgetsBound() {
super.onRecommendedWidgetsBound();
- if (mSuggestedWidgetsContainer == null && mHasRecommendedWidgets) {
+ if (mSuggestedWidgetsContainer == null && mRecommendedWidgetsCount > 0) {
setupSuggestedWidgets(LayoutInflater.from(getContext()));
mSuggestedWidgetsHeader.callOnClick();
}
@@ -209,8 +209,9 @@
packageItemInfo.title = suggestionsHeaderTitle;
WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create(
packageItemInfo,
- suggestionsHeaderTitle,
- mActivityContext.getPopupDataProvider().getRecommendedWidgets())
+ /*titleSectionName=*/ suggestionsHeaderTitle,
+ /*items=*/ mActivityContext.getPopupDataProvider().getRecommendedWidgets(),
+ /*visibleWidgetsCount=*/ mRecommendedWidgetsCount)
.withWidgetListShown();
mSuggestedWidgetsHeader.applyFromItemInfoWithIcon(widgetsListHeaderEntry);
@@ -233,7 +234,7 @@
@Override
@Px
protected float getMaxTableHeight(@Px float noWidgetsViewHeight) {
- return Float.MAX_VALUE;
+ return mContent.getMeasuredHeight() - measureHeightWithVerticalMargins(mHeaderTitle);
}
@Override
diff --git a/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSize.kt b/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSize.kt
new file mode 100644
index 0000000..a0414ba
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSize.kt
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker.util
+
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.model.WidgetItem
+import kotlin.math.abs
+
+/** Size of a preview container in terms of the grid spans. */
+data class WidgetPreviewContainerSize(@JvmField val spanX: Int, @JvmField val spanY: Int) {
+ companion object {
+ /**
+ * Returns the size of the preview container in which the given widget's preview should be
+ * displayed (by scaling it if necessary).
+ */
+ fun forItem(item: WidgetItem, dp: DeviceProfile): WidgetPreviewContainerSize {
+ val sizes =
+ if (dp.isTablet && !dp.isTwoPanels) {
+ TABLET_WIDGET_PREVIEW_SIZES
+ } else {
+ HANDHELD_WIDGET_PREVIEW_SIZES
+ }
+
+ for ((index, containerSize) in sizes.withIndex()) {
+ if (containerSize.spanX == item.spanX && containerSize.spanY == item.spanY) {
+ return containerSize // Exact match!
+ }
+ if (containerSize.spanX <= item.spanX && containerSize.spanY <= item.spanY) {
+ return findClosestFittingContainer(
+ containerSizes = sizes.toList(),
+ startIndex = index,
+ item = item
+ )
+ }
+ }
+ // Use largest container if no match found
+ return sizes.elementAt(0)
+ }
+
+ private fun findClosestFittingContainer(
+ containerSizes: List<WidgetPreviewContainerSize>,
+ startIndex: Int,
+ item: WidgetItem
+ ): WidgetPreviewContainerSize {
+ // Checks if it's a smaller container, but close enough to keep the down-scale minimal.
+ fun hasAcceptableSize(currentIndex: Int): Boolean {
+ val container = containerSizes[currentIndex]
+ val isSmallerThanItem =
+ container.spanX <= item.spanX && container.spanY <= item.spanY
+ val isCloseToItemSize =
+ (item.spanY - container.spanY <= 1) && (item.spanX - container.spanX <= 1)
+
+ return isSmallerThanItem && isCloseToItemSize
+ }
+
+ var currentIndex = startIndex
+ var match = containerSizes[currentIndex]
+ val itemCellSizeRatio = item.spanX.toFloat() / item.spanY
+ var lastCellSizeRatioDiff = Float.MAX_VALUE
+
+ // Look for a smaller container (up to an acceptable extent) with closest cell size
+ // ratio.
+ while (currentIndex <= containerSizes.lastIndex && hasAcceptableSize(currentIndex)) {
+ val current = containerSizes[currentIndex]
+ val currentCellSizeRatio = current.spanX.toFloat() / current.spanY
+ val currentCellSizeRatioDiff = abs(itemCellSizeRatio - currentCellSizeRatio)
+
+ if (currentCellSizeRatioDiff < lastCellSizeRatioDiff) {
+ lastCellSizeRatioDiff = currentCellSizeRatioDiff
+ match = containerSizes[currentIndex]
+ }
+ currentIndex++
+ }
+ return match
+ }
+ }
+}
diff --git a/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizes.kt b/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizes.kt
new file mode 100644
index 0000000..a016676
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizes.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker.util
+
+/**
+ * An ordered list of recommended sizes for the preview containers in handheld devices.
+ *
+ * Size of the preview container in which a widget's preview can be displayed.
+ */
+val HANDHELD_WIDGET_PREVIEW_SIZES: List<WidgetPreviewContainerSize> =
+ listOf(
+ WidgetPreviewContainerSize(spanX = 4, spanY = 3),
+ WidgetPreviewContainerSize(spanX = 4, spanY = 2),
+ WidgetPreviewContainerSize(spanX = 2, spanY = 3),
+ WidgetPreviewContainerSize(spanX = 2, spanY = 2),
+ WidgetPreviewContainerSize(spanX = 4, spanY = 1),
+ WidgetPreviewContainerSize(spanX = 2, spanY = 1),
+ WidgetPreviewContainerSize(spanX = 1, spanY = 1),
+ )
+
+/**
+ * An ordered list of recommended sizes for the preview containers in tablet devices (with larger
+ * grids).
+ *
+ * Size of the preview container in which a widget's preview can be displayed (by scaling the
+ * preview if necessary).
+ */
+val TABLET_WIDGET_PREVIEW_SIZES: List<WidgetPreviewContainerSize> =
+ listOf(
+ WidgetPreviewContainerSize(spanX = 3, spanY = 4),
+ WidgetPreviewContainerSize(spanX = 3, spanY = 3),
+ WidgetPreviewContainerSize(spanX = 3, spanY = 2),
+ WidgetPreviewContainerSize(spanX = 2, spanY = 3),
+ WidgetPreviewContainerSize(spanX = 2, spanY = 2),
+ WidgetPreviewContainerSize(spanX = 3, spanY = 1),
+ WidgetPreviewContainerSize(spanX = 2, spanY = 1),
+ WidgetPreviewContainerSize(spanX = 1, spanY = 1),
+ )
diff --git a/src/com/android/launcher3/widget/util/WidgetsTableUtils.java b/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
index 74d3062..5e0e203 100644
--- a/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
+++ b/src/com/android/launcher3/widget/util/WidgetsTableUtils.java
@@ -16,11 +16,13 @@
package com.android.launcher3.widget.util;
import android.content.Context;
+import android.util.Size;
import androidx.annotation.Px;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.widget.picker.util.WidgetPreviewContainerSize;
import java.util.ArrayList;
import java.util.Comparator;
@@ -33,8 +35,8 @@
/**
* Groups widgets in the following order:
* 1. Widgets always go before shortcuts.
- * 2. Widgets with smaller horizontal spans will be shown first.
- * 3. If widgets have the same horizontal spans, then widgets with a smaller vertical spans will
+ * 2. Widgets with smaller vertical spans will be shown first.
+ * 3. If widgets have the same vertical spans, then widgets with a smaller horizontal spans will
* go first.
* 4. If both widgets have the same horizontal and vertical spans, they will use the same order
* from the given {@code widgetItems}.
@@ -43,14 +45,29 @@
if (item.widgetInfo != null && otherItem.widgetInfo == null) return -1;
if (item.widgetInfo == null && otherItem.widgetInfo != null) return 1;
- if (item.spanX == otherItem.spanX) {
- if (item.spanY == otherItem.spanY) return 0;
- return item.spanY > otherItem.spanY ? 1 : -1;
+ if (item.spanY == otherItem.spanY) {
+ if (item.spanX == otherItem.spanX) return 0;
+ return item.spanX > otherItem.spanX ? 1 : -1;
}
- return item.spanX > otherItem.spanX ? 1 : -1;
+ return item.spanY > otherItem.spanY ? 1 : -1;
};
/**
+ * Comparator that enables displaying rows in increasing order of their size (totalW * H);
+ * except for shortcuts which always show at the bottom.
+ */
+ public static final Comparator<ArrayList<WidgetItem>> WIDGETS_TABLE_ROW_SIZE_COMPARATOR =
+ Comparator.comparingInt(row -> {
+ if (row.stream().anyMatch(WidgetItem::isShortcut)) {
+ return Integer.MAX_VALUE;
+ } else {
+ int rowWidth = row.stream().mapToInt(w -> w.spanX).sum();
+ int rowHeight = row.get(0).spanY;
+ return (rowWidth * rowHeight);
+ }
+ });
+
+ /**
* Groups {@code widgetItems} items into a 2D array which matches their appearance in a UI
* table. This takes liberty to rearrange widgets to make the table visually appealing.
*/
@@ -59,72 +76,70 @@
final @Px int rowPx, final @Px int cellPadding) {
List<WidgetItem> sortedWidgetItems = widgetItems.stream().sorted(WIDGET_SHORTCUT_COMPARATOR)
.collect(Collectors.toList());
- return groupWidgetItemsUsingRowPxWithoutReordering(sortedWidgetItems, context, dp, rowPx,
+ List<ArrayList<WidgetItem>> rows = groupWidgetItemsUsingRowPxWithoutReordering(
+ sortedWidgetItems, context, dp, rowPx,
cellPadding);
+ return rows.stream().sorted(WIDGETS_TABLE_ROW_SIZE_COMPARATOR).toList();
}
/**
* Groups {@code widgetItems} into a 2D array which matches their appearance in a UI table while
* maintaining their order. This function is a variant of
- * {@code groupWidgetItemsIntoTableWithoutReordering} in that this uses widget pixels for
- * calculation.
+ * {@code groupWidgetItemsIntoTableWithoutReordering} in that this uses widget container's
+ * pixels for calculation.
*
* <p>Grouping:
* 1. Widgets and shortcuts never group together in the same row.
- * 2. The ordered widgets are grouped together in the same row until their individual occupying
- * pixels exceed the total allowed pixels for the cell.
+ * 2. Widgets are grouped together only if they have same preview container size.
+ * 3. Widgets are grouped together in the same row until the total of individual container sizes
+ * exceed the total allowed pixels for the row.
* 3. The ordered shortcuts are grouped together in the same row until their individual
* occupying pixels exceed the total allowed pixels for the cell.
* 4. If there is only one widget in a row, its width may exceed the {@code rowPx}.
*
- * <p>Let's say the {@code rowPx} is set to 600 and we have 5 widgets. Widgets can be grouped
- * in the same row if each of their individual occupying pixels does not exceed
- * {@code rowPx} / 5 - 2 * {@code cellPadding}.
- * Example 1: Row 1: 200x200, 200x300, 100x100. Average horizontal pixels is 200 and no widgets
- * exceed that width. This is okay.
- * Example 2: Row 1: 200x200, 400x300, 100x100. Average horizontal pixels is 200 and one widget
- * exceed that width. This is not allowed.
- * Example 3: Row 1: 700x400. This is okay because this is the only item in the row.
+ * <p>See WidgetTableUtilsTest
*/
public static List<ArrayList<WidgetItem>> groupWidgetItemsUsingRowPxWithoutReordering(
List<WidgetItem> widgetItems, Context context, final DeviceProfile dp,
final @Px int rowPx, final @Px int cellPadding) {
-
List<ArrayList<WidgetItem>> widgetItemsTable = new ArrayList<>();
ArrayList<WidgetItem> widgetItemsAtRow = null;
+ // A row displays only items of same container size.
+ WidgetPreviewContainerSize containerSizeForRow = null;
+ @Px int currentRowWidth = 0;
+
for (WidgetItem widgetItem : widgetItems) {
if (widgetItemsAtRow == null) {
widgetItemsAtRow = new ArrayList<>();
widgetItemsTable.add(widgetItemsAtRow);
}
int numOfWidgetItems = widgetItemsAtRow.size();
- @Px int individualSpan = (rowPx / (numOfWidgetItems + 1)) - (2 * cellPadding);
+
+ WidgetPreviewContainerSize containerSize =
+ WidgetPreviewContainerSize.Companion.forItem(widgetItem, dp);
+ Size containerSizePx = WidgetSizes.getWidgetSizePx(dp, containerSize.spanX,
+ containerSize.spanY);
+ @Px int containerWidth = containerSizePx.getWidth() + (2 * cellPadding);
+
if (numOfWidgetItems == 0) {
widgetItemsAtRow.add(widgetItem);
- } else if (
- // Since the size of the widget cell is determined by dividing the maximum span
- // pixels evenly, making sure that each widget would have enough span pixels to
- // show their contents.
- widgetItem.hasSameType(widgetItemsAtRow.get(numOfWidgetItems - 1))
- && widgetItemsAtRow.stream().allMatch(
- item -> WidgetSizes.getWidgetItemSizePx(context, dp, item)
- .getWidth() <= individualSpan)
- && WidgetSizes.getWidgetItemSizePx(context, dp, widgetItem)
- .getWidth() <= individualSpan) {
+ containerSizeForRow = containerSize;
+ currentRowWidth = containerWidth;
+ } else if ((currentRowWidth + containerWidth) <= rowPx
+ && widgetItem.hasSameType(widgetItemsAtRow.get(numOfWidgetItems - 1))
+ && containerSize.equals(containerSizeForRow)) {
// Group items in the same row if
// 1. they are with the same type, i.e. a row can only have widgets or shortcuts but
// never a mix of both.
- // 2. Each widget will have horizontal cell span pixels that is at least as large as
- // it is required to fit in the horizontal content, unless the widget horizontal
- // span pixels is larger than the maximum allowed.
- // If an item has horizontal span pixels larger than the maximum allowed pixels
- // per row, we just place it in its own row regardless of the horizontal span
- // limit.
+ // 2. Each widget in the given row has same preview container size.
widgetItemsAtRow.add(widgetItem);
+ currentRowWidth += containerWidth;
} else {
widgetItemsAtRow = new ArrayList<>();
widgetItemsTable.add(widgetItemsAtRow);
widgetItemsAtRow.add(widgetItem);
+ containerSizeForRow = containerSize;
+ currentRowWidth = containerWidth;
}
}
return widgetItemsTable;
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
index efde7d8..90271c1 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/ApiWrapper.java
@@ -108,6 +108,13 @@
}
/**
+ * Returns an intent which can be used to open Private Space Settings.
+ */
+ public static Intent getPrivateSpaceSettingsIntent(Context context) {
+ return null;
+ }
+
+ /**
* Checks if an activity is flagged as non-resizeable.
*/
public static boolean isNonResizeableActivity(LauncherActivityInfo lai) {
diff --git a/tests/Android.bp b/tests/Android.bp
index e9111ea..24ae158 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -177,7 +177,7 @@
name: "launcher-testing-shared",
srcs: [
"multivalentTests/shared/com/android/launcher3/testing/shared/**/*.java",
- "multivalentTests/shared/com/android/launcher3/testing/shared/**/*.kt"
+ "multivalentTests/shared/com/android/launcher3/testing/shared/**/*.kt",
],
resource_dirs: [],
manifest: "multivalentTests/shared/AndroidManifest.xml",
@@ -225,8 +225,8 @@
// multivalentTests directory is a shared folder for not only robolectric converted test
// classes but also shared helper classes.
srcs: [
- "multivalentTests/src/com/android/launcher3/util/*.java",
- "multivalentTests/src/com/android/launcher3/util/*.kt",
+ "multivalentTests/src/**/*.java",
+ "multivalentTests/src/**/*.kt",
// Test util classes
":launcher-testing-helpers",
@@ -246,7 +246,8 @@
"androidx.test.uiautomator_uiautomator",
"androidx.core_core-animation-testing",
"androidx.test.ext.junit",
- "inline-mockito-robolectric-prebuilt",
+ "mockito-robolectric-prebuilt",
+ "mockito-kotlin2",
"platform-parametric-runner-lib",
"testables",
"Launcher3TestResources",
diff --git a/tests/assets/databases/GridMigrationTest/flagged_result5x5to5x8.db b/tests/assets/databases/GridMigrationTest/flagged_result5x5to5x8.db
new file mode 100644
index 0000000..8bea3ce
--- /dev/null
+++ b/tests/assets/databases/GridMigrationTest/flagged_result5x5to5x8.db
Binary files differ
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
index af8f67f..197e687 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait.txt
@@ -123,7 +123,7 @@
dropTargetBarBottomMarginPx: 42.0px (16.0dp)
getCellLayoutSpringLoadShrunkTop(): 391.0px (148.95238dp)
getCellLayoutSpringLoadShrunkBottom(): 1927.0px (734.0952dp)
- workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
- getWorkspaceSpringLoadScale(): 0.7781155px (0.29642496dp)
+ workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
+ getWorkspaceSpringLoadScale(): 0.7666667px (0.2920635dp)
getCellLayoutHeight(): 1974.0px (752.0dp)
getCellLayoutWidth(): 1080.0px (411.42856dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
index 5b83dd7..4a9e2e6 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phonePortrait3Button.txt
@@ -123,7 +123,7 @@
dropTargetBarBottomMarginPx: 42.0px (16.0dp)
getCellLayoutSpringLoadShrunkTop(): 391.0px (148.95238dp)
getCellLayoutSpringLoadShrunkBottom(): 1906.0px (726.0952dp)
- workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
- getWorkspaceSpringLoadScale(): 0.77572966px (0.29551607dp)
+ workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
+ getWorkspaceSpringLoadScale(): 0.76666665px (0.29206347dp)
getCellLayoutHeight(): 1953.0px (744.0dp)
getCellLayoutWidth(): 1080.0px (411.42856dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
index 03a0048..9e89a16 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar.txt
@@ -123,7 +123,7 @@
dropTargetBarBottomMarginPx: 16.0px (6.095238dp)
getCellLayoutSpringLoadShrunkTop(): 201.0px (76.57143dp)
getCellLayoutSpringLoadShrunkBottom(): 961.0px (366.09525dp)
- workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
+ workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
getWorkspaceSpringLoadScale(): 0.8059385px (0.30702418dp)
getCellLayoutHeight(): 943.0px (359.2381dp)
getCellLayoutWidth(): 2073.0px (789.7143dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
index 84258b3..ce168b4 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/phoneVerticalBar3Button.txt
@@ -123,7 +123,7 @@
dropTargetBarBottomMarginPx: 16.0px (6.095238dp)
getCellLayoutSpringLoadShrunkTop(): 201.0px (76.57143dp)
getCellLayoutSpringLoadShrunkBottom(): 1017.0px (387.42856dp)
- workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
+ workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
getWorkspaceSpringLoadScale(): 0.8111332px (0.3090031dp)
getCellLayoutHeight(): 1006.0px (383.2381dp)
getCellLayoutWidth(): 1947.0px (741.7143dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
index 87a9700..7926033 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape.txt
@@ -123,7 +123,7 @@
dropTargetBarBottomMarginPx: 64.0px (32.0dp)
getCellLayoutSpringLoadShrunkTop(): 312.0px (156.0dp)
getCellLayoutSpringLoadShrunkBottom(): 1272.0px (636.0dp)
- workspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)
+ workspaceSpringLoadedMinNextPageVisiblePx: 96.0px (48.0dp)
getWorkspaceSpringLoadScale(): 0.76677316px (0.38338658dp)
getCellLayoutHeight(): 1252.0px (626.0dp)
getCellLayoutWidth(): 2198.0px (1099.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
index 169256d..eb20578 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletLandscape3Button.txt
@@ -123,7 +123,7 @@
dropTargetBarBottomMarginPx: 64.0px (32.0dp)
getCellLayoutSpringLoadShrunkTop(): 312.0px (156.0dp)
getCellLayoutSpringLoadShrunkBottom(): 1272.0px (636.0dp)
- workspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)
+ workspaceSpringLoadedMinNextPageVisiblePx: 96.0px (48.0dp)
getWorkspaceSpringLoadScale(): 0.76677316px (0.38338658dp)
getCellLayoutHeight(): 1252.0px (626.0dp)
getCellLayoutWidth(): 2198.0px (1099.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
index 59da1be..dba0ec4 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait.txt
@@ -123,7 +123,7 @@
dropTargetBarBottomMarginPx: 96.0px (48.0dp)
getCellLayoutSpringLoadShrunkTop(): 564.0px (282.0dp)
getCellLayoutSpringLoadShrunkBottom(): 2072.0px (1036.0dp)
- workspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)
+ workspaceSpringLoadedMinNextPageVisiblePx: 96.0px (48.0dp)
getWorkspaceSpringLoadScale(): 0.8125px (0.40625dp)
getCellLayoutHeight(): 1856.0px (928.0dp)
getCellLayoutWidth(): 1528.0px (764.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
index ad1f095..495afb2 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/tabletPortrait3Button.txt
@@ -123,7 +123,7 @@
dropTargetBarBottomMarginPx: 96.0px (48.0dp)
getCellLayoutSpringLoadShrunkTop(): 564.0px (282.0dp)
getCellLayoutSpringLoadShrunkBottom(): 2072.0px (1036.0dp)
- workspaceSpringLoadedMinNextPageVisiblePx: 48.0px (24.0dp)
+ workspaceSpringLoadedMinNextPageVisiblePx: 96.0px (48.0dp)
getWorkspaceSpringLoadScale(): 0.8125px (0.40625dp)
getCellLayoutHeight(): 1856.0px (928.0dp)
getCellLayoutWidth(): 1528.0px (764.0dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
index 61d5ee6..e7dd3e0 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape.txt
@@ -123,7 +123,7 @@
dropTargetBarBottomMarginPx: 42.0px (16.0dp)
getCellLayoutSpringLoadShrunkTop(): 299.0px (113.90476dp)
getCellLayoutSpringLoadShrunkBottom(): 1457.0px (555.0476dp)
- workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
+ workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
getWorkspaceSpringLoadScale(): 0.8452555px (0.32200208dp)
getCellLayoutHeight(): 1370.0px (521.9048dp)
getCellLayoutWidth(): 1083.0px (412.57144dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
index ac73e2f..fcbd427 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelLandscape3Button.txt
@@ -123,7 +123,7 @@
dropTargetBarBottomMarginPx: 42.0px (16.0dp)
getCellLayoutSpringLoadShrunkTop(): 299.0px (113.90476dp)
getCellLayoutSpringLoadShrunkBottom(): 1457.0px (555.0476dp)
- workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
+ workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
getWorkspaceSpringLoadScale(): 0.8452555px (0.32200208dp)
getCellLayoutHeight(): 1370.0px (521.9048dp)
getCellLayoutWidth(): 1083.0px (412.57144dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
index 3169f41..319247c 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait.txt
@@ -123,7 +123,7 @@
dropTargetBarBottomMarginPx: 84.0px (32.0dp)
getCellLayoutSpringLoadShrunkTop(): 364.0px (138.66667dp)
getCellLayoutSpringLoadShrunkBottom(): 1773.0px (675.4286dp)
- workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
+ workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
getWorkspaceSpringLoadScale(): 0.81871px (0.31188953dp)
getCellLayoutHeight(): 1721.0px (655.619dp)
getCellLayoutWidth(): 899.0px (342.4762dp)
diff --git a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
index 9d3d7bc..50c1d4b 100644
--- a/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
+++ b/tests/assets/dumpTests/DeviceProfileDumpTest/twoPanelPortrait3Button.txt
@@ -123,7 +123,7 @@
dropTargetBarBottomMarginPx: 84.0px (32.0dp)
getCellLayoutSpringLoadShrunkTop(): 364.0px (138.66667dp)
getCellLayoutSpringLoadShrunkBottom(): 1773.0px (675.4286dp)
- workspaceSpringLoadedMinNextPageVisiblePx: 63.0px (24.0dp)
+ workspaceSpringLoadedMinNextPageVisiblePx: 126.0px (48.0dp)
getWorkspaceSpringLoadScale(): 0.81871px (0.31188953dp)
getCellLayoutHeight(): 1721.0px (655.619dp)
getCellLayoutWidth(): 899.0px (342.4762dp)
diff --git a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
index d02ad3b..e0fafcc 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -120,6 +120,8 @@
public static final String REQUEST_CLEAR_DATA = "clear-data";
public static final String REQUEST_HOTSEAT_ICON_NAMES = "get-hotseat-icon-names";
public static final String REQUEST_IS_TABLET = "is-tablet";
+ public static final String REQUEST_IS_PREDICTIVE_BACK_SWIPE_ENABLED =
+ "is-predictive-back-swipe-enabled";
public static final String REQUEST_ENABLE_TASKBAR_NAVBAR_UNIFICATION =
"enable-taskbar-navbar-unification";
public static final String REQUEST_NUM_ALL_APPS_COLUMNS = "num-all-apps-columns";
diff --git a/tests/src/com/android/launcher3/celllayout/CellPosMapperTest.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/CellPosMapperTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/celllayout/CellPosMapperTest.java
rename to tests/multivalentTests/src/com/android/launcher3/celllayout/CellPosMapperTest.java
diff --git a/tests/src/com/android/launcher3/logging/FileLogTest.java b/tests/multivalentTests/src/com/android/launcher3/logging/FileLogTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/logging/FileLogTest.java
rename to tests/multivalentTests/src/com/android/launcher3/logging/FileLogTest.java
diff --git a/tests/src/com/android/launcher3/model/data/ItemInfoWithIconTest.kt b/tests/multivalentTests/src/com/android/launcher3/model/data/ItemInfoWithIconTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/model/data/ItemInfoWithIconTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/model/data/ItemInfoWithIconTest.kt
diff --git a/tests/src/com/android/launcher3/popup/PopupPopulatorTest.java b/tests/multivalentTests/src/com/android/launcher3/popup/PopupPopulatorTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/popup/PopupPopulatorTest.java
rename to tests/multivalentTests/src/com/android/launcher3/popup/PopupPopulatorTest.java
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/rule/BackAndRestoreRule.kt b/tests/multivalentTests/src/com/android/launcher3/util/rule/BackAndRestoreRule.kt
index cb3550a..da96939 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/rule/BackAndRestoreRule.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/rule/BackAndRestoreRule.kt
@@ -16,7 +16,6 @@
package com.android.launcher3.util.rule
-import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.InvariantDeviceProfile
import com.android.launcher3.LauncherPrefs
@@ -36,17 +35,16 @@
private val phoneContext = getInstrumentation().targetContext
+ private fun dbBackUp() = File(phoneContext.dataDir.path, "/databasesBackUp")
+
+ private fun dbDirectory() = File(phoneContext.dataDir.path, "/databases")
+
private fun isWorkspaceDatabase(rawFileName: String): Boolean {
val fileName = Paths.get(rawFileName).fileName.pathString
return fileName.startsWith("launcher") && fileName.endsWith(".db")
}
- fun getDatabaseFiles() =
- File(phoneContext.dataDir.path, "/databases").listFiles().filter {
- isWorkspaceDatabase(it.name)
- }
-
- private fun deleteDBs() = getDatabaseFiles().forEach { it.delete() }
+ fun getDatabaseFiles() = dbDirectory().listFiles().filter { isWorkspaceDatabase(it.name) }
/**
* Setting RESTORE_DEVICE would trigger a restore next time the Launcher starts, and we remove
@@ -62,7 +60,7 @@
private fun uploadDatabase(dbName: String) {
val file = File(File(getInstrumentation().targetContext.dataDir, "/databases"), dbName)
file.writeBytes(
- InstrumentationRegistry.getInstrumentation()
+ getInstrumentation()
.context
.assets
.open("databases/BackupAndRestore/$dbName")
@@ -71,25 +69,51 @@
file.setWritable(true, false)
}
- fun before() {
- setRestoreConstants()
- deleteDBs()
+ private fun uploadDbs() {
uploadDatabase("launcher.db")
uploadDatabase("launcher_4_by_4.db")
uploadDatabase("launcher_4_by_5.db")
uploadDatabase("launcher_3_by_3.db")
}
+ private fun savePreviousState() {
+ dbBackUp().deleteRecursively()
+ if (!dbDirectory().renameTo(dbBackUp())) {
+ throw Exception("Unable to move databases to backup directory")
+ }
+ dbDirectory().mkdir()
+ if (!dbDirectory().exists()) {
+ throw Exception("Databases directory doesn't exists")
+ }
+ }
+
+ private fun restorePreviousState() {
+ dbDirectory().deleteRecursively()
+ if (!dbBackUp().renameTo(dbDirectory())) {
+ throw Exception("Unable to restore backup directory to databases directory")
+ }
+ dbBackUp().delete()
+ }
+
+ fun before() {
+ savePreviousState()
+ setRestoreConstants()
+ uploadDbs()
+ }
+
fun after() {
- deleteDBs()
+ restorePreviousState()
}
override fun apply(base: Statement?, description: Description?): Statement =
object : Statement() {
override fun evaluate() {
before()
- base?.evaluate()
- after()
+ try {
+ base?.evaluate()
+ } finally {
+ after()
+ }
}
}
}
diff --git a/tests/src/com/android/launcher3/util/window/WindowManagerProxyTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/window/WindowManagerProxyTest.kt
similarity index 100%
rename from tests/src/com/android/launcher3/util/window/WindowManagerProxyTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/util/window/WindowManagerProxyTest.kt
diff --git a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index 3ba563d..ffcf83f 100644
--- a/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -38,17 +38,17 @@
import com.android.launcher3.util.window.CachedDisplayInfo
import com.android.launcher3.util.window.WindowManagerProxy
import com.google.common.truth.Truth
+import org.junit.Rule
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.spy
+import org.mockito.kotlin.whenever
import java.io.BufferedReader
import java.io.File
import java.io.PrintWriter
import java.io.StringWriter
import kotlin.math.max
import kotlin.math.min
-import org.junit.Rule
-import org.mockito.kotlin.any
-import org.mockito.kotlin.mock
-import org.mockito.kotlin.spy
-import org.mockito.kotlin.whenever
/**
* This is an abstract class for DeviceProfile tests that create an InvariantDeviceProfile based on
@@ -274,7 +274,8 @@
isGestureMode: Boolean = true,
densityDpi: Int
) {
- setFlagsRule.setFlags(false, Flags.FLAG_ENABLE_TWOLINE_TOGGLE)
+ setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_TWOLINE_TOGGLE)
+ LauncherPrefs.get(testContext).put(LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE, true)
val windowsBounds = perDisplayBoundsCache[displayInfo]!!
val realBounds = windowsBounds[rotation]
whenever(windowManagerProxy.getDisplayInfo(any())).thenReturn(displayInfo)
diff --git a/tests/src/com/android/launcher3/LauncherIntentTest.java b/tests/src/com/android/launcher3/LauncherIntentTest.java
index e2971e8..e8822c3 100644
--- a/tests/src/com/android/launcher3/LauncherIntentTest.java
+++ b/tests/src/com/android/launcher3/LauncherIntentTest.java
@@ -29,6 +29,7 @@
import com.android.launcher3.allapps.SearchRecyclerView;
import com.android.launcher3.ui.AbstractLauncherUiTest;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -39,6 +40,7 @@
public final Intent allAppsIntent = new Intent(Intent.ACTION_ALL_APPS);
@Test
+ @Ignore("b/329152799")
public void testAllAppsIntent() {
// setup by moving to home
mLauncher.goHome();
diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
index 0907f8f..eea4fe5 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -47,6 +47,7 @@
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.pm.UserCache;
+import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.ActivityContextWrapper;
import com.android.launcher3.util.UserIconInfo;
import com.android.launcher3.util.rule.TestStabilityRule;
@@ -176,17 +177,15 @@
}
@Test
- public void openPrivateSpaceSettings_triggersSecurityAndPrivacyIntent() {
- Intent expectedIntent = PrivateProfileManager.PRIVATE_SPACE_INTENT;
+ public void openPrivateSpaceSettings_triggersCorrectIntent() {
+ Intent expectedIntent = ApiWrapper.getPrivateSpaceSettingsIntent(mContext);
ArgumentCaptor<Intent> acIntent = ArgumentCaptor.forClass(Intent.class);
mPrivateProfileManager.setPrivateSpaceSettingsAvailable(true);
mPrivateProfileManager.openPrivateSpaceSettings();
Mockito.verify(mContext).startActivity(acIntent.capture());
- Intent actualIntent = acIntent.getValue();
- assertEquals("Intent Action is different", expectedIntent.getAction(),
- actualIntent.getAction());
+ assertEquals("Intent Action is different", expectedIntent, acIntent.getValue());
}
private static void awaitTasksCompleted() throws Exception {
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
index 490cb47..043461d 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
@@ -18,6 +18,7 @@
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
import static com.android.launcher3.allapps.UserProfileManager.STATE_DISABLED;
import static com.android.launcher3.allapps.UserProfileManager.STATE_ENABLED;
import static com.android.launcher3.allapps.UserProfileManager.STATE_TRANSITION;
@@ -25,13 +26,19 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import static org.mockito.AdditionalAnswers.answer;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
+import android.os.Process;
+import android.os.UserHandle;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
@@ -44,6 +51,7 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.R;
+import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.util.ActivityContextWrapper;
import org.junit.Before;
@@ -52,32 +60,53 @@
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
+import java.util.ArrayList;
+import java.util.List;
+
@SmallTest
@RunWith(AndroidJUnit4.class)
public class PrivateSpaceHeaderViewControllerTest {
+ private static final UserHandle MAIN_HANDLE = Process.myUserHandle();
+ private static final UserHandle PRIVATE_HANDLE = new UserHandle(11);
private static final int CONTAINER_HEADER_ELEMENT_COUNT = 1;
private static final int LOCK_UNLOCK_BUTTON_COUNT = 1;
private static final int PS_SETTINGS_BUTTON_COUNT_VISIBLE = 1;
private static final int PS_SETTINGS_BUTTON_COUNT_INVISIBLE = 0;
private static final int PS_TRANSITION_IMAGE_COUNT = 1;
+ private static final int NUM_APP_COLS = 4;
+ private static final int NUM_PRIVATE_SPACE_APPS = 50;
+ private static final int ALL_APPS_HEIGHT = 10;
+ private static final int ALL_APPS_CELL_HEIGHT = 1;
+ private static final int PS_HEADER_HEIGHT = 1;
+ private static final int BIGGER_PS_HEADER_HEIGHT = 2;
+ private static final int SCROLL_NO_WHERE = -1;
+ private static final float HEADER_PROTECTION_HEIGHT = 1F;
private Context mContext;
private PrivateSpaceHeaderViewController mPsHeaderViewController;
private RelativeLayout mPsHeaderLayout;
+ private AlphabeticalAppsList<?> mAlphabeticalAppsList;
@Mock
private PrivateProfileManager mPrivateProfileManager;
@Mock
private ActivityAllAppsContainerView mAllApps;
+ @Mock
+ private AllAppsStore<?> mAllAppsStore;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = new ActivityContextWrapper(getApplicationContext());
+ when(mPrivateProfileManager.getItemInfoMatcher()).thenReturn(info ->
+ info != null && info.user.equals(PRIVATE_HANDLE));
mPsHeaderViewController = new PrivateSpaceHeaderViewController(mAllApps,
mPrivateProfileManager);
mPsHeaderLayout = (RelativeLayout) LayoutInflater.from(mContext).inflate(
R.layout.private_space_header, null);
+ mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+ null, mPrivateProfileManager);
+ mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
}
@Test
@@ -223,6 +252,88 @@
assertEquals(PS_TRANSITION_IMAGE_COUNT, totalLockUnlockButtonView);
}
+ @Test
+ public void scrollForViewToBeVisibleInContainer_withHeader() {
+ when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
+ when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
+ .thenAnswer(answer(this::addPrivateSpaceHeader));
+ when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+ when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+ .thenReturn(iteminfo -> iteminfo.componentName == null
+ || !iteminfo.componentName.getPackageName()
+ .equals("com.android.launcher3.tests.camera"));
+ when(mAllApps.getContext()).thenReturn(mContext);
+ mAlphabeticalAppsList.updateItemFilter(info -> info != null
+ && info.user.equals(MAIN_HANDLE));
+ when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
+ when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+ int rows = (int) (ALL_APPS_HEIGHT - PS_HEADER_HEIGHT - HEADER_PROTECTION_HEIGHT);
+ int position = rows * NUM_APP_COLS - (NUM_APP_COLS-1) + 1;
+
+ // The number of adapterItems should be the private space apps + one main app + header.
+ assertEquals(NUM_PRIVATE_SPACE_APPS + 1 + 1,
+ mAlphabeticalAppsList.getAdapterItems().size());
+ assertEquals(position,
+ mPsHeaderViewController.scrollForViewToBeVisibleInContainer(
+ new AllAppsRecyclerView(mContext),
+ mAlphabeticalAppsList.getAdapterItems(),
+ PS_HEADER_HEIGHT,
+ ALL_APPS_CELL_HEIGHT));
+ }
+
+ @Test
+ public void scrollForViewToBeVisibleInContainer_withHeaderAndLessAppRowSpace() {
+ when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
+ when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
+ .thenAnswer(answer(this::addPrivateSpaceHeader));
+ when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+ when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+ .thenReturn(iteminfo -> iteminfo.componentName == null
+ || !iteminfo.componentName.getPackageName()
+ .equals("com.android.launcher3.tests.camera"));
+ when(mAllApps.getContext()).thenReturn(mContext);
+ mAlphabeticalAppsList.updateItemFilter(info -> info != null
+ && info.user.equals(MAIN_HANDLE));
+ when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
+ when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+ int rows = (int) (ALL_APPS_HEIGHT - BIGGER_PS_HEADER_HEIGHT - HEADER_PROTECTION_HEIGHT);
+ int position = rows * NUM_APP_COLS - (NUM_APP_COLS-1) + 1;
+
+ // The number of adapterItems should be the private space apps + one main app + header.
+ assertEquals(NUM_PRIVATE_SPACE_APPS + 1 + 1,
+ mAlphabeticalAppsList.getAdapterItems().size());
+ assertEquals(position,
+ mPsHeaderViewController.scrollForViewToBeVisibleInContainer(
+ new AllAppsRecyclerView(mContext),
+ mAlphabeticalAppsList.getAdapterItems(),
+ BIGGER_PS_HEADER_HEIGHT,
+ ALL_APPS_CELL_HEIGHT));
+ }
+
+ @Test
+ public void scrollForViewToBeVisibleInContainer_withNoHeader() {
+ when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
+ when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+ when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+ .thenReturn(iteminfo -> iteminfo.componentName == null
+ || !iteminfo.componentName.getPackageName()
+ .equals("com.android.launcher3.tests.camera"));
+ when(mAllApps.getContext()).thenReturn(mContext);
+ mAlphabeticalAppsList.updateItemFilter(info -> info != null
+ && info.user.equals(MAIN_HANDLE));
+ when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
+ when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+
+ // The number of adapterItems should be the private space apps + one main app.
+ assertEquals(NUM_PRIVATE_SPACE_APPS + 1,
+ mAlphabeticalAppsList.getAdapterItems().size());
+ assertEquals(SCROLL_NO_WHERE, mPsHeaderViewController.scrollForViewToBeVisibleInContainer(
+ new AllAppsRecyclerView(mContext),
+ mAlphabeticalAppsList.getAdapterItems(),
+ BIGGER_PS_HEADER_HEIGHT,
+ ALL_APPS_CELL_HEIGHT));
+ }
+
private Bitmap getBitmap(Drawable drawable) {
Bitmap result;
if (drawable instanceof BitmapDrawable) {
@@ -249,4 +360,28 @@
private static void awaitTasksCompleted() throws Exception {
UI_HELPER_EXECUTOR.submit(() -> null).get();
}
+
+ private int addPrivateSpaceHeader(List<BaseAllAppsAdapter.AdapterItem> adapterItemList) {
+ BaseAllAppsAdapter.AdapterItem privateSpaceHeader =
+ new BaseAllAppsAdapter.AdapterItem(VIEW_TYPE_PRIVATE_SPACE_HEADER);
+ adapterItemList.add(privateSpaceHeader);
+ return adapterItemList.size();
+ }
+
+ private AppInfo[] createAppInfoList() {
+ List<AppInfo> appInfos = new ArrayList<>();
+ ComponentName gmailComponentName = new ComponentName(mContext,
+ "com.android.launcher3.tests.Activity" + "Gmail");
+ AppInfo gmailAppInfo = new
+ AppInfo(gmailComponentName, "Gmail", MAIN_HANDLE, new Intent());
+ appInfos.add(gmailAppInfo);
+ ComponentName privateCameraComponentName = new ComponentName(
+ "com.android.launcher3.tests.camera", "CameraActivity");
+ for (int i = 0; i < NUM_PRIVATE_SPACE_APPS; i++) {
+ AppInfo privateCameraAppInfo = new AppInfo(privateCameraComponentName,
+ "Private Camera " + i, PRIVATE_HANDLE, new Intent());
+ appInfos.add(privateCameraAppInfo);
+ }
+ return appInfos.toArray(AppInfo[]::new);
+ }
}
diff --git a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
index 4d73f7a..e462c4f 100644
--- a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
+++ b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
@@ -20,7 +20,6 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import android.content.Intent;
@@ -29,7 +28,6 @@
import androidx.test.filters.FlakyTest;
import androidx.test.platform.app.InstrumentationRegistry;
-import com.android.launcher3.Flags;
import com.android.launcher3.LauncherState;
import com.android.launcher3.tapl.AllApps;
import com.android.launcher3.ui.AbstractLauncherUiTest;
@@ -199,7 +197,6 @@
public void testPressBackFromAllAppsToHome() {
InstrumentationRegistry.getInstrumentation().getUiAutomation().adoptShellPermissionIdentity(
READ_DEVICE_CONFIG_PERMISSION);
- assumeFalse(Flags.enablePredictiveBackGesture());
mLauncher
.getWorkspace()
.switchToAllApps()
diff --git a/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
index a1aede8..479b201 100644
--- a/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
+++ b/tests/src/com/android/launcher3/backuprestore/BackupAndRestoreDBSelectionTest.kt
@@ -21,6 +21,7 @@
import androidx.test.filters.MediumTest
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.Flags
+import com.android.launcher3.LauncherPrefs
import com.android.launcher3.model.ModelDbController
import com.android.launcher3.util.Executors.MODEL_EXECUTOR
import com.android.launcher3.util.TestUtil
@@ -47,7 +48,7 @@
@Before
fun setUp() {
- setFlagsRule.setFlags(true, Flags.FLAG_NARROW_GRID_RESTORE)
+ setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_NARROW_GRID_RESTORE)
}
@Test
@@ -58,6 +59,12 @@
assert(backAndRestoreRule.getDatabaseFiles().size == 1) {
"There should only be one database after restoring, the last one used. Actual databases ${backAndRestoreRule.getDatabaseFiles()}"
}
+ assert(
+ !LauncherPrefs.get(getInstrumentation().targetContext)
+ .has(LauncherPrefs.RESTORE_DEVICE)
+ ) {
+ "RESTORE_DEVICE shouldn't be present after a backup and restore."
+ }
}
}
}
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index d1227d8..bf1ba39 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -96,6 +96,21 @@
MAPS_APP_NAME);
}
+ /**
+ * Adds two icons to the Workspace and combines them into a folder, then makes sure we are able
+ * to remove an icon from the folder and that the folder ceases to exist since it only has one
+ * icon left.
+ */
+ @Test
+ public void testDragOutOfFolder() {
+ final HomeAppIcon playStoreIcon = createShortcutIfNotExist(STORE_APP_NAME, 0, 1);
+ final HomeAppIcon photosIcon = createShortcutInCenterIfNotExist(PHOTOS_APP_NAME);
+ FolderIcon folderIcon = photosIcon.dragToIcon(playStoreIcon);
+ Folder folder = folderIcon.open();
+ folder.getAppIcon(STORE_APP_NAME).internalDragToWorkspace(false, false);
+ assertNotNull(mLauncher.getWorkspace().tryGetWorkspaceAppIcon(STORE_APP_NAME));
+ assertNotNull(mLauncher.getWorkspace().tryGetWorkspaceAppIcon(PHOTOS_APP_NAME));
+ }
/** Drags a shortcut from a long press menu into the workspace.
* 1. Open all apps and wait for load complete.
diff --git a/tests/src/com/android/launcher3/model/GridMigrationTest.kt b/tests/src/com/android/launcher3/model/GridMigrationTest.kt
index eb8604e..15222a4 100644
--- a/tests/src/com/android/launcher3/model/GridMigrationTest.kt
+++ b/tests/src/com/android/launcher3/model/GridMigrationTest.kt
@@ -16,14 +16,18 @@
package com.android.launcher3.model
+import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.Flags
import com.android.launcher3.InvariantDeviceProfile.TYPE_PHONE
import com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME
import com.android.launcher3.celllayout.board.CellLayoutBoard
import com.android.launcher3.pm.UserCache
import com.android.launcher3.util.rule.TestToPhoneFileCopier
+import com.android.launcher3.util.rule.setFlags
+import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
@@ -65,11 +69,24 @@
class GridMigrationTest {
private val DB_FILE = "test_launcher.db"
+ @JvmField
+ @Rule
+ val setFlagsRule = SetFlagsRule(SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT)
+
// Copying the src db for all tests.
@JvmField
@Rule
val fileCopier =
- TestToPhoneFileCopier("databases/GridMigrationTest/$DB_FILE", "databases/$DB_FILE", true)
+ TestToPhoneFileCopier(
+ src = "databases/GridMigrationTest/$DB_FILE",
+ dest = "databases/$DB_FILE",
+ removeOnFinish = true
+ )
+
+ @Before
+ fun setup() {
+ setFlagsRule.setFlags(false, Flags.FLAG_ENABLE_GRID_MIGRATION_FIX)
+ }
private fun migrate(src: GridMigrationData, dst: GridMigrationData) {
GridSizeMigrationUtil.migrateGridIfNeeded(
@@ -86,8 +103,10 @@
* same space in the db.
*/
private fun validateDb(data: GridMigrationData) {
- val cellLayoutBoard = CellLayoutBoard(data.gridState.columns, data.gridState.rows)
+ // The array size is just a big enough number to fit all the number of workspaces
+ val boards = Array(100) { CellLayoutBoard(data.gridState.columns, data.gridState.rows) }
data.readEntries().forEach {
+ val cellLayoutBoard = boards[it.screenId]
assert(cellLayoutBoard.isEmpty(it.cellX, it.cellY, it.spanX, it.spanY)) {
"Db has overlapping items"
}
@@ -96,13 +115,13 @@
}
private fun compare(dst: GridMigrationData, target: GridMigrationData) {
- val sortX = { it: GridSizeMigrationUtil.DbEntry -> it.cellX }
- val sortY = { it: GridSizeMigrationUtil.DbEntry -> it.cellX }
+ val sort = compareBy<GridSizeMigrationUtil.DbEntry>({ it.cellX }, { it.cellY })
val mapF = { it: GridSizeMigrationUtil.DbEntry ->
EntryData(it.cellX, it.cellY, it.spanX, it.spanY, it.rank)
}
- val entriesDst = dst.readEntries().sortedBy(sortX).sortedBy(sortY).map(mapF)
- val entriesTarget = target.readEntries().sortedBy(sortX).sortedBy(sortY).map(mapF)
+ val entriesDst = dst.readEntries().sortedWith(sort).map(mapF)
+ val entriesTarget = target.readEntries().sortedWith(sort).map(mapF)
+
assert(entriesDst == entriesTarget) {
"The elements on the dst database is not the same as in the target"
}
@@ -128,9 +147,9 @@
@Rule
val result5x5to3x3 =
TestToPhoneFileCopier(
- "databases/GridMigrationTest/result5x5to3x3.db",
- "databases/result5x5to3x3.db",
- true
+ src = "databases/GridMigrationTest/result5x5to3x3.db",
+ dest = "databases/result5x5to3x3.db",
+ removeOnFinish = true
)
@Test
@@ -151,9 +170,9 @@
@Rule
val result5x5to4x7 =
TestToPhoneFileCopier(
- "databases/GridMigrationTest/result5x5to4x7.db",
- "databases/result5x5to4x7.db",
- true
+ src = "databases/GridMigrationTest/result5x5to4x7.db",
+ dest = "databases/result5x5to4x7.db",
+ removeOnFinish = true
)
@Test
@@ -174,9 +193,9 @@
@Rule
val result5x5to5x8 =
TestToPhoneFileCopier(
- "databases/GridMigrationTest/result5x5to5x8.db",
- "databases/result5x5to5x8.db",
- true
+ src = "databases/GridMigrationTest/result5x5to5x8.db",
+ dest = "databases/result5x5to5x8.db",
+ removeOnFinish = true
)
@Test
@@ -192,4 +211,32 @@
target =
GridMigrationData("result5x5to5x8.db", DeviceGridState(5, 8, 5, TYPE_PHONE, ""))
)
+
+ @JvmField
+ @Rule
+ val flaggedResult5x5to5x8 =
+ TestToPhoneFileCopier(
+ src = "databases/GridMigrationTest/flagged_result5x5to5x8.db",
+ dest = "databases/flagged_result5x5to5x8.db",
+ removeOnFinish = true
+ )
+
+ @Test
+ fun `flagged 5x5 to 5x8`() {
+ setFlagsRule.setFlags(true, Flags.FLAG_ENABLE_GRID_MIGRATION_FIX)
+ runTest(
+ src = GridMigrationData(DB_FILE, DeviceGridState(5, 5, 5, TYPE_PHONE, DB_FILE)),
+ dst =
+ GridMigrationData(
+ null, // in memory db, to download a new db change null for the filename of the
+ // db name to store it. Do not use existing names.
+ DeviceGridState(5, 8, 5, TYPE_PHONE, "")
+ ),
+ target =
+ GridMigrationData(
+ "flagged_result5x5to5x8.db",
+ DeviceGridState(5, 8, 5, TYPE_PHONE, "")
+ )
+ )
+ }
}
diff --git a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
index 6df3ecd..90ded10 100644
--- a/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
+++ b/tests/src/com/android/launcher3/ui/BubbleTextViewTest.java
@@ -22,7 +22,7 @@
import static com.android.launcher3.BubbleTextView.DISPLAY_PREDICTION_ROW;
import static com.android.launcher3.BubbleTextView.DISPLAY_SEARCH_RESULT;
import static com.android.launcher3.BubbleTextView.DISPLAY_SEARCH_RESULT_SMALL;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TWOLINE_ALLAPPS;
+import static com.android.launcher3.LauncherPrefs.ENABLE_TWOLINE_ALLAPPS_TOGGLE;
import static com.google.common.truth.Truth.assertThat;
@@ -39,6 +39,7 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Flags;
+import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.Utilities;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -46,7 +47,6 @@
import com.android.launcher3.util.ActivityContextWrapper;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.IntArray;
-import com.android.launcher3.util.TestUtil;
import com.android.launcher3.views.BaseDragLayer;
import org.junit.Before;
@@ -96,13 +96,14 @@
private Context mContext;
private int mLimitedWidth;
private AppInfo mGmailAppInfo;
+ private LauncherPrefs mLauncherPrefs;
@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
Utilities.enableRunningInTestHarnessForTests();
- mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
mContext = new ActivityContextWrapper(getApplicationContext());
+ mLauncherPrefs = LauncherPrefs.get(mContext);
mBubbleTextView = new BubbleTextView(mContext);
mBubbleTextView.reset();
@@ -130,190 +131,155 @@
@Test
public void testEmptyString_flagOn() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
- mItemInfoWithIcon.title = EMPTY_STRING;
- mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+ mItemInfoWithIcon.title = EMPTY_STRING;
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertNotEquals(TWO_LINE, mBubbleTextView.getMaxLines());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertNotEquals(TWO_LINE, mBubbleTextView.getMaxLines());
}
@Test
public void testEmptyString_flagOff() {
- mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) {
- mItemInfoWithIcon.title = EMPTY_STRING;
- mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ mItemInfoWithIcon.title = EMPTY_STRING;
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testStringWithSpaceLongerThanCharLimit_flagOn() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
- // test string: "Battery Stats"
- mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+ // test string: "Battery Stats"
+ mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testStringWithSpaceLongerThanCharLimit_flagOff() {
- mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) {
- // test string: "Battery Stats"
- mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ // test string: "Battery Stats"
+ mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testLongStringNoSpaceLongerThanCharLimit_flagOn() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
- // test string: "flutterappflorafy"
- mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+ // test string: "flutterappflorafy"
+ mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testLongStringNoSpaceLongerThanCharLimit_flagOff() {
- mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) {
- // test string: "flutterappflorafy"
- mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ // test string: "flutterappflorafy"
+ mItemInfoWithIcon.title = TEST_LONG_STRING_NO_SPACE_LONGER_THAN_CHAR_LIMIT;
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testLongStringWithSpaceLongerThanCharLimit_flagOn() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
- // test string: "System UWB Field Test"
- mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+ // test string: "System UWB Field Test"
+ mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testLongStringWithSpaceLongerThanCharLimit_flagOff() {
- mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) {
- // test string: "System UWB Field Test"
- mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ // test string: "System UWB Field Test"
+ mItemInfoWithIcon.title = TEST_LONG_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testLongStringSymbolLongerThanCharLimit_flagOn() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
- // test string: "LEGO®Builder"
- mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+ // test string: "LEGO®Builder"
+ mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
}
@Test
public void testLongStringSymbolLongerThanCharLimit_flagOff() {
- mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, false)) {
- // test string: "LEGO®Builder"
- mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ // test string: "LEGO®Builder"
+ mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
@@ -374,58 +340,49 @@
@Test
public void testEnsurePredictionRowIsTwoLine() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
- // test string: "Battery Stats"
- mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
- mBubbleTextView.setDisplay(DISPLAY_PREDICTION_ROW);
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+ // test string: "Battery Stats"
+ mItemInfoWithIcon.title = TEST_STRING_WITH_SPACE_LONGER_THAN_CHAR_LIMIT;
+ mBubbleTextView.setDisplay(DISPLAY_PREDICTION_ROW);
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
}
@Test
public void modifyTitleToSupportMultiLine_whenLimitedHeight_shouldBeOneLine() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
- // test string: "LEGO®Builder"
- mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+ // test string: "LEGO®Builder"
+ mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, LIMITED_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertEquals(ONE_LINE, mBubbleTextView.getLineCount());
}
@Test
public void modifyTitleToSupportMultiLine_whenUnlimitedHeight_shouldBeTwoLine() {
- mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_ALLAPPS);
- try (AutoCloseable flag = TestUtil.overrideFlag(ENABLE_TWOLINE_ALLAPPS, true)) {
- // test string: "LEGO®Builder"
- mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
- mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
- mBubbleTextView.applyLabel(mItemInfoWithIcon);
- mBubbleTextView.setTypeface(Typeface.MONOSPACE);
- mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
+ mSetFlagsRule.enableFlags(Flags.FLAG_ENABLE_TWOLINE_TOGGLE);
+ mLauncherPrefs.put(ENABLE_TWOLINE_ALLAPPS_TOGGLE, true);
+ // test string: "LEGO®Builder"
+ mItemInfoWithIcon.title = TEST_LONG_STRING_SYMBOL_LONGER_THAN_CHAR_LIMIT;
+ mBubbleTextView.setDisplay(DISPLAY_ALL_APPS);
+ mBubbleTextView.applyLabel(mItemInfoWithIcon);
+ mBubbleTextView.setTypeface(Typeface.MONOSPACE);
+ mBubbleTextView.measure(mLimitedWidth, MAX_HEIGHT);
- mBubbleTextView.onPreDraw();
+ mBubbleTextView.onPreDraw();
- assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
+ assertEquals(TWO_LINE, mBubbleTextView.getLineCount());
}
@Test
diff --git a/tests/src/com/android/launcher3/util/rule/TestToPhoneFileCopier.kt b/tests/src/com/android/launcher3/util/rule/TestToPhoneFileCopier.kt
index 72c4f16..d3516d1 100644
--- a/tests/src/com/android/launcher3/util/rule/TestToPhoneFileCopier.kt
+++ b/tests/src/com/android/launcher3/util/rule/TestToPhoneFileCopier.kt
@@ -49,7 +49,11 @@
object : Statement() {
override fun evaluate() {
before()
- base.evaluate()
+ try {
+ base.evaluate()
+ } finally {
+ after()
+ }
}
}
}
diff --git a/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt b/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
index 11855e6..460058b 100644
--- a/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
+++ b/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
@@ -12,6 +12,7 @@
import android.platform.test.annotations.RequiresFlagsEnabled
import android.platform.test.flag.junit.CheckFlagsRule
import android.platform.test.flag.junit.DeviceFlagsValueProvider
+import android.view.ContextThemeWrapper
import android.view.LayoutInflater
import android.widget.RemoteViews
import androidx.test.core.app.ApplicationProvider.getApplicationContext
@@ -53,7 +54,14 @@
context = getApplicationContext()
generatedPreview = RemoteViews(context.packageName, generatedPreviewLayout)
widgetCell =
- LayoutInflater.from(ActivityContextWrapper(context))
+ LayoutInflater.from(
+ ActivityContextWrapper(
+ ContextThemeWrapper(
+ context,
+ com.android.launcher3.R.style.WidgetContainerTheme
+ )
+ )
+ )
.inflate(com.android.launcher3.R.layout.widget_cell, null) as WidgetCell
appWidgetProviderInfo =
AppWidgetProviderInfo()
@@ -111,6 +119,18 @@
}
@Test
+ @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+ fun widgetItem_hasGeneratedPreview_nullPreview() {
+ appWidgetProviderInfo.generatedPreviewCategories =
+ WIDGET_CATEGORY_HOME_SCREEN or WIDGET_CATEGORY_KEYGUARD
+ createWidgetItem()
+ assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isTrue()
+ // loadGeneratedPreview returns null for KEYGUARD, so this should still be false.
+ assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
+ assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
+ }
+
+ @Test
@RequiresFlagsDisabled(FLAG_ENABLE_GENERATED_PREVIEWS)
fun widgetItem_hasGeneratedPreview_flagDisabled() {
assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isFalse()
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetImageViewTest.kt b/tests/src/com/android/launcher3/widget/picker/WidgetImageViewTest.kt
new file mode 100644
index 0000000..6e751e0
--- /dev/null
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetImageViewTest.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker
+
+import android.content.Context
+import android.graphics.Rect
+import android.graphics.drawable.Drawable
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.widget.WidgetImageView
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.Mockito.spy
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.whenever
+
+@MediumTest
+@RunWith(AndroidJUnit4::class)
+class WidgetImageViewTest {
+ private lateinit var context: Context
+ private lateinit var widgetImageView: WidgetImageView
+
+ @Mock private lateinit var testDrawable: Drawable
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+ widgetImageView = spy(WidgetImageView(context))
+ }
+
+ @Test
+ fun getBitmapBounds_aspectRatioLargerThanView_scaledByWidth() {
+ // view - 100 x 100
+ whenever(widgetImageView.width).thenReturn(100)
+ whenever(widgetImageView.height).thenReturn(100)
+ // bitmap - 200 x 100
+ whenever(testDrawable.intrinsicWidth).thenReturn(200)
+ whenever(testDrawable.intrinsicHeight).thenReturn(100)
+
+ widgetImageView.drawable = testDrawable
+ val bitmapBounds = widgetImageView.bitmapBounds
+
+ // new scaled width of bitmap is = 100, and height is scaled to 1/2 = 50
+ assertThat(bitmapBounds).isEqualTo(Rect(0, 25, 100, 75))
+ }
+
+ @Test
+ fun getBitmapBounds_aspectRatioSmallerThanView_scaledByHeight() {
+ // view - 100 x 100
+ whenever(widgetImageView.width).thenReturn(100)
+ whenever(widgetImageView.height).thenReturn(100)
+ // bitmap - 100 x 200
+ whenever(testDrawable.intrinsicWidth).thenReturn(100)
+ whenever(testDrawable.intrinsicHeight).thenReturn(200)
+ widgetImageView.drawable = testDrawable
+
+ val bitmapBounds = widgetImageView.bitmapBounds
+
+ // new scaled height of bitmap is = 100, and width is scaled to 1/2 = 50
+ assertThat(bitmapBounds).isEqualTo(Rect(25, 0, 75, 100))
+ }
+
+ @Test
+ fun getBitmapBounds_noScale_returnsOriginalDrawableBounds() {
+ // view - 200 x 100
+ whenever(widgetImageView.width).thenReturn(200)
+ whenever(widgetImageView.height).thenReturn(100)
+ // bitmap - 200 x 100
+ whenever(testDrawable.intrinsicWidth).thenReturn(200)
+ whenever(testDrawable.intrinsicHeight).thenReturn(100)
+
+ widgetImageView.drawable = testDrawable
+ val bitmapBounds = widgetImageView.bitmapBounds
+
+ // no scaling
+ assertThat(bitmapBounds).isEqualTo(Rect(0, 0, 200, 100))
+ }
+}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProviderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProviderTest.java
index c807771..60a4cd3 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProviderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetRecommendationCategoryProviderTest.java
@@ -23,6 +23,7 @@
import static android.content.pm.ApplicationInfo.CATEGORY_SOCIAL;
import static android.content.pm.ApplicationInfo.CATEGORY_UNDEFINED;
import static android.content.pm.ApplicationInfo.CATEGORY_VIDEO;
+import static android.content.pm.ApplicationInfo.FLAG_INSTALLED;
import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
@@ -30,8 +31,7 @@
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
-import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;
@@ -41,7 +41,7 @@
import android.content.Context;
import android.content.ContextWrapper;
import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
+import android.content.pm.LauncherApps;
import android.os.Process;
import androidx.test.core.content.pm.ApplicationInfoBuilder;
@@ -70,10 +70,25 @@
public class WidgetRecommendationCategoryProviderTest {
private static final String TEST_PACKAGE = "com.foo.test";
private static final String TEST_APP_NAME = "foo";
- public static final WidgetRecommendationCategory SOCIAL_AND_ENTERTAINMENT_CATEGORY =
+ private static final WidgetRecommendationCategory PRODUCTIVITY =
new WidgetRecommendationCategory(
- R.string.social_and_entertainment_widget_recommendation_category_label,
- /*order=*/4);
+ R.string.productivity_widget_recommendation_category_label,
+ /*order=*/0);
+ private static final WidgetRecommendationCategory NEWS =
+ new WidgetRecommendationCategory(
+ R.string.news_widget_recommendation_category_label, /*order=*/1);
+ private static final WidgetRecommendationCategory SUGGESTED_FOR_YOU =
+ new WidgetRecommendationCategory(
+ R.string.others_widget_recommendation_category_label, /*order=*/4);
+ private static final WidgetRecommendationCategory SOCIAL =
+ new WidgetRecommendationCategory(
+ R.string.social_widget_recommendation_category_label,
+ /*order=*/5);
+ private static final WidgetRecommendationCategory ENTERTAINMENT =
+ new WidgetRecommendationCategory(
+ R.string.entertainment_widget_recommendation_category_label,
+ /*order=*/6);
+
private final ApplicationInfo mTestAppInfo = ApplicationInfoBuilder.newBuilder().setPackageName(
TEST_PACKAGE).setName(TEST_APP_NAME).build();
private Context mContext;
@@ -82,7 +97,7 @@
private WidgetItem mTestWidgetItem;
@Mock
- private PackageManager mPackageManager;
+ private LauncherApps mLauncherApps;
private InvariantDeviceProfile mTestProfile;
@Before
@@ -90,10 +105,12 @@
MockitoAnnotations.initMocks(this);
mContext = new ContextWrapper(getInstrumentation().getTargetContext()) {
@Override
- public PackageManager getPackageManager() {
- return mPackageManager;
+ public Object getSystemService(String name) {
+ return LAUNCHER_APPS_SERVICE.equals(name) ? mLauncherApps : super.getSystemService(
+ name);
}
};
+ mTestAppInfo.flags = FLAG_INSTALLED;
mTestProfile = new InvariantDeviceProfile();
mTestProfile.numRows = 5;
mTestProfile.numColumns = 5;
@@ -103,25 +120,22 @@
@Test
public void getWidgetRecommendationCategory_returnsMappedCategory() throws Exception {
ImmutableMap<Integer, WidgetRecommendationCategory> testCategories = ImmutableMap.of(
- CATEGORY_PRODUCTIVITY, new WidgetRecommendationCategory(
- R.string.productivity_widget_recommendation_category_label,
- /*order=*/
- 0),
- CATEGORY_NEWS, new WidgetRecommendationCategory(
- R.string.news_widget_recommendation_category_label, /*order=*/1),
- CATEGORY_SOCIAL, SOCIAL_AND_ENTERTAINMENT_CATEGORY,
- CATEGORY_AUDIO, SOCIAL_AND_ENTERTAINMENT_CATEGORY,
- CATEGORY_IMAGE, SOCIAL_AND_ENTERTAINMENT_CATEGORY,
- CATEGORY_VIDEO, SOCIAL_AND_ENTERTAINMENT_CATEGORY,
- CATEGORY_UNDEFINED, new WidgetRecommendationCategory(
- R.string.others_widget_recommendation_category_label, /*order=*/5));
+ CATEGORY_PRODUCTIVITY, PRODUCTIVITY,
+ CATEGORY_NEWS, NEWS,
+ CATEGORY_SOCIAL, SOCIAL,
+ CATEGORY_AUDIO, ENTERTAINMENT,
+ CATEGORY_IMAGE, ENTERTAINMENT,
+ CATEGORY_VIDEO, ENTERTAINMENT,
+ CATEGORY_UNDEFINED, SUGGESTED_FOR_YOU);
for (Map.Entry<Integer, WidgetRecommendationCategory> testCategory :
testCategories.entrySet()) {
mTestAppInfo.category = testCategory.getKey();
- when(mPackageManager.getApplicationInfo(anyString(), anyInt())).thenReturn(
- mTestAppInfo);
+ when(mLauncherApps.getApplicationInfo(/*packageName=*/ eq(TEST_PACKAGE),
+ /*flags=*/ eq(0),
+ /*user=*/ eq(Process.myUserHandle())))
+ .thenReturn(mTestAppInfo);
WidgetRecommendationCategory category = Executors.MODEL_EXECUTOR.submit(() ->
new WidgetRecommendationCategoryProvider().getWidgetRecommendationCategory(
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
index 0286279..85fb380 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
@@ -29,6 +29,7 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.os.UserHandle;
+import android.view.ContextThemeWrapper;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
@@ -96,7 +97,8 @@
mViewHolderBinder = new WidgetsListTableViewHolderBinder(
mContext,
- LayoutInflater.from(mContext),
+ LayoutInflater.from(new ContextThemeWrapper(mContext,
+ com.android.launcher3.R.style.WidgetContainerTheme)),
mOnIconClickListener,
mOnLongClickListener);
}
diff --git a/tests/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizesTest.kt b/tests/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizesTest.kt
new file mode 100644
index 0000000..040fbf5
--- /dev/null
+++ b/tests/src/com/android/launcher3/widget/picker/util/WidgetPreviewContainerSizesTest.kt
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker.util
+
+import android.content.ComponentName
+import android.content.Context
+import android.graphics.Point
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.icons.IconCache
+import com.android.launcher3.model.WidgetItem
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.WidgetUtils.createAppWidgetProviderInfo
+import com.android.launcher3.widget.LauncherAppWidgetProviderInfo
+import com.google.common.truth.Truth.assertWithMessage
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class WidgetPreviewContainerSizesTest {
+ private lateinit var context: Context
+ private lateinit var deviceProfile: DeviceProfile
+ private lateinit var testInvariantProfile: InvariantDeviceProfile
+
+ @Mock private lateinit var iconCache: IconCache
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+ testInvariantProfile = LauncherAppState.getIDP(context)
+ deviceProfile = testInvariantProfile.getDeviceProfile(context).copy(context)
+ }
+
+ @Test
+ fun widgetPreviewContainerSize_forItem_returnsCorrectContainerSize() {
+ val testSizes = getTestSizes(deviceProfile)
+ val expectedPreviewContainers = testSizes.values.toList()
+
+ for ((index, widgetSize) in testSizes.keys.withIndex()) {
+ val widgetItem = createWidgetItem(widgetSize, context, testInvariantProfile, iconCache)
+
+ assertWithMessage("size for $widgetSize should be: ${expectedPreviewContainers[index]}")
+ .that(WidgetPreviewContainerSize.forItem(widgetItem, deviceProfile))
+ .isEqualTo(expectedPreviewContainers[index])
+ }
+ }
+
+ companion object {
+ private const val TEST_PACKAGE = "com.google.test"
+
+ private val HANDHELD_TEST_SIZES: Map<Point, WidgetPreviewContainerSize> =
+ mapOf(
+ // 1x1
+ Point(1, 1) to WidgetPreviewContainerSize(1, 1),
+ // 2x1
+ Point(2, 1) to WidgetPreviewContainerSize(2, 1),
+ Point(3, 1) to WidgetPreviewContainerSize(2, 1),
+ // 4x1
+ Point(4, 1) to WidgetPreviewContainerSize(4, 1),
+ // 2x2
+ Point(2, 2) to WidgetPreviewContainerSize(2, 2),
+ Point(3, 3) to WidgetPreviewContainerSize(2, 2),
+ Point(3, 2) to WidgetPreviewContainerSize(2, 2),
+ // 2x3
+ Point(2, 3) to WidgetPreviewContainerSize(2, 3),
+ Point(3, 4) to WidgetPreviewContainerSize(2, 3),
+ Point(3, 5) to WidgetPreviewContainerSize(2, 3),
+ // 4x2
+ Point(4, 2) to WidgetPreviewContainerSize(4, 2),
+ // 4x3
+ Point(4, 3) to WidgetPreviewContainerSize(4, 3),
+ Point(4, 4) to WidgetPreviewContainerSize(4, 3),
+ )
+
+ private val TABLET_TEST_SIZES: Map<Point, WidgetPreviewContainerSize> =
+ mapOf(
+ // 1x1
+ Point(1, 1) to WidgetPreviewContainerSize(1, 1),
+ // 2x1
+ Point(2, 1) to WidgetPreviewContainerSize(2, 1),
+ // 3x1
+ Point(3, 1) to WidgetPreviewContainerSize(3, 1),
+ Point(4, 1) to WidgetPreviewContainerSize(3, 1),
+ // 2x2
+ Point(2, 2) to WidgetPreviewContainerSize(2, 2),
+ // 2x3
+ Point(2, 3) to WidgetPreviewContainerSize(2, 3),
+ // 3x2
+ Point(3, 2) to WidgetPreviewContainerSize(3, 2),
+ Point(4, 2) to WidgetPreviewContainerSize(3, 2),
+ Point(5, 2) to WidgetPreviewContainerSize(3, 2),
+ // 3x3
+ Point(3, 3) to WidgetPreviewContainerSize(3, 3),
+ Point(4, 4) to WidgetPreviewContainerSize(3, 3),
+ // 3x4
+ Point(5, 4) to WidgetPreviewContainerSize(3, 4),
+ Point(3, 4) to WidgetPreviewContainerSize(3, 4),
+ Point(5, 5) to WidgetPreviewContainerSize(3, 4),
+ Point(6, 4) to WidgetPreviewContainerSize(3, 4),
+ Point(6, 5) to WidgetPreviewContainerSize(3, 4),
+ )
+
+ private fun getTestSizes(dp: DeviceProfile) =
+ if (dp.isTablet && !dp.isTwoPanels) {
+ TABLET_TEST_SIZES
+ } else {
+ HANDHELD_TEST_SIZES
+ }
+
+ private fun createWidgetItem(
+ widgetSize: Point,
+ context: Context,
+ invariantDeviceProfile: InvariantDeviceProfile,
+ iconCache: IconCache
+ ): WidgetItem {
+ val providerInfo =
+ createAppWidgetProviderInfo(
+ ComponentName.createRelative(
+ TEST_PACKAGE,
+ /*cls=*/ ".WidgetProvider_" + widgetSize.x + "x" + widgetSize.y
+ )
+ )
+ val widgetInfo =
+ LauncherAppWidgetProviderInfo.fromProviderInfo(context, providerInfo).apply {
+ spanX = widgetSize.x
+ spanY = widgetSize.y
+ }
+ return WidgetItem(widgetInfo, invariantDeviceProfile, iconCache, context)
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java b/tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
index 2c5a396..b2cb266 100644
--- a/tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/util/WidgetsTableUtilsTest.java
@@ -63,6 +63,7 @@
private static final String TEST_PACKAGE = "com.google.test";
private static final int SPACE_SIZE = 10;
+ // Note - actual widget size includes SPACE_SIZE (border) + cell padding.
private static final int CELL_SIZE = 50;
private static final int NUM_OF_COLS = 5;
private static final int NUM_OF_ROWS = 5;
@@ -105,7 +106,7 @@
@Test
- public void groupWidgetItemsIntoTableWithReordering_widgetsOnly_maxSpanPxPerRow220_cellPadding0_shouldGroupWidgetsInTable() {
+ public void groupWithReordering_widgetsOnly_maxSpanPxPerRow220_cellPadding0() {
List<WidgetItem> widgetItems = List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4,
mWidget2x2);
@@ -113,17 +114,20 @@
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
mTestDeviceProfile, 220, 0);
- // Row 0: 1x1(50px), 2x2(110px)
- // Row 1: 2x3(110px), 2x4(110px)
- // Row 2: 4x4(230px)
- assertThat(widgetItemInTable).hasSize(3);
- assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1, mWidget2x2);
- assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x3, mWidget2x4);
- assertThat(widgetItemInTable.get(2)).containsExactly(mWidget4x4);
+ // With reordering, rows displayed in order of increasing size.
+ // Row 0: 1x1(50px)
+ // Row 1: 2x2(in a 2x2 container - 110px)
+ // Row 2: 2x3(in a 2x3 container - 110px), 2x4(in a 2x3 container - 110px)
+ // Row 3: 4x4(in a 3x3 container in tablet - 170px; 4x3 on phone - 230px)
+ assertThat(widgetItemInTable).hasSize(4);
+ assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
+ assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
+ assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3, mWidget2x4);
+ assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
}
@Test
- public void groupWidgetItemsIntoTableWithReordering_widgetsOnly_maxSpanPxPerRow220_cellPadding10_shouldGroupWidgetsInTable() {
+ public void groupWithReordering_widgetsOnly_maxSpanPxPerRow220_cellPadding10() {
List<WidgetItem> widgetItems = List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4,
mWidget2x2);
@@ -131,9 +135,13 @@
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
mTestDeviceProfile, 220, 10);
- // Row 0: 1x1(50px), 2x2(110px)
- // Row 1: 2x3(110px), 2x4(110px)
- // Row 2: 4x4(230px)
+ // With reordering, but space taken up by cell padding, so, no grouping (even if 2x2 and 2x3
+ // use same preview container).
+ // Row 0: 1x1(50px)
+ // Row 1: 2x2(in a 2x2 container: 130px)
+ // Row 2: 2x3(in a 2x3 container: 130px)
+ // Row 3: 2x4(in a 2x3 container: 130px)
+ // Row 4: 4x4(in a 3x3 container in tablet - 190px; 4x3 on phone - 250px)
assertThat(widgetItemInTable).hasSize(5);
assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
@@ -143,7 +151,29 @@
}
@Test
- public void groupWidgetItemsIntoTableWithReordering_widgetsOnly_maxSpanPxPerRow350_cellPadding0_shouldGroupWidgetsInTable() {
+ public void groupWithReordering_widgetsOnly_maxSpanPxPerRow260_cellPadding10() {
+ List<WidgetItem> widgetItems = List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4,
+ mWidget2x2);
+
+ List<ArrayList<WidgetItem>> widgetItemInTable =
+ WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
+ mTestDeviceProfile, 260, 10);
+
+ // With reordering, even with cellPadding, enough space to group 2x3 and 2x4 (which also use
+ // same container)
+ // Row 0: 1x1(50px)
+ // Row 1: 2x2(in a 2x2 container: 130px)
+ // Row 2: 2x3(in a 2x3 container: 130px), 2x4(in a 2x3 container: 130px)
+ // Row 3: 4x4(in a 3x3 container in tablet - 190px; 4x3 on phone - 250px)
+ assertThat(widgetItemInTable).hasSize(4);
+ assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
+ assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
+ assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3, mWidget2x4);
+ assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
+ }
+
+ @Test
+ public void groupWithReordering_widgetsOnly_maxSpanPxPerRow350_cellPadding0() {
List<WidgetItem> widgetItems = List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4,
mWidget2x2);
@@ -151,17 +181,20 @@
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
mTestDeviceProfile, 350, 0);
- // Row 0: 1x1(50px), 2x2(110px), 2x3(110px)
- // Row 1: 2x4(110px)
- // Row 2: 4x4(230px)
- assertThat(widgetItemInTable).hasSize(3);
- assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1, mWidget2x2, mWidget2x3);
- assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x4);
- assertThat(widgetItemInTable.get(2)).containsExactly(mWidget4x4);
+ // With reordering, rows displayed in order of increasing size.
+ // Row 0: 1x1(50px)
+ // Row 1: 2x2(in a 2x2 container: 110px)
+ // Row 2: 2x3(in a 2x3 container: 110px), 2x4(in a 2x3 container: 110px)
+ // Row 3: 4x4(in a 3x3 container in tablet - 170px; 4x3 on phone - 230px)
+ assertThat(widgetItemInTable).hasSize(4);
+ assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
+ assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
+ assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3, mWidget2x4);
+ assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
}
@Test
- public void groupWidgetItemsIntoTableWithReordering_mixItems_maxSpanPxPerRow350_cellPadding0_shouldGroupWidgetsInTable() {
+ public void groupWithReordering_mixItems_maxSpanPxPerRow350_cellPadding0() {
List<WidgetItem> widgetItems = List.of(mWidget4x4, mShortcut3, mWidget2x3, mShortcut1,
mWidget1x1, mShortcut2, mWidget2x4, mWidget2x2);
@@ -169,19 +202,22 @@
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithReordering(widgetItems, mContext,
mTestDeviceProfile, 350, 0);
- // Row 0: 1x1(50px), 2x2(110px), 2x3(110px)
- // Row 1: 2x4(110px),
- // Row 2: 4x4(230px)
- // Row 3: shortcut3(50px), shortcut1(50px), shortcut2(50px)
- assertThat(widgetItemInTable).hasSize(4);
- assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1, mWidget2x2, mWidget2x3);
- assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x4);
- assertThat(widgetItemInTable.get(2)).containsExactly(mWidget4x4);
- assertThat(widgetItemInTable.get(3)).containsExactly(mShortcut3, mShortcut2, mShortcut1);
+ // With reordering - rows displays in order of increasing size:
+ // Row 0: 1x1(50px)
+ // Row 1: 2x2(110px)
+ // Row 2: 2x3 (in a 2x3 container 110px), 2x4 (in a 2x3 container 110px)
+ // Row 3: 4x4 (in a 3x3 container in tablet - 170px; 4x3 on phone - 230px)
+ // Row 4: shortcut3, shortcut1, shortcut2 (shortcuts are always displayed at bottom)
+ assertThat(widgetItemInTable).hasSize(5);
+ assertThat(widgetItemInTable.get(0)).containsExactly(mWidget1x1);
+ assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x2);
+ assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x3, mWidget2x4);
+ assertThat(widgetItemInTable.get(3)).containsExactly(mWidget4x4);
+ assertThat(widgetItemInTable.get(4)).containsExactly(mShortcut3, mShortcut2, mShortcut1);
}
@Test
- public void groupWidgetItemsIntoTableWithoutReordering_maxSpanPxPerRow220_cellPadding0_shouldMaintainTheOrder() {
+ public void groupWithoutReordering_maxSpanPxPerRow220_cellPadding0() {
List<WidgetItem> widgetItems =
List.of(mWidget4x4, mWidget2x3, mWidget1x1, mWidget2x4, mWidget2x2);
@@ -189,13 +225,19 @@
WidgetsTableUtils.groupWidgetItemsUsingRowPxWithoutReordering(widgetItems, mContext,
mTestDeviceProfile, 220, 0);
- // Row 0: 4x4(230px)
- // Row 1: 2x3(110px), 1x1(50px)
- // Row 2: 2x4(110px), 2x2(110px)
- assertThat(widgetItemInTable).hasSize(3);
+ // Without reordering, widgets are grouped only if the next one fits and uses same preview
+ // container:
+ // Row 0: 4x4(in a 3x3 container in tablet - 170px; 4x3 on phone - 230px)
+ // Row 1: 2x3(in a 2x3 container - 110px)
+ // Row 2: 1x1(50px)
+ // Row 3: 2x4(in a 2x3 container - 110px)
+ // Row 4: 2x2(in a 2x2 container - 110px)
+ assertThat(widgetItemInTable).hasSize(5);
assertThat(widgetItemInTable.get(0)).containsExactly(mWidget4x4);
- assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x3, mWidget1x1);
- assertThat(widgetItemInTable.get(2)).containsExactly(mWidget2x4, mWidget2x2);
+ assertThat(widgetItemInTable.get(1)).containsExactly(mWidget2x3);
+ assertThat(widgetItemInTable.get(2)).containsExactly(mWidget1x1);
+ assertThat(widgetItemInTable.get(3)).containsExactly(mWidget2x4);
+ assertThat(widgetItemInTable.get(4)).containsExactly(mWidget2x2);
}
private void initDP() {
diff --git a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
index b5414b7..3f96999 100644
--- a/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
+++ b/tests/tapl/com/android/launcher3/tapl/LaunchedAppState.java
@@ -26,11 +26,11 @@
import static com.android.launcher3.testing.shared.TestProtocol.REQUEST_TASKBAR_FROM_NAV_THRESHOLD;
import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemClock;
+import android.util.Log;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
@@ -141,7 +141,7 @@
return new Taskbar(mLauncher);
} finally {
- testLogD(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
+ Log.d(SUCCESSFUL_GESTURE_MISMATCH_EVENTS,
"swipeUpToUnstashTaskbar: completed gesture");
mLauncher.getTestInfo(REQUEST_DISABLE_BLOCK_TIMEOUT);
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 0e2735f..bfff541 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -402,6 +402,11 @@
.getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
+ private boolean isPredictiveBackSwipeEnabled() {
+ return getTestInfo(TestProtocol.REQUEST_IS_PREDICTIVE_BACK_SWIPE_ENABLED)
+ .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
public boolean isTaskbarNavbarUnificationEnabled() {
return getTestInfo(TestProtocol.REQUEST_ENABLE_TASKBAR_NAVBAR_UNIFICATION)
.getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
@@ -1211,8 +1216,7 @@
waitForNavigationUiObject("back").click();
}
if (launcherVisible) {
- if (InstrumentationRegistry.getTargetContext().getApplicationInfo()
- .isOnBackInvokedCallbackEnabled()) {
+ if (isPredictiveBackSwipeEnabled()) {
expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_ON_BACK_INVOKED);
} else {
expectEvent(TestProtocol.SEQUENCE_MAIN, EVENT_KEY_BACK_UP);
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
index afe5722..1cfbf09 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java
@@ -19,8 +19,10 @@
import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.DEFAULT;
import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.SPLIT_BOTTOM_OR_RIGHT;
import static com.android.launcher3.tapl.OverviewTask.OverviewSplitTask.SPLIT_TOP_OR_LEFT;
+import static com.android.launcher3.testing.shared.TestProtocol.SUCCESSFUL_GESTURE_MISMATCH_EVENTS;
import android.graphics.Rect;
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.test.uiautomator.By;
@@ -219,6 +221,7 @@
return new LaunchedAppState(mLauncher);
}
} else {
+ Log.d(SUCCESSFUL_GESTURE_MISMATCH_EVENTS, "TaskView.launchTaskAnimated");
mLauncher.expectEvent(TestProtocol.SEQUENCE_MAIN, TASK_START_EVENT);
return new LaunchedAppState(mLauncher);
}