Merge "Update dump tests for the bottomsheet top padding alignment." into main
diff --git a/Android.bp b/Android.bp
index 61042f6..4354b66 100644
--- a/Android.bp
+++ b/Android.bp
@@ -203,6 +203,7 @@
"animationlib",
"com_android_launcher3_flags_lib",
"com_android_wm_shell_flags_lib",
+ "android.appwidget.flags-aconfig-java",
],
sdk_version: "current",
min_sdk_version: min_launcher3_sdk_version,
diff --git a/OWNERS b/OWNERS
index 4409b33..31e4610 100644
--- a/OWNERS
+++ b/OWNERS
@@ -10,8 +10,6 @@
vadimt@google.com
winsonc@google.com
jonmiranda@google.com
-alexchau@google.com
-patmanning@google.com
awickham@google.com
# Launcher workspace eng team
@@ -30,5 +28,15 @@
peanutbutter@google.com
jeremysim@google.com
+# Overview eng team
+alexchau@google.com
+samcackett@google.com
+silvajordan@google.com
+uwaisashraf@google.com
+
+# Physical Keyboard & Trackpad eng team
+patmanning@google.com
+helencheuk@google.com
+
per-file FeatureFlags.java, globs = set noparent
per-file FeatureFlags.java = sunnygoyal@google.com, winsonc@google.com, adamcohen@google.com, hyunyoungs@google.com, captaincole@google.com
diff --git a/aconfig/Android.bp b/aconfig/Android.bp
index dc30a35..5413601 100644
--- a/aconfig/Android.bp
+++ b/aconfig/Android.bp
@@ -20,6 +20,7 @@
aconfig_declarations {
name: "com_android_launcher3_flags",
package: "com.android.launcher3",
+ container: "system",
srcs: ["**/*.aconfig"],
}
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 82ae4cb..25db4d7 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -1,4 +1,5 @@
package: "com.android.launcher3"
+container: "system"
flag {
name: "enable_expanding_pause_work_button"
@@ -82,6 +83,9 @@
namespace: "launcher"
description: "Enables full width two pane widget picker for tablets in landscape and portrait"
bug: "315055849"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
flag {
@@ -149,6 +153,13 @@
}
flag {
+ name: "enable_generated_previews"
+ namespace: "launcher"
+ description: "Enables support for RemoteViews previews in the widget picker."
+ bug: "306546610"
+}
+
+flag {
name: "enable_categorized_widget_suggestions"
namespace: "launcher"
description: "Enables widget suggestions in widget picker to be displayed in categories"
@@ -156,6 +167,13 @@
}
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"
+}
+
+flag {
name: "use_activity_overlay"
namespace: "launcher"
description: "Use an activity for home screen overlay"
diff --git a/aconfig/launcher_search.aconfig b/aconfig/launcher_search.aconfig
index 4e16e7f..2f2690e 100644
--- a/aconfig/launcher_search.aconfig
+++ b/aconfig/launcher_search.aconfig
@@ -1,4 +1,5 @@
package: "com.android.launcher3"
+container: "system"
flag {
name: "enable_private_space"
diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
index 29b24b7..6e7a82a 100644
--- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
+++ b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
@@ -33,6 +33,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.ShortcutAndWidgetContainer;
+import com.android.launcher3.icons.ClockDrawableWrapper;
import com.android.launcher3.testing.shared.TestProtocol;
import java.util.ArrayList;
@@ -136,10 +137,12 @@
case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
TestProtocol.sDebugTracing = true;
+ ClockDrawableWrapper.sRunningInTest = true;
return response;
case TestProtocol.REQUEST_DISABLE_DEBUG_TRACING:
TestProtocol.sDebugTracing = false;
+ ClockDrawableWrapper.sRunningInTest = false;
return response;
case TestProtocol.REQUEST_PID: {
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index db46508..e75812a 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -43,6 +43,12 @@
<uses-permission android:name="android.permission.SYSTEM_APPLICATION_OVERLAY" />
+ <!--
+ Permission required to access profiles which are otherwise hidden
+ from being visible via APIs, e.g. private profile.
+ -->
+ <uses-permission android:name="android.permission.ACCESS_HIDDEN_PROFILES_FULL" />
+
<!-- Permission required to start a WidgetPickerActivity. -->
<permission android:name="${packageName}.permission.START_WIDGET_PICKER_ACTIVITY"
android:protectionLevel="signature|privileged" />
@@ -73,7 +79,7 @@
android:clearTaskOnLaunch="true"
android:stateNotNeeded="true"
android:theme="@style/LauncherTheme"
- android:screenOrientation="unspecified"
+ android:screenOrientation="behind"
android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
diff --git a/quickstep/res/drawable/ic_chevron_down.xml b/quickstep/res/drawable/ic_chevron_down.xml
index 77a8295..f246cbc 100644
--- a/quickstep/res/drawable/ic_chevron_down.xml
+++ b/quickstep/res/drawable/ic_chevron_down.xml
@@ -13,35 +13,22 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:aapt="http://schemas.android.com/aapt"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
- <target android:name="scaleGroup">
- <aapt:attr name="android:animation">
- <objectAnimator
- android:duration="150"
- android:propertyName="scaleX"
- android:valueFrom="1"
- android:valueTo="-1" />
- </aapt:attr>
- </target>
- <aapt:attr name="android:drawable">
- <vector
- android:width="48dp"
- android:height="48dp"
- android:autoMirrored="true"
- android:tint="?androidprv:attr/materialColorOnSurface"
- android:viewportHeight="48"
- android:viewportWidth="48">
- <group
- android:name="scaleGroup"
- android:pivotX="24"
- android:pivotY="24"
- android:rotation="90">
- <path
- android:fillColor="@android:color/white"
- android:pathData="M18.75,36 L16.6,33.85 26.5,23.95 16.6,14.05 18.75,11.9 30.8,23.95Z" />
- </group>
- </vector>
- </aapt:attr>
-</animated-vector>
+<vector
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:width="48dp"
+ android:height="48dp"
+ android:autoMirrored="true"
+ android:tint="?androidprv:attr/materialColorOnSurface"
+ android:viewportHeight="48"
+ android:viewportWidth="48">
+ <group
+ android:name="scaleGroup"
+ android:pivotX="24"
+ android:pivotY="24"
+ android:rotation="90">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M18.75,36 L16.6,33.85 26.5,23.95 16.6,14.05 18.75,11.9 30.8,23.95Z" />
+ </group>
+</vector>
diff --git a/quickstep/res/drawable/view_carousel.xml b/quickstep/res/drawable/view_carousel.xml
new file mode 100644
index 0000000..16c8e78
--- /dev/null
+++ b/quickstep/res/drawable/view_carousel.xml
@@ -0,0 +1,30 @@
+<?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="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <group>
+ <clip-path
+ android:pathData="M0,0h24v24h-24z"/>
+ <path
+ android:pathData="M17,19H7V4H17V19ZM6,6H2V17H6V6ZM9,6H15V17H9V6ZM22,6H18V17H22V6Z"
+ android:fillColor="#ffffff"
+ android:fillType="evenOdd"/>
+ </group>
+</vector>
diff --git a/quickstep/res/layout/keyboard_quick_switch_overview.xml b/quickstep/res/layout/keyboard_quick_switch_overview.xml
index 4a9b023..30ca32d 100644
--- a/quickstep/res/layout/keyboard_quick_switch_overview.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_overview.xml
@@ -40,7 +40,7 @@
android:layout_width="@dimen/keyboard_quick_switch_recents_icon_size"
android:layout_height="@dimen/keyboard_quick_switch_recents_icon_size"
android:layout_marginBottom="8dp"
- android:src="@drawable/ic_empty_recents"
+ android:src="@drawable/view_carousel"
android:tint="?androidprv:attr/materialColorOnSurface"
app:layout_constraintVertical_chainStyle="packed"
diff --git a/quickstep/res/layout/keyboard_quick_switch_view.xml b/quickstep/res/layout/keyboard_quick_switch_view.xml
index 5af8d51..2bba788 100644
--- a/quickstep/res/layout/keyboard_quick_switch_view.xml
+++ b/quickstep/res/layout/keyboard_quick_switch_view.xml
@@ -42,8 +42,8 @@
android:layout_width="@dimen/keyboard_quick_switch_no_recent_items_icon_size"
android:layout_height="@dimen/keyboard_quick_switch_no_recent_items_icon_size"
android:layout_marginBottom="@dimen/keyboard_quick_switch_no_recent_items_icon_margin"
- android:src="@drawable/ic_empty_recents"
- android:tint="?androidprv:attr/materialColorOnSurfaceInverse"
+ android:src="@drawable/view_carousel"
+ android:tint="?androidprv:attr/materialColorOnSurface"
android:importantForAccessibility="no"
app:layout_constraintVertical_chainStyle="packed"
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 6e4fe82..28fcdca 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Maak seker dat jy van die rand heel regs of heel links af swiep"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Maak seker dat jy van die regter- of linkerrand af na die middel van die skerm toe swiep en laat los"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Jy het geleer hoe om van regs af te swiep om terug te gaan. Nou kan jy leer hoe om tussen apps te wissel."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Jy het die \"gaan terug\"-gebaar voltooi. Nou kan jy leer hoe om tussen programme te wissel."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Jy het die Gaan Terug-gebaar voltooi"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Maak seker dat jy nie te naby aan die onderkant van die skerm swiep nie"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Gaan na Instellings om sensitiwiteit van teruggebaar te verander"</string>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index 4395fe3..a5f5359 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ከቀኝ ጥግ ወይም ከግራ ጥግ ጠርዝ ጀምሮ ማንሸራተትዎን ያረጋግጡ"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ከቀኝ ወይም ከግራ ጠርዝ ወደ ማያ ገጹ መሃል ማንሸራተትዎን እና መልቀቅዎን ያረጋግጡ"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ወደ ኋላ ለመመለስ ከቀኝ ጀምሮ እንዴት ማንሸራተት እንደሚችሉ አውቀዋል። ቀጥለው መተግበሪያዎችን እንዴት መቀየር እንደሚችሉ ይወቁ።"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ወደኋላ የመመለስ ምልክትን አጠናቀዋል። ቀጥሎም መተግበሪያዎችን እንዴት መቀየር እንደሚችሉ ይወቁ።"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ወደኋላ የመመለስ ምልክትን አጠናቅቀዋል"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ከማያ ገጹ ታችኛው ክፍል ጋር በጣም ጠጋ ብለው አለማንሸራተትዎን ያረጋግጡ"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ከኋላ ስሜት ሰጭነት ደረጃ ለመለወጥ ወደ ቅንብሮች ይመለሱ"</string>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index 615217e..3b13f7b 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"تأكَّد من التمرير سريعًا من أقصى الحافة اليسرى أو اليمنى."</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"تأكَّد من التمرير سريعًا من الحافة اليسرى أو اليمنى إلى وسط الشاشة ثم ارفع إصبعك."</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"لقد تعلمت كيفية التمرير سريعًا من اليسار للرجوع. تعرّف بعد ذلك على كيفية التبديل بين التطبيقات."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"لقد أكملت التدريب على إيماءة الرجوع. تعرّف بعد ذلك على كيفية التبديل بين التطبيقات."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"لقد أكملت التدريب على إيماءة الرجوع."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"تأكَّد من عدم التمرير سريعًا بالقرب من أسفل الشاشة."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"لتغيير مستوى حساسية إيماءة الرجوع، انتقِل إلى \"الإعدادات\""</string>
@@ -95,10 +96,10 @@
<string name="action_screenshot" msgid="8171125848358142917">"لقطة شاشة"</string>
<string name="action_split" msgid="2098009717623550676">"تقسيم"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"انقر على تطبيق آخر لاستخدام وضع تقسيم الشاشة."</string>
- <string name="toast_contextual_split_select_app" msgid="433510957123687090">"اختَر تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string>
+ <string name="toast_contextual_split_select_app" msgid="433510957123687090">"اختَر تطبيقًا آخر لاستخدام \"وضع تقسيم الشاشة\"."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"إلغاء"</b></string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"الخروج من وضع تقسيم الشاشة"</string>
- <string name="toast_split_app_unsupported" msgid="2360229567007828914">"اختَر تطبيقًا آخر لاستخدام وضع تقسيم الشاشة."</string>
+ <string name="toast_split_app_unsupported" msgid="2360229567007828914">"اختَر تطبيقًا آخر لاستخدام \"وضع تقسيم الشاشة\"."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"لا يسمح التطبيق أو لا تسمح مؤسستك بهذا الإجراء."</string>
<string name="split_widgets_not_supported" msgid="1355743038053053866">"التطبيقات المصغّرة غير متوفّرة حاليًا، يرجى اختيار تطبيق آخر."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"هل تريد تخطي الدليل التوجيهي للتنقّل؟"</string>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 37fc1d4..88c50e0 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"আপুনি সোঁ অথবা বাওঁ কাষৰ একেবাৰে সীমাৰ পৰা ছোৱাইপ কৰাটো নিশ্চিত কৰক"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"আপুনি স্ক্ৰীনৰ সোঁ অথবা বাওঁ কাষৰ পৰা মধ্যভাগলৈকে ছোৱাইপ কৰি এৰি দিয়াটো নিশ্চিত কৰক"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"সোঁফালৰ পৰা ছোৱাইপ কৰি কেনেকৈ উভতি যাব লাগে, সেইটো আপুনি জানিলে। ইয়াৰ পাছত, এপ্ কেনেকৈ সলনি কৰিব সেয়া জানক।"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"আপুনি উভতি যাওক নিৰ্দেশটো সম্পূৰ্ণ কৰিলে। ইয়াৰ পাছত, এপ্ কেনেকৈ সলনি কৰিব সেয়া জানক।"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"আপুনি উভতি যাওক নিৰ্দেশটো সম্পূৰ্ণ কৰিলে"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"আপুনি স্ক্ৰীনৰ তলৰ অংশৰ বেছি ওচৰলৈ ছোৱাইপ নকৰাটো নিশ্চিত কৰক"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"উভতি যোৱাৰ নির্দেশটোৰ সংবেদনশীলতা সলনি কৰিবলৈ ছেটিঙলৈ যাওক"</string>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index a48dc37..bb51b42 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Ən sağ və ya sol kənardan sürüşdürün"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Sağ və ya sol kənardan ekranın ortasına sürüşdürüb, buraxın"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Geri qayıtmaq üçün sağdan sürüşdürmək qaydasını öyrəndiniz. Sonra tətbiqləri keçirməyi öyrənin."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Geri getmə jestini tamamladınız. Sonra tətbiqləri keçirməyi öyrənin."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Geri qayıtma jestini tamamladınız"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Barmağınızı ekranın aşağı kənarına çox yaxınlaşdırmayın"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Geri qayıtma jestinin həssaslığını dəyişmək üçün Ayarlara keçin"</string>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index c637084..ec0f934 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Obavezno prevucite od same desne ili leve ivice"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Obavezno prevucite od desne ili leve ivice do sredine ekrana i otpustite"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako da prevlačite zdesna da biste se vratili unazad. Sada naučite da zamenite aplikacije."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Dovršili ste pokret za povratak. Sada saznajte kako da promenite aplikacije."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Dovršili ste pokret za povratak"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Nikako ne prevlačite previše blizu dna ekrana"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Osetljivost pok. za nazad možete da promenite u Podešavanjima"</string>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 849a64f..646c6d9 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Правядзіце пальцам справа налева ці злева направа ад самага краю экрана"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Правядзіце пальцам ад правага або левага краю экрана ў цэнтр і адпусціце палец"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Вы даведаліся, як гартаць справа для вяртання. Цяпер даведайцеся, як пераключацца паміж праграмамі."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Вы навучыліся рабіць жэст вяртання. А зараз даведайцеся, як пераключацца паміж праграмамі."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Вы навучыліся рабіць жэст для пераходу назад"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Не праводзьце пальцам занадта блізка да ніжняга краю экрана"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Каб змяніць адчувальнасць жэста вяртання, адкрыйце налады"</string>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index 8c4f9e5..d1f59e8 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Трябва да плъзнете пръст от най-дясната или най-лявата част на екрана"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Трябва да плъзнете пръст от десния или левия край до средата на екрана, след което да го отпуснете"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Научихте жеста за връщане с плъзгане от дясно. Сега научете как се превключва между приложения."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Изпълнихте жеста за връщане назад. В следващия урок ще научите как се превключва между приложения."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Изпълнихте жеста за връщане назад"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Не плъзвайте пръста си твърде близо до долната част на екрана"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Променете чувств. на жеста за връщане назад от настройките"</string>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index 2b851dc..9a86646 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"স্ক্রিনের একেবারে ডান বা বাঁদিকের প্রান্ত থেকে সোয়াইপ করেছেন কিনা তা দেখে নিন"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"স্ক্রিনের ডান বা বাঁদিকের প্রান্ত থেকে মাঝখান পর্যন্ত সোয়াইপ করেছেন কিনা দেখে নিয়ে আঙুল তুলে নিন"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ফিরে যেতে, কীভাবে ডানদিক থেকে সোয়াইপ করতে হয় তা আপনি শিখেছেন। এরপর, একটি অ্যাপ থেকে অন্য অ্যাপে কীভাবে যাবেন জেনে নিন।"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"আপনি ফিরে যাওয়ার জেসচার সম্পর্কে জেনেছেন। এরপর, একটি অ্যাপ থেকে অন্য অ্যাপে কীভাবে যাবেন জেনে নিন।"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"আপনি জেনেছেন হাতের জেসচার ব্যবহার করে আগের স্ক্রিনে কীভাবে ফিরে যাওয়া যায়"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"স্ক্রিনের নিচের প্রান্তের খুব কাছে পর্যন্ত যাতে সোয়াইপ না করেন সেটি ভাল করে দেখে নিন"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ফিরে যাওয়ার জেসচারের সেন্সিটিভিটি পরিবর্তন করতে, সেটিংসে যান"</string>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 354fc34..eb777b4 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Prevucite s krajnjeg desnog ili krajnjeg lijevog ruba"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Prevucite s desnog ili lijevog ruba prema sredini ekrana i pustite"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako prevući zdesna da se vratite. Sljedeće naučite kako prebacivati između aplikacija."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Savladali ste pokret za vraćanje. Sljedeće naučite kako prebacivati između aplikacija."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Savladali ste pokret za vraćanje"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pazite da ne prevučete preblizu donjem dijelu ekrana"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Promijenite osjetljivost pokreta za povratak u Postavkama"</string>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index f4dd4a83..328ae07 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Assegura\'t de lliscar des de l\'extrem dret o esquerre de la pantalla."</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Assegura\'t de lliscar des de la vora dreta o esquerra cap al centre de la pantalla i deixar anar"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Has après a lliscar des de la dreta per tornar enrere. Ara, descobreix com pots canviar d\'aplicació."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Has completat el gest per tornar enrere. Ara, descobreix com pots canviar d\'aplicació."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Has completat el gest per tornar enrere"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Assegura\'t de no lliscar massa a prop de la part inferior de la pantalla."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Per canviar la sensibilitat del gest, ves a Configuració"</string>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index de609f1..151a09a 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Přejeďte prstem z úplného pravého nebo levého okraje obrazovky"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Přejeďte prstem z pravého nebo levého okraje doprostřed obrazovky a zdvihněte prst"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili jste se, jak se vrátit zpět přejetím prstem zprava. Teď se naučíte přepínat mezi aplikacemi."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Dokončili jste gesto pro přechod zpět. Teď se naučíte přepínat aplikace."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Dokončili jste gesto pro přechod zpět"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Dejte pozor, abyste prstem nepřejížděli moc blízko ke spodnímu okraji obrazovky"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Citlivost gesta pro přechod zpět můžete změnit v Nastavení"</string>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 720a7c5..cc534e7 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Stryg fra kanten yderst til højre eller venstre"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Stryg fra højre eller venstre kant mod midten af skærmen, og løft fingeren"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Du har lært, hvordan du stryger fra højre for at gå tilbage. Nu skal du se, hvordan du skifter app."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Du har fuldført bevægelsen for Gå tilbage. Som det næste kan du se, hvordan du skifter app."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Du har fuldført bevægelsen for Gå tilbage"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Undgå at stryge for tæt på bunden af skærmen"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Juster følsomheden for bevægelsen Gå tilbage i Indstillinger"</string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 6a71b89..10a85d5 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Wische vom äußersten rechten oder linken Displayrand"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Wische vom rechten oder linken Displayrand zur Displaymitte und lass los"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Du hast jetzt gelernt, vom rechten Displayrand aus zu wischen, um zurückzugehen. Gleich erfährst du, wie man zwischen Apps wechselt."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Du hast die „Zurück“-Touch-Geste abgeschlossen. Gleich lernst du, wie man zwischen Apps wechselt."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Du hast den Schritt für die „Zurück“-Touch-Geste abgeschlossen"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Wische nicht zu nah an den unteren Displayrand"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Du kannst die Empfindlichkeit von „Zurück“ in den Einstellungen ändern"</string>
@@ -95,7 +96,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
<string name="action_split" msgid="2098009717623550676">"Teilen"</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">"Andere App für Splitscreen auswählen"</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>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Splitscreen-Auswahl beenden"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Für Splitscreen andere App auswählen"</string>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index a59a407..5543636 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Φροντίστε να σύρετε από το άκρο της δεξιάς ή της αριστερής πλευράς."</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Σύρετε από το δεξί ή το αριστερό άκρο προς το κέντρο της οθόνης και απομακρύνετε το δάχτυλό σας"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Μάθατε πώς να σύρετε από τα δεξιά για επιστροφή. Τώρα, μάθετε πώς να κάνετε εναλλαγή εφαρμογών."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Ολοκληρώσατε την κίνηση επιστροφής. Στη συνέχεια, μάθετε πώς να κάνετε εναλλαγή εφαρμογών."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Ολοκληρώσατε την κίνηση επιστροφής"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Φροντίστε να μην σύρετε υπερβολικά κοντά στο κάτω μέρος της οθόνης"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Μεταβείτε στις Ρυθμίσεις για αλλαγή ευαισθ. κίνησης επιστρ."</string>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index 025e409..10aeee5 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Make sure you swipe from the far-right or far-left edge"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Make sure you swipe from the right or left edge to the middle of the screen and let go"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"You\'ve learned how to swipe from the right to go back. Next, learn how to switch apps."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"You completed the go back gesture. Next, learn how to switch apps."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"You completed the go back gesture"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Make sure you don\'t swipe too close to the bottom of the screen"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"To change sensitivity of the back gesture, go to Settings"</string>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 499ccda..bdc3c22 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Make sure you swipe from the far-right or far-left edge"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Make sure you swipe from the right or left edge to the middle of the screen and let go"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"You learned how to swipe from the right to go back. Next up, learn how to switch apps."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"You completed the go back gesture. Next up, learn how to switch apps."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"You completed the go back gesture"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Make sure you don\'t swipe too close to the bottom of the screen"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"To change the sensitivity of the back gesture, go to Settings"</string>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index 025e409..10aeee5 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Make sure you swipe from the far-right or far-left edge"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Make sure you swipe from the right or left edge to the middle of the screen and let go"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"You\'ve learned how to swipe from the right to go back. Next, learn how to switch apps."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"You completed the go back gesture. Next, learn how to switch apps."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"You completed the go back gesture"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Make sure you don\'t swipe too close to the bottom of the screen"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"To change sensitivity of the back gesture, go to Settings"</string>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index 025e409..10aeee5 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Make sure you swipe from the far-right or far-left edge"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Make sure you swipe from the right or left edge to the middle of the screen and let go"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"You\'ve learned how to swipe from the right to go back. Next, learn how to switch apps."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"You completed the go back gesture. Next, learn how to switch apps."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"You completed the go back gesture"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Make sure you don\'t swipe too close to the bottom of the screen"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"To change sensitivity of the back gesture, go to Settings"</string>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index e293813..4d87246 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Make sure you swipe from the far-right or far-left edge"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Make sure you swipe from the right or left edge to the middle of the screen and let go"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"You learned how to swipe from the right to go back. Next up, learn how to switch apps."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"You completed the go back gesture. Next up, learn how to switch apps."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"You completed the go back gesture"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Make sure you don\'t swipe too close to the bottom of the screen"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"To change the sensitivity of the back gesture, go to Settings"</string>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 265c8e2..8fcad7e 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Asegúrate de deslizar desde el extremo derecho o izquierdo"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Recuerda deslizar desde el borde izquierdo o derecho hacia el centro de la pantalla y, luego, soltar"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ya sabes deslizar el dedo desde la derecha para ir atrás. Ahora, descubre cómo cambiar de app."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Completaste el gesto \"Atrás\". A continuación, obtén información para cambiar de app."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Completaste el gesto para ir atrás"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Asegúrate de no deslizar muy cerca de la parte inferior de la pantalla"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Cambia sensibilidad de gesto \"Atrás\" en Configuración"</string>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index 0b3bb49..2afa3b8 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Asegúrate de deslizar desde el borde derecho o izquierdo de la pantalla"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Asegúrate de deslizar desde el borde derecho o izquierdo de la pantalla hasta el centro y soltar"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ya sabes deslizar el dedo desde la derecha para ir atrás. Descubre ahora cómo cambiar de aplicación."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Has completado el gesto para volver. Ahora, descubre cómo cambiar de aplicación."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Has completado el gesto para volver"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"No deslices demasiado cerca de la parte inferior de la pantalla"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Para cambiar la sensibilidad del gesto, ve a Ajustes"</string>
@@ -95,10 +96,10 @@
<string name="action_screenshot" msgid="8171125848358142917">"Hacer captura"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</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_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>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Salir de la selección de pantalla dividida"</string>
- <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida"</string>
+ <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Elige otra app para usar la pantalla dividida."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"No puedes hacerlo porque la aplicación o tu organización no lo permiten"</string>
<string name="split_widgets_not_supported" msgid="1355743038053053866">"Actualmente no se admiten widgets; selecciona otra aplicación"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"¿Saltar tutorial de navegación?"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index 3c978da..8801a7b 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pühkige kindlasti parem- või vasakpoolsest servast"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pühkige ekraani paremast või vasakust servast keskele ja eemaldage sõrm"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Õppisite, kuidas tagasiliikumiseks paremalt pühkida. Nüüd vaadake, kuidas rakenduste vahel vahetada."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Tegite tagasiliikumise liigutuse. Järgmisena vaadake, kuidas rakenduste vahel vahetada."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Tegite tagasiliikumise liigutuse"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Veenduge, et te ei pühiks liiga ekraani allosa lähedalt."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Tagasiliigutuse tundlikkuse muutmiseks avage menüü Seaded"</string>
@@ -95,10 +96,10 @@
<string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
<string name="action_split" msgid="2098009717623550676">"Eralda"</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_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>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Jagatud ekraanikuva valikust väljumine"</string>
- <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Valige jagatud ekraanikuva jaoks muu rakendus"</string>
+ <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Rakendus või teie organisatsioon on selle toimingu keelanud"</string>
<string name="split_widgets_not_supported" msgid="1355743038053053866">"Vidinaid praegu ei toetata, valige mõni muu rakendus"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Kas jätta navigeerimise õpetused vahele?"</string>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index 45068c4..24eb78d 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Ziurtatu hatza pantailaren eskuineko edo ezkerreko ertzetik hasten zarela pasatzen"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Ziurtatu hatza pantailaren eskuineko edo ezkerreko ertzetik erdialdera pasatzen duzula eta ondoren hatza jasotzen duzula"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Hatza eskuinetik pasatuta atzera egiten ikasi duzu. Jarraian, ikasi aplikazioa aldatzen."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Ikasi duzu atzera egiteko keinua. Jarraian, ikasi aplikazioa aldatzen."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Ikasi duzu atzera egiteko keinua"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Ziurtatu hatza ez duzula pasatzen pantailaren behealdetik gertuegi"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Keinuaren sentikortasuna aldatzeko, joan ezarpenetara"</string>
@@ -95,7 +96,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"Atera pantaila-argazki bat"</string>
<string name="action_split" msgid="2098009717623550676">"Zatitu"</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 zatitzea erabiltzeko, aukeratu beste aplikazio bat"</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>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Irten pantaila zatituaren hautapenetik"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Pantaila zatitzeko, aukeratu beste aplikazio bat"</string>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index bdcd7dc..24ec9f3 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"دقت کنید که از انتهای لبه سمت راست یا سمت چپ تند بکشید"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"دقت کنید که از لبه سمت راست یا سمت چپ تند به وسط صفحه بکشید و رها کنید"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"یاد گرفتید چگونه برای رفتن به عقب از سمت راست تند بکشید. مورد بعدی، با نحوه جابهجا شدن بین برنامهها آشنا شوید."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"اشاره برگشتن را تکمیل کردید. مورد بعدی، با نحوه جابهجا شدن بین برنامهها آشنا شوید."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"اشاره برگشتن را تکمیل کردید"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"دقت کنید که موقع تند کشیدن، بیشاز حد به پایین صفحه نزدیک نشوید"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"برای تغییر حساسیت اشاره برگشت، به «تنظیمات» بروید"</string>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 7038be8..5f57016 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pyyhkäise aivan oikeasta tai vasemmasta reunasta"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pyyhkäise näytön oikeasta tai vasemmasta reunasta keskelle ja päästä irti"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Osaat palata takaisin pyyhkäisemällä oikeasta reunasta. Opettele seuraavaksi vaihtamaan sovellusta."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Olet oppinut Takaisin-eleen. Opettele seuraavaksi vaihtamaan sovellusta."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Olet oppinut takaisin-eleen"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Varo, ettet pyyhkäise liian lähellä alareunaa"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Voit muuttaa Takaisin-eleen herkkyyttä asetuksista"</string>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index ab497a0..b8a1d8d 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Assurez-vous de balayer l\'écran à partir de l\'extrémité droite ou gauche"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Assurez-vous de balayer l\'écran à partir de l\'extrémité droite ou gauche vers le centre, puis allons-y"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Vous avez appris à balayer de la droite pour revenir en arrière. Apprenez comment changer d\'appli."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Vous avez appris le geste de retour en arrière. Maintenant, apprenez comment changer d\'application."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Vous avez appris le geste de retour en arrière"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Assurez-vous de ne pas balayer trop près du bas de l\'écran"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Modifiez la sensibilité du geste de retour dans Paramètres"</string>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index 8b3492f..dafc3c6 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Veillez à bien balayer l\'écran depuis le bord gauche ou droit"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Balayez bien l\'écran depuis le bord gauche ou droit jusqu\'au centre avant de relever le doigt"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Vous savez revenir en arrière en balayant depuis la droite. Apprenez à passer d\'une appli à l\'autre."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Vous avez appris le geste pour revenir en arrière. Apprenez ensuite à passer d\'une appli à l\'autre."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Vous avez appris le geste pour revenir en arrière"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Veillez à ne pas balayer l\'écran trop près du bas"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Modifiez la sensibilité du geste retour dans les paramètres"</string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 87f80dd..242be7a 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Asegúrate de pasar o dedo desde o bordo dereito ou esquerdo"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Asegúrate de pasar o dedo desde o bordo dereito ou esquerdo ata o medio da pantalla e levantalo"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Aprendiches a pasar o dedo desde a dereita para volver. Agora, aprende a cambiar de aplicación."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Completaches o xesto de volver á última pantalla. O próximo é aprender a cambiar de aplicación."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Completaches o xesto de volver á última pantalla"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Asegúrate de non pasar o dedo demasiado preto da parte inferior da pantalla"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Podes cambiar a sensibilidade do xesto en Configuración"</string>
@@ -95,7 +96,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</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_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>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Saír da selección de pantalla dividida"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Escolle outra app para usar a pantalla dividida"</string>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index f919593..f754675 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ખાતરી કરો કે તમે એકદમ દૂરની જમણી કે ડાબી કિનારીએથી સ્વાઇપ કરો છો"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ખાતરી કરો કે તમે જમણી કે ડાબી કિનારીએથી સ્ક્રીનના મધ્ય ભાગ સુધી સ્વાઇપ કરો છો અને આંગળી ઊંચકી લો છો"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"પાછળ જવા જમણેથી કેવી રીતે સ્વાઇપ કરવું એ તમે શીખી લીધું છે. હવે પછી, ઍપ સ્વિચ કરવાની રીત જાણો."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"તમે પાછા જવાનો સંકેત પૂર્ણ કર્યો છે. હવે પછી, ઍપ સ્વિચ કરવાની રીત વિશે જાણો."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"તમે પાછા જવાનો સંકેત પૂર્ણ કર્યો છે"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ખાતરી કરો કે તમારાથી સ્ક્રીનની એકદમ નીચેની કિનારીની ખૂબ નજીક સુધી સ્વાઇપ ન થઈ જાય"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"પાછા જવાના સંકેતની સંવેદિતા બદલવા માટે, સેટિંગમાં જાઓ"</string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 032f225..2a97eb1 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"स्क्रीन पर बिलकुल दाएं या बाएं किनारे से स्वाइप करें"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"स्क्रीन पर दाएं या बाएं किनारे से बीच तक स्वाइप करें और फिर अपनी उंगली को स्क्रीन से हटा दें"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"आपने स्क्रीन के दाएं किनारे से स्वाइप करके, पिछली स्क्रीन पर वापस जाने का तरीका सीख लिया है. अब, एक ऐप से दूसरे ऐप पर जाने का तरीका सीखें."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"आपने पीछे ले जाने वाले हाथ के जेस्चर के बारे में जान लिया है. एक ऐप से दूसरे पर जाने का तरीका जानें."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"आपने जान लिया है कि हाथ का जेस्चर इस्तेमाल करके पिछली स्क्रीन पर वापस कैसे जाएं"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"स्क्रीन पर बिलकुल नीचे तक स्वाइप न करें"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"\'सेटिंग\' में जाकर, पीछे जाने के लिए इस्तेमाल होने वाले हाथ के जेस्चर (हाव-भाव) की संवेदनशीलता बदलें"</string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index 3268293..ee52d99 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pazite da prijeđete prstom od krajnjeg desnog ili krajnjeg lijevog ruba"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pazite da prijeđete prstom od desnog ili lijevog ruba do sredine zaslona i podignite prst"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste kako prijeći prstom zdesna da biste se vratili. Sad saznajte kako promijeniti aplikaciju."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Izvršili ste pokret za povratak. Sad saznajte kako promijeniti aplikaciju."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Izvršili ste pokret za povratak"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pazite da ne prijeđete prstom preblizu dnu zaslona"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Osjetljivost pokreta povratka promijenite u postavkama"</string>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index ee410c0..ff784c3 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Csúsztasson a képernyő jobb vagy bal széléről."</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Csúsztassa ujját a képernyő jobb vagy bal széléről a képernyő közepéig, majd emelje fel."</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Megtanulta, hogyan léphet vissza jobbról csúsztatva. A következő az appok közötti váltás."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Teljesítette a visszalépési kézmozdulatot. Most megtanulhatja, hogyan válthat az appok között."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Teljesítette a visszalépési kézmozdulatot."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Ne csúsztasson túl közel a képernyő aljához."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"A vissza mozdulat érzékenysége a Beállításokban módosítható"</string>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 1f6cd6d..840b6da 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Համոզվեք, որ մատը սահեցնում եք էկրանի աջ կամ ձախ եզրից"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Մատը սահեցրեք էկրանի աջ կամ ձախ եզրից դեպի կենտրոն և բաց թողեք"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Դուք սովորեցիք՝ ինչպես մատը աջից սահեցնելով հետ գնալ։ Այժմ սովորենք՝ ինչպես անցնել մի հավելվածից մյուսը։"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Դուք սովորեցիք հետ գնալու ժեստը։ Այժմ սովորենք՝ ինչպես անցնել մի հավելվածից մյուսը։"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Դուք սովորեցիք հետ գնալու ժեստը"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Համոզվեք, որ մատը չափազանց մոտ չեք սահեցնում էկրանի ներքևի հատվածին"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Հետ գնալու ժեստի զգայունությունը փոփոխեք կարգավորումներում"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index a5e5fbd..12ebae0 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pastikan Anda menggeser dari tepi ujung kanan atau ujung kiri"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pastikan Anda menggeser dari tepi kanan atau kiri ke tengah layar, lalu lepaskan"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Anda telah belajar cara geser dari kanan untuk kembali. Berikutnya, pelajari cara beralih aplikasi."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Anda telah menyelesaikan gestur kembali. Selanjutnya, pelajari cara beralih aplikasi."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Anda telah menyelesaikan gestur kembali"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pastikan Anda tidak menggeser terlalu dekat ke bagian bawah layar"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Untuk mengubah sensitivitas gestur kembali, buka Setelan"</string>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index 1e7a791..ae809a5 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Passaðu að strjúka frá jaðri hægri eða vinstri brúnar"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Passaðu að strjúka frá jaðri hægri eða vinstri brúnar að miðju skjásins og sleppa síðan"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Þú lærðir að strjúka frá hægri til að bakka. Næst skaltu læra hvernig þú skiptir á milli forrita."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Þú laukst við að kynna þér bendinguna „til baka“. Næst skaltu læra hvernig þú skiptir á milli forrita."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Þú laukst við að kynna þér bendinguna „til baka“"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Passaðu að strjúka ekki of nálægt neðri brún skjásins"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Til að breyta næmi til baka-bendingar ferðu í stillingar"</string>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index cbd34c6..b6cc105 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Assicurati di scorrere dal bordo all\'estrema destra o all\'estrema sinistra"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Assicurati di scorrere dal bordo destro o sinistro verso il centro dello schermo e solleva il dito"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Hai imparato a scorrere da destra per tornare indietro. Ora impara come passare da un\'app all\'altra."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Hai completato il gesto Indietro. Ora, impara come passare da un\'app all\'altra."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Hai completato il gesto Indietro"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Assicurati di non scorrere troppo vicino alla parte inferiore dello schermo"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Usa Impostazioni per cambiare sensibilità del gesto Indietro"</string>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index dcd04e7..68cdd07 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"חשוב להחליק מהקצה השמאלי או הימני"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"חשוב להחליק מהקצה השמאלי או הימני למרכז המסך ואז לשחרר"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"למדת איך להחליק מצד ימין כדי לחזור אחורה. בשלב הבא לומדים איך לעבור בין אפליקציות."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"השלמת את תנועת \'הקודם\'. בשלב הבא לומדים איך לעבור בין אפליקציות."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"השלמת את התנועה \'חזרה אחורה\'"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"חשוב שלא להחליק קרוב מדי לתחתית המסך"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"כדי לשנות את מידת הרגישות של תנועת החזרה, יש לעבור להגדרות"</string>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index 4848f4b..a817ce7 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"右端または左端からスワイプしてください"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"画面の右端または左端から中央に向かってスワイプし、指を離してください"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"右側からスワイプして前の画面に戻る方法を学習しました。次は、アプリを切り替える方法を覚えましょう。"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"「戻る」操作を完了しました。次は、アプリを切り替える方法を覚えましょう。"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"「戻る」操作を学習しました"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"スワイプする際は画面の下部に近づきすぎないようにしましょう"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"「戻る」操作の感度を変更するには [設定] に移動します"</string>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 74bbc5b..13d2445 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"გადაფურცლეთ უკიდურესი მარჯვენა ან მარცხენა ბოლოდან"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"გადაფურცლეთ მარჯვენა ან მარცხენა კიდიდან ეკრანის ცენტრისკენ და თითი აუშვით"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"თქვენ ისწავლეთ მარჯვნიდან გადაფურცვლა უკან დასაბრუნებლად. ახლა კი შეიტყვეთ, როგორ გადართოთ აპები."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"თქვენ შეასრულეთ უკან დაბრუნების ჟესტი. ახლა კი შევიტყოთ, როგორ გადავრთოთ აპები."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"თქვენ შეასრულეთ უკან დაბრუნების ჟესტი"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"არ გადაფურცლოთ ეკრანის ბოლოსთან ახლოს"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"დაბრუნების ჟესტის მგრძნობელობის შესაცვლელად გადადით პარამეტრებზე"</string>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 737ecc0..9f25aac 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Экранның оң немесе сол жиегінен сырғытыңыз."</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Экранның оң немесе сол жиегінен ортасына қарай сырғытып, саусағыңызды жіберіңіз."</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Оңнан солға сырғыту арқылы артқа қайтуды үйрендіңіз. Енді қолданбаларды ауыстыруды үйреніңіз."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Артқа қайту қимылын аяқтадыңыз. Енді қолданбаларды ауыстыруды үйреніңіз."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Артқа қайту қимылын аяқтадыңыз."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Сырғытқанда саусақты экранның төменгі жағына қатты жақындатпаңыз."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Артқа қайту қимылы сезгіштігін параметрлерден өзгертіңіз."</string>
@@ -95,8 +96,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="action_split" msgid="2098009717623550676">"Бөлу"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлу режимін пайдалану үшін басқа қолданбаны түртіңіз."</string>
- <!-- no translation found for toast_contextual_split_select_app (433510957123687090) -->
- <skip />
+ <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Экранды бөлу үшін басқа қолданбаны таңдаңыз."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Бас тарту"</b></string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Экранды бөлу режимінен шығу"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Экранды бөлу үшін басқа қолданбаны таңдаңыз."</string>
@@ -113,10 +113,8 @@
<string name="taskbar_edu_suggestions" msgid="8215044496435527982">"Іс-әрекеттеріңізге негізделген қолданба ұсыныстарын алыңыз."</string>
<string name="taskbar_edu_pinning" msgid="6708550858580071558">"Тапсырмалар жолағын бекіту үшін бөлгішті ұзақ басып тұрыңыз"</string>
<string name="taskbar_edu_features" msgid="3320337287472848162">"Тапсырмалар жолағында мүмкіндік көп"</string>
- <!-- no translation found for taskbar_edu_pinning_title (210102174154211712) -->
- <skip />
- <!-- no translation found for taskbar_edu_pinning_standalone (2636919474366410467) -->
- <skip />
+ <string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Тапсырмалар жолағын әрдайым көрсету"</string>
+ <string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Экранның төменгі жағында тапсырмалар жолағы әрдайым көрсетілуі үшін, бөлгішті басып тұрыңыз."</string>
<string name="taskbar_edu_close" msgid="887022990168191073">"Жабу"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"Дайын"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"Негізгі экран"</string>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 43b0424..3a56606 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ត្រូវប្រាកដថាអ្នកអូសពីគែមខាងស្ដាំ ឬខាងឆ្វេង"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ត្រូវប្រាកដថាអ្នកអូសពីគែមខាងស្ដាំ ឬខាងឆ្វេងទៅផ្នែកកណ្ដាលនៃអេក្រង់ រួចដកដៃ"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"អ្នកបានស្វែងយល់ពីរបៀបអូសពីខាងស្ដាំ ដើម្បីថយក្រោយ។ បន្ទាប់ទៀត សូមស្វែងយល់ពីរបៀបប្ដូរកម្មវិធី។"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"អ្នកបានបញ្ចប់ចលនាថយក្រោយហើយ។ បន្ទាប់មកទៀត សូមស្វែងយល់ពីរបៀបប្ដូរកម្មវិធី។"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"អ្នកបានបញ្ចប់ចលនាថយក្រោយហើយ"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ត្រូវប្រាកដថាអ្នកមិនអូសទៅជិតផ្នែកខាងក្រោមនៃអេក្រង់ពេក"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ដើម្បីប្ដូរកម្រិតរំញោចនឹងចលនាថយក្រោយ សូមចូលទៅកាន់ការកំណត់"</string>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 342a05f..14e8570 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ನೀವು ಬಲಕೊನೆಯ ಅಂಚಿನಿಂದ ಅಥವಾ ಎಡಕೊನೆಯ ಅಂಚಿನಿಂದ ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಿ"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ನೀವು ಬಲ ಅಥವಾ ಎಡ ಅಂಚಿನಿಂದ ಸ್ಕ್ರೀನ್ನ ಮಧ್ಯಕ್ಕೆ ಸ್ವೈಪ್ ಮಾಡುತ್ತಿದ್ದೀರಿ ಎಂದು ಖಚಿತಪಡಿಸಿಕೊಂಡು ಬಿಟ್ಟುಬಿಡಿ"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ಹಿಂದೆ ಹೋಗಲು ಬಲದಿಂದ ಸ್ವೈಪ್ ಮಾಡುವುದು ಹೇಗೆಂದು ಕಲಿತಿರಿ. ಮುಂದೆ, ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಿಸುವುದು ಹೇಗೆಂದು ತಿಳಿಯಿರಿ."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ನೀವು ಗೋ ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ. ಮುಂದೆ, ಆ್ಯಪ್ಗಳನ್ನು ಬದಲಾಯಿಸುವುದು ಹೇಗೆ ಎಂದು ತಿಳಿಯಿರಿ."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ನೀವು ಗೋ ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ ಅನ್ನು ಪೂರ್ಣಗೊಳಿಸಿದ್ದೀರಿ"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ನೀವು ಸ್ಕ್ರೀನ್ನ ಕೆಳಭಾಗಕ್ಕೆ ಹೆಚ್ಚು ಹತ್ತಿರ ಸ್ವೈಪ್ ಮಾಡದಂತೆ ನೋಡಿಕೊಳ್ಳಿ"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ಬ್ಯಾಕ್ ಗೆಸ್ಚರ್ನ ಸೂಕ್ಷ್ಮತೆ ಬದಲಾಯಿಸಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ"</string>
@@ -95,7 +96,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string>
<string name="action_split" msgid="2098009717623550676">"ವಿಭಜಿಸಿ"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="toast_contextual_split_select_app" msgid="433510957123687090">"\"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್\" ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
+ <string name="toast_contextual_split_select_app" msgid="433510957123687090">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಬಳಸಲು ಇನ್ನೊಂದು ಆ್ಯಪ್ ಆಯ್ಕೆಮಾಡಿ"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"ರದ್ದುಮಾಡಿ"</b></string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್ ಆಯ್ಕೆಯಿಂದ ನಿರ್ಗಮಿಸಿ"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"\"ಪರದೆ ಬೇರ್ಪಡಿಸಿ\" ಬಳಸಲು ಬೇರೆ ಆ್ಯಪ್ ಅನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index e485d9a..8221935 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"오른쪽 또는 왼쪽 가장자리 끝에서 스와이프하세요."</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"오른쪽 또는 왼쪽 가장자리에서 화면 중앙으로 스와이프한 후 손가락을 떼세요."</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"오른쪽에서 스와이프하여 뒤로 돌아가는 방법을 배웠습니다. 이번에는 앱 전환 방법을 알아보겠습니다."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"돌아가기 동작을 완료했습니다. 이번에는 앱 전환 방법을 알아보겠습니다."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"돌아가기 동작을 완료했습니다."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"화면 하단에 지나치게 가까운 곳에서 스와이프하면 안 됩니다."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"돌아가기 동작의 민감도를 변경하려면 설정으로 이동하세요"</string>
@@ -95,7 +96,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"스크린샷"</string>
<string name="action_split" msgid="2098009717623550676">"분할"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"다른 앱을 탭하여 화면 분할 사용"</string>
- <string name="toast_contextual_split_select_app" msgid="433510957123687090">"화면 분할을 사용하려면 다른 앱 선택"</string>
+ <string name="toast_contextual_split_select_app" msgid="433510957123687090">"화면 분할을 사용하려면 다른 앱을 선택하세요."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"취소"</b></string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"화면 분할 선택 종료"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"화면 분할을 사용하려면 다른 앱을 선택하세요."</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 2d1718d..d90174c 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Экранды эң четинен оңдон солго же солдон оңго карай сүрүңүз"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Экранды оң же сол жагынан ортосуна карай сүрүп, манжаңызды алыңыз"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Артка кайтуу үчүн экранды оңдон солго карай сүрүүнү үйрөндүңүз. Эми колдонмолорду которуштурганды үйрөнүп алыңыз."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"\"Артка\" жаңсоосун үйрөндүңүз. Эми колдонмолорду которуштурганды үйрөнүп алыңыз."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"\"Артка\" жаңсоосун үйрөндүңүз"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Манжаңызды экрандын ылдый жагына өтө жакындатпай сүрүңүз"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"\"Артка\" жаң-нун сезгичтигин өзгөртүү үчүн параметрлерге өтүңүз"</string>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index bebfc2a..fa72bd1 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ກະລຸນາກວດສອບວ່າທ່ານປັດຈາກຂອບຂວາສຸດ ຫຼື ຊ້າຍສຸດ"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ກະລຸນາກວດສອບວ່າທ່ານປັດຈາກຂອບຂວາ ຫຼື ຊ້າຍໄປຫາທາງກາງຂອງໜ້າຈໍແລ້ວປ່ອຍນິ້ວ"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ທ່ານຮຽນຮູ້ວິທີປັດຈາກຂວາເພື່ອກັບຄືນແລ້ວ. ຕໍ່ໄປ, ມາສຶກສາວິທີສະຫຼັບແອັບ."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ທ່ານໃຊ້ທ່າທາງກັບຄືນສຳເລັດແລ້ວ. ຕໍ່ໄປ, ມາສຶກສາວິທີສະຫຼັບແອັບ."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ທ່ານໃຊ້ທ່າທາງກັບຄືນສຳເລັດແລ້ວ"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ກະລຸນາກວດສອບວ່າທ່ານບໍ່ໄດ້ປັດໃກ້ກັບທາງລຸ່ມຂອງໜ້າຈໍເກີນໄປ"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ເພື່ອປ່ຽນຄວາມລະອຽດອ່ອນຂອງທ່າທາງກັບຄືນ, ໃຫ້ໄປຫາການຕັ້ງຄ່າ"</string>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index 77c81ed..6e71234 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Turite perbraukti nuo dešiniojo ar kairiojo krašto"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Turite perbraukti nuo dešiniojo ar kairiojo krašto link ekrano vidurio ir pakelti pirštą"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Išmokote, kaip sugrįžti perbraukiant iš dešinės. Toliau sužinosite, kaip perjungti programas."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Atlikote grįžimo atgal gestą. Toliau sužinosite, kaip perjungti programas."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Atlikote grįžimo atgal gestą"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Nebraukite per arti ekrano apačios"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Norėd. pak. grįžimo gesto jautr., eikite į sk. „Nustatymai“"</string>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index d7772a2..8fd7b12 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Jāvelk no pašas labās vai kreisās malas."</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Jāvelk no ekrāna labās vai kreisās malas uz vidu un jāatlaiž."</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Jūs esat apguvis, kā vilkt no labās malas, lai pārietu atpakaļ. Tagad mācieties pārslēgt lietotnes."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Jūs sekmīgi veicāt atgriešanās žestu. Tagad varat iemācīties, kā pārslēgt lietotnes."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Jūs sekmīgi veicāt atgriešanās žestu."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Nevelciet pārāk tuvu ekrāna apakšdaļai."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Atgriešanās žesta jutīguma līmeni varat mainīt iestatījumos."</string>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index fff10c2..aed558a 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Повлечете од крајниот десен или крајниот лев раб"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Повлечете од десниот или левиот раб кон средината на екранот и пуштете"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Научивте како да повлекувате оддесно за враќање назад. Научете и како да се префрлате помеѓу апликациите."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Го научивте движењето за враќање назад. Научете го и движењето за префрлање помеѓу апликациите."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Завршивте со упатството за враќање назад"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Не повлекувајте преблиску до дното на екранот"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"За да ја промените чувствителноста, одете во „Поставки“"</string>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 6dfe3dc..3e6d075 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"വലത്തേയറ്റത്തെയോ ഇടത്തേയറ്റത്തെയോ അരികിൽ നിന്നാണ് സ്വെെപ്പ് ചെയ്യുന്നതെന്ന് ഉറപ്പാക്കുക"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"വലതോ ഇടതോ അരികിൽ നിന്ന് സ്ക്രീനിന്റെ മധ്യഭാഗത്തേക്കാണ് സ്വെെപ്പ് ചെയ്യുന്നതെന്ന് ഉറപ്പാക്കുക"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"മടങ്ങാൻ വലതുഭാഗത്ത് നിന്ന് സ്വൈപ്പ് ചെയ്യുന്ന രീതി മനസ്സിലായി. ഇനി, ആപ്പുകൾ മാറുന്ന രീതി അറിയുക."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"മടങ്ങുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി. അടുത്തത്, എങ്ങനെ ആപ്പുകൾ തമ്മിൽ മാറാമെന്ന് മനസ്സിലാക്കുക."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"മടങ്ങുക ജെസ്ച്ചർ നിങ്ങൾ പൂർത്തിയാക്കി"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"സ്ക്രീനിന്റെ ഏറ്റവും അടിഭാഗത്തേക്ക് സ്വെെപ്പ് ചെയ്യുന്നില്ലെന്ന് ഉറപ്പാക്കുക"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ബാക്ക്ജെസ്റ്ററിന്റെ സെൻസിറ്റിവിറ്റി മാറ്റാൻ ക്രമീകരണത്തിൽ പോകൂ"</string>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index fd6ca92..71e7fb5 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Та баруун зах эсвэл зүүн захын ирмэгээс шударна уу"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Та баруун эсвэл зүүн ирмэгээс дэлгэцийн дунд хэсэг хүртэл шударч, суллана уу"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Та буцахын тулд баруунаас хэрхэн шудрахыг мэдэж авлаа. Дараа нь аппууд хооронд хэрхэн сэлгэхийг мэдэж аваарай."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Та буцах зангааг гүйцэтгэлээ. Дараа нь аппуудыг хэрхэн сэлгэх талаар мэдэж авна уу."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Та буцах зангааг гүйцэтгэлээ"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Та дэлгэцийн доод хэсэгтэй хэт ойр бүү шудраарай"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Буцах зангааны мэдрэгшлийг өөрчлөх бол Тохиргоо руу очно уу"</string>
@@ -95,7 +96,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"Дэлгэцийн агшин дарах"</string>
<string name="action_split" msgid="2098009717623550676">"Хуваах"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Дэлгэцийг хуваахыг ашиглахын тулд өөр аппыг товш"</string>
- <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Дэлгэцийг хуваахыг ашиглахын тулд өөр апп сонгоно уу"</string>
+ <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Дэлгэц хуваахыг ашиглахын тулд өөр апп сонгоно уу"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Цуцлах"</b></string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Дэлгэцийг хуваах сонголтоос гарах"</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Дэлгэцийг хуваах горим ашиглах өөр апп сонгоно уу"</string>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index 5d32ed0..eea6f85 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"तुम्ही स्क्रीनच्या अगदी उजव्या किंवा अगदी डाव्या कडेपासून स्वाइप करत आहात खात्री करा"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"तुम्ही स्क्रीनच्या उजव्या किंवा डाव्या कडेपासून मध्यभागी स्वाइप करून सोडून देत आहात याची खात्री करा"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"मागे जाण्यासाठी उजवीकडून कसे स्वाइप करावे ते शिकलात. आता पुढे, ॲप्स कशी स्विच करायची ते जाणून घ्या."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"तुम्ही गो बॅक जेश्चर पूर्ण केले. आता, ॲप्स कशी स्विच करायची ते जाणून घ्या."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"तुम्ही गो बॅक जेश्चर पूर्ण केले आहे"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"तुम्ही स्क्रीनच्या तळाच्या अगदी जवळून स्वाइप करत नाही याची खात्री करा"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"बॅक जेश्चरची संवेदनशीलता बदलण्यासाठी, सेटिंग्ज वर जा"</string>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index 863bb2d..1a72f1a 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pastikan anda meleret dari hujung sebelah kanan atau hujung sebelah kiri"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pastikan anda meleret dari tepi sebelah kanan atau kiri ke bahagian tengah skrin dan lepaskan"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Anda sudah belajar cara meleret dari kanan untuk kembali. Seterusnya, ketahui cara menukar apl."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Anda telah melengkapkan gerak isyarat undur. Seterusnya, ketahui cara menukar apl."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Anda telah melengkapkan gerak isyarat undur"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pastikan anda tidak meleret terlalu dekat dengan bahagian bawah skrin"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Utk mengubah kepekaan gerak isyarat undur, pergi ke Tetapan"</string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index cd5a1a3..2f8daf3 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ညာ (သို့) ဘယ်အစွန်း၏ ခပ်လှမ်းလှမ်းမှ ပွတ်ဆွဲကြောင်း သေချာပါစေ"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ဖန်သားပြင်၏ ညာ (သို့) ဘယ်အစွန်းမှ အလယ်သို့ ပွတ်ဆွဲပြီး လွှတ်လိုက်ကြောင်း သေချာပါစေ"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"နောက်ပြန်သွားရန် ညာဘက်မှပွတ်ဆွဲနည်းကို သိသွားပါပြီ။ နောက်အဆင့်တွင် အက်ပ်များပြောင်းနည်းကို လေ့လာပါ။"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"နောက်ဆုတ်လက်ဟန် ရှင်းလင်းပို့ချချက် ပြီးပါပြီ။ နောက်အဆင့်တွင် အက်ပ်များပြောင်းနည်းကို လေ့လာပါ။"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"နောက်သို့ လက်ဟန် အပြီးသတ်လိုက်ပါပြီ"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ဖန်သားပြင် အောက်ခြေနှင့် အလွန်နီးကပ်စွာ ပွတ်ဆွဲခြင်းမရှိကြောင်း သေချာပါစေ"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"နောက်ဆုတ်လက်ဟန်၏ အာရုံခံစွမ်းကိုပြောင်းရန် ‘ဆက်တင်များ’ သို့ သွားပါ"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index c5e0893..ffbb73c 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Sørg for at du sveiper fra kanten helt til høyre eller venstre"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Sørg for at du sveiper fra den høyre eller venstre kanten til midten av skjermen og slipper"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Du har lært hvordan du sveiper fra høyre for å gå tilbake. I neste trinn lærer du å bytte app."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Du har fullført bevegelsen for å gå tilbake. I neste trinn lærer du hvordan du bytter app."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Du har fullført bevegelsen for å gå tilbake"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Sørg for at du ikke sveiper for nær bunnen av skjermen"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Gå til Innstillinger for å endre tilbakebevegelsefølsomheten"</string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 61e68cb..f7569a1 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"स्क्रिनको सबैभन्दा दायाँ किनारा वा सबैभन्दा बायाँ किनाराबाट स्वाइप गर्नुहोस्"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"स्क्रिनको दायाँ वा बायाँ किनाराबाट मध्य भागसम्म स्वाइप गर्नुहोस् अनि औँला उठाउनुहोस्"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"तपाईंले स्क्रिनको दायाँ किनाराबाट स्वाइप गरेर अघिल्लो स्क्रिनमा फर्कने तरिका सिक्नुभयो। अब एउटा एपबाट अर्को एपमा जाने तरिका सिक्नुहोस्।"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"तपाईंले \'पछाडि जानुहोस्\' नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो। अब एउटा एपबाट अर्को एपमा जाने तरिका सिक्नुहोस्।"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"तपाईंले \"पछाडि जानुहोस्\" नामक इसारा प्रयोग गर्ने तरिका सिक्नुभयो"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"स्क्रिनको फेदको धेरै नजिकसम्म स्वाइप नगर्नुहोस्"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"\'पछाडि\' नामक इसाराको संवेदनशीलता बदल्न सेटिङमा जानुहोस्"</string>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index 30dc645..aa66546 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Swipe vanaf de rechter- of linkerrand"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Swipe vanaf de rechter- of linkerrand naar het midden van het scherm en laat los"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Je weet nu hoe je vanaf rechts kunt swipen om terug te gaan. Ontdek nu hoe je tussen apps schakelt."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Je weet nu hoe je het gebaar Terug maakt. Ontdek als volgende hoe je tussen apps schakelt."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Je weet nu hoe je het gebaar Terug maakt"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Swipe niet te dicht bij de onderkant van het scherm"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Open Instellingen om de gevoeligheid van Terug te wijzigen"</string>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index d0d7988..9c32921 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ଆପଣ ସ୍କ୍ରିନର ଏକଦମ୍-ଡାହାଣ ବା ବାମ ଧାରରୁ ସ୍ୱାଇପ୍ କରୁଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ।"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ଆପଣ ସ୍କ୍ରିନର ଡାହାଣ ବା ବାମ ଧାରରୁ ମଝିକୁ ସ୍ୱାଇପ କରି ଛାଡ଼ି ଦେଉଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ଆପଣ ଡାହାଣରୁ ସ୍ୱାଇପ୍ କରି ପଛକୁ କିପରି ଫେରିବେ ତାହା ଜାଣିଲେ। ତା\'ପରେ, ଆପକୁ କିପରି ସ୍ୱିଚ୍ କରିବେ ତାହା ଜାଣନ୍ତୁ।"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ଆପଣ \'ପଛକୁ ଫେରନ୍ତୁ\' ଜେଶ୍ଚର୍ ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି। ତା\'ପରେ, ଆପଗୁଡ଼ିକୁ କିପରି ସ୍ୱିଚ୍ କରିବେ ତାହା ଜାଣନ୍ତୁ।"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ଆପଣ \'ପଛକୁ ଫେରନ୍ତୁ\' ଜେଶ୍ଚର ସମ୍ପୂର୍ଣ୍ଣ କରିଛନ୍ତି"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ଆପଣ ସ୍କ୍ରିନର ତଳଭାଗର ଅତି ନିକଟରୁ ସ୍ୱାଇପ କରୁନଥିବା ସୁନିଶ୍ଚିତ କରନ୍ତୁ"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ପଛକୁ ଫେରିବା ଜେଶ୍ଚରର ସମ୍ବେଦନଶୀଳତା ବଦଳାଇବାକୁ ସେଟିଂସକୁ ଯାଆନ୍ତୁ"</string>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 90d1adc..c422cd1 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸੱਜੇ ਜਾਂ ਖੱਬੇ ਪਾਸੇ ਦੇ ਬਿਲਕੁਲ ਕਿਨਾਰੇ ਤੋਂ ਸਵਾਈਪ ਕਰਦੇ ਹੋ"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸੱਜੇ ਜਾਂ ਖੱਬੇ ਕਿਨਾਰੇ ਤੋਂ ਸਕ੍ਰੀਨ ਦੇ ਵਿਚਕਾਰ ਤੱਕ ਸਵਾਈਪ ਕਰਦੇ ਹੋ ਅਤੇ ਛੱਡ ਦਿੰਦੇ ਹੋ"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ਤੁਸੀਂ ਪਿੱਛੇ ਜਾਣ ਲਈ ਸੱਜੇ ਪਾਸੇ ਤੋਂ ਸਵਾਈਪ ਕਰਨ ਦਾ ਤਰੀਕਾ ਜਾਣਿਆ। ਅੱਗੇ, ਐਪਾਂ ਵਿਚਾਲੇ ਸਵਿੱਚ ਕਰਨ ਦਾ ਤਰੀਕਾ ਜਾਣੋ।"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ਤੁਸੀਂ \'ਵਾਪਸ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ। ਅੱਗੇ, ਜਾਣੋ ਕਿ ਐਪਾਂ ਵਿਚਾਲੇ ਅਦਲਾ-ਬਦਲੀ ਕਿਵੇਂ ਕਰਨੀ ਹੈ।"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ਤੁਸੀਂ \'ਵਾਪਸ ਜਾਓ\' ਦਾ ਇਸ਼ਾਰਾ ਪੂਰਾ ਕੀਤਾ"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ਇਹ ਪੱਕਾ ਕਰੋ ਕਿ ਤੁਸੀਂ ਸਕ੍ਰੀਨ ਦੇ ਹੇਠਲੇ ਹਿੱਸੇ ਦੇ ਬਹੁਤ ਨੇੜੇ ਸਵਾਈਪ ਨਾ ਕਰੋ"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ਪਿੱਛੇ ਜਾਣ ਦੇ ਸੰਕੇਤ ਦੀ ਸੰਵੇਦਨਸ਼ੀਲਤਾ ਬਦਲਣ ਲਈ, ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index ed9a76f..b9744ad 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pamiętaj, aby przesuwać palcem od samej krawędzi (prawej lub lewej)"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pamiętaj, aby przesuwać palcem od prawej lub lewej krawędzi do środka ekranu i podnieść palec"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Wiesz już, jak przesuwać palcem, aby przejść wstecz. Poćwicz teraz przełączanie aplikacji."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Gest przejścia wstecz został opanowany. Poćwicz teraz przełączanie aplikacji."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Gest przejścia wstecz został opanowany"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pamiętaj, aby nie przesuwać palcem zbyt blisko dolnej części ekranu"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Czułość gestu cofania możesz zmienić w Ustawieniach"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index 0be61b8..30a0992 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Deslize rapidamente a partir da extremidade mais à direita ou mais à esquerda"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Deslize rapidamente a partir da extremidade esquerda ou direita até ao centro do ecrã e solte"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Aprendeu a deslizar a partir da direita para retroceder. A seguir, saiba como alternar entre apps."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Concluiu o gesto para retroceder. A seguir, saiba como alternar entre apps."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Concluiu o gesto para retroceder"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Garanta que não desliza rapidamente com o dedo demasiado perto da parte inferior do ecrã"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Altere a sensibilidade do gesto para voltar nas Definições."</string>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index 1a93e0a..c129187 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Deslize da borda direita ou esquerda"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Deslize da borda direita ou esquerda até o meio da tela e solte"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Você aprendeu a deslizar da direita para voltar. A seguir, aprenda a trocar de app."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Você concluiu o gesto para voltar. A seguir, aprenda a trocar de app."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Você concluiu o gesto para voltar"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Não deslize perto demais da parte inferior da tela"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Mude a sensibilidade do gesto de voltar nas configurações"</string>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 0ca4fb2..2c3c8cd 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Glisează dinspre marginea dreaptă îndepărtată sau dinspre marginea stângă îndepărtată"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Glisează dinspre marginea dreaptă sau stângă spre mijlocul ecranului și eliberează"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ai învățat să revii la ecranul anterior glisând din dreapta. Acum învață să comuți între aplicații."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Ați finalizat gestul „înapoi”. În continuare, aflați cum să comutați între aplicații."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Ai finalizat gestul „înapoi”"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Nu glisa prea aproape de partea de jos a ecranului"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Schimbă sensibilitatea gestului „Înapoi” accesând Setările"</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index 134ab66..87f7bcc 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Проведите справа налево или слева направо от самого края экрана."</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Проведите от правого или левого края экрана к центру и отпустите палец."</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Теперь вы знаете, как вернуться, проведя справа налево. Далее мы расскажем, как переключаться между приложениями."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Вы выполнили жест для перехода назад. Теперь мы расскажем, как переключаться между приложениями."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Вы выполнили жест для возврата на предыдущий экран."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Проведите пальцем не слишком близко к нижнему краю экрана."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Уровень чувствительности можно изменить в настройках."</string>
@@ -95,7 +96,7 @@
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="action_split" msgid="2098009717623550676">"Разделить"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Для разделения экрана выберите другое приложение."</string>
- <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Выберите другое приложение для разделения экрана."</string>
+ <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Чтобы использовать разделенный экран, выберите другое приложение."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Отмена"</b></string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Выйдите из режима разделения экрана."</string>
<string name="toast_split_app_unsupported" msgid="2360229567007828914">"Выберите другое приложение для разделения экрана."</string>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 884e590..cef1091 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ඔබ ඈත දකුණු හෝ ඈත වම් දාරයේ සිට ස්වයිප් කරන බව සහතික කර ගන්න"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ඔබ දකුණු හෝ වම් දාරයේ සිට තිරයේ මැදට ස්වයිප් කර අත හරින බව සහතික කර ගන්න"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"ආපසු යාමට දකුණේ සිට ස්වයිප් කරන්නේ කෙසේදැයි ඔබ දැන ගත්තේය. ඊළඟට, යෙදුම් මාරු කරන ආකාරය දැන ගන්න."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"ඔබ ආපසු යාමේ ඉංගිතය සම්පූර්ණ කරන ලදි. ඊළඟට, යෙදුම් මාරු කරන ආකාරය දැන ගන්න."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"ඔබ ආපසු යාමේ ඉංගිතය සම්පූර්ණ කළා"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ඔබ තිරයේ පහළට ඉතාම සමීපව ස්වයිප් නොකරන බවට සහතික කර ගන්න"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"ආපසු ඉංගිතයෙහි සංවේදීතාව වෙනස් කිරීමට, සැකසීම් වෙත යන්න"</string>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index 12ef302..22a7c0c 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Musíte potiahnuť úplne z pravého alebo ľavého okraja"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Musíte potiahnuť z pravého alebo ľavého okraja do stredu obrazovky a potom uvoľniť"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste sa prejsť späť potiahnutím sprava. V ďalšom kroku sa naučíte prepínať aplikácie."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Dokončili ste gesto na prechod späť. V ďalšom kroku sa naučíte, ako prepínať aplikácie."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Dokončili ste gesto na prechod späť"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Nesmiete potiahnuť príliš blízko dolnej časti obrazovky"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Ak chcete zmeniť citlivosť gesta Späť, prejdite do Nastavení"</string>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index a5ca1b8..a5d8d9f 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Pazite, da povlečete s skrajno desnega ali skrajno levega roba."</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Pazite, da povlečete z desnega ali levega roba do sredine zaslona in dvignete prst."</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Naučili ste se, kako povlečete z desne za vrnitev. Zdaj se naučite preklapljanja med aplikacijami."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Izvedli ste potezo za pomik nazaj. Zdaj se naučite preklapljanja med aplikacijami."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Izvedli ste potezo za pomik nazaj."</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Pazite, da ne povlečete preblizu dna zaslona."</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Občutljivost poteze za nazaj lahko spremenite v nastavitvah."</string>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 2d97e69..bf44975 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Sigurohu që të rrëshqasësh shpejt nga skaji më i djathtë ose më i majtë"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Sigurohu që të rrëshqasësh shpejt nga skaji i djathtë ose i majtë drejt mesit të ekranit dhe lëshoje"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ke mësuar si të rrëshqasësh shpejt nga e djathta për t\'u kthyer prapa. Në vijim do të mësosh se si t\'i ndërrosh aplikacionet."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"E ke përfunduar gjestin e kthimit prapa. Në vijim do të mësosh se si t\'i ndërrosh aplikacionet."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"E ke përfunduar gjestin e kthimit prapa"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Sigurohu që të mos rrëshqasësh shpejt shumë afër pjesës së poshtme të ekranit"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Për të ndryshuar ndjeshmërinë e gjestit të kthimit prapa, shko te \"Cilësimet\""</string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 2a31ffd..def58b8 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Обавезно превуците од саме десне или леве ивице"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Обавезно превуците од десне или леве ивице до средине екрана и отпустите"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Научили сте како да превлачите здесна да бисте се вратили уназад. Сада научите да замените апликације."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Довршили сте покрет за повратак. Сада сазнајте како да промените апликације."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Довршили сте покрет за повратак"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Никако не превлачите превише близу дна екрана"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Осетљивост пок. за назад можете да промените у Подешавањима"</string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 4e6fa29..58e5fc4 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Se till att du sveper ända från högerkanten eller vänsterkanten"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Se till att du sveper från den högra eller vänstra kanten till mitten av skärmen och sedan släpper"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Nu kan du svepa från höger för att gå tillbaka. Nu ska du få lära dig hur du byter mellan appar."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Du är klar med rörelsen för att gå tillbaka. Nu ska du få lära dig hur du byter mellan appar."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Du är klar med rörelsen för att gå tillbaka"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Se till att du inte sveper för nära skärmens nederkant"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Öppna inställningarna om du vill ändra rörelsens känslighet"</string>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index b6c23a5..a650ece 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Hakikisha unatelezesha kidole kutoka ukingo wa kulia au kushoto kabisa"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Hakikisha unatelezesha kidole kutoka ukingo wa kulia au kushoto hadi katikati ya skrini na uachilie"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Umejifunza jinsi ya kutelezesha kidole kuanzia kulia ili kurudi nyuma. Sasa jifunze jinsi ya kubadilisha programu."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Umekamilisha ishara ya kurudi nyuma. Hatua inayofuata, jifunze jinsi ya kubadilisha programu."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Umeweka ishara ya kurudi nyuma"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Hakikisha hutelezeshi kidole karibu sana na sehemu ya chini ya skrini"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Kubadilisha hisi ya ishara ya nyuma, nenda kwenye Mipangilio"</string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index c4e39d8..cf5806c 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"வலது அல்லது இடது ஓரத்தின் விளிம்பிலிருந்து ஸ்வைப் செய்வதை உறுதிசெய்துகொள்ளுங்கள்"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"வலது அல்லது இடது ஓரத்திலிருந்து திரையின் மையப் பகுதிக்கு ஸ்வைப் செய்தபிறகு விடுவிப்பதை உறுதிசெய்க"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"பின்செல்வதற்கு எப்படி வலதுபுறத்திலிருந்து ஸ்வைப் செய்வதென்று கற்றுக்கொண்டீர்கள். அடுத்து ஆப்ஸுக்கிடையே எப்படி மாறுவது என்பதை அறிக."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"பின்செல் சைகைப் பயிற்சியை முடித்துவிட்டீர்கள். அடுத்து, ஆப்ஸுக்கிடையே மாறுவது எப்படி என்பதை அறிக."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"பின்செல் சைகைப் பயிற்சியை நிறைவுசெய்துவிட்டீர்கள்"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"திரையின் கீழ்ப்பகுதிக்கு மிக நெருக்கமாக ஸ்வைப் செய்யவில்லை என்பதை உறுதிசெய்துகொள்ளுங்கள்"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"பின்செல் சைகையின் உணர்திறனை மாற்ற அமைப்புகளுக்குச் செல்க"</string>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index d32ce5d..14bb314 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"కుడి వైపు చిట్ట చివరి లేదా ఎడమ వైపు చిట్ట చివరి అంచు నుండి స్వైప్ చేస్తున్నారని నిర్ధారించుకోండి"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"మీరు కుడి లేదా ఎడమ అంచు నుండి స్క్రీన్ మధ్యలోకి స్వైప్ చేశారని నిర్ధారించుకుని, మీ వేలిని ఎత్తండి"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"వెనుకకు వెళ్లడానికి కుడి నుండి స్వైప్ ఎలానో మీకు తెలుసు. తర్వాత, యాప్ల మధ్య ఎలా మారాలో తెలుసుకోండి."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"మీరు తిరిగి వెనక్కు వెళ్లే సంజ్ఞను పూర్తి చేశారు. తర్వాత, యాప్ల మధ్య ఎలా మారాలో తెలుసుకోండి."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"మీరు పేజీ నుండి వెనుకకు వెళ్లే సంజ్ఞను పూర్తి చేశారు"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"మీరు స్క్రీన్ దిగువకు చాలా దగ్గరగా స్వైప్ చేయకుండా చూసుకోండి"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"వెనుక సంజ్ఞ సున్నితత్వం మార్చడానికి, సెట్టింగ్లకు వెళ్లండి"</string>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index fe8ec8e..3b246d6 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"ตรวจสอบว่าปัดจากขอบด้านขวาสุดหรือซ้ายสุด"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"ตรวจสอบว่าปัดจากขอบด้านขวาหรือซ้ายไปตรงกลางหน้าจอ แล้วยกนิ้วขึ้น"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"คุณรู้วิธีปัดจากด้านขวาเพื่อย้อนกลับแล้ว ต่อไปดูวิธีสลับแอป"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับเสร็จแล้ว ต่อไปดูวิธีสลับแอป"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"คุณทำท่าทางสัมผัสเพื่อย้อนกลับเสร็จแล้ว"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"ไม่ปัดใกล้กับด้านล่างของหน้าจอมากเกินไป"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"เปลี่ยนความไวของท่าทางสัมผัสเพื่อย้อนกลับได้ที่การตั้งค่า"</string>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index b8c86c6..1ca5064 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Tiyaking magsa-swipe ka mula sa dulong kanan o dulong kaliwang gilid"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Tiyaking magsa-swipe mula sa kanan o kaliwang gilid papunta sa gitna ng screen at iangat ang daliri"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Natuto kang mag-swipe mula sa kanan para bumalik. Sunod, alamin kung paano magpalipat-lipat ng app."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Nakumpleto mo na ang galaw para bumalik. Susunod, alamin kung paano magpalipat-lipat sa mga app."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Nakumpleto mo na ang galaw para bumalik"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Tiyaking hindi ka magsa-swipe nang masyadong malapit sa ibaba ng screen"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Pumunta sa Settings para baguhin ang sensitivity ng pagbalik"</string>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index b96cbfa..efd907a 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"En sağ veya en sol kenardan kaydırdığınızdan emin olun"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Ekranın sağ veya sol kenarından ortasına doğru sürükleyip bıraktığınızdan emin olun."</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Geri dönmek için sağdan kaydırmayı öğrendiniz. Sırada uygulamalar arasında geçiş yapma var."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Geri dön hareketini tamamladınız. Sırada, uygulamalar arasında geçiş yapmayı öğrenmek var."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Geri dön hareketini tamamladınız"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Ekranın alt kısmına çok yakın bir şekilde kaydırmadığınızdan emin olun"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Geri hareketinin hassasiyetini değiştirmek için Ayarlar\'a gidin"</string>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index e6030e6..e18ddf5 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Проведіть пальцем від самого краю екрана (правого або лівого)"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Проведіть пальцем від правого або лівого краю до середини екрана й підніміть палець"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Тепер ви знаєте, як повернутися на попередній екран, провівши пальцем справа наліво. Дізнайтеся, як переключатися між додатками."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Ви виконали жест \"Назад\". Тепер дізнайтеся, як переходити між додатками."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Ви виконали жест \"Назад\""</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Не проводьте пальцем надто близько до нижнього краю екрана"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Щоб змінити чутливість жесту \"Назад\", відкрийте налаштування"</string>
@@ -95,10 +96,10 @@
<string name="action_screenshot" msgid="8171125848358142917">"Знімок екрана"</string>
<string name="action_split" msgid="2098009717623550676">"Розділити"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Щоб розділити екран, виберіть ще один додаток"</string>
- <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Щоб розділити екран, виберіть ще один додаток"</string>
+ <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Щоб розділити екран, виберіть ще один додаток."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Скасувати"</b></string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Вийти з режиму розділення екрана"</string>
- <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Щоб розділити екран, виберіть ще один додаток"</string>
+ <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Щоб розділити екран, виберіть ще один додаток."</string>
<string name="blocked_by_policy" msgid="2071401072261365546">"Ця дія заборонена додатком або адміністратором організації"</string>
<string name="split_widgets_not_supported" msgid="1355743038053053866">"Віджети наразі не підтримуються. Виберіть інший додаток."</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Пропустити посібник із навігації?"</string>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 66839ae..9beaf07 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"یقینی بنائیں کہ آپ دائیں یا بائیں کنارے سے دور سے سوائپ کریں"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"یقینی بنائیں کہ آپ دائیں یا بائیں کنارے سے اسکرین کے وسط تک سوائپ کریں اور پھر اپنی انگلی اٹھا لیں"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"آپ نے واپس جانے کے لیے دائیں کنارے سے سوائپ کرنے کا طریقہ سیکھ لیا۔ اس کے بعد ایپس سوئچ کرنے کا طریقہ جانیں۔"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"آپ نے واپس جائیں اشارے کو مکمل کر لیا۔ اس کے بعد ایپس سوئچ کرنے کا طریقہ جانیں۔"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"آپ نے واپس جائیں اشارے کو مکمل کر لیا"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"اس بات کو یقینی بنائیں کہ آپ اسکرین کے نچلے حصے سے زیادہ قریب سے سوائپ نہ کریں"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"پچھلے اشارے کی حساسیت تبدیل کرنے کے لیے ترتیبات پر جائیں"</string>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 3a942cd..532fd92 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Ekran chetidan boshlab oʻngdan yoki chapdan suring"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Ekranning oʻng yoki chap chetidan oʻrtasigacha suring va qoʻyib yuboring"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ortga qaytish uchun oʻngdan surishni oʻrgandingiz. Endi ilovalarni almashtirishni oʻrganamiz."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Ortga qaytish ishorasi darsini tamomladingiz. Endi ilovalarni almashtirishni oʻrganamiz."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Ortga qaytish ishorasi darsini tamomladingiz"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Barmoqni ekran pastiga yaqin surmaslikka harakat qiling"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Orqaga ishorasi sezuvchanligi Sozlamalardan oʻzgartiriladi"</string>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index fbd8608..bc03d2c 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Hãy vuốt từ mép ngoài cùng bên phải hoặc ngoài cùng bên trái"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Hãy vuốt từ mép phải hoặc mép trái tới giữa màn hình rồi nhấc ngón tay ra"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Bạn đã học được cách vuốt từ mép phải để quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Bạn đã thực hiện xong cử chỉ quay lại. Tiếp theo, hãy tìm hiểu cách chuyển đổi ứng dụng."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Bạn đã thực hiện xong cử chỉ quay lại"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Hãy nhớ không được vuốt quá gần phần dưới cùng của màn hình"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Để thay đổi độ nhạy của cử chỉ quay lại, hãy vào mục Cài đặt"</string>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index ab61f15..7713a59 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"确保从最右侧或最左侧边缘开始滑动"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"确保从右侧或左侧边缘滑动到屏幕中间位置后再松开手指"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"您已了解如何使用“从右侧向左滑动”手势返回。接下来学习切换应用吧!"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"您完成了“返回”手势教程。接下来了解如何切换应用。"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"您完成了“返回”手势"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"确保滑动时手的位置不要太靠近屏幕底部"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"如要调节“返回”手势的灵敏度,请转到“设置”"</string>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 8e7c2e6..e4d43ba 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"請確保從螢幕最右側或最左側邊緣滑動"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"請確保從螢幕右側或左側邊緣往中央滑動,然後放開手指"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"你已瞭解如何透過「由右向左滑動」手勢返回。接下來一起瞭解如何切換應用程式。"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"你已完成「返回」手勢的教學課程。接下來一起瞭解如何切換應用程式。"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"你已完成「返回」手勢的教學課程"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"滑動時,手的位置不要太接近螢幕底部"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"如要變更「返回」手勢的敏感度,請前往「設定」"</string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index e9b860d..bf7b764 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"請務必從螢幕最右側或最左側滑動"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"請務必從螢幕右側或左側往中央滑動,然後放開手指"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"你已瞭解如何透過「由右向左滑動」手勢返回。接著,一起來瞭解如何切換應用程式。"</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"你已完成「返回」手勢的教學課程。接著,一起來瞭解如何切換應用程式。"</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"你已完成「返回」手勢的教學課程"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"滑動時,手的位置不要太接近螢幕底部"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"如要變更「返回」手勢的敏感度,請前往「設定」"</string>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index d2a7e70..bf5a1b7 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -49,6 +49,7 @@
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"Qinisekisa ukuthi uswayipha ukusuka onqenqemeni olukude ngakwesokudla noma olukude ngakwesokunxele"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"Qinisekisa ukuthi uswayipha ukusuka kunqenqema olungakwesokudla noma olungakwesokunxele ukuya maphakathi nesikrini bese uyadedela."</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"Ufunde indlela yokuswayipha kusuka kwesokudla ukuze ubuyele emuva. Ngokulandelayo, funda indlela yokushintsha ama-app."</string>
+ <string name="back_gesture_feedback_complete_with_follow_up" msgid="8653374779579748392">"Ukuqedile ukuthinta kokubuyela emuva. Ngokulandelayo, funda indlela yokushintsha ama-app."</string>
<string name="back_gesture_feedback_complete_without_follow_up" msgid="197189945858268342">"Ukuqedile ukuthinta kokubuyela emuva"</string>
<string name="back_gesture_feedback_swipe_in_nav_bar" msgid="9157480023651452969">"Qinisekisa ukuba awuswayipheli eduze kakhulu naphansi kwesikrini"</string>
<string name="back_gesture_tutorial_confirm_subtitle" msgid="5181305411668713250">"Ukuze ushintshe ukuzwela kokuthinta emuva, iya Kumasethingi"</string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 68bad5c..853ac74 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -32,8 +32,11 @@
<dimen name="overview_minimum_next_prev_size">50dp</dimen>
<!-- Overview Task Views -->
- <!-- The primary task thumbnail uses up to this much of the total screen height/width -->
+ <!-- The thumbnail uses up to this much of the total screen height/width in Overview -->
<item name="overview_max_scale" format="float" type="dimen">0.7</item>
+ <!-- The thumbnail should not go smaller than this much of the total screen height/width in
+ tablet app to Overview carousel -->
+ <item name="overview_carousel_min_scale" format="float" type="dimen">0.46</item>
<!-- A touch target for icons, sometimes slightly larger than the icons themselves -->
<dimen name="task_thumbnail_icon_size">48dp</dimen>
<!-- The icon size for the focused task, placed in center of touch target -->
diff --git a/quickstep/res/values/override.xml b/quickstep/res/values/override.xml
index 29779a7..cba1f5b 100644
--- a/quickstep/res/values/override.xml
+++ b/quickstep/res/values/override.xml
@@ -33,6 +33,8 @@
<string name="taskbar_model_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarModelCallbacksFactory</string>
+ <string name="taskbar_view_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarViewCallbacksFactory</string>
+
<string name="assist_state_manager_class" translatable="false"></string>
<string name="launcher_restore_event_logger_class" translatable="false">com.android.quickstep.LauncherRestoreEventLoggerImpl</string>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index 325c255..14f615e 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -105,6 +105,8 @@
<string name="back_gesture_feedback_cancelled">Make sure you swipe from the right or left edge to the middle of the screen and let go</string>
<!-- Feedback shown after completing the back gesture step if the user is following the full gesture tutorial flow. [CHAR LIMIT=100] -->
<string name="back_gesture_feedback_complete_with_overview_follow_up">You learned how to swipe from the right to go back. Next up, learn how to switch apps.</string>
+ <!-- Feedback shown after completing the back gesture step if the user is following the full gesture tutorial flow. [CHAR LIMIT=100] -->
+ <string name="back_gesture_feedback_complete_with_follow_up">You completed the go back gesture. Next up, learn how to switch apps.</string>
<!-- Feedback shown after completing the back gesture step if the user started this tutorial individually. [CHAR LIMIT=100] -->
<string name="back_gesture_feedback_complete_without_follow_up">You completed the go back gesture</string>
<!-- Feedback shown during interactive parts of Back gesture tutorial when the gesture is within the nav bar region. [CHAR LIMIT=100] -->
diff --git a/quickstep/res/values/styles.xml b/quickstep/res/values/styles.xml
index bdc86b2..350c752 100644
--- a/quickstep/res/values/styles.xml
+++ b/quickstep/res/values/styles.xml
@@ -273,7 +273,7 @@
</style>
<style name="KeyboardQuickSwitchText.OnBackground" parent="KeyboardQuickSwitchText">
- <item name="android:textColor">?androidprv:attr/materialColorOnSurfaceInverse</item>
+ <item name="android:textColor">?androidprv:attr/materialColorOnSurface</item>
</style>
<style name="GestureTutorialActivity" parent="@style/AppTheme">
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index 436fe3b..68e7824 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.ClipData;
import android.content.ClipDescription;
@@ -50,7 +51,6 @@
/** An Activity that can host Launcher's widget picker. */
public class WidgetPickerActivity extends BaseActivity {
private static final String TAG = "WidgetPickerActivity";
- private static final boolean DEBUG = false;
/**
* Name of the extra that indicates that a widget being dragged.
@@ -65,13 +65,13 @@
private static final String EXTRA_DESIRED_WIDGET_WIDTH = "desired_widget_width";
private static final String EXTRA_DESIRED_WIDGET_HEIGHT = "desired_widget_height";
-
private SimpleDragLayer<WidgetPickerActivity> mDragLayer;
private WidgetsModel mModel;
private final PopupDataProvider mPopupDataProvider = new PopupDataProvider(i -> {});
private int mDesiredWidgetWidth;
private int mDesiredWidgetHeight;
+ private int mWidgetCategoryFilter;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -104,6 +104,10 @@
mDesiredWidgetHeight =
getIntent().getIntExtra(EXTRA_DESIRED_WIDGET_HEIGHT, 0);
+ // Defaults to '0' to indicate that there isn't a category filter.
+ mWidgetCategoryFilter =
+ getIntent().getIntExtra(AppWidgetManager.EXTRA_CATEGORY_FILTER, 0);
+
refreshAndBindWidgets();
}
@@ -199,6 +203,14 @@
return rejectWidget(widget, "shortcut");
}
+ if (mWidgetCategoryFilter > 0 && (info.widgetCategory & mWidgetCategoryFilter) == 0) {
+ return rejectWidget(
+ widget,
+ "doesn't match category filter [filter=%d, widget=%d]",
+ mWidgetCategoryFilter,
+ info.widgetCategory);
+ }
+
if (mDesiredWidgetWidth == 0 && mDesiredWidgetHeight == 0) {
// Accept the widget if the desired dimensions are unspecified.
return acceptWidget(widget);
@@ -210,22 +222,18 @@
if (info.maxResizeWidth > 0 && info.maxResizeWidth < mDesiredWidgetWidth) {
return rejectWidget(
widget,
- String.format(
- Locale.ENGLISH,
- "maxResizeWidth[%d] < mDesiredWidgetWidth[%d]",
- info.maxResizeWidth,
- mDesiredWidgetWidth));
+ "maxResizeWidth[%d] < mDesiredWidgetWidth[%d]",
+ info.maxResizeWidth,
+ mDesiredWidgetWidth);
}
final int minWidth = info.minResizeWidth > 0 ? info.minResizeWidth : info.minWidth;
if (minWidth > mDesiredWidgetWidth) {
return rejectWidget(
widget,
- String.format(
- Locale.ENGLISH,
- "minWidth[%d] > mDesiredWidgetWidth[%d]",
- minWidth,
- mDesiredWidgetWidth));
+ "minWidth[%d] > mDesiredWidgetWidth[%d]",
+ minWidth,
+ mDesiredWidgetWidth);
}
}
@@ -235,22 +243,18 @@
if (info.maxResizeHeight > 0 && info.maxResizeHeight < mDesiredWidgetHeight) {
return rejectWidget(
widget,
- String.format(
- Locale.ENGLISH,
- "maxResizeHeight[%d] < mDesiredWidgetHeight[%d]",
- info.maxResizeHeight,
- mDesiredWidgetHeight));
+ "maxResizeHeight[%d] < mDesiredWidgetHeight[%d]",
+ info.maxResizeHeight,
+ mDesiredWidgetHeight);
}
final int minHeight = info.minResizeHeight > 0 ? info.minResizeHeight : info.minHeight;
if (minHeight > mDesiredWidgetHeight) {
return rejectWidget(
widget,
- String.format(
- Locale.ENGLISH,
- "minHeight[%d] > mDesiredWidgetHeight[%d]",
- minHeight,
- mDesiredWidgetHeight));
+ "minHeight[%d] > mDesiredWidgetHeight[%d]",
+ minHeight,
+ mDesiredWidgetHeight);
}
}
@@ -264,8 +268,11 @@
}
private static WidgetAcceptabilityVerdict rejectWidget(
- WidgetItem widget, String rejectionReason) {
- return new WidgetAcceptabilityVerdict(false, widget.label, rejectionReason);
+ WidgetItem widget, String rejectionReason, Object... args) {
+ return new WidgetAcceptabilityVerdict(
+ false,
+ widget.label,
+ String.format(Locale.ENGLISH, rejectionReason, args));
}
private static WidgetAcceptabilityVerdict acceptWidget(WidgetItem widget) {
@@ -276,7 +283,7 @@
boolean isAcceptable, String widgetLabel, String reason) {
void maybeLogVerdict() {
// Only log a verdict if a reason is specified.
- if (DEBUG && !reason.isEmpty()) {
+ if (Log.isLoggable(TAG, Log.DEBUG) && !reason.isEmpty()) {
Log.i(TAG, String.format(
Locale.ENGLISH,
"%s: %s because %s",
diff --git a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
index 037f7a8..694475a 100644
--- a/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
+++ b/quickstep/src/com/android/launcher3/appprediction/AppsDividerView.java
@@ -77,19 +77,15 @@
public AppsDividerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- boolean isMainColorDark = Themes.getAttrBoolean(context, R.attr.isMainColorDark);
mDividerSize = new int[]{
getResources().getDimensionPixelSize(R.dimen.all_apps_divider_width),
getResources().getDimensionPixelSize(R.dimen.all_apps_divider_height)
};
- mStrokeColor = ContextCompat.getColor(context, isMainColorDark
- ? R.color.all_apps_prediction_row_separator_dark
- : R.color.all_apps_prediction_row_separator);
+ mStrokeColor = ContextCompat.getColor(context, R.color.material_color_outline_variant);
- mAllAppsLabelTextColor = ContextCompat.getColor(context, isMainColorDark
- ? R.color.all_apps_label_text_dark
- : R.color.all_apps_label_text);
+ mAllAppsLabelTextColor = ContextCompat.getColor(context,
+ R.color.material_color_on_surface_variant);
mShowAllAppsLabel = !ALL_APPS_VISITED_COUNT.hasReachedMax(context);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
index 2421c94..3e262e5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchViewController.java
@@ -32,7 +32,6 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
-import com.android.launcher3.taskbar.overlay.TaskbarOverlayDragLayer;
import com.android.quickstep.SystemUiProxy;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.SlideInRemoteTransition;
@@ -84,9 +83,7 @@
boolean updateTasks,
int currentFocusIndexOverride,
boolean onDesktop) {
- TaskbarOverlayDragLayer dragLayer = mOverlayContext.getDragLayer();
- dragLayer.addView(mKeyboardQuickSwitchView);
- dragLayer.runOnClickOnce(v -> closeQuickSwitchView(true));
+ mOverlayContext.getDragLayer().addView(mKeyboardQuickSwitchView);
mOnDesktop = onDesktop;
mKeyboardQuickSwitchView.applyLoadPlan(
diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
index 37e5309..50e8d0e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java
@@ -176,6 +176,7 @@
/**
* Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
*/
+ @Override
public void onLauncherVisibilityChanged(boolean isVisible) {
onLauncherVisibilityChanged(isVisible, false /* fromInit */);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 55deca8..b69f657 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -36,12 +36,14 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
+import static com.android.launcher3.taskbar.TaskbarDragLayerController.TASKBAR_REAPPEAR_DELAY_MS;
import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
@@ -77,6 +79,7 @@
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.config.FeatureFlags;
@@ -1377,6 +1380,23 @@
});
}
+ public void hideTaskbarWhenFolding() {
+ AnimatedFloat alphaAnim = mControllers.taskbarDragLayerController.getTaskbarAlpha();
+ alphaAnim.cancelAnimation();
+ alphaAnim.updateValue(0);
+ ObjectAnimator animator = alphaAnim.animateToValue(1).setDuration(0);
+ animator.setStartDelay(TASKBAR_REAPPEAR_DELAY_MS);
+ animator.start();
+ }
+
+ public void cancelHideTaskbarWhenFolding() {
+ mControllers.taskbarDragLayerController.getTaskbarAlpha().cancelAnimation();
+ }
+
+ public void resetHideTaskbarWhenUnfolding() {
+ mControllers.taskbarDragLayerController.getTaskbarAlpha().updateValue(1);
+ }
+
protected boolean isUserSetupComplete() {
return mIsUserSetupComplete;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 3f5402f..74eda24 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -44,6 +44,12 @@
private static final boolean DEBUG = SystemProperties.getBoolean(
"persist.debug.draw_taskbar_debug_ui", false);
+ // Delay to reset the task bar alpha back to 1 after fading it for transition from unfold to
+ // fold. Normally this is not needed since the new task bar is recreated after fading, but in
+ // case something goes wrong this provides a fallback mechanism to make sure the task bar is
+ // visible after the transition finishes.
+ public static final long TASKBAR_REAPPEAR_DELAY_MS = 2000;
+
private final TaskbarActivityContext mActivity;
private final TaskbarDragLayer mTaskbarDragLayer;
private final int mFolderMargin;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index b8e6889..aa457ca 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -24,11 +24,13 @@
import android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR
import android.os.Binder
import android.os.IBinder
+import android.view.DisplayInfo
import android.view.Gravity
import android.view.InsetsFrameProvider
import android.view.InsetsFrameProvider.SOURCE_DISPLAY
import android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER
import android.view.InsetsSource.FLAG_SUPPRESS_SCRIM
+import android.view.Surface
import android.view.ViewTreeObserver
import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME
import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
@@ -155,19 +157,20 @@
}
val gravity = windowLayoutParams.gravity
- for (provider in windowLayoutParams.providedInsets) {
- setProviderInsets(provider, gravity)
- }
- if (windowLayoutParams.paramsForRotation != null) {
+ // 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
- for (layoutParams in windowLayoutParams.paramsForRotation) {
+ if (windowLayoutParams.paramsForRotation != null) {
+ val layoutParams = windowLayoutParams.paramsForRotation[rotation]
for (provider in layoutParams.providedInsets) {
- setProviderInsets(provider, layoutParams.gravity)
+ setProviderInsets(provider, layoutParams.gravity, rotation)
}
}
+ for (provider in windowLayoutParams.providedInsets) {
+ setProviderInsets(provider, gravity, rotation)
+ }
}
-
context.notifyUpdateLayoutParams()
}
@@ -211,12 +214,12 @@
)
}
- private fun setProviderInsets(provider: InsetsFrameProvider, gravity: Int) {
+ private fun setProviderInsets(provider: InsetsFrameProvider, gravity: Int, endRotation: Int) {
val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
val res = context.resources
if (provider.type == navigationBars() || provider.type == mandatorySystemGestures()) {
- provider.insetsSize = getInsetsForGravity(contentHeight, gravity)
+ provider.insetsSize = getInsetsForGravityWithCutout(contentHeight, gravity, endRotation)
} else if (provider.type == tappableElement()) {
provider.insetsSize = getInsetsForGravity(tappableHeight, gravity)
} else if (provider.type == systemGestures() && provider.index == INDEX_LEFT) {
@@ -275,6 +278,30 @@
}
/**
+ * Calculate the [Insets] for taskbar after a rotation, specifically for any potential cutouts
+ * in the screen that can come from the camera.
+ */
+ private fun getInsetsForGravityWithCutout(inset: Int, gravity: Int, rot: Int): Insets {
+ val display = context.display
+ // If there is no cutout, fall back to the original method of calculating insets
+ val cutout = display.cutout ?: return getInsetsForGravity(inset, gravity)
+ val rotation = display.rotation
+ val info = DisplayInfo()
+ display.getDisplayInfo(info)
+ val rotatedCutout = cutout.getRotated(info.logicalWidth, info.logicalHeight, rotation, rot)
+
+ if ((gravity and Gravity.BOTTOM) == Gravity.BOTTOM) {
+ return Insets.of(0, 0, 0, maxOf(inset, rotatedCutout.safeInsetBottom))
+ }
+
+ // TODO(b/230394142): seascape
+ val isSeascape = (gravity and Gravity.START) == Gravity.START
+ val leftInset = if (isSeascape) maxOf(inset, rotatedCutout.safeInsetLeft) else 0
+ val rightInset = if (isSeascape) 0 else maxOf(inset, rotatedCutout.safeInsetRight)
+ return Insets.of(leftInset, 0, rightInset, 0)
+ }
+
+ /**
* @return [Insets] where the [inset] is either used as a bottom inset or right/left inset if
* using 3 button nav
*/
@@ -309,9 +336,11 @@
controllers.bubbleControllers.isPresent &&
controllers.bubbleControllers.get().bubbleBarViewController.isBubbleBarVisible()
var insetsIsTouchableRegion = true
- if (context.isPhoneButtonNavMode &&
- (!controllers.navbarButtonsViewController.isImeVisible
- || !controllers.navbarButtonsViewController.isImeRenderingNavButtons)) {
+ if (
+ context.isPhoneButtonNavMode &&
+ (!controllers.navbarButtonsViewController.isImeVisible ||
+ !controllers.navbarButtonsViewController.isImeRenderingNavButtons)
+ ) {
insetsInfo.setTouchableInsets(TOUCHABLE_INSETS_FRAME)
insetsIsTouchableRegion = false
} else if (context.dragLayer.alpha < AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 7c7c426..4dd2f44 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -30,6 +30,7 @@
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING;
import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
+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.FlagDebugUtils.formatFlagChange;
import static com.android.quickstep.util.SystemActionConstants.ACTION_SHOW_TASKBAR;
@@ -43,6 +44,7 @@
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
+import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Handler;
@@ -109,6 +111,7 @@
private final Context mContext;
private final @Nullable Context mNavigationBarPanelContext;
+ private final DeviceStateManager mDeviceStateManager;
private WindowManager mWindowManager;
private FrameLayout mTaskbarRootLayout;
private boolean mAddedWindow;
@@ -175,7 +178,8 @@
}
};
- UnfoldTransitionProgressProvider.TransitionProgressListener mUnfoldTransitionProgressListener =
+ private final UnfoldTransitionProgressProvider.TransitionProgressListener
+ mUnfoldTransitionProgressListener =
new UnfoldTransitionProgressProvider.TransitionProgressListener() {
@Override
public void onTransitionStarted() {
@@ -204,6 +208,9 @@
}
};
+ private final DeviceStateManager.FoldStateListener mFoldStateListener;
+ private Boolean mFolded;
+
@SuppressLint("WrongConstant")
public TaskbarManager(TouchInteractionService service) {
Display display =
@@ -229,6 +236,29 @@
}
};
}
+ // Temporary solution to mitigate the visual jump from folding the device. Currently, the
+ // screen turns on much earlier than we receive the onConfigurationChanged callback or
+ // receiving the correct device profile. While the ideal the solution is to align turning
+ // the screen on after onConfigurationChanged (by either delaying turning on the screen or
+ // figuring out what is causing the delay in getting onConfigurationChanged callback), one
+ // easy temporary mitigation is to dimming the bar so that the visual jump isn't as glaring.
+ mFoldStateListener = new DeviceStateManager.FoldStateListener(mContext, folded -> {
+ boolean firstTime = mFolded == null;
+ if (mTaskbarActivityContext == null) {
+ return;
+ }
+ if (!firstTime && mFolded.booleanValue() != folded) {
+ mTaskbarActivityContext.cancelHideTaskbarWhenFolding();
+ }
+ mFolded = folded;
+ if (folded && !firstTime) {
+ mTaskbarActivityContext.hideTaskbarWhenFolding();
+ } else {
+ mTaskbarActivityContext.resetHideTaskbarWhenUnfolding();
+ }
+ });
+ mDeviceStateManager = mContext.getSystemService(DeviceStateManager.class);
+ mDeviceStateManager.registerCallback(MAIN_EXECUTOR, mFoldStateListener);
mNavButtonController = new TaskbarNavButtonController(service,
SystemUiProxy.INSTANCE.get(mContext), new Handler(),
AssistUtils.newInstance(mContext));
@@ -588,6 +618,7 @@
Log.d(TASKBAR_NOT_DESTROYED_TAG, "unregistering component callbacks from destroy().");
mContext.unregisterComponentCallbacks(mComponentCallbacks);
mContext.unregisterReceiver(mShutdownReceiver);
+ mDeviceStateManager.unregisterCallback(mFoldStateListener);
}
public @Nullable TaskbarActivityContext getCurrentActivityContext() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 7a69c55..8db343f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -120,8 +120,7 @@
*
* Use {@link #getStashDuration()} to query duration
*/
- private static final long TASKBAR_STASH_DURATION =
- InsetsController.ANIMATION_DURATION_RESIZE;
+ private static final long TASKBAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE;
/**
* How long to stash/unstash transient taskbar.
@@ -803,6 +802,11 @@
private void addJankMonitorListener(
AnimatorSet animator, boolean expanding, @StashAnimation int animationType) {
View v = mControllers.taskbarActivityContext.getDragLayer();
+ if (!v.isAttachedToWindow()) {
+ // If the task bar drag layer is not attached to window, we don't need to monitor jank
+ // (actually we can't pass in an unattached view either).
+ return;
+ }
int action = expanding ? InteractionJankMonitor.CUJ_TASKBAR_EXPAND :
InteractionJankMonitor.CUJ_TASKBAR_COLLAPSE;
animator.addListener(new AnimatorListenerAdapter() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
index 916b1e6..144c0c2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarTranslationController.java
@@ -53,6 +53,7 @@
private boolean mHasSprungOnceThisGesture;
private @Nullable ValueAnimator mSpringBounce;
+ private boolean mGestureInProgress;
private boolean mGestureEnded;
private boolean mAnimationToHomeRunning;
@@ -155,7 +156,12 @@
/**
* Returns an animation to reset the taskbar translation to {@code 0}.
*/
- public ObjectAnimator createAnimToResetTranslation(long duration) {
+ public ValueAnimator createAnimToResetTranslation(long duration) {
+ if (mGestureInProgress) {
+ // Return an empty animator as the translation will reset itself after gesture ends.
+ return ValueAnimator.ofFloat(0).setDuration(duration);
+ }
+
ObjectAnimator animator = mTranslationYForSwipe.animateToValue(0);
animator.setInterpolator(Interpolators.LINEAR);
animator.setDuration(duration);
@@ -192,6 +198,7 @@
mAnimationToHomeRunning = false;
cancelSpringIfExists();
reset();
+ mGestureInProgress = true;
}
/**
* Called when there is movement to move the taskbar.
@@ -215,6 +222,7 @@
mGestureEnded = true;
startSpring();
}
+ mGestureInProgress = false;
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index bb2ac73..8a26054 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -358,4 +358,13 @@
/** Adjusts the hotseat for the bubble bar. */
public void adjustHotseatForBubbleBar(boolean isBubbleBarVisible) {}
+
+ /**
+ * Adjusts the taskbar based on the visibility of the launcher.
+ * @param isVisible True if launcher is visible, false otherwise.
+ */
+ public void onLauncherVisibilityChanged(boolean isVisible) {
+ mControllers.taskbarStashController.updateStateForFlag(FLAG_IN_APP, !isVisible);
+ mControllers.taskbarStashController.applyState();
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 666d98e..d9e2330 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -85,7 +85,7 @@
private final TaskbarActivityContext mActivityContext;
// Initialized in init.
- private TaskbarViewController.TaskbarViewCallbacks mControllerCallbacks;
+ private TaskbarViewCallbacks mControllerCallbacks;
private View.OnClickListener mIconClickListener;
private View.OnLongClickListener mIconLongClickListener;
@@ -258,7 +258,7 @@
return mIconTouchSize;
}
- protected void init(TaskbarViewController.TaskbarViewCallbacks callbacks) {
+ protected void init(TaskbarViewCallbacks callbacks) {
// set taskbar pane title so that accessibility service know it window and focuses.
setAccessibilityPaneTitle(getContext().getString(R.string.taskbar_a11y_title));
mControllerCallbacks = callbacks;
@@ -267,6 +267,10 @@
if (mAllAppsButton != null) {
mAllAppsButton.setOnClickListener(mControllerCallbacks.getAllAppsButtonClickListener());
+ mAllAppsButton.setOnLongClickListener(
+ mControllerCallbacks.getAllAppsButtonLongClickListener());
+ mAllAppsButton.setHapticFeedbackEnabled(
+ mControllerCallbacks.isAllAppsButtonHapticFeedbackEnabled());
}
if (mTaskbarDivider != null) {
mTaskbarDivider.setOnLongClickListener(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
new file mode 100644
index 0000000..c841cac
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacks.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar;
+
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
+
+import android.view.InputDevice;
+import android.view.MotionEvent;
+import android.view.View;
+
+import com.android.internal.jank.Cuj;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
+
+/**
+ * Callbacks for {@link TaskbarView} to interact with its controller.
+ */
+public class TaskbarViewCallbacks {
+
+ private final TaskbarActivityContext mActivity;
+ private final TaskbarControllers mControllers;
+ private final TaskbarView mTaskbarView;
+
+ public TaskbarViewCallbacks(TaskbarActivityContext activity, TaskbarControllers controllers,
+ TaskbarView taskbarView) {
+ mActivity = activity;
+ mControllers = controllers;
+ mTaskbarView = taskbarView;
+ }
+
+ public View.OnClickListener getIconOnClickListener() {
+ return mActivity.getItemOnClickListener();
+ }
+
+ public View.OnClickListener getAllAppsButtonClickListener() {
+ return v -> {
+ InteractionJankMonitorWrapper.begin(v, Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS,
+ /* tag= */ "TASKBAR_BUTTON");
+ mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP);
+ mControllers.taskbarAllAppsController.toggle();
+ };
+ }
+
+ public View.OnLongClickListener getAllAppsButtonLongClickListener() {
+ return v -> {
+ mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS);
+ return true;
+ };
+ }
+
+ public boolean isAllAppsButtonHapticFeedbackEnabled() {
+ return false;
+ }
+
+ public View.OnLongClickListener getTaskbarDividerLongClickListener() {
+ return v -> {
+ mControllers.taskbarPinningController.showPinningView(v);
+ return true;
+ };
+ }
+
+ public View.OnTouchListener getTaskbarDividerRightClickListener() {
+ return (v, event) -> {
+ if (event.isFromSource(InputDevice.SOURCE_MOUSE)
+ && event.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
+ mControllers.taskbarPinningController.showPinningView(v);
+ return true;
+ }
+ return false;
+ };
+ }
+
+ public View.OnLongClickListener getIconOnLongClickListener() {
+ return mControllers.taskbarDragController::startDragOnLongClick;
+ }
+
+ /** Gets the hover listener for the provided icon view. */
+ public View.OnHoverListener getIconOnHoverListener(View icon) {
+ return new TaskbarHoverToolTipController(mActivity, mTaskbarView, icon);
+ }
+
+ /**
+ * Notifies launcher to update icon alignment.
+ */
+ public void notifyIconLayoutBoundsChanged() {
+ mControllers.uiController.onIconLayoutBoundsChanged();
+ }
+
+ /**
+ * Notifies the taskbar scrim when the visibility of taskbar changes.
+ */
+ public void notifyVisibilityChanged() {
+ mControllers.taskbarScrimViewController.onTaskbarVisibilityChanged(
+ mTaskbarView.getVisibility());
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacksFactory.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacksFactory.kt
new file mode 100644
index 0000000..ba0f5a0
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewCallbacksFactory.kt
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.content.Context
+import com.android.launcher3.R
+import com.android.launcher3.util.ResourceBasedOverride
+import com.android.launcher3.util.ResourceBasedOverride.Overrides
+
+/** Creates [TaskbarViewCallbacks] instances. */
+open class TaskbarViewCallbacksFactory : ResourceBasedOverride {
+
+ open fun create(
+ activity: TaskbarActivityContext,
+ controllers: TaskbarControllers,
+ taskbarView: TaskbarView,
+ ): TaskbarViewCallbacks = TaskbarViewCallbacks(activity, controllers, taskbarView)
+
+ companion object {
+ @JvmStatic
+ fun newInstance(context: Context): TaskbarViewCallbacksFactory {
+ return Overrides.getObject(
+ TaskbarViewCallbacksFactory::class.java,
+ context,
+ R.string.taskbar_view_callbacks_factory_class,
+ )
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 614dc14..5494853 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -26,7 +26,6 @@
import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT;
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
@@ -41,7 +40,6 @@
import android.annotation.NonNull;
import android.graphics.Rect;
import android.util.Log;
-import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
import android.view.animation.Interpolator;
@@ -193,7 +191,8 @@
public void init(TaskbarControllers controllers) {
mControllers = controllers;
- mTaskbarView.init(new TaskbarViewCallbacks());
+ mTaskbarView.init(TaskbarViewCallbacksFactory.newInstance(mActivity).create(
+ mActivity, mControllers, mTaskbarView));
mTaskbarView.getLayoutParams().height = mActivity.isPhoneMode()
? mActivity.getResources().getDimensionPixelSize(R.dimen.taskbar_phone_size)
: mActivity.getDeviceProfile().taskbarHeight;
@@ -891,66 +890,4 @@
mModelCallbacks.updateRunningApps();
}
- /**
- * Callbacks for {@link TaskbarView} to interact with its controller.
- */
- public class TaskbarViewCallbacks {
- private final float mSquaredTouchSlop = Utilities.squaredTouchSlop(mActivity);
-
- private float mDownX, mDownY;
- private boolean mCanceledStashHint;
-
- public View.OnClickListener getIconOnClickListener() {
- return mActivity.getItemOnClickListener();
- }
-
- public View.OnClickListener getAllAppsButtonClickListener() {
- return v -> {
- mActivity.getStatsLogManager().logger().log(LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP);
- mControllers.taskbarAllAppsController.toggle();
- };
- }
-
- public View.OnLongClickListener getTaskbarDividerLongClickListener() {
- return v -> {
- mControllers.taskbarPinningController.showPinningView(v);
- return true;
- };
- }
-
- public View.OnTouchListener getTaskbarDividerRightClickListener() {
- return (v, event) -> {
- if (event.isFromSource(InputDevice.SOURCE_MOUSE)
- && event.getButtonState() == MotionEvent.BUTTON_SECONDARY) {
- mControllers.taskbarPinningController.showPinningView(v);
- return true;
- }
- return false;
- };
- }
-
- public View.OnLongClickListener getIconOnLongClickListener() {
- return mControllers.taskbarDragController::startDragOnLongClick;
- }
-
- /** Gets the hover listener for the provided icon view. */
- public View.OnHoverListener getIconOnHoverListener(View icon) {
- return new TaskbarHoverToolTipController(mActivity, mTaskbarView, icon);
- }
-
- /**
- * Notifies launcher to update icon alignment.
- */
- public void notifyIconLayoutBoundsChanged() {
- mControllers.uiController.onIconLayoutBoundsChanged();
- }
-
- /**
- * Notifies the taskbar scrim when the visibility of taskbar changes.
- */
- public void notifyVisibilityChanged() {
- mControllers.taskbarScrimViewController.onTaskbarVisibilityChanged(
- mTaskbarView.getVisibility());
- }
- }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
index b1c5151..ba4fa45 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsViewController.java
@@ -20,6 +20,7 @@
import androidx.annotation.Nullable;
+import com.android.internal.jank.Cuj;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.allapps.AllAppsTransitionListener;
import com.android.launcher3.anim.PendingAnimation;
@@ -31,6 +32,7 @@
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
import com.android.launcher3.util.DisplayController;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import java.util.Optional;
@@ -136,6 +138,9 @@
&& mAppsView.getSearchUiManager().getEditText() != null) {
mAppsView.getSearchUiManager().getEditText().requestFocus();
}
+ if (toAllApps) {
+ InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_OPEN_ALL_APPS);
+ }
}
/** Invoked on back press, returning {@code true} if the search session handled it. */
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
index 41c3dec..73c71c8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
@@ -185,20 +185,23 @@
}
mMagnetizedObject.setMagnetListener(new MagnetizedObject.MagnetListener() {
@Override
- public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+ public void onStuckToTarget(@NonNull MagnetizedObject.MagneticTarget target,
+ @NonNull MagnetizedObject<?> draggedObject) {
if (mAnimator == null) return;
mAnimator.animateDismissCaptured();
}
@Override
public void onUnstuckFromTarget(@NonNull MagnetizedObject.MagneticTarget target,
+ @NonNull MagnetizedObject<?> draggedObject,
float velX, float velY, boolean wasFlungOut) {
if (mAnimator == null) return;
mAnimator.animateDismissReleased();
}
@Override
- public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target) {
+ public void onReleasedInTarget(@NonNull MagnetizedObject.MagneticTarget target,
+ @NonNull MagnetizedObject<?> draggedObject) {
dismissMagnetizedObject();
}
});
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
index 432d272..9c3e8af 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayDragLayer.java
@@ -40,7 +40,6 @@
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.CopyOnWriteArrayList;
/** Root drag layer for the Taskbar overlay window. */
public class TaskbarOverlayDragLayer extends
@@ -48,28 +47,6 @@
ViewTreeObserver.OnComputeInternalInsetsListener {
private SafeCloseable mViewCaptureCloseable;
- private final List<OnClickListener> mOnClickListeners = new CopyOnWriteArrayList<>();
- private final TouchController mClickListenerTouchController = new TouchController() {
- @Override
- public boolean onControllerTouchEvent(MotionEvent ev) {
- if (ev.getActionMasked() == MotionEvent.ACTION_UP) {
- for (OnClickListener listener : mOnClickListeners) {
- listener.onClick(TaskbarOverlayDragLayer.this);
- }
- }
- return false;
- }
-
- @Override
- public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- for (int i = 0; i < getChildCount(); i++) {
- if (isEventOverView(getChildAt(i), ev)) {
- return false;
- }
- }
- return true;
- }
- };
private final List<TouchController> mTouchControllers = new ArrayList<>();
TaskbarOverlayDragLayer(Context context) {
@@ -98,9 +75,6 @@
List<TouchController> controllers = new ArrayList<>();
controllers.add(mActivity.getDragController());
controllers.addAll(mTouchControllers);
- if (!mOnClickListeners.isEmpty()) {
- controllers.add(mClickListenerTouchController);
- }
mControllers = controllers.toArray(new TouchController[0]);
}
@@ -152,51 +126,6 @@
mActivity.getOverlayController().maybeCloseWindow();
}
- /**
- * Adds the given callback to clicks to this drag layer.
- * <p>
- * Clicks are only accepted on this drag layer if they fall within this drag layer's bounds and
- * outside the bounds of all child views.
- * <p>
- * If the click falls within the bounds of a child view, then this callback does not run and
- * that child can optionally handle it.
- */
- private void addOnClickListener(@NonNull OnClickListener listener) {
- boolean wasEmpty = mOnClickListeners.isEmpty();
- mOnClickListeners.add(listener);
- if (wasEmpty) {
- recreateControllers();
- }
- }
-
- /**
- * Removes the given on click callback.
- * <p>
- * No-op if the callback was never added.
- */
- private void removeOnClickListener(@NonNull OnClickListener listener) {
- boolean wasEmpty = mOnClickListeners.isEmpty();
- mOnClickListeners.remove(listener);
- if (!wasEmpty && mOnClickListeners.isEmpty()) {
- recreateControllers();
- }
- }
-
- /**
- * Queues the given callback on the next click on this drag layer.
- * <p>
- * Once run, this callback is immediately removed.
- */
- public void runOnClickOnce(@NonNull OnClickListener listener) {
- addOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- listener.onClick(v);
- removeOnClickListener(this);
- }
- });
- }
-
/** Adds a {@link TouchController} to this drag layer. */
public void addTouchController(@NonNull TouchController touchController) {
mTouchControllers.add(touchController);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index c2a248d..f3f36c5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -21,6 +21,7 @@
import static android.view.accessibility.AccessibilityEvent.TYPE_VIEW_FOCUSED;
import static com.android.app.animation.Interpolators.EMPHASIZED;
+import static com.android.launcher3.Flags.enablePredictiveBackGesture;
import static com.android.launcher3.Flags.enableUnfoldStateAnimation;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.PENDING_SPLIT_SELECT_INFO;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
@@ -61,7 +62,6 @@
import static com.android.quickstep.views.DesktopTaskView.isDesktopModeSupported;
import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY;
import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
-import static com.android.launcher3.Flags.enablePredictiveBackGesture;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -1103,21 +1103,11 @@
// populating workspace.
// TODO: Find a better place for this
WellbeingModel.INSTANCE.get(this);
- }
- @Override
- public void onInitialBindComplete(IntSet boundPages, RunnableList pendingTasks,
- int workspaceItemCount, boolean isBindSync) {
- pendingTasks.add(() -> {
- // This is added in pending task as we need to wait for views to be positioned
- // correctly before registering them for the animation.
- if (mLauncherUnfoldAnimationController != null) {
- // This is needed in case items are rebound while the unfold animation is in
- // progress.
- mLauncherUnfoldAnimationController.updateRegisteredViewsIfNeeded();
- }
- });
- super.onInitialBindComplete(boundPages, pendingTasks, workspaceItemCount, isBindSync);
+ if (mLauncherUnfoldAnimationController != null) {
+ // This is needed in case items are rebound while the unfold animation is in progress.
+ mLauncherUnfoldAnimationController.updateRegisteredViewsIfNeeded();
+ }
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index 3767cce..577eba6 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -20,6 +20,7 @@
import android.content.Context;
+import com.android.internal.jank.Cuj;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
@@ -27,6 +28,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.ActivityContext;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
/**
* Definition for AllApps state
@@ -49,6 +51,24 @@
}
@Override
+ public void onBackPressed(Launcher launcher) {
+ InteractionJankMonitorWrapper.begin(launcher.getAppsView(),
+ Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
+ super.onBackPressed(launcher);
+ }
+
+ @Override
+ protected void onBackPressCompleted(boolean success) {
+ if (success) {
+ // Animation was successful.
+ InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
+ } else {
+ // Animation was canceled.
+ InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
+ }
+ }
+
+ @Override
public String getDescription(Launcher launcher) {
return launcher.getAppsView().getDescription();
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 0650f9d..72218bf 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -55,14 +55,12 @@
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import android.animation.ValueAnimator;
-import android.util.Log;
import com.android.launcher3.CellLayout;
import com.android.launcher3.Hotseat;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Workspace;
import com.android.launcher3.states.StateAnimationConfig;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.touch.AllAppsSwipeController;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.DisplayController;
@@ -96,8 +94,6 @@
@Override
public void prepareForAtomicAnimation(LauncherState fromState, LauncherState toState,
StateAnimationConfig config) {
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "creating animation fromState: "
- + fromState + " toState: " + toState);
RecentsView overview = mActivity.getOverviewPanel();
if ((fromState == OVERVIEW || fromState == OVERVIEW_SPLIT_SELECT) && toState == NORMAL) {
overview.switchToScreenshot(() ->
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
index ca598c8..fc3eeba 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonNavbarToOverviewTouchController.java
@@ -38,6 +38,7 @@
import android.view.MotionEvent;
import android.view.ViewConfiguration;
+import com.android.internal.jank.Cuj;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
@@ -53,6 +54,7 @@
import com.android.quickstep.util.MotionPauseDetector;
import com.android.quickstep.util.OverviewToHomeAnim;
import com.android.quickstep.views.RecentsView;
+import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
import java.util.function.Consumer;
@@ -148,6 +150,8 @@
mMotionPauseDetector.clear();
if (handlingOverviewAnim()) {
+ InteractionJankMonitorWrapper.begin(mRecentsView, Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS,
+ "Home");
mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseDetected);
}
@@ -182,6 +186,7 @@
if (mStartedOverview) {
goToOverviewOrHomeOnDragEnd(velocity);
} else {
+ InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
super.onDragEnd(velocity);
}
@@ -237,6 +242,7 @@
private void maybeSwipeInteractionToOverviewComplete() {
if (mReachedOverview && !mDetector.isDraggingState()) {
+ InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
onSwipeInteractionCompleted(OVERVIEW);
}
}
@@ -280,6 +286,7 @@
if (goToHomeInsteadOfOverview) {
new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(NORMAL), null)
.animateWithVelocity(velocity);
+ InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
}
if (mReachedOverview) {
float distanceDp = dpiFromPx(Math.max(
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
index 6d3b60a..b7a907f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java
@@ -193,6 +193,8 @@
mMotionPauseDetector.clear();
if (start) {
InteractionJankMonitorWrapper.begin(mRecentsView, Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
+ InteractionJankMonitorWrapper.begin(mRecentsView, Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS,
+ "Home");
mStartState = mLauncher.getStateManager().getState();
@@ -350,6 +352,7 @@
.dispatchOnStart();
return;
}
+ InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
final LauncherState targetState;
if (horizontalFling && verticalFling) {
@@ -471,6 +474,8 @@
if (targetState == QUICK_SWITCH_FROM_HOME) {
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_QUICK_SWITCH);
+ } else if (targetState == OVERVIEW) {
+ InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_APP_SWIPE_TO_RECENTS);
}
mLauncher.getStateManager().goToState(targetState, false, forEndCallback(this::clearState));
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 6698600..4752225 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -30,6 +30,7 @@
import static com.android.launcher3.BaseActivity.EVENT_STARTED;
import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER;
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
+import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
import static com.android.launcher3.PagedView.INVALID_PAGE;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
@@ -2561,9 +2562,11 @@
}
float scrollOffset = Math.abs(mRecentsView.getScrollOffset(mRecentsView.getCurrentPage()));
+ Rect carouselTaskSize = enableGridOnlyOverview()
+ ? mRecentsView.getLastComputedCarouselTaskSize()
+ : mRecentsView.getLastComputedTaskSize();
int maxScrollOffset = mRecentsView.getPagedOrientationHandler().getPrimaryValue(
- mRecentsView.getLastComputedTaskSize().width(),
- mRecentsView.getLastComputedTaskSize().height());
+ carouselTaskSize.width(), carouselTaskSize.height());
maxScrollOffset += mRecentsView.getPageSpacing();
float maxScaleProgress =
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index b89d20c..2341e4c 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -261,6 +261,23 @@
}
}
+ /**
+ * Calculates the taskView size for carousel during app to overview animation on tablets.
+ */
+ public final void calculateCarouselTaskSize(Context context, DeviceProfile dp, Rect outRect,
+ PagedOrientationHandler orientedState) {
+ if (dp.isTablet && dp.isGestureMode) {
+ Resources res = context.getResources();
+ float minScale = res.getFloat(R.dimen.overview_carousel_min_scale);
+ Rect gridRect = new Rect();
+ calculateGridSize(dp, context, gridRect);
+ calculateTaskSizeInternal(context, dp, gridRect, minScale, Gravity.CENTER | Gravity.TOP,
+ outRect);
+ } else {
+ calculateTaskSize(context, dp, outRect, orientedState);
+ }
+ }
+
private void calculateFocusTaskSize(Context context, DeviceProfile dp, Rect outRect) {
Resources res = context.getResources();
float maxScale = res.getFloat(R.dimen.overview_max_scale);
@@ -286,13 +303,13 @@
}
private void calculateTaskSizeInternal(Context context, DeviceProfile dp,
- Rect potentialTaskRect, float maxScale, int gravity, Rect outRect) {
+ Rect potentialTaskRect, float targetScale, int gravity, Rect outRect) {
PointF taskDimension = getTaskDimension(context, dp);
float scale = Math.min(
potentialTaskRect.width() / taskDimension.x,
potentialTaskRect.height() / taskDimension.y);
- scale = Math.min(scale, maxScale);
+ scale = Math.min(scale, targetScale);
int outWidth = Math.round(scale * taskDimension.x);
int outHeight = Math.round(scale * taskDimension.y);
@@ -408,11 +425,14 @@
if (activity == null) {
return null;
}
+ RecentsView recentsView = activity.getOverviewPanel();
STATE_TYPE state = stateFromGestureEndTarget(endTarget);
ScrimView scrimView = activity.getScrimView();
ObjectAnimator anim = ObjectAnimator.ofArgb(scrimView, VIEW_BACKGROUND_COLOR,
getOverviewScrimColorForState(activity, state));
anim.setDuration(duration);
+ anim.setInterpolator(recentsView == null || !recentsView.isKeyboardTaskFocusPending()
+ ? LINEAR : INSTANT);
return anim;
}
return null;
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index e448a14..febfc3a 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -218,9 +218,13 @@
return true;
}
}
- if (cmd.type == TYPE_KEYBOARD_INPUT && allowQuickSwitch) {
- uiController.openQuickSwitchView();
- return true;
+ if (cmd.type == TYPE_KEYBOARD_INPUT) {
+ if (allowQuickSwitch) {
+ uiController.openQuickSwitchView();
+ return true;
+ } else {
+ mKeyboardTaskFocusIndex = 0;
+ }
}
if (cmd.type == TYPE_HOME) {
ActiveGestureLog.INSTANCE.addLog("OverviewCommandHelper.executeCommand(TYPE_HOME)");
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 52f9d8d..72f67fc 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -82,13 +82,13 @@
import com.android.wm.shell.back.IBackAnimation;
import com.android.wm.shell.bubbles.IBubbles;
import com.android.wm.shell.bubbles.IBubblesListener;
+import com.android.wm.shell.common.pip.IPip;
+import com.android.wm.shell.common.pip.IPipAnimationListener;
import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
import com.android.wm.shell.desktopmode.IDesktopMode;
import com.android.wm.shell.desktopmode.IDesktopTaskListener;
import com.android.wm.shell.draganddrop.IDragAndDrop;
import com.android.wm.shell.onehanded.IOneHanded;
-import com.android.wm.shell.pip.IPip;
-import com.android.wm.shell.pip.IPipAnimationListener;
import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.recents.IRecentTasksListener;
import com.android.wm.shell.splitscreen.ISplitScreen;
diff --git a/quickstep/src/com/android/quickstep/TaskViewUtils.java b/quickstep/src/com/android/quickstep/TaskViewUtils.java
index c2cd11c..03e6c99 100644
--- a/quickstep/src/com/android/quickstep/TaskViewUtils.java
+++ b/quickstep/src/com/android/quickstep/TaskViewUtils.java
@@ -68,6 +68,7 @@
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.statehandlers.DepthController;
import com.android.launcher3.statemanager.StateManager;
+import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.RemoteTargetGluer.RemoteTargetHandle;
import com.android.quickstep.util.MultiValueUpdateListener;
@@ -207,7 +208,8 @@
BaseActivity baseActivity = BaseActivity.fromContext(context);
DeviceProfile dp = baseActivity.getDeviceProfile();
boolean showAsGrid = dp.isTablet;
- boolean parallaxCenterAndAdjacentTask = taskIndex != recentsView.getCurrentPage();
+ boolean parallaxCenterAndAdjacentTask =
+ !showAsGrid && taskIndex != recentsView.getCurrentPage();
int taskRectTranslationPrimary = recentsView.getScrollOffset(taskIndex);
int taskRectTranslationSecondary = showAsGrid ? (int) v.getGridTranslationY() : 0;
@@ -643,6 +645,21 @@
recentsView.post(() -> {
stateManager.moveToRestState();
stateManager.reapplyState();
+
+ // We may have notified launcher is not visible so that taskbar can
+ // stash immediately. Now that the animation is over, we can update
+ // that launcher is still visible.
+ TaskbarUIController controller = recentsView.getSizeStrategy()
+ .getTaskbarController();
+ if (controller != null) {
+ boolean launcherVisible = true;
+ for (RemoteAnimationTarget target : appTargets) {
+ launcherVisible &= target.isTranslucent;
+ }
+ if (launcherVisible) {
+ controller.onLauncherVisibilityChanged(true);
+ }
+ }
});
});
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index b6b7d58..f9486bd 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -47,6 +47,7 @@
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+import static com.android.wm.shell.Flags.enableBubblesLongPressNavHandle;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_DESKTOP_MODE;
@@ -134,10 +135,10 @@
import com.android.systemui.unfold.progress.IUnfoldAnimation;
import com.android.wm.shell.back.IBackAnimation;
import com.android.wm.shell.bubbles.IBubbles;
+import com.android.wm.shell.common.pip.IPip;
import com.android.wm.shell.desktopmode.IDesktopMode;
import com.android.wm.shell.draganddrop.IDragAndDrop;
import com.android.wm.shell.onehanded.IOneHanded;
-import com.android.wm.shell.pip.IPip;
import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.startingsurface.IStartingWindow;
@@ -1006,6 +1007,17 @@
mOverviewCommandHelper);
}
}
+ if (enableBubblesLongPressNavHandle()) {
+ // Create bubbles input consumer before NavHandleLongPressInputConsumer.
+ // This allows for nav handle to fall back to bubbles.
+ if (mDeviceState.isBubblesExpanded()) {
+ reasonString = newCompoundString(reasonPrefix)
+ .append(SUBSTRING_PREFIX)
+ .append("bubbles expanded, trying to use default input consumer");
+ // Bubbles can handle home gesture itself.
+ base = getDefaultInputConsumer(reasonString);
+ }
+ }
NavHandle navHandle = tac != null ? tac.getNavHandle()
: SystemUiProxy.INSTANCE.get(this);
@@ -1023,12 +1035,15 @@
mDeviceState, navHandle);
}
- if (mDeviceState.isBubblesExpanded()) {
- reasonString = newCompoundString(reasonPrefix)
- .append(SUBSTRING_PREFIX)
- .append("bubbles expanded, trying to use default input consumer");
- // Bubbles can handle home gesture itself.
- base = getDefaultInputConsumer(reasonString);
+ if (!enableBubblesLongPressNavHandle()) {
+ // Continue overriding nav handle input consumer with bubbles
+ if (mDeviceState.isBubblesExpanded()) {
+ reasonString = newCompoundString(reasonPrefix)
+ .append(SUBSTRING_PREFIX)
+ .append("bubbles expanded, trying to use default input consumer");
+ // Bubbles can handle home gesture itself.
+ base = getDefaultInputConsumer(reasonString);
+ }
}
if (mDeviceState.isSystemUiDialogShowing()) {
diff --git a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
index 404bca9..6757cd8 100644
--- a/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
+++ b/quickstep/src/com/android/quickstep/interaction/BackGestureTutorialController.java
@@ -85,7 +85,9 @@
public int getSuccessFeedbackSubtitle() {
return mTutorialFragment.isAtFinalStep()
? R.string.back_gesture_feedback_complete_without_follow_up
- : R.string.back_gesture_feedback_complete_with_overview_follow_up;
+ : ENABLE_NEW_GESTURE_NAV_TUTORIAL.get()
+ ? R.string.back_gesture_feedback_complete_with_follow_up
+ : R.string.back_gesture_feedback_complete_with_overview_follow_up;
}
@Override
diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
index 278ca56..1e05a69 100644
--- a/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
+++ b/quickstep/src/com/android/quickstep/util/ActiveGestureLog.java
@@ -67,15 +67,15 @@
/**
* Adds a log to be printed at log-dump-time.
*/
- public void addLog(String event) {
+ public void addLog(@NonNull String event) {
addLog(event, null);
}
- public void addLog(String event, int extras) {
+ public void addLog(@NonNull String event, int extras) {
addLog(event, extras, null);
}
- public void addLog(String event, boolean extras) {
+ public void addLog(@NonNull String event, boolean extras) {
addLog(event, extras, null);
}
@@ -85,30 +85,30 @@
* @param gestureEvent GestureEvent representing the event being logged.
*/
public void addLog(
- String event, @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
+ @NonNull String event, @Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
addLog(new CompoundString(event), gestureEvent);
}
public void addLog(
- String event,
+ @NonNull String event,
int extras,
@Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
addLog(new CompoundString(event).append(": ").append(extras), gestureEvent);
}
public void addLog(
- String event,
+ @NonNull String event,
boolean extras,
@Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
addLog(new CompoundString(event).append(": ").append(extras), gestureEvent);
}
- public void addLog(CompoundString compoundString) {
+ public void addLog(@NonNull CompoundString compoundString) {
addLog(compoundString, null);
}
public void addLog(
- CompoundString compoundString,
+ @NonNull CompoundString compoundString,
@Nullable ActiveGestureErrorDetector.GestureEvent gestureEvent) {
EventLog lastEventLog = logs[(nextIndex + logs.length - 1) % logs.length];
if (lastEventLog == null || mCurrentLogId != lastEventLog.logId) {
@@ -259,21 +259,20 @@
public CompoundString(String substring) {
mIsNoOp = substring == null;
- if (mIsNoOp) {
- mSubstrings = null;
- mArgs = null;
- return;
+ mSubstrings = mIsNoOp ? null : new ArrayList<>();
+ mArgs = mIsNoOp ? null : new ArrayList<>();
+
+ if (!mIsNoOp) {
+ mSubstrings.add(substring);
}
- mSubstrings = new ArrayList<>();
- mSubstrings.add(substring);
- mArgs = new ArrayList<>();
}
public CompoundString append(CompoundString substring) {
- if (mIsNoOp) {
+ if (mIsNoOp || substring.mIsNoOp) {
return this;
}
mSubstrings.addAll(substring.mSubstrings);
+ mArgs.addAll(substring.mArgs);
return this;
}
@@ -288,30 +287,53 @@
}
public CompoundString append(int num) {
+ if (mIsNoOp) {
+ return this;
+ }
+ mArgs.add(num);
+
+ return append("%d");
+ }
+
+ public CompoundString append(long num) {
+ if (mIsNoOp) {
+ return this;
+ }
mArgs.add(num);
return append("%d");
}
public CompoundString append(float num) {
+ if (mIsNoOp) {
+ return this;
+ }
mArgs.add(num);
return append("%.2f");
}
public CompoundString append(double num) {
+ if (mIsNoOp) {
+ return this;
+ }
mArgs.add(num);
return append("%.2f");
}
public CompoundString append(boolean bool) {
+ if (mIsNoOp) {
+ return this;
+ }
mArgs.add(bool);
return append("%b");
}
- public Object[] getArgs() {
+ private Object[] getArgs() {
+ Preconditions.assertTrue(!mIsNoOp);
+
return mArgs.toArray();
}
@@ -320,7 +342,7 @@
return String.format(toUnformattedString(), getArgs());
}
- public String toUnformattedString() {
+ private String toUnformattedString() {
Preconditions.assertTrue(!mIsNoOp);
StringBuilder sb = new StringBuilder();
@@ -333,7 +355,7 @@
@Override
public int hashCode() {
- return Objects.hash(mIsNoOp, mSubstrings);
+ return Objects.hash(mIsNoOp, mSubstrings, mArgs);
}
@Override
@@ -342,7 +364,9 @@
return false;
}
CompoundString other = (CompoundString) obj;
- return (mIsNoOp == other.mIsNoOp) && Objects.equals(mSubstrings, other.mSubstrings);
+ return (mIsNoOp == other.mIsNoOp)
+ && Objects.equals(mSubstrings, other.mSubstrings)
+ && Objects.equals(mArgs, other.mArgs);
}
}
}
diff --git a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
index bc8b571..16f2065 100644
--- a/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
+++ b/quickstep/src/com/android/quickstep/util/AnimatorControllerWithResistance.java
@@ -17,6 +17,7 @@
import static com.android.app.animation.Interpolators.DECELERATE;
import static com.android.app.animation.Interpolators.LINEAR;
+import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.LauncherPrefs.ALL_APPS_OVERVIEW_THRESHOLD;
import static com.android.quickstep.views.RecentsView.RECENTS_SCALE_PROPERTY;
import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION;
@@ -58,6 +59,7 @@
FROM_APP(0.75f, 0.5f, 1f, false),
FROM_APP_TO_ALL_APPS(1f, 0.6f, 0.8f, false),
FROM_APP_TABLET(1f, 0.7f, 1f, true),
+ FROM_APP_TABLET_GRID_ONLY(1f, 1f, 1f, true),
FROM_APP_TO_ALL_APPS_TABLET(1f, 0.5f, 0.5f, false),
FROM_OVERVIEW(1f, 0.75f, 0.5f, false);
@@ -239,10 +241,10 @@
float stopResist =
params.resistanceParams.stopScalingAtTop ? 1f - startRect.top / endRectF.top : 1f;
final TimeInterpolator scaleInterpolator = t -> {
- if (t < startResist) {
+ if (t <= startResist) {
return t;
}
- if (t > stopResist) {
+ if (t >= stopResist) {
return maxResist;
}
float resistProgress = Utilities.getProgress(t, startResist, stopResist);
@@ -304,7 +306,9 @@
resistanceParams =
recentsOrientedState.getActivityInterface().allowAllAppsFromOverview()
? RecentsResistanceParams.FROM_APP_TO_ALL_APPS_TABLET
- : RecentsResistanceParams.FROM_APP_TABLET;
+ : enableGridOnlyOverview()
+ ? RecentsResistanceParams.FROM_APP_TABLET_GRID_ONLY
+ : RecentsResistanceParams.FROM_APP_TABLET;
} else {
resistanceParams =
recentsOrientedState.getActivityInterface().allowAllAppsFromOverview()
diff --git a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
index a8a96ce..b8bc828 100644
--- a/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
+++ b/quickstep/src/com/android/quickstep/util/MotionPauseDetector.java
@@ -96,8 +96,14 @@
mSpeedSomewhatFast = res.getDimension(R.dimen.motion_pause_detector_speed_somewhat_fast);
mSpeedFast = res.getDimension(R.dimen.motion_pause_detector_speed_fast);
mForcePauseTimeout = new Alarm();
- mForcePauseTimeout.setOnAlarmListener(alarm -> updatePaused(true /* isPaused */,
- "Force pause timeout after " + alarm.getLastSetTimeout() + "ms" /* reason */));
+ mForcePauseTimeout.setOnAlarmListener(alarm -> {
+ ActiveGestureLog.CompoundString log =
+ new ActiveGestureLog.CompoundString("Force pause timeout after ")
+ .append(alarm.getLastSetTimeout())
+ .append("ms");
+ addLogs(log);
+ updatePaused(true /* isPaused */, log);
+ });
mMakePauseHarderToTrigger = makePauseHarderToTrigger;
mVelocityProvider = new SystemVelocityProvider(axis);
}
@@ -113,8 +119,14 @@
* @param disallowPause If true, we will not detect any pauses until this is set to false again.
*/
public void setDisallowPause(boolean disallowPause) {
+ ActiveGestureLog.CompoundString log =
+ new ActiveGestureLog.CompoundString("Set disallowPause=")
+ .append(disallowPause);
+ if (mDisallowPause != disallowPause) {
+ addLogs(log);
+ }
mDisallowPause = disallowPause;
- updatePaused(mIsPaused, "Set disallowPause=" + disallowPause);
+ updatePaused(mIsPaused, log);
}
/**
@@ -148,27 +160,30 @@
float speed = Math.abs(velocity);
float previousSpeed = Math.abs(prevVelocity);
boolean isPaused;
- String isPausedReason = "";
+ ActiveGestureLog.CompoundString isPausedReason;
if (mIsPaused) {
// Continue to be paused until moving at a fast speed.
isPaused = speed < mSpeedFast || previousSpeed < mSpeedFast;
- isPausedReason = "Was paused, but started moving at a fast speed";
+ isPausedReason = new ActiveGestureLog.CompoundString(
+ "Was paused, but started moving at a fast speed");
} else {
if (velocity < 0 != prevVelocity < 0) {
// We're just changing directions, not necessarily stopping.
isPaused = false;
- isPausedReason = "Velocity changed directions";
+ isPausedReason = new ActiveGestureLog.CompoundString("Velocity changed directions");
} else {
isPaused = speed < mSpeedVerySlow && previousSpeed < mSpeedVerySlow;
- isPausedReason = "Pause requires back to back slow speeds";
+ isPausedReason = new ActiveGestureLog.CompoundString(
+ "Pause requires back to back slow speeds");
if (!isPaused && !mHasEverBeenPaused) {
// We want to be more aggressive about detecting the first pause to ensure it
// feels as responsive as possible; getting two very slow speeds back to back
// takes too long, so also check for a rapid deceleration.
boolean isRapidDeceleration = speed < previousSpeed * RAPID_DECELERATION_FACTOR;
isPaused = isRapidDeceleration && speed < mSpeedSomewhatFast;
- isPausedReason = "Didn't have back to back slow speeds, checking for rapid"
- + " deceleration on first pause only";
+ isPausedReason = new ActiveGestureLog.CompoundString(
+ "Didn't have back to back slow speeds, checking for rapid ")
+ .append(" deceleration on first pause only");
}
if (mMakePauseHarderToTrigger) {
if (speed < mSpeedSlow) {
@@ -176,12 +191,14 @@
mSlowStartTime = time;
}
isPaused = time - mSlowStartTime >= HARDER_TRIGGER_TIMEOUT;
- isPausedReason = "Maintained slow speed for sufficient duration when making"
- + " pause harder to trigger";
+ isPausedReason = new ActiveGestureLog.CompoundString(
+ "Maintained slow speed for sufficient duration when making")
+ .append(" pause harder to trigger");
} else {
mSlowStartTime = 0;
isPaused = false;
- isPausedReason = "Intentionally making pause harder to trigger";
+ isPausedReason = new ActiveGestureLog.CompoundString(
+ "Intentionally making pause harder to trigger");
}
}
}
@@ -189,18 +206,21 @@
updatePaused(isPaused, isPausedReason);
}
- private void updatePaused(boolean isPaused, String reason) {
+ private void updatePaused(boolean isPaused, ActiveGestureLog.CompoundString reason) {
if (mDisallowPause) {
- reason = "Disallow pause; otherwise, would have been " + isPaused + " due to " + reason;
+ reason = new ActiveGestureLog.CompoundString(
+ "Disallow pause; otherwise, would have been ")
+ .append(isPaused)
+ .append(" due to reason:")
+ .append(reason);
isPaused = false;
}
if (mIsPaused != isPaused) {
mIsPaused = isPaused;
- String logString = "onMotionPauseChanged, paused=" + mIsPaused + " reason=" + reason;
- if (Utilities.isRunningInTestHarness()) {
- Log.d(TAG, logString);
- }
- ActiveGestureLog.INSTANCE.addLog(logString);
+ addLogs(new ActiveGestureLog.CompoundString("onMotionPauseChanged triggered; paused=")
+ .append(mIsPaused)
+ .append(", reason=")
+ .append(reason));
boolean isFirstDetectedPause = !mHasEverBeenPaused && mIsPaused;
if (mIsPaused) {
AccessibilityManagerCompat.sendTestProtocolEventToTest(mContext,
@@ -219,6 +239,16 @@
}
}
+ private void addLogs(ActiveGestureLog.CompoundString compoundString) {
+ ActiveGestureLog.CompoundString logString =
+ new ActiveGestureLog.CompoundString("MotionPauseDetector: ")
+ .append(compoundString);
+ if (Utilities.isRunningInTestHarness()) {
+ Log.d(TAG, logString.toString());
+ }
+ ActiveGestureLog.INSTANCE.addLog(logString);
+ }
+
public void clear() {
mVelocityProvider.clear();
mPreviousVelocity = null;
diff --git a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
index 0bb6b23..1152de2 100644
--- a/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
+++ b/quickstep/src/com/android/quickstep/util/TaskViewSimulator.java
@@ -38,10 +38,12 @@
import android.graphics.RectF;
import android.util.Log;
import android.view.RemoteAnimationTarget;
+import android.view.animation.Interpolator;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
@@ -76,6 +78,8 @@
private final Rect mTaskRect = new Rect();
private final Rect mFullTaskSize = new Rect();
+ private final Rect mCarouselTaskSize = new Rect();
+ private PointF mPivotOverride = null;
private final PointF mPivot = new PointF();
private DeviceProfile mDp;
@StagePosition
@@ -95,6 +99,11 @@
public final AnimatedFloat taskPrimaryTranslation = new AnimatedFloat();
public final AnimatedFloat taskSecondaryTranslation = new AnimatedFloat();
+ // Carousel properties
+ public final AnimatedFloat carouselScale = new AnimatedFloat();
+ public final AnimatedFloat carouselPrimaryTranslation = new AnimatedFloat();
+ public final AnimatedFloat carouselSecondaryTranslation = new AnimatedFloat();
+
// RecentsView properties
public final AnimatedFloat recentsViewScale = new AnimatedFloat();
public final AnimatedFloat fullScreenProgress = new AnimatedFloat();
@@ -109,9 +118,9 @@
private Boolean mDrawsBelowRecents = null;
private boolean mIsGridTask;
private boolean mIsDesktopTask;
+ private boolean mScaleToCarouselTaskSize = false;
private int mTaskRectTranslationX;
private int mTaskRectTranslationY;
- private int mPivotOffsetX;
public TaskViewSimulator(Context context, BaseActivityInterface sizeStrategy) {
mContext = context;
@@ -124,6 +133,7 @@
mOrientationStateId = mOrientationState.getStateId();
Resources resources = context.getResources();
mIsRecentsRtl = mOrientationState.getOrientationHandler().getRecentsRtlSetting(resources);
+ carouselScale.value = 1f;
}
/**
@@ -149,6 +159,11 @@
mOrientationState.getOrientationHandler());
}
+ if (enableGridOnlyOverview()) {
+ mSizeStrategy.calculateCarouselTaskSize(mContext, mDp, mCarouselTaskSize,
+ mOrientationState.getOrientationHandler());
+ }
+
if (mSplitBounds != null) {
// The task rect changes according to the staged split task sizes, but recents
// fullscreen scale and pivot remains the same since the task fits into the existing
@@ -193,9 +208,18 @@
}
// Copy mFullTaskSize instead of updating it directly so it could be reused next time
// without recalculating
- Rect scaleRect = new Rect(mFullTaskSize);
- scaleRect.offset(mTaskRectTranslationX + mPivotOffsetX, mTaskRectTranslationY);
- return mOrientationState.getFullScreenScaleAndPivot(scaleRect, mDp, mPivot);
+ Rect scaleRect = new Rect();
+ if (mScaleToCarouselTaskSize) {
+ scaleRect.set(mCarouselTaskSize);
+ } else {
+ scaleRect.set(mFullTaskSize);
+ }
+ scaleRect.offset(mTaskRectTranslationX, mTaskRectTranslationY);
+ float scale = mOrientationState.getFullScreenScaleAndPivot(scaleRect, mDp, mPivot);
+ if (mPivotOverride != null) {
+ mPivot.set(mPivotOverride);
+ }
+ return scale;
}
/**
@@ -278,14 +302,64 @@
/**
* Adds animation for all the components corresponding to transition from an app to overview.
*/
- public void addAppToOverviewAnim(PendingAnimation pa, TimeInterpolator interpolator) {
+ public void addAppToOverviewAnim(PendingAnimation pa, Interpolator interpolator) {
pa.addFloat(fullScreenProgress, AnimatedFloat.VALUE, 1, 0, interpolator);
- if (enableGridOnlyOverview() && mDp.isTablet) {
- int translationXToMiddle = mDp.widthPx / 2 - mFullTaskSize.centerX();
- taskPrimaryTranslation.value = translationXToMiddle;
- mPivotOffsetX = translationXToMiddle;
+ float fullScreenScale;
+ if (enableGridOnlyOverview() && mDp.isTablet && mDp.isGestureMode) {
+ // Move pivot to top right edge of the screen, to avoid task scaling down in opposite
+ // direction of app window movement, otherwise the animation will wiggle left and right.
+ // Also translate the app window to top right edge of the screen to simplify
+ // calculations.
+ taskPrimaryTranslation.value = mIsRecentsRtl
+ ? mDp.widthPx - mFullTaskSize.right
+ : -mFullTaskSize.left;
+ taskSecondaryTranslation.value = -mFullTaskSize.top;
+ mPivotOverride = new PointF(mIsRecentsRtl ? mDp.widthPx : 0, 0);
+
+ // Scale down to the carousel and use the carousel Rect to calculate fullScreenScale.
+ mScaleToCarouselTaskSize = true;
+ carouselScale.value = mCarouselTaskSize.width() / (float) mFullTaskSize.width();
+ fullScreenScale = getFullScreenScale();
+
+ float carouselPrimaryTranslationTarget = mIsRecentsRtl
+ ? mCarouselTaskSize.right - mDp.widthPx
+ : mCarouselTaskSize.left;
+ float carouselSecondaryTranslationTarget = mCarouselTaskSize.top;
+
+ // Expected carousel position's center is in the middle, and invariant of
+ // recentsViewScale.
+ float exceptedCarouselCenterX = mCarouselTaskSize.centerX();
+ // Animating carousel translations linearly will result in a curved path, therefore
+ // we'll need to calculate the expected translation at each recentsView scale. Luckily
+ // primary and secondary follow the same translation, and primary is used here due to
+ // it being simpler.
+ Interpolator carouselTranslationInterpolator = t -> {
+ // recentsViewScale is calculated rather than using recentsViewScale.value, so that
+ // this interpolator works independently even if recentsViewScale don't animate.
+ float recentsViewScale =
+ Utilities.mapToRange(t, 0, 1, fullScreenScale, 1, Interpolators.LINEAR);
+ // Without the translation, the app window will animate from fullscreen into top
+ // right corner.
+ float expectedTaskCenterX = mIsRecentsRtl
+ ? mDp.widthPx - mCarouselTaskSize.width() * recentsViewScale / 2f
+ : mCarouselTaskSize.width() * recentsViewScale / 2f;
+ // Calculate the expected translation, then work back the animatedFraction that
+ // results in this value.
+ float carouselPrimaryTranslation =
+ (exceptedCarouselCenterX - expectedTaskCenterX) / recentsViewScale;
+ return carouselPrimaryTranslation / carouselPrimaryTranslationTarget;
+ };
+
+ // Use addAnimatedFloat so this animation can later be canceled and animate to a
+ // different value in RecentsView.onPrepareGestureEndAnimation.
+ pa.addAnimatedFloat(carouselPrimaryTranslation, 0, carouselPrimaryTranslationTarget,
+ carouselTranslationInterpolator);
+ pa.addAnimatedFloat(carouselSecondaryTranslation, 0, carouselSecondaryTranslationTarget,
+ carouselTranslationInterpolator);
+ } else {
+ fullScreenScale = getFullScreenScale();
}
- pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, getFullScreenScale(), 1, interpolator);
+ pa.addFloat(recentsViewScale, AnimatedFloat.VALUE, fullScreenScale, 1, interpolator);
}
/**
@@ -382,7 +456,7 @@
float fullScreenProgress = Utilities.boundToRange(this.fullScreenProgress.value, 0, 1);
mCurrentFullscreenParams.setProgress(fullScreenProgress, recentsViewScale.value,
- /* taskViewScale= */1f);
+ carouselScale.value);
// Apply thumbnail matrix
float taskWidth = mTaskRect.width();
@@ -396,6 +470,13 @@
taskPrimaryTranslation.value);
mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
taskSecondaryTranslation.value);
+
+ mMatrix.postScale(carouselScale.value, carouselScale.value, mPivot.x, mPivot.y);
+ mOrientationState.getOrientationHandler().setPrimary(mMatrix, MATRIX_POST_TRANSLATE,
+ carouselPrimaryTranslation.value);
+ mOrientationState.getOrientationHandler().setSecondary(mMatrix, MATRIX_POST_TRANSLATE,
+ carouselSecondaryTranslation.value);
+
mOrientationState.getOrientationHandler().setPrimary(
mMatrix, MATRIX_POST_TRANSLATE, recentsViewScroll.value);
@@ -420,15 +501,18 @@
return;
}
Log.d(TAG, "progress: " + fullScreenProgress
+ + " carouselScale: " + carouselScale.value
+ " recentsViewScale: " + recentsViewScale.value
+ " crop: " + mTmpCropRect
+ " radius: " + getCurrentCornerRadius()
+ " taskW: " + taskWidth + " H: " + taskHeight
+ " taskRect: " + mTaskRect
+ " taskPrimaryT: " + taskPrimaryTranslation.value
+ + " taskSecondaryT: " + taskSecondaryTranslation.value
+ + " carouselPrimaryT: " + carouselPrimaryTranslation.value
+ + " carouselSecondaryT: " + carouselSecondaryTranslation.value
+ " recentsPrimaryT: " + recentsViewPrimaryTranslation.value
+ " recentsSecondaryT: " + recentsViewSecondaryTranslation.value
- + " taskSecondaryT: " + taskSecondaryTranslation.value
+ " recentsScroll: " + recentsViewScroll.value
+ " pivot: " + mPivot
);
diff --git a/quickstep/src/com/android/quickstep/views/IconAppChipView.java b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
index cb3566e..6bb98e1 100644
--- a/quickstep/src/com/android/quickstep/views/IconAppChipView.java
+++ b/quickstep/src/com/android/quickstep/views/IconAppChipView.java
@@ -30,7 +30,6 @@
import android.content.res.Resources;
import android.graphics.Outline;
import android.graphics.Rect;
-import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
@@ -121,36 +120,12 @@
}
/**
- * Translate the View on the X-axis without overriding the raw translation.
- * This function is used for the menu split animation. It allows external animations to
- * translate this view without affecting the value of the original translation. Thus,
- * it is possible to restore the initial translation value.
- *
- * @param translationX Animated translation to be aggregated to the raw translation.
- */
- public void setMenuTranslationX(float translationX) {
- mViewTranslationX.get(INDEX_MENU_TRANSLATION).setValue(translationX);
- }
-
- /**
* Gets the menu y-axis translation for split task
*/
public MultiPropertyFactory<View>.MultiProperty getMenuTranslationY() {
return mViewTranslationY.get(INDEX_MENU_TRANSLATION);
}
- /**
- * Translate the View on the Y-axis without overriding the raw translation.
- * This function is used for the menu split animation. It allows external animations to
- * translate this view without affecting the value of the original translation. Thus,
- * it is possible to restore the initial translation value.
- *
- * @param translationY Animated translation to be aggregated to the raw translation.
- */
- public void setMenuTranslationY(float translationY) {
- mViewTranslationY.get(INDEX_MENU_TRANSLATION).setValue(translationY);
- }
-
public IconAppChipView(Context context) {
this(context, null);
}
@@ -330,6 +305,7 @@
LayoutParams iconArrowParams = (LayoutParams) mIconArrowView.getLayoutParams();
int arrowMarginStart = collapsedBackgroundBounds.right - mArrowMarginEnd - mArrowSize;
orientationHandler.setIconAppChipChildrenParams(iconArrowParams, arrowMarginStart);
+ mIconArrowView.setPivotY(iconArrowParams.height / 2f);
mIconArrowView.setLayoutParams(iconArrowParams);
// This method is called twice sometimes (like when rotating split tasks). It is called
@@ -378,7 +354,6 @@
if (isRevealing) {
boolean isRtl = isLayoutRtl();
bringToFront();
- ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).start();
// Clip expanded text with reveal animation so it doesn't go beyond the edge of the menu
Animator expandedTextRevealAnim = ViewAnimationUtils.createCircularReveal(
mIconTextExpandedView, 0, mIconTextExpandedView.getHeight() / 2,
@@ -412,10 +387,10 @@
textTranslationXWithRtl),
ObjectAnimator.ofFloat(mIconTextCollapsedView, ALPHA, 0),
ObjectAnimator.ofFloat(mIconTextExpandedView, ALPHA, 1),
- ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X, arrowTranslationWithRtl));
+ ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X, arrowTranslationWithRtl),
+ ObjectAnimator.ofFloat(mIconArrowView, SCALE_Y, -1));
mAnimator.setDuration(MENU_BACKGROUND_REVEAL_DURATION);
} else {
- ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).reverse();
// Clip expanded text with reveal animation so it doesn't go beyond the edge of the menu
Animator expandedTextClipAnim = ViewAnimationUtils.createCircularReveal(
mIconTextExpandedView, 0, mIconTextExpandedView.getHeight() / 2,
@@ -436,7 +411,8 @@
ObjectAnimator.ofFloat(mIconTextExpandedView, TRANSLATION_X, 0),
ObjectAnimator.ofFloat(mIconTextCollapsedView, ALPHA, 1),
ObjectAnimator.ofFloat(mIconTextExpandedView, ALPHA, 0),
- ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X, 0));
+ ObjectAnimator.ofFloat(mIconArrowView, TRANSLATION_X, 0),
+ ObjectAnimator.ofFloat(mIconArrowView, SCALE_Y, 1));
mAnimator.setDuration(MENU_BACKGROUND_HIDE_DURATION);
}
@@ -458,19 +434,6 @@
return new Rect(0, 0, mExpandedMenuDefaultWidth, mExpandedMenuDefaultHeight);
}
- protected void reset() {
- mBackgroundRelativeLtrLocation.set(getCollapsedBackgroundLtrBounds());
- mIconView.setScaleX(1);
- mIconView.setScaleY(1);
- mIconTextCollapsedView.setTranslationX(0);
- mIconTextExpandedView.setTranslationX(0);
- mIconTextCollapsedView.setAlpha(1);
- mIconTextExpandedView.setAlpha(0);
- mIconArrowView.setTranslationX(0);
- ((AnimatedVectorDrawable) mIconArrowView.getDrawable()).reset();
- mAnimator = null;
- }
-
private void cancelInProgressAnimations() {
// We null the `AnimatorSet` because it holds references to the `Animators` which aren't
// expecting to be mutable and will cause a crash if they are re-used.
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index 9bb9775a..a27875a 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -31,7 +31,6 @@
import android.content.Context;
import android.os.Build;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
@@ -45,7 +44,6 @@
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StateManager;
import com.android.launcher3.statemanager.StateManager.StateListener;
-import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.PendingSplitSelectInfo;
import com.android.launcher3.util.SplitConfigurationOptions;
@@ -187,8 +185,6 @@
@Override
public void setOverviewStateEnabled(boolean enabled) {
super.setOverviewStateEnabled(enabled);
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "overview state enabled state has changed: "
- + enabled);
if (enabled) {
LauncherState state = mActivity.getStateManager().getState();
boolean hasClearAllButton = (state.getVisibleElements(mActivity)
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index b549058..8281ad7 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -20,6 +20,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
@@ -41,6 +42,8 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Arrays;
+import java.util.stream.Collectors;
/**
* View for showing action buttons in Overview
@@ -220,6 +223,17 @@
boolean shouldBeVisible = mSplitButtonHiddenFlags == 0;
mSplitButton.setVisibility(shouldBeVisible ? VISIBLE : GONE);
findViewById(R.id.action_split_space).setVisibility(shouldBeVisible ? VISIBLE : GONE);
+
+ String callStack = Arrays.stream(
+ Log.getStackTraceString(new Exception("thread stacktrace"))
+ .split("\\n"))
+ .limit(5)
+ .skip(1) // Removes the line "java.lang.Exception: thread stacktrace"
+ .collect(Collectors.joining("\n"));
+ Log.d("b/321291049", "updateSplitButtonHiddenFlags called with flag: " + flag
+ + " enabled: " + enable
+ + " shouldBeVisible: " + shouldBeVisible
+ + " partial trace: \n" + callStack);
}
/**
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 9884d8d..ecff6b4 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -89,7 +89,6 @@
import android.graphics.Bitmap;
import android.graphics.BlendMode;
import android.graphics.Canvas;
-import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.PointF;
@@ -214,7 +213,7 @@
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
-import com.android.wm.shell.pip.IPipAnimationListener;
+import com.android.wm.shell.common.pip.IPipAnimationListener;
import java.util.ArrayList;
import java.util.Arrays;
@@ -442,6 +441,8 @@
private static final float SIGNIFICANT_MOVE_SCREEN_WIDTH_PERCENTAGE = 0.15f;
+ private static final float FOREGROUND_SCRIM_TINT = 0.32f;
+
protected final RecentsOrientedState mOrientationState;
protected final BaseActivityInterface<STATE_TYPE, ACTIVITY_TYPE> mSizeStrategy;
@Nullable
@@ -459,6 +460,7 @@
@Nullable
protected RemoteTargetHandle[] mRemoteTargetHandles;
+ protected final Rect mLastComputedCarouselTaskSize = new Rect();
protected final Rect mLastComputedTaskSize = new Rect();
protected final Rect mLastComputedGridSize = new Rect();
protected final Rect mLastComputedGridTaskSize = new Rect();
@@ -2108,6 +2110,10 @@
mSizeStrategy.calculateDesktopTaskSize(mActivity, mActivity.getDeviceProfile(),
mLastComputedDesktopTaskSize);
}
+ if (enableGridOnlyOverview()) {
+ mSizeStrategy.calculateCarouselTaskSize(mActivity, dp, mLastComputedCarouselTaskSize,
+ getPagedOrientationHandler());
+ }
mTaskGridVerticalDiff = mLastComputedGridTaskSize.top - mLastComputedTaskSize.top;
mTopBottomRowHeightDiff =
@@ -2116,6 +2122,7 @@
// Force TaskView to update size from thumbnail
updateTaskSize();
+ updatePivots();
}
/**
@@ -2137,9 +2144,12 @@
}
float accumulatedTranslationX = 0;
- float translateXToMiddle = enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet
- ? mActivity.getDeviceProfile().widthPx / 2 - mLastComputedGridTaskSize.centerX()
- : 0;
+ float translateXToMiddle = 0;
+ if (enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet) {
+ translateXToMiddle = mIsRtl
+ ? mLastComputedCarouselTaskSize.right - mLastComputedTaskSize.right
+ : mLastComputedCarouselTaskSize.left - mLastComputedTaskSize.left;
+ }
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
taskView.updateTaskSize();
@@ -2206,6 +2216,10 @@
return mLastComputedDesktopTaskSize;
}
+ public Rect getLastComputedCarouselTaskSize() {
+ return mLastComputedCarouselTaskSize;
+ }
+
/** Gets the task size for modal state. */
public void getModalTaskSize(Rect outRect) {
mSizeStrategy.calculateModalTaskSize(mActivity, mActivity.getDeviceProfile(), outRect,
@@ -2444,19 +2458,21 @@
mTaskListChangeId = -1;
mFocusedTaskViewId = -1;
- if (mRecentsAnimationController != null) {
- if (mEnableDrawingLiveTile) {
- // We are still drawing the live tile, finish it now to clean up.
+ Log.d(TAG, "reset - mEnableDrawingLiveTile: " + mEnableDrawingLiveTile
+ + ", mRecentsAnimationController: " + mRecentsAnimationController);
+ if (mEnableDrawingLiveTile) {
+ if (mRecentsAnimationController != null) {
+ // We owns mRecentsAnimationController, finish it now to clean up.
finishRecentsAnimation(true /* toRecents */, null);
} else {
- mRecentsAnimationController = null;
+ // Only clean up target set if we no longer owns mRecentsAnimationController.
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTransformParams().setTargetSet(null));
}
+ setEnableDrawingLiveTile(false);
}
- setEnableDrawingLiveTile(false);
- runActionOnRemoteHandles(remoteTargetHandle -> {
- remoteTargetHandle.getTransformParams().setTargetSet(null);
- remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false);
- });
+ runActionOnRemoteHandles(remoteTargetHandle ->
+ remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false));
if (!FeatureFlags.enableSplitContextually()) {
resetFromSplitSelectionState();
}
@@ -2650,6 +2666,7 @@
public void onPrepareGestureEndAnimation(
@Nullable AnimatorSet animatorSet, GestureState.GestureEndTarget endTarget,
TaskViewSimulator[] taskViewSimulators) {
+ Log.d(TAG, "onPrepareGestureEndAnimation - endTarget: " + endTarget);
mCurrentGestureEndTarget = endTarget;
boolean isOverviewEndTarget = endTarget == GestureState.GestureEndTarget.RECENTS;
if (isOverviewEndTarget) {
@@ -2675,6 +2692,9 @@
tvs.taskSecondaryTranslation.value = runningTaskSecondaryGridTranslation;
} else {
animatorSet.play(ObjectAnimator.ofFloat(this, RECENTS_GRID_PROGRESS, 1));
+ animatorSet.play(tvs.carouselScale.animateToValue(1));
+ animatorSet.play(tvs.carouselPrimaryTranslation.animateToValue(0));
+ animatorSet.play(tvs.carouselSecondaryTranslation.animateToValue(0));
animatorSet.play(tvs.taskPrimaryTranslation.animateToValue(
runningTaskPrimaryGridTranslation));
animatorSet.play(tvs.taskSecondaryTranslation.animateToValue(
@@ -2702,6 +2722,7 @@
setEnableFreeScroll(true);
setEnableDrawingLiveTile(mCurrentGestureEndTarget == GestureState.GestureEndTarget.RECENTS);
+ Log.d(TAG, "onGestureAnimationEnd - mEnableDrawingLiveTile: " + mEnableDrawingLiveTile);
setRunningTaskHidden(false);
animateUpTaskIconScale();
animateActionsViewIn();
@@ -4411,12 +4432,13 @@
mTempPointF.set(mLastComputedTaskSize.centerX(), mLastComputedTaskSize.bottom);
}
} else {
- mTempRect.set(mLastComputedTaskSize);
// Only update pivot when it is tablet and not in grid yet, so the pivot is correct
// for non-current tasks when swiping up to overview
if (enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet
&& !mOverviewGridEnabled) {
- mTempRect.offset(mActivity.getDeviceProfile().widthPx / 2 - mTempRect.centerX(), 0);
+ mTempRect.set(mLastComputedCarouselTaskSize);
+ } else {
+ mTempRect.set(mLastComputedTaskSize);
}
getPagedViewOrientedState().getFullScreenScaleAndPivot(mTempRect,
mActivity.getDeviceProfile(), mTempPointF);
@@ -5117,7 +5139,12 @@
* Returns the scale up required on the view, so that it coves the screen completely
*/
public float getMaxScaleForFullScreen() {
- getTaskSize(mTempRect);
+ if (enableGridOnlyOverview() && mActivity.getDeviceProfile().isTablet
+ && !mOverviewGridEnabled) {
+ mTempRect.set(mLastComputedCarouselTaskSize);
+ } else {
+ mTempRect.set(mLastComputedTaskSize);
+ }
return getPagedViewOrientedState().getFullScreenScaleAndPivot(
mTempRect, mActivity.getDeviceProfile(), mTempPointF);
}
@@ -5297,6 +5324,9 @@
// TODO: To be removed in a follow up CL
public void setRecentsAnimationTargets(RecentsAnimationController recentsAnimationController,
RecentsAnimationTargets recentsAnimationTargets) {
+ Log.d(TAG, "setRecentsAnimationTargets "
+ + "- recentsAnimationController: " + recentsAnimationController
+ + ", recentsAnimationTargets: " + recentsAnimationTargets);
mRecentsAnimationController = recentsAnimationController;
mSplitSelectStateController.setRecentsAnimationRunning(true);
if (recentsAnimationTargets == null || recentsAnimationTargets.apps.length == 0) {
@@ -5361,6 +5391,8 @@
public void finishRecentsAnimation(boolean toRecents, boolean shouldPip,
@Nullable Runnable onFinishComplete) {
+ Log.d(TAG, "finishRecentsAnimation - mRecentsAnimationController: "
+ + mRecentsAnimationController);
// TODO(b/197232424#comment#10) Move this back into onRecentsAnimationComplete(). Maybe?
cleanupRemoteTargets();
@@ -5545,7 +5577,7 @@
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
float scrollDiff = taskView.getScrollAdjustment(showAsGrid);
- int pageScroll = newPageScrolls[i] + (int) scrollDiff;
+ int pageScroll = newPageScrolls[i] + Math.round(scrollDiff);
if ((mIsRtl && pageScroll < lastTaskScroll)
|| (!mIsRtl && pageScroll > lastTaskScroll)) {
pageScroll = lastTaskScroll;
@@ -5915,7 +5947,8 @@
return;
}
- mTintingAnimator = ObjectAnimator.ofFloat(this, COLOR_TINT, show ? 0.5f : 0f);
+ mTintingAnimator = ObjectAnimator.ofFloat(this, COLOR_TINT,
+ show ? FOREGROUND_SCRIM_TINT : 0f);
mTintingAnimator.setAutoCancel(true);
mTintingAnimator.start();
}
@@ -5958,6 +5991,7 @@
}
public void cleanupRemoteTargets() {
+ Log.d(TAG, "cleanupRemoteTargets");
mRemoteTargetHandles = null;
}
@@ -6162,9 +6196,7 @@
/** Get the color used for foreground scrimming the RecentsView for sharing. */
public static int getForegroundScrimDimColor(Context context) {
- int baseColor = Themes.getAttrColor(context, R.attr.overviewScrimColor);
- // The Black blending is temporary until we have the proper color token.
- return ColorUtils.blendARGB(Color.BLACK, baseColor, 0.25f);
+ return context.getColor(R.color.overview_foreground_scrim_color);
}
/** Get the RecentsAnimationController */
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 39f1e46..a5e8989 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -113,7 +113,7 @@
@Override
protected void handleClose(boolean animate) {
- if (animate) {
+ if (animate || enableOverviewIconMenu()) {
animateClose();
} else {
closeComplete();
@@ -305,6 +305,8 @@
: Interpolators.DECELERATE);
if (enableOverviewIconMenu()) {
+ IconAppChipView iconAppChip = (IconAppChipView) mTaskContainer.getIconView().asView();
+
float additionalTranslationY = 0;
if (((RecentsView) mActivity.getOverviewPanel()).isOnGridBottomRow(mTaskView)) {
// Animate menu up for enough room to display full menu when task on bottom row.
@@ -320,34 +322,33 @@
: mMenuTranslationYBeforeOpen + additionalTranslationY);
translationYAnim.setInterpolator(EMPHASIZED);
- IconAppChipView iconAppChip = (IconAppChipView) mTaskContainer.getIconView().asView();
ObjectAnimator menuTranslationYAnim = ObjectAnimator.ofFloat(
iconAppChip.getMenuTranslationY(),
MULTI_PROPERTY_VALUE, closing ? 0 : additionalTranslationY);
menuTranslationYAnim.setInterpolator(EMPHASIZED);
- mOpenCloseAnimator.playTogether(translationYAnim, menuTranslationYAnim);
- }
- // Animate menu and icon when split task would display off the side of the screen.
- if (enableOverviewIconMenu() && mActivity.getDeviceProfile().isLandscape
- && mTaskContainer.getStagePosition() == STAGE_POSITION_BOTTOM_OR_RIGHT) {
- float additionalTranslationX = Math.max(
- getTranslationX() + getWidth() - (mActivity.getDeviceProfile().widthPx
- - getResources().getDimensionPixelSize(
- R.dimen.task_menu_edge_padding) * 2), 0);
+ float additionalTranslationX = 0;
+ if (mActivity.getDeviceProfile().isLandscape
+ && mTaskContainer.getStagePosition() == STAGE_POSITION_BOTTOM_OR_RIGHT) {
+ // Animate menu and icon when split task would display off the side of the screen.
+ additionalTranslationX = Math.max(
+ getTranslationX() + getWidth() - (mActivity.getDeviceProfile().widthPx
+ - getResources().getDimensionPixelSize(
+ R.dimen.task_menu_edge_padding) * 2), 0);
+ }
ObjectAnimator translationXAnim = ObjectAnimator.ofFloat(this, TRANSLATION_X,
closing ? mMenuTranslationXBeforeOpen
: mMenuTranslationXBeforeOpen - additionalTranslationX);
translationXAnim.setInterpolator(EMPHASIZED);
- IconAppChipView iconAppChip = (IconAppChipView) mTaskContainer.getIconView().asView();
ObjectAnimator menuTranslationXAnim = ObjectAnimator.ofFloat(
iconAppChip.getMenuTranslationX(),
MULTI_PROPERTY_VALUE, closing ? 0 : -additionalTranslationX);
menuTranslationXAnim.setInterpolator(EMPHASIZED);
- mOpenCloseAnimator.playTogether(translationXAnim, menuTranslationXAnim);
+ mOpenCloseAnimator.playTogether(translationYAnim, translationXAnim,
+ menuTranslationXAnim);
}
mOpenCloseAnimator.playTogether(mRevealAnimator,
@@ -377,21 +378,10 @@
private void closeComplete() {
mIsOpen = false;
- resetOverviewIconMenu();
mActivity.getDragLayer().removeView(this);
mRevealAnimator = null;
}
- private void resetOverviewIconMenu() {
- if (enableOverviewIconMenu()) {
- IconAppChipView iconAppChipView = (IconAppChipView) mTaskContainer.getIconView();
- iconAppChipView.reset();
- iconAppChipView.setMenuTranslationX(0);
- iconAppChipView.setMenuTranslationY(0);
- setTranslationY(mMenuTranslationYBeforeOpen);
- }
- }
-
private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() {
float radius = TaskCornerRadius.get(mContext);
Rect fromRect = new Rect(
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index 5057c38..55da160 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -23,6 +23,7 @@
import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.Flags.enableCursorHoverStates;
+import static com.android.launcher3.Flags.enableGridOnlyOverview;
import static com.android.launcher3.Flags.enableOverviewIconMenu;
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
@@ -1750,7 +1751,13 @@
expectedHeight = boxHeight + thumbnailPadding;
// Scale to to fit task Rect.
- nonGridScale = taskWidth / (float) boxWidth;
+ if (enableGridOnlyOverview()) {
+ final Rect lastComputedCarouselTaskSize =
+ getRecentsView().getLastComputedCarouselTaskSize();
+ nonGridScale = lastComputedCarouselTaskSize.width() / (float) taskWidth;
+ } else {
+ nonGridScale = taskWidth / (float) boxWidth;
+ }
// Align to top of task Rect.
boxTranslationY = (expectedHeight - thumbnailPadding - taskHeight) / 2.0f;
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
index 87cbdd1..c327166 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/navbutton/NavButtonLayoutFactoryTest.kt
@@ -1,12 +1,12 @@
package com.android.launcher3.taskbar.navbutton
+import android.content.res.Configuration
import android.content.res.Resources
import android.view.Surface
import android.view.Surface.ROTATION_270
import android.view.Surface.Rotation
import android.view.View
import android.view.ViewGroup
-import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.Space
@@ -14,7 +14,9 @@
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
import com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION
-import com.android.launcher3.taskbar.TaskbarManager
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_CONTEXTUAL_BUTTONS
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_END_NAV_BUTTONS
+import com.android.launcher3.taskbar.navbutton.LayoutResourceHelper.ID_START_CONTEXTUAL_BUTTONS
import com.android.systemui.shared.rotation.RotationButton
import java.lang.IllegalStateException
import org.junit.Assume.assumeTrue
@@ -40,6 +42,7 @@
private val mockRotationButton: RotationButton = mock()
private val mockA11yButton: ImageView = mock()
private val mockSpace: Space = mock()
+ private val mockConfiguration: Configuration = mock();
private var surfaceRotation = Surface.ROTATION_0
@@ -52,12 +55,15 @@
whenever(mockNavLayout.findViewById<View>(R.id.recent_apps)).thenReturn(mockRecentsButton)
// Init top level layout
- whenever(mockParentButtonContainer.findViewById<LinearLayout>(R.id.end_nav_buttons))
+ whenever(mockParentButtonContainer.requireViewById<LinearLayout>(ID_END_NAV_BUTTONS))
.thenReturn(mockNavLayout)
- whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.end_contextual_buttons))
+ whenever(mockParentButtonContainer.requireViewById<ViewGroup>(ID_END_CONTEXTUAL_BUTTONS))
.thenReturn(mockEndContextualLayout)
- whenever(mockParentButtonContainer.findViewById<ViewGroup>(R.id.start_contextual_buttons))
+ whenever(mockParentButtonContainer.requireViewById<ViewGroup>(ID_START_CONTEXTUAL_BUTTONS))
.thenReturn(mockStartContextualLayout)
+ whenever(mockBackButton.resources).thenReturn(mockResources)
+ whenever(mockResources.configuration).thenReturn(mockConfiguration)
+ whenever(mockConfiguration.layoutDirection).thenReturn(0)
}
@Test
@@ -165,17 +171,19 @@
assert(layoutter is PhoneSeascapeNavLayoutter)
}
- @Test(expected = IllegalStateException::class)
- fun noValidLayoutForPhoneGestureNav() {
+ @Test
+ fun getTaskbarPhoneGestureNavLayoutter() {
assumeTrue(ENABLE_TASKBAR_NAVBAR_UNIFICATION)
mockDeviceProfile.isTaskbarPresent = false
- getLayoutter(
- isKidsMode = false,
- isInSetup = false,
- isThreeButtonNav = false,
- phoneMode = true,
- surfaceRotation = surfaceRotation
- )
+ val layoutter: NavButtonLayoutFactory.NavButtonLayoutter =
+ getLayoutter(
+ isKidsMode = false,
+ isInSetup = false,
+ isThreeButtonNav = false,
+ phoneMode = true,
+ surfaceRotation = surfaceRotation
+ )
+ assert(layoutter is PhoneGestureLayoutter)
}
private fun setDeviceProfileLandscape() {
diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
index 39d6f03..213f58f 100644
--- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
+++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java
@@ -252,6 +252,7 @@
// b/143488140
//@NavigationModeSwitch
@Test
+ @ScreenRecordRule.ScreenRecord // b/321775748
public void testOverview() {
startAppFast(getAppPackageName());
startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java b/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java
index a050464..36c591e 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsKeyboardQuickSwitch.java
@@ -22,8 +22,6 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.tapl.KeyboardQuickSwitch;
-import com.android.launcher3.tapl.LaunchedAppState;
-import com.android.launcher3.tapl.Taskbar;
import com.android.launcher3.taskbar.KeyboardQuickSwitchController;
import com.android.launcher3.ui.AbstractLauncherUiTest;
@@ -38,7 +36,6 @@
private enum TestSurface {
HOME(true),
LAUNCHED_APP(false),
- TASKBAR_ALL_APPS(false),
HOME_ALL_APPS(true),
WIDGETS(true);
@@ -85,11 +82,6 @@
}
@Test
- public void testDismiss_fromTaskbarAllApps() {
- runTest(TestSurface.TASKBAR_ALL_APPS, TestCase.DISMISS);
- }
-
- @Test
public void testDismiss_fromHomeAllApps() {
runTest(TestSurface.HOME_ALL_APPS, TestCase.DISMISS);
}
@@ -110,11 +102,6 @@
}
@Test
- public void testLaunchLastTask_fromTaskbarAllApps() {
- runTest(TestSurface.TASKBAR_ALL_APPS, TestCase.LAUNCH_LAST_APP);
- }
-
- @Test
public void testLaunchLastTask_fromHomeAllApps() {
runTest(TestSurface.HOME_ALL_APPS, TestCase.LAUNCH_LAST_APP);
}
@@ -135,11 +122,6 @@
}
@Test
- public void testLaunchSelectedTask_fromTaskbarAllApps() {
- runTest(TestSurface.TASKBAR_ALL_APPS, TestCase.LAUNCH_SELECTED_APP);
- }
-
- @Test
public void testLaunchSelectedTask_fromHomeAllApps() {
runTest(TestSurface.HOME_ALL_APPS, TestCase.LAUNCH_SELECTED_APP);
}
@@ -160,11 +142,6 @@
}
@Test
- public void testLaunchOverviewTask_fromTaskbarAllApps() {
- runTest(TestSurface.TASKBAR_ALL_APPS, TestCase.LAUNCH_OVERVIEW);
- }
-
- @Test
public void testLaunchOverviewTask_fromHomeAllApps() {
runTest(TestSurface.HOME_ALL_APPS, TestCase.LAUNCH_OVERVIEW);
}
@@ -188,12 +165,6 @@
mLauncher.setIgnoreTaskbarVisibility(true);
kqs = mLauncher.getLaunchedAppState().showQuickSwitchView();
break;
- case TASKBAR_ALL_APPS:
- LaunchedAppState launchedApp = mLauncher.getLaunchedAppState();
- Taskbar taskbar = mLauncher.isTransientTaskbar()
- ? launchedApp.swipeUpToUnstashTaskbar() : launchedApp.getTaskbar();
- kqs = taskbar.openAllApps().showQuickSwitchView();
- break;
case HOME_ALL_APPS:
kqs = mLauncher.goHome().switchToAllApps().showQuickSwitchView();
break;
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
index 360d1a7..cbb4894 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsQuickstep.java
@@ -304,6 +304,7 @@
@Test
@NavigationModeSwitch
@PortraitLandscape
+ @ScreenRecord // b/313464374
public void testQuickSwitchFromApp() throws Exception {
startTestActivity(2);
startTestActivity(3);
diff --git a/res/drawable/ic_install_to_private.xml b/res/drawable/ic_install_to_private.xml
index 7f00f8d..0e9833c 100644
--- a/res/drawable/ic_install_to_private.xml
+++ b/res/drawable/ic_install_to_private.xml
@@ -18,11 +18,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
- android:viewportWidth="960"
- android:viewportHeight="960"
- android:tint="?attr/colorControlNormal">
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?android:attr/textColorPrimary">
<path
android:fillColor="@android:color/white"
- android:pathData="M420,600L540,600L517,471Q537,461 548.5,442Q560,423 560,400Q560,367 536.5,343.5Q513,320 480,320Q447,320 423.5,343.5Q400,367 400,400Q400,423 411.5,442Q423,461 443,471L420,600ZM480,880Q341,845 250.5,720.5Q160,596 160,444L160,200L480,80L800,200L800,444Q800,596 709.5,720.5Q619,845 480,880ZM480,796Q584,763 652,664Q720,565 720,444L720,255L480,165L240,255L240,444Q240,565 308,664Q376,763 480,796ZM480,480Q480,480 480,480Q480,480 480,480L480,480L480,480L480,480L480,480Q480,480 480,480Q480,480 480,480Z"/>
+ android:pathData="M19,5V19H5V5H19ZM19,3H5C3.9,3 3,3.9 3,5V19C3,20.1 3.9,21 5,21H19C20.1,21 21,20.1 21,19V5C21,3.9 20.1,3 19,3Z" />
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M12.93,12.27L13.5,15.5H10.5L11.07,12.27C10.43,11.94 10,11.27 10,10.5C10,9.4 10.9,8.5 12,8.5C13.1,8.5 14,9.4 14,10.5C14,11.27 13.57,11.94 12.93,12.27Z" />
</vector>
diff --git a/res/drawable/ic_lock.xml b/res/drawable/ic_lock.xml
new file mode 100644
index 0000000..055e6b4
--- /dev/null
+++ b/res/drawable/ic_lock.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="20dp"
+ android:height="20dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960">
+ <path
+ android:fillColor="?attr/materialColorOnPrimaryFixed"
+ android:pathData="M263.72,864Q234,864 213,842.85Q192,821.7 192,792L192,408Q192,378.3 213.15,357.15Q234.3,336 264,336L288,336L288,240Q288,160.32 344.23,104.16Q400.45,48 480.23,48Q560,48 616,104.16Q672,160.32 672,240L672,336L696,336Q725.7,336 746.85,357.15Q768,378.3 768,408L768,792Q768,821.7 746.84,842.85Q725.68,864 695.96,864L263.72,864ZM264,792L696,792Q696,792 696,792Q696,792 696,792L696,408Q696,408 696,408Q696,408 696,408L264,408Q264,408 264,408Q264,408 264,408L264,792Q264,792 264,792Q264,792 264,792ZM480.21,672Q510,672 531,650.79Q552,629.58 552,599.79Q552,570 530.79,549Q509.58,528 479.79,528Q450,528 429,549.21Q408,570.42 408,600.21Q408,630 429.21,651Q450.42,672 480.21,672ZM360,336L600,336L600,240Q600,190 565,155Q530,120 480,120Q430,120 395,155Q360,190 360,240L360,336ZM264,792Q264,792 264,792Q264,792 264,792L264,408Q264,408 264,408Q264,408 264,408L264,408Q264,408 264,408Q264,408 264,408L264,792Q264,792 264,792Q264,792 264,792L264,792Z"/>
+</vector>
diff --git a/res/drawable/bg_ps_settings_button.xml b/res/drawable/ic_ps_settings.xml
similarity index 93%
rename from res/drawable/bg_ps_settings_button.xml
rename to res/drawable/ic_ps_settings.xml
index c06e0c0..47edeb8 100644
--- a/res/drawable/bg_ps_settings_button.xml
+++ b/res/drawable/ic_ps_settings.xml
@@ -15,13 +15,10 @@
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="@dimen/ps_button_height"
+ android:width="@dimen/ps_button_width"
android:height="@dimen/ps_button_height"
android:viewportWidth="40"
android:viewportHeight="40">
- <path
- android:pathData="M20,0L20,0A20,20 0,0 1,40 20L40,20A20,20 0,0 1,20 40L20,40A20,20 0,0 1,0 20L0,20A20,20 0,0 1,20 0z"
- android:fillColor="?attr/materialColorSurfaceBright"/>
<group>
<clip-path
android:pathData="M10,10h20v20h-20z"/>
diff --git a/res/drawable/ps_lock_background.xml b/res/drawable/ps_lock_background.xml
new file mode 100644
index 0000000..b81c23f
--- /dev/null
+++ b/res/drawable/ps_lock_background.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:inset="4dp">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/ps_lock_corner_radius" />
+ <solid android:color="?attr/materialColorPrimaryFixedDim" />
+ <padding
+ android:left="@dimen/ps_lock_button_background_padding"
+ android:right="@dimen/ps_lock_button_background_padding" />
+ </shape>
+</inset>
\ No newline at end of file
diff --git a/res/drawable/ps_settings_background.xml b/res/drawable/ps_settings_background.xml
new file mode 100644
index 0000000..b0c6b5b
--- /dev/null
+++ b/res/drawable/ps_settings_background.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:inset="4dp">
+ <shape android:shape="rectangle">
+ <corners android:radius="@dimen/ps_lock_corner_radius" />
+ <solid android:color="?attr/materialColorSurfaceBright" />
+ </shape>
+</inset>
\ No newline at end of file
diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml
index 24e290d..0b0af87 100644
--- a/res/layout/private_space_header.xml
+++ b/res/layout/private_space_header.xml
@@ -18,6 +18,7 @@
<RelativeLayout
android:id="@+id/ps_header_layout"
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="@dimen/ps_header_height"
android:background="@drawable/bg_ps_header"
@@ -25,27 +26,53 @@
android:gravity="center_vertical"
android:orientation="horizontal">
- <ImageButton
- android:id="@+id/ps_lock_unlock_button"
+ <LinearLayout
+ android:id="@+id/settingsAndLockGroup"
android:layout_width="wrap_content"
- android:layout_height="@dimen/ps_header_image_height"
+ android:layout_height="wrap_content"
+ android:layout_centerVertical="true"
+ android:gravity="center_vertical"
android:layout_alignParentEnd="true"
- android:layout_centerVertical="true"
- android:background="@android:color/transparent"
- android:layout_marginEnd="@dimen/ps_header_layout_margin"
- android:contentDescription="@string/ps_container_lock_unlock_button" />
-
- <ImageButton
- android:id="@+id/ps_settings_button"
- android:layout_width="wrap_content"
- android:layout_height="@dimen/ps_header_image_height"
- android:layout_toStartOf="@+id/ps_lock_unlock_button"
- android:layout_centerVertical="true"
- android:background="@android:color/transparent"
- android:layout_marginEnd="@dimen/ps_header_settings_icon_margin_end"
- android:src="@drawable/bg_ps_settings_button"
- android:contentDescription="@string/ps_container_settings" />
-
+ android:animateLayoutChanges="true">
+ <ImageButton
+ android:id="@+id/ps_settings_button"
+ android:layout_width="@dimen/ps_header_image_height"
+ android:layout_height="@dimen/ps_header_image_height"
+ android:background="@drawable/ps_settings_background"
+ android:layout_marginEnd="@dimen/ps_header_settings_icon_margin_end"
+ android:src="@drawable/ic_ps_settings"
+ android:contentDescription="@string/ps_container_settings" />
+ <LinearLayout
+ android:id="@+id/ps_lock_unlock_button"
+ android:layout_width="wrap_content"
+ android:layout_height="@dimen/ps_header_image_height"
+ android:background="@drawable/ps_lock_background"
+ android:gravity="center_vertical"
+ android:layout_marginEnd="@dimen/ps_header_layout_margin"
+ android:contentDescription="@string/ps_container_lock_unlock_button">
+ <ImageView
+ android:id="@+id/lock_icon"
+ android:layout_width="@dimen/ps_lock_icon_size"
+ android:layout_height="@dimen/ps_lock_icon_size"
+ android:layout_marginTop="@dimen/ps_lock_icon_margin_top"
+ android:layout_marginBottom="@dimen/ps_lock_icon_margin_bottom"
+ android:importantForAccessibility="no"
+ android:src="@drawable/ic_lock"
+ app:tint="@color/material_color_primary_fixed_dim"
+ android:scaleType="center"/>
+ <TextView
+ android:id="@+id/lock_text"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginStart="@dimen/ps_lock_icon_text_margin_start_expanded"
+ android:layout_marginEnd="@dimen/ps_lock_icon_text_margin_end_expanded"
+ android:textColor="@color/material_color_on_primary_fixed"
+ android:textSize="14sp"
+ android:text="@string/ps_container_lock_title"
+ android:visibility="gone"
+ style="@style/TextHeadline"/>
+ </LinearLayout>
+ </LinearLayout>
<ImageView
android:id="@+id/ps_transition_image"
android:layout_width="wrap_content"
@@ -63,6 +90,7 @@
android:layout_height="@dimen/ps_header_text_height"
android:layout_alignParentStart="true"
android:layout_centerVertical="true"
+ android:layout_toStartOf="@+id/settingsAndLockGroup"
android:gravity="center_vertical"
android:layout_marginStart="@dimen/ps_header_layout_margin"
android:text="@string/ps_container_title"
diff --git a/res/layout/widget_recommendations.xml b/res/layout/widget_recommendations.xml
new file mode 100644
index 0000000..89821ac
--- /dev/null
+++ b/res/layout/widget_recommendations.xml
@@ -0,0 +1,58 @@
+<?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.
+ -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:launcher="http://schemas.android.com/apk/res-auto">
+
+ <!--
+ Shown when there are more than one pages
+ Note: on page change, using accessibility live region lets user know that the title has changed.
+ -->
+ <TextView
+ android:id="@+id/recommendations_page_title"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginBottom="12dp"
+ android:layout_marginTop="16dp"
+ android:accessibilityLiveRegion="polite"
+ android:gravity="center_horizontal"
+ android:lineHeight="20sp"
+ android:textColor="?attr/widgetPickerTitleColor"
+ android:textFontWeight="500"
+ android:textSize="16sp"
+ android:visibility="gone" />
+ <!-- Shown when there are more than one pages -->
+ <com.android.launcher3.pageindicators.PageIndicatorDots
+ android:id="@+id/widget_recommendations_page_indicator"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center_horizontal"
+ android:elevation="1dp"
+ android:visibility="gone" />
+ <!--
+ Note: importantForAccessibility = yes on this view ensures that with talkback, when user
+ swipes right on the last item in current page, they are taken to the next page. And, doing
+ the same on the last page, takes them to the next section e.g. apps list in single pane
+ picker.
+ -->
+ <com.android.launcher3.widget.picker.WidgetRecommendationsView
+ android:id="@+id/widget_recommendations_view"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:background="@drawable/widgets_surface_background"
+ android:importantForAccessibility="yes"
+ launcher:pageIndicator="@+id/widget_recommendations_page_indicator" />
+</merge>
\ No newline at end of file
diff --git a/res/layout/widget_recommendations_table.xml b/res/layout/widget_recommendations_table.xml
new file mode 100644
index 0000000..e3f0562
--- /dev/null
+++ b/res/layout/widget_recommendations_table.xml
@@ -0,0 +1,21 @@
+<?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.
+ -->
+<com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
+ 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 069d4bc..1d37043 100644
--- a/res/layout/widgets_full_sheet_paged_view.xml
+++ b/res/layout/widgets_full_sheet_paged_view.xml
@@ -73,15 +73,18 @@
<include layout="@layout/widgets_search_bar" />
</FrameLayout>
- <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
- android:id="@+id/recommended_widget_table"
+ <!-- Shown when there are recommendations to display -->
+ <LinearLayout
+ android:id="@+id/widget_recommendations_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
- android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
android:background="@drawable/widgets_surface_background"
- android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
- android:visibility="gone" />
+ android:orientation="vertical"
+ android:layout_marginHorizontal="@dimen/widget_list_horizontal_margin"
+ android:visibility="gone">
+ <include layout="@layout/widget_recommendations" />
+ </LinearLayout>
<com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip
android:id="@+id/tabs"
diff --git a/res/layout/widgets_full_sheet_recyclerview.xml b/res/layout/widgets_full_sheet_recyclerview.xml
index 25bbad4..dca08ff 100644
--- a/res/layout/widgets_full_sheet_recyclerview.xml
+++ b/res/layout/widgets_full_sheet_recyclerview.xml
@@ -56,14 +56,17 @@
<include layout="@layout/widgets_search_bar" />
</FrameLayout>
- <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
- android:id="@+id/recommended_widget_table"
+ <!-- Shown when there are recommendations to display -->
+ <LinearLayout
+ android:id="@+id/widget_recommendations_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="@drawable/widgets_surface_background"
- android:paddingVertical="@dimen/recommended_widgets_table_vertical_padding"
- android:visibility="gone" />
+ android:orientation="vertical"
+ android:visibility="gone">
+ <include layout="@layout/widget_recommendations" />
+ </LinearLayout>
</com.android.launcher3.views.StickyHeaderLayout>
</merge>
\ No newline at end of file
diff --git a/res/layout/widgets_two_pane_sheet.xml b/res/layout/widgets_two_pane_sheet.xml
index cd7f2e1..8e45740f 100644
--- a/res/layout/widgets_two_pane_sheet.xml
+++ b/res/layout/widgets_two_pane_sheet.xml
@@ -116,14 +116,18 @@
android:clipToOutline="true"
android:paddingBottom="36dp"
android:background="@drawable/widgets_surface_background"
+ android:importantForAccessibility="yes"
android:id="@+id/right_pane">
- <com.android.launcher3.widget.picker.WidgetsRecommendationTableLayout
- android:id="@+id/recommended_widget_table"
+ <!-- Shown when there are recommendations to display -->
+ <LinearLayout
+ android:id="@+id/widget_recommendations_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:paddingHorizontal=
- "@dimen/widget_list_horizontal_margin_two_pane"
- android:visibility="gone" />
+ android:background="@drawable/widgets_surface_background"
+ android:orientation="vertical"
+ android:visibility="gone">
+ <include layout="@layout/widget_recommendations" />
+ </LinearLayout>
</LinearLayout>
</ScrollView>
</FrameLayout>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 15045a7..835c201 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 35ef171..98c41de 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ምግብር}one{# ምግብሮች}other{# ምግብሮች}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# አቋራጭ}one{# አቋራጭ}other{# አቋራጮች}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>፣ <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 3367b68..91e2337 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>، <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 4c984a3..3fa40d5 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# টা ৱিজেট}one{# টা ৱিজেট}other{# টা ৱিজেট}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# টা শ্বৰ্টকাট}one{# টা শ্বৰ্টকাট}other{# টা শ্বৰ্টকাট}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 3d7b348..2848606 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index d6dfd26..f75dd60 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 998cf11..4b3780b 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 35d3185..40c9c6a 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# приспособление}other{# приспособления}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# пряк път}other{# преки пътя}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 955fa71..c34b641 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{#টি উইজেট}one{#টি উইজেট}other{#টি উইজেট}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{#টি শর্টকাট}one{#টি শর্টকাট}other{#টি শর্টকাট}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index f4b3208..e2955c3 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 2905676..a8bae8b 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 68ba856..312b57b 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index f82f539..967a720 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 574a805..478aabc 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 3bd3271..092f8d8 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# γραφικό στοιχείο}other{# γραφικά στοιχεία}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# συντόμευση}other{# συντομεύσεις}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 6a591f6..c88d5e6 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 374102b..fc611f3 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -46,6 +46,7 @@
<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="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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 6a591f6..c88d5e6 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 6a591f6..c88d5e6 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index a3473d6..5ce5858 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -46,6 +46,7 @@
<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="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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index c1d404b..dc087f2 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 5a4a0f5..94d83bd 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 7ed76cc..4b30dce 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index f0da1e1..3c708f8 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 3487632..f9ed4a0 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ابزارک}one{# ابزارک}other{# ابزارک}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# میانبر}one{# میانبر}other{# میانبر}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>،<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index f924205..6d9cf77 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index bcd0d61..a3ed04c 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index c9818ef..80e3059 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 20eebf1..677cfe3 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 376448e..a77cbfd 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# વિજેટ}one{# વિજેટ}other{# વિજેટ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# શૉર્ટકટ}one{# શૉર્ટકટ}other{# શૉર્ટકટ}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 05325e2..b08230e 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -42,10 +42,12 @@
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"सुझाव"</string>
<string name="productivity_widget_recommendation_category_label" msgid="3939186477156514997">"अपना दिन बेहतर बनाएं"</string>
<string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"आपके लिए खबरें"</string>
- <string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"आपके लिए आरामदायक माहौल"</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>
+ <!-- no translation found for widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}one{# विजेट}other{# विजेट}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# शॉर्टकट}one{# शॉर्टकट}other{# शॉर्टकट}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index d06016a..1d85b4c 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 1f0026a..3ee1143 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index bc8af27..4f69c17 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# վիջեթ}one{# վիջեթ}other{# վիջեթ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# դյուրանցում}one{# դյուրանցում}other{# դյուրանցում}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index fc972c8..a1bd81e 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
@@ -94,7 +96,7 @@
<string name="gadget_setup_text" msgid="8348374825537681407">"Setelan widget"</string>
<string name="gadget_complete_setup_text" msgid="309040266978007925">"Ketuk untuk menyelesaikan penyiapan"</string>
<string name="uninstall_system_app_text" msgid="4172046090762920660">"Ini adalah aplikasi sistem dan tidak dapat di-uninstal."</string>
- <string name="folder_hint_text" msgid="5174843001373488816">"Sunting Nama"</string>
+ <string name="folder_hint_text" msgid="5174843001373488816">"Edit Nama"</string>
<string name="disabled_app_label" msgid="6673129024321402780">"<xliff:g id="APP_NAME">%1$s</xliff:g> dinonaktifkan"</string>
<string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{{app_name} memiliki # notifikasi}other{{app_name} memiliki # notifikasi}}"</string>
<string name="default_scroll_format" msgid="7475544710230993317">"Halaman %1$d dari %2$d"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index aa45117..034362e 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 5d91698..808ee5b 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 58bd427..b0e4fc6 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index 6cb99a1..9cb3fd5 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 件のウィジェット}other{# 件のウィジェット}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 件のショートカット}other{# 件のショートカット}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>、<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 0289582..d765680 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ვიჯეტი}other{# ვიჯეტი}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# მალსახმობი}other{# მალსახმობი}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index fb377f4..e0f14ba 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -40,17 +40,13 @@
<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>
- <!-- no translation found for productivity_widget_recommendation_category_label (3939186477156514997) -->
- <skip />
- <!-- no translation found for news_widget_recommendation_category_label (3908242346768119070) -->
- <skip />
- <!-- no translation found for social_and_entertainment_widget_recommendation_category_label (2923840997302308191) -->
- <skip />
- <!-- no translation found for fitness_widget_recommendation_category_label (2657652999128882431) -->
- <skip />
- <!-- no translation found for weather_widget_recommendation_category_label (6712678763480668598) -->
- <skip />
- <!-- no translation found for others_widget_recommendation_category_label (897876078077284733) -->
+ <string name="productivity_widget_recommendation_category_label" msgid="3939186477156514997">"Күні бойы қуатты болыңыз"</string>
+ <string name="news_widget_recommendation_category_label" msgid="3908242346768119070">"Сізге арналған жаңалықтар"</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>
+ <!-- no translation found for widget_picker_right_pane_accessibility_title (1673313931455067502) -->
<skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}other{# виджет}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# таңбаша}other{# таңбаша}}"</string>
@@ -185,8 +181,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Сүзгі"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Қате шықты: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Жеке бөлме"</string>
- <!-- no translation found for private_space_secondary_label (611902414159280263) -->
- <skip />
+ <string name="private_space_secondary_label" msgid="611902414159280263">"Құпия кеңістіктегі қолданбаларды құлыптаулы және жасырын күйде қалдырыңыз."</string>
<string name="ps_container_title" msgid="4391796149519594205">"Жеке"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Жеке бөлме параметрлері"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке бөлмені құлыптау/оның құлпын ашу"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index d1cfaab..c68194a 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ធាតុក្រាហ្វិក #}other{ធាតុក្រាហ្វិក #}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ផ្លូវកាត់ #}other{ផ្លូវកាត់ #}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 86829bd..c82288f 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ವಿಜೆಟ್}one{# ವಿಜೆಟ್ಗಳು}other{# ವಿಜೆಟ್ಗಳು}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ಶಾರ್ಟ್ಕಟ್}one{# ಶಾರ್ಟ್ಕಟ್ಗಳು}other{# ಶಾರ್ಟ್ಕಟ್ಗಳು}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 68a6669..d8e64d6 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{위젯 #개}other{위젯 #개}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{바로가기 #개}other{바로가기 #개}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 2f8784c..8b2fef4 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}other{# виджет}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ыкчам баскыч}other{# ыкчам баскыч}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ldrtl/strings.xml b/res/values-ldrtl/strings.xml
new file mode 100644
index 0000000..118b499
--- /dev/null
+++ b/res/values-ldrtl/strings.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+/*
+* Copyright (C) 2008 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <!-- General -->
+ <skip />
+
+ <!-- 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 left, search and options on right</string>
+</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index c09ae70..99f3042 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ວິດເຈັດ}other{# ວິດເຈັດ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ທາງລັດ}other{# ທາງລັດ}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 5810e53..6579674 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 17d52fa..7df06a9 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index c5fdc03..7dd8926 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виџет}one{# виџет}other{# виџети}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# кратенка}one{# кратенка}other{# кратенки}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 64d6fc9..2abab01 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# വിജറ്റ്}other{# വിജറ്റുകൾ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# കുറുക്കുവഴി}other{# കുറുക്കുവഴികൾ}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 3383e17..71b7d4f 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# виджет}other{# виджет}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# товчлол}other{# товчлол}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 719681a..7b1ceb9 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}other{# विजेट}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# शॉर्टकट}other{# शॉर्टकट}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 18c8b21..94e89e0 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index a25295c..c10ddcd 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{ဝိဂျက် # ခု}other{ဝိဂျက် # ခု}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ဖြတ်လမ်းလင့်ခ် # ခု}other{ဖြတ်လမ်းလင့်ခ် # ခု}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>၊ <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 318c639..ee73d51 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index f9c7c11..f061a82 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}other{# वटा विजेट}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# सर्टकट}other{# वटा सर्टकट}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 1f0d424..557fab3 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index be86550..ed62a35 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ୱିଜେଟ}other{# ୱିଜେଟ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{#ଟି ସର୍ଟକଟ୍}other{#ଟି ସର୍ଟକଟ୍}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 696dfa8..661f035 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ਵਿਜੇਟ}one{# ਵਿਜੇਟ}other{# ਵਿਜੇਟ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ਸ਼ਾਰਟਕੱਟ}one{# ਸ਼ਾਰਟਕੱਟ}other{# ਸ਼ਾਰਟਕੱਟ}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index df685ff..a2627ff 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -46,6 +46,8 @@
<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>
+ <!-- no translation found for widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 44a3168..46ace14 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 0f2791a..f12bd4f 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index e143613..93fb1b1 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g> <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 9e1d87b..4942eeb 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 2b08bc3..a0b54eb 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{විජට් #}one{විජට් #}other{විජට් #}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{කෙටි මං #}one{කෙටි මං #}other{කෙටි මං #}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 5e20961..7853de1 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 3f63d4a..c1f6599 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 1559b17..9dab542 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 6d3a1d3..8553e58 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index d68acad..24cf747 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index dbbf925..4537d82 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-sw720dp-land/dimens.xml b/res/values-sw720dp-land/dimens.xml
index 4d0ac38..dd58cee 100644
--- a/res/values-sw720dp-land/dimens.xml
+++ b/res/values-sw720dp-land/dimens.xml
@@ -32,7 +32,4 @@
<!-- Widget picker-->
<dimen name="widget_list_horizontal_margin">49dp</dimen>
<dimen name="widget_list_horizontal_margin_two_pane">24dp</dimen>
-
-<!-- Bottom sheet-->
- <dimen name="bottom_sheet_extra_top_padding">0dp</dimen>
</resources>
diff --git a/res/values-sw720dp/dimens.xml b/res/values-sw720dp/dimens.xml
index 2b0382d..3c79588 100644
--- a/res/values-sw720dp/dimens.xml
+++ b/res/values-sw720dp/dimens.xml
@@ -38,9 +38,6 @@
<!-- Widget picker-->
<dimen name="widget_list_horizontal_margin">30dp</dimen>
-<!-- Bottom sheet-->
- <dimen name="bottom_sheet_extra_top_padding">300dp</dimen>
-
<!-- Folder spaces -->
<dimen name="folder_footer_horiz_padding">24dp</dimen>
</resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index b7b70af..fede476 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# விட்ஜெட்}other{# விட்ஜெட்டுகள்}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# ஷார்ட்கட்}other{# ஷார்ட்கட்கள்}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 9a0b5a9..9fcc88f 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# విడ్జెట్}other{# విడ్జెట్లు}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# షార్ట్కట్}other{# షార్ట్కట్లు}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index da9b29b..d189ed4 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{วิดเจ็ต # รายการ}other{วิดเจ็ต # รายการ}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{ทางลัด # รายการ}other{ทางลัด # รายการ}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 4719610..3dedd43 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -46,6 +46,8 @@
<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>
+ <!-- no translation found for widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 3fe7b06..561f82e 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 1a09cc0..83727f8 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 529c1aa..c38fde3 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# ویجیٹ}other{# ویجیٹس}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# شارٹ کٹ}other{# شارٹ کٹس}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>، <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index e303642..5c885cd 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-v31/colors.xml b/res/values-v31/colors.xml
index 841e07b..e2f610e 100644
--- a/res/values-v31/colors.xml
+++ b/res/values-v31/colors.xml
@@ -103,6 +103,7 @@
<color name="work_fab_icon_color">
@android:color/system_accent1_900</color>
+ <color name="overview_foreground_scrim_color">@android:color/system_neutral1_1000</color>
<color name="material_color_on_secondary_fixed_variant">@android:color/system_accent2_700</color>
<color name="material_color_on_tertiary_fixed_variant">@android:color/system_accent3_700</color>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index e0af1bf..cf66729 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 2549fe9..5c9f7ac 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 个微件}other{# 个微件}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 个快捷方式}other{# 个快捷方式}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>,<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 1359d31..e0e07c1 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 個小工具}other{# 個小工具}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 個捷徑}other{# 個捷徑}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>、<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index ea3bfa8..bd46e26 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# 項小工具}other{# 項小工具}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# 個捷徑}other{# 個捷徑}}"</string>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>、<xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 2858dda..e5c1924 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -46,6 +46,8 @@
<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 widget_picker_right_pane_accessibility_title (1673313931455067502) -->
+ <skip />
<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>
<string name="widgets_and_shortcuts_count" msgid="7209136747878365116">"<xliff:g id="WIDGETS_COUNT">%1$s</xliff:g>, <xliff:g id="SHORTCUTS_COUNT">%2$s</xliff:g>"</string>
diff --git a/res/values/config.xml b/res/values/config.xml
index 1b74238..21d6024 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -89,6 +89,7 @@
<string name="widget_holder_factory_class" translatable="false"></string>
<string name="taskbar_search_session_controller_class" translatable="false"></string>
<string name="taskbar_model_callbacks_factory_class" translatable="false"></string>
+ <string name="taskbar_view_callbacks_factory_class" translatable="false"></string>
<string name="launcher_restore_event_logger_class" translatable="false"></string>
<!-- View ID to use for QSB widget -->
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index c187000..c101762 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -182,9 +182,8 @@
<dimen name="widget_apps_tabs_vertical_padding">6dp</dimen>
<dimen name="widget_picker_landscape_tablet_left_right_margin">117dp</dimen>
<dimen name="widget_picker_two_panels_left_right_margin">0dp</dimen>
-
- <dimen name="recommended_widgets_table_vertical_padding">8dp</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 -->
@@ -454,7 +453,6 @@
<dimen name="padded_rounded_button_padding">8dp</dimen>
<!-- Bottom sheet related parameters -->
- <dimen name="bottom_sheet_extra_top_padding">0dp</dimen>
<dimen name="bottom_sheet_handle_area_height">36dp</dimen>
<dimen name="bottom_sheet_handle_width">32dp</dimen>
<dimen name="bottom_sheet_handle_height">4dp</dimen>
@@ -476,15 +474,22 @@
<dimen name="ps_container_corner_radius">24dp</dimen>
<dimen name="ps_header_height">64dp</dimen>
<dimen name="ps_header_relative_layout_height">48dp</dimen>
- <dimen name="ps_header_image_height">36dp</dimen>
+ <dimen name="ps_header_image_height">48dp</dimen>
<dimen name="ps_header_text_height">24dp</dimen>
<dimen name="ps_header_layout_margin">16dp</dimen>
<dimen name="ps_header_settings_icon_margin_end">8dp</dimen>
<dimen name="ps_header_text_size">16sp</dimen>
- <dimen name="ps_button_height">36dp</dimen>
- <dimen name="ps_button_width">36dp</dimen>
+ <dimen name="ps_button_height">40dp</dimen>
+ <dimen name="ps_button_width">40dp</dimen>
<dimen name="ps_lock_button_width">89dp</dimen>
<dimen name="ps_app_divider_padding">16dp</dimen>
+ <dimen name="ps_lock_corner_radius">20dp</dimen>
+ <dimen name="ps_lock_icon_size">20dp</dimen>
+ <dimen name="ps_lock_icon_margin_top">10dp</dimen>
+ <dimen name="ps_lock_icon_margin_bottom">10dp</dimen>
+ <dimen name="ps_lock_icon_text_margin_start_expanded">8dp</dimen>
+ <dimen name="ps_lock_icon_text_margin_end_expanded">6dp</dimen>
+ <dimen name="ps_lock_button_background_padding">10dp</dimen>
<!-- WindowManagerProxy -->
<dimen name="max_width_and_height_of_small_display_cutout">136px</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index 5cc4616..379cdda 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -71,12 +71,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">Boost your day</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="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>
+ <!-- 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.
[CHAR_LIMIT=25][ICU SYNTAX] -->
<string name="widgets_count">
@@ -463,6 +465,7 @@
<string name="ps_container_settings">Private Space Settings</string>
<!-- Description for Private Space Lock/Unlock button -->
<string name="ps_container_lock_unlock_button">Lock/Unlock Private Space</string>
+ <string name="ps_container_lock_title">Lock</string>
<!-- Description for Private Space Transition button -->
<string name="ps_container_transition">Private Space Transitioning</string>
<!-- Title for Private Space install app icon -->
diff --git a/res/values/styles.xml b/res/values/styles.xml
index b83be35..401155d 100644
--- a/res/values/styles.xml
+++ b/res/values/styles.xml
@@ -441,5 +441,6 @@
<item name="android:textSize">16sp</item>
<item name="android:textColor">@color/material_color_on_surface</item>
<item name="android:fontFamily">google-sans-text-medium</item>
+ <item name="android:ellipsize">end</item>
</style>
</resources>
diff --git a/src/com/android/launcher3/BaseActivity.java b/src/com/android/launcher3/BaseActivity.java
index 1049314..acfc5e4 100644
--- a/src/com/android/launcher3/BaseActivity.java
+++ b/src/com/android/launcher3/BaseActivity.java
@@ -16,6 +16,8 @@
package com.android.launcher3;
+import static com.android.launcher3.testing.shared.TestProtocol.ACTIVITY_NOT_RESUMED_AFTER_BACK;
+import static com.android.launcher3.testing.shared.TestProtocol.sDebugTracing;
import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
import static com.android.launcher3.util.SystemUiController.UI_STATE_FULLSCREEN_TASK;
@@ -308,6 +310,9 @@
* Sets the activity to appear as paused.
*/
public void setPaused() {
+ if (sDebugTracing) {
+ Log.d(ACTIVITY_NOT_RESUMED_AFTER_BACK, "Activity setPaused: " + this, new Throwable());
+ }
removeActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_DEFERRED_RESUMED);
}
@@ -315,6 +320,7 @@
* Sets the activity to appear as resumed.
*/
public void setResumed() {
+ if (sDebugTracing) Log.d(ACTIVITY_NOT_RESUMED_AFTER_BACK, "Activity setResumed: " + this);
addActivityFlags(ACTIVITY_STATE_RESUMED | ACTIVITY_STATE_USER_ACTIVE);
removeActivityFlags(ACTIVITY_STATE_USER_WILL_BE_ACTIVE);
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 2f0c096..38ddfec 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -294,6 +294,12 @@
mIconLoadRequest.cancel();
mIconLoadRequest = null;
}
+ // Reset any shifty arrangements in case animation is disrupted.
+ setPivotY(0);
+ setAlpha(1);
+ setScaleY(1);
+ setTranslationY(0);
+ setVisibility(VISIBLE);
}
private void cancelDotScaleAnim() {
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 563dfe2..4afa8e0 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -416,15 +416,18 @@
gridVisualizationPaddingY = res.getDimensionPixelSize(
R.dimen.grid_visualization_vertical_cell_spacing);
- // Tablet portrait mode uses a single pane widget picker and extra padding may be applied on
- // top to avoid making it look too elongated.
- final boolean applyExtraTopPadding = isTablet
- && !isLandscape
- && (aspectRatio > MIN_ASPECT_RATIO_FOR_EXTRA_TOP_PADDING);
- bottomSheetTopPadding = mInsets.top // statusbar height
- + (applyExtraTopPadding ? res.getDimensionPixelSize(
- R.dimen.bottom_sheet_extra_top_padding) : 0)
- + (isTablet ? 0 : edgeMarginPx); // phones need edgeMarginPx additional padding
+ {
+ // In large screens, in portrait mode, a bottom sheet can appear too elongated, so, we
+ // apply additional padding.
+ final boolean applyExtraTopPadding = isTablet
+ && !isLandscape
+ && (aspectRatio > MIN_ASPECT_RATIO_FOR_EXTRA_TOP_PADDING);
+ final int derivedTopPadding = heightPx / 6;
+ bottomSheetTopPadding = mInsets.top // statusbar height
+ + (applyExtraTopPadding ? derivedTopPadding : 0)
+ + (isTablet ? 0 : edgeMarginPx); // phones need edgeMarginPx additional padding
+ }
+
bottomSheetOpenDuration = res.getInteger(R.integer.config_bottomSheetOpenDuration);
bottomSheetCloseDuration = res.getInteger(R.integer.config_bottomSheetCloseDuration);
if (isTablet) {
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index 7ec0a89..51c7a05 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -201,7 +201,6 @@
if (mScrollbar != null) {
mScrollbar.reattachThumbToScroll();
}
- // Emphasized interpolators with 500ms duration
smoothScrollBy(0, getAvailableScrollHeight(), Interpolators.EMPHASIZED, duration);
}
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 496cb4e..07eea32 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -27,6 +27,7 @@
import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
+import static com.android.launcher3.Flags.enableAddAppWidgetViaConfigActivityV2;
import static com.android.launcher3.LauncherAnimUtils.HOTSEAT_SCALE_PROPERTY_FACTORY;
import static com.android.launcher3.LauncherAnimUtils.SCALE_INDEX_WIDGET_TRANSITION;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
@@ -116,6 +117,8 @@
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.database.sqlite.SQLiteDatabase;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -237,7 +240,6 @@
import com.android.launcher3.util.Thunk;
import com.android.launcher3.util.TouchController;
import com.android.launcher3.util.TraceHelper;
-import com.android.launcher3.util.ViewOnDrawExecutor;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.ComposeInitializer;
import com.android.launcher3.views.FloatingIconView;
@@ -258,7 +260,7 @@
import com.android.systemui.plugins.LauncherOverlayPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.plugins.shared.LauncherOverlayManager;
-import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
+import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
import com.android.wm.shell.Flags;
import java.io.FileDescriptor;
@@ -829,7 +831,7 @@
announceForAccessibility(R.string.item_added_to_workspace);
break;
case REQUEST_CREATE_APPWIDGET:
- completeAddAppWidget(appWidgetId, info, null, null);
+ completeAddAppWidget(appWidgetId, info, null, null, false, null);
break;
case REQUEST_RECONFIGURE_APPWIDGET:
getStatsLogManager().logger().withItemInfo(info).log(LAUNCHER_WIDGET_RECONFIGURED);
@@ -1016,11 +1018,18 @@
AppWidgetHostView boundWidget = null;
if (resultCode == RESULT_OK) {
animationType = Workspace.COMPLETE_TWO_STAGE_WIDGET_DROP_ANIMATION;
- final AppWidgetHostView layout = mAppWidgetHolder.createView(appWidgetId,
- requestArgs.getWidgetHandler().getProviderInfo(this));
+
+ // Now that we are exiting the config activity with RESULT_OK.
+ // If FLAG_ENABLE_ADD_APP_WIDGET_VIA_CONFIG_ACTIVITY_V2 is enabled, we can retrieve the
+ // PendingAppWidgetHostView from LauncherWidgetHolder (it was added to
+ // LauncherWidgetHolder when starting the config activity).
+ final AppWidgetHostView layout = enableAddAppWidgetViaConfigActivityV2()
+ ? getWorkspace().getWidgetForAppWidgetId(appWidgetId)
+ : mAppWidgetHolder.createView(appWidgetId,
+ requestArgs.getWidgetHandler().getProviderInfo(this));
boundWidget = layout;
onCompleteRunnable = () -> {
- completeAddAppWidget(appWidgetId, requestArgs, layout, null);
+ completeAddAppWidget(appWidgetId, requestArgs, layout, null, false, null);
if (!isInState(EDIT_MODE)) {
mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
}
@@ -1450,14 +1459,15 @@
*/
@Thunk
void completeAddAppWidget(int appWidgetId, ItemInfo itemInfo,
- AppWidgetHostView hostView, LauncherAppWidgetProviderInfo appWidgetInfo) {
+ @Nullable AppWidgetHostView hostView, LauncherAppWidgetProviderInfo appWidgetInfo,
+ boolean showPendingWidget, @Nullable Bitmap widgetPreviewBitmap) {
if (appWidgetInfo == null) {
appWidgetInfo = mAppWidgetManager.getLauncherAppWidgetInfo(appWidgetId,
itemInfo.getTargetComponent());
}
- if (hostView == null) {
+ if (hostView == null && !showPendingWidget) {
// Perform actual inflation because we're live
hostView = mAppWidgetHolder.createView(appWidgetId, appWidgetInfo);
}
@@ -1471,39 +1481,71 @@
launcherInfo.minSpanX = itemInfo.minSpanX;
launcherInfo.minSpanY = itemInfo.minSpanY;
launcherInfo.user = appWidgetInfo.getProfile();
+ CellPos presenterPos = getCellPosMapper().mapModelToPresenter(itemInfo);
+ if (showPendingWidget) {
+ launcherInfo.restoreStatus = LauncherAppWidgetInfo.FLAG_UI_NOT_READY;
+ PendingAppWidgetHostView pendingAppWidgetHostView =
+ new PendingAppWidgetHostView(this, launcherInfo, appWidgetInfo);
+ pendingAppWidgetHostView.setPreviewBitmap(widgetPreviewBitmap);
+ hostView = pendingAppWidgetHostView;
+ } else if (hostView instanceof PendingAppWidgetHostView) {
+ ((PendingAppWidgetHostView) hostView).setPreviewBitmap(null);
+ // User has selected a widget config and exited the config activity, we can trigger
+ // re-inflation of PendingAppWidgetHostView to replace it with
+ // LauncherAppWidgetHostView in workspace.
+ completeRestoreAppWidget(appWidgetId, LauncherAppWidgetInfo.RESTORE_COMPLETED);
+
+ // Show resize frame on the newly inflated LauncherAppWidgetHostView.
+ LauncherAppWidgetHostView reInflatedHostView =
+ getWorkspace().getWidgetForAppWidgetId(appWidgetId);
+ showWidgetResizeFrame(
+ reInflatedHostView,
+ (LauncherAppWidgetInfo) reInflatedHostView.getTag(),
+ presenterPos);
+ return;
+ }
if (itemInfo instanceof PendingAddWidgetInfo) {
launcherInfo.sourceContainer = ((PendingAddWidgetInfo) itemInfo).sourceContainer;
} else if (itemInfo instanceof PendingRequestArgs) {
launcherInfo.sourceContainer =
((PendingRequestArgs) itemInfo).getWidgetSourceContainer();
}
- CellPos presenterPos = getCellPosMapper().mapModelToPresenter(itemInfo);
getModelWriter().addItemToDatabase(launcherInfo,
itemInfo.container, presenterPos.screenId, presenterPos.cellX, presenterPos.cellY);
hostView.setVisibility(View.VISIBLE);
mItemInflater.prepareAppWidget(hostView, launcherInfo);
- mWorkspace.addInScreen(hostView, launcherInfo);
+ if (!enableAddAppWidgetViaConfigActivityV2() || hostView.getParent() == null) {
+ mWorkspace.addInScreen(hostView, launcherInfo);
+ }
announceForAccessibility(R.string.item_added_to_workspace);
// Show the widget resize frame.
if (hostView instanceof LauncherAppWidgetHostView) {
final LauncherAppWidgetHostView launcherHostView = (LauncherAppWidgetHostView) hostView;
- CellLayout cellLayout = getCellLayout(launcherInfo.container, presenterPos.screenId);
- if (mStateManager.getState() == NORMAL) {
- AppWidgetResizeFrame.showForWidget(launcherHostView, cellLayout);
- } else {
- mStateManager.addStateListener(new StateManager.StateListener<LauncherState>() {
- @Override
- public void onStateTransitionComplete(LauncherState finalState) {
- if ((mPrevLauncherState == SPRING_LOADED || mPrevLauncherState == EDIT_MODE)
- && finalState == NORMAL) {
- AppWidgetResizeFrame.showForWidget(launcherHostView, cellLayout);
- mStateManager.removeStateListener(this);
- }
+ showWidgetResizeFrame(launcherHostView, launcherInfo, presenterPos);
+ }
+ }
+
+ /** Show widget resize frame. */
+ private void showWidgetResizeFrame(
+ LauncherAppWidgetHostView launcherHostView,
+ LauncherAppWidgetInfo launcherInfo,
+ CellPos presenterPos) {
+ CellLayout cellLayout = getCellLayout(launcherInfo.container, presenterPos.screenId);
+ if (mStateManager.getState() == NORMAL) {
+ AppWidgetResizeFrame.showForWidget(launcherHostView, cellLayout);
+ } else {
+ mStateManager.addStateListener(new StateManager.StateListener<LauncherState>() {
+ @Override
+ public void onStateTransitionComplete(LauncherState finalState) {
+ if ((mPrevLauncherState == SPRING_LOADED || mPrevLauncherState == EDIT_MODE)
+ && finalState == NORMAL) {
+ AppWidgetResizeFrame.showForWidget(launcherHostView, cellLayout);
+ mStateManager.removeStateListener(this);
}
- });
- }
+ }
+ });
}
}
@@ -1760,19 +1802,39 @@
addAppWidgetImpl(appWidgetId, info, boundWidget, addFlowHandler, 0);
}
+ /**
+ * If FLAG_ENABLE_ADD_APP_WIDGET_VIA_CONFIG_ACTIVITY_V2 is enabled, we always add widget
+ * host view to workspace, otherwise we only add widget to host view if config activity is
+ * not started.
+ */
void addAppWidgetImpl(int appWidgetId, ItemInfo info,
AppWidgetHostView boundWidget, WidgetAddFlowHandler addFlowHandler, int delay) {
- if (!addFlowHandler.startConfigActivity(this, appWidgetId, info,
- REQUEST_CREATE_APPWIDGET)) {
- // If the configuration flow was not started, add the widget
+ final boolean isActivityStarted = addFlowHandler.startConfigActivity(
+ this, appWidgetId, info, REQUEST_CREATE_APPWIDGET);
- // Exit spring loaded mode if necessary after adding the widget
- Runnable onComplete = MULTI_SELECT_EDIT_MODE.get() ? null
- : () -> mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
- completeAddAppWidget(appWidgetId, info, boundWidget,
- addFlowHandler.getProviderInfo(this));
- mWorkspace.removeExtraEmptyScreenDelayed(delay, false, onComplete);
+ if (!enableAddAppWidgetViaConfigActivityV2() && isActivityStarted) {
+ return;
}
+
+ // If FLAG_ENABLE_ADD_APP_WIDGET_VIA_CONFIG_ACTIVITY_V2 is enabled and config activity is
+ // started, we should remove the dropped AppWidgetHostView from drag layer and extract the
+ // Bitmap that shows the preview. Then pass the Bitmap to completeAddAppWidget() to create
+ // a PendingWidgetHostView.
+ Bitmap widgetPreviewBitmap = null;
+ if (isActivityStarted) {
+ DragView dropView = getDragLayer().clearAnimatedView();
+ if (dropView != null && dropView.containsAppWidgetHostView()) {
+ widgetPreviewBitmap = getBitmapFromView(dropView.getContentView());
+ }
+ }
+
+ // Exit spring loaded mode if necessary after adding the widget
+ Runnable onComplete = MULTI_SELECT_EDIT_MODE.get() ? null
+ : () -> mStateManager.goToState(NORMAL, SPRING_LOADED_EXIT_DELAY);
+ completeAddAppWidget(appWidgetId, info, boundWidget,
+ addFlowHandler.getProviderInfo(this), addFlowHandler.needsConfigure(),
+ widgetPreviewBitmap);
+ mWorkspace.removeExtraEmptyScreenDelayed(delay, false, onComplete);
}
public void addPendingItem(PendingAddItemInfo info, int container, int screenId,
@@ -2233,12 +2295,6 @@
return info;
}
- public void clearPendingExecutor(ViewOnDrawExecutor executor) {
- if (mModelCallbacks.getPendingExecutor() == executor) {
- mModelCallbacks.setPendingExecutor(null);
- }
- }
-
/**
* Call back when ModelCallbacks finish binding the Launcher data.
*/
@@ -2373,6 +2429,18 @@
return null;
}
+ /** Convert a {@link View} to {@link Bitmap}. */
+ private static Bitmap getBitmapFromView(@Nullable View view) {
+ if (view == null) {
+ return null;
+ }
+ Bitmap returnedBitmap =
+ Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);
+ Canvas canvas = new Canvas(returnedBitmap);
+ view.draw(canvas);
+ return returnedBitmap;
+ }
+
/**
* Returns the first view matching the operator in the given ViewGroups, or null if none.
* Forward iteration matters.
@@ -2810,7 +2878,7 @@
/**
* Call this after onCreate to set or clear overlay.
*/
- public void setLauncherOverlay(LauncherOverlay overlay) {
+ public void setLauncherOverlay(LauncherOverlayTouchProxy overlay) {
mWorkspace.setLauncherOverlay(overlay);
}
diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java
index d124746..99fca62 100644
--- a/src/com/android/launcher3/LauncherModel.java
+++ b/src/com/android/launcher3/LauncherModel.java
@@ -441,17 +441,35 @@
@Override
public void execute(@NonNull final LauncherAppState app,
@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<>();
synchronized (dataModel) {
for (ItemInfo info : dataModel.itemsIdMap) {
if (info instanceof WorkspaceItemInfo
&& ((WorkspaceItemInfo) info).hasPromiseIconUi()
&& user.equals(info.user)
- && info.getIntent() != null
- && TextUtils.equals(packageName, info.getIntent().getPackage())) {
- removedIds.add(info.id);
+ && info.getIntent() != null) {
+ if (TextUtils.equals(packageName, info.getIntent().getPackage())) {
+ removedIds.add(info.id);
+ }
+ 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);
+ }
}
}
+ if (!archivedPackagesToCacheRefresh.isEmpty()) {
+ apps.updateIconsAndLabels(archivedPackagesToCacheRefresh, user);
+ }
}
if (!removedIds.isEmpty()) {
@@ -459,6 +477,10 @@
ItemInfoMatcher.ofItemIds(removedIds),
"removed because install session failed");
}
+ if (!archivedItemsToCacheRefresh.isEmpty()) {
+ bindUpdatedWorkspaceItems(archivedItemsToCacheRefresh.stream().toList());
+ bindApplicationsIfNeeded();
+ }
}
});
}
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index d2ea7cc..6e66c14 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -17,6 +17,7 @@
import static com.android.app.animation.Interpolators.ACCELERATE_2;
import static com.android.app.animation.Interpolators.DECELERATE_2;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_OVERVIEW;
import static com.android.launcher3.testing.shared.TestProtocol.ALL_APPS_STATE_ORDINAL;
@@ -427,11 +428,20 @@
if (this != NORMAL) {
StateManager<LauncherState> lsm = launcher.getStateManager();
LauncherState lastState = lsm.getLastState();
- lsm.goToState(lastState);
+ lsm.goToState(lastState, forEndCallback(this::onBackPressCompleted));
}
}
/**
+ * To be called if back press is completed in a launcher state.
+ *
+ * @param success whether back press animation was successful or canceled.
+ */
+ protected void onBackPressCompleted(boolean success) {
+ // Do nothing. To be overridden by child class.
+ }
+
+ /**
* Find {@link StateManager} and target {@link LauncherState} to handle back progress in
* predictive back gesture.
*/
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index 5172999..0e38007 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -3,7 +3,6 @@
import android.annotation.TargetApi
import android.os.Build
import android.os.Trace
-import android.view.ViewTreeObserver.OnDrawListener
import androidx.annotation.UiThread
import com.android.launcher3.LauncherConstants.TraceEvents
import com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID
@@ -18,7 +17,6 @@
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.popup.PopupContainerWithArrow
import com.android.launcher3.util.ComponentKey
-import com.android.launcher3.util.Executors
import com.android.launcher3.util.IntArray as LIntArray
import com.android.launcher3.util.IntSet as LIntSet
import com.android.launcher3.util.PackageUserKey
@@ -77,11 +75,15 @@
workspaceItemCount: Int,
isBindSync: Boolean
) {
+ if (Utilities.ATLEAST_S) {
+ Trace.endAsyncSection(
+ TraceEvents.DISPLAY_WORKSPACE_TRACE_METHOD_NAME,
+ TraceEvents.DISPLAY_WORKSPACE_TRACE_COOKIE
+ )
+ }
synchronouslyBoundPages = boundPages
pagesToBindSynchronously = LIntSet()
clearPendingBinds()
- val executor = ViewOnDrawExecutor(pendingTasks)
- pendingExecutor = executor
if (!launcher.isInState(LauncherState.ALL_APPS)) {
launcher.appsView.appsStore.enableDeferUpdates(AllAppsStore.DEFER_UPDATES_NEXT_DRAW)
pendingTasks.add {
@@ -90,24 +92,15 @@
)
}
}
- executor.onLoadAnimationCompleted()
- executor.attachTo(launcher)
- if (Utilities.ATLEAST_S) {
- Trace.endAsyncSection(
- TraceEvents.DISPLAY_WORKSPACE_TRACE_METHOD_NAME,
- TraceEvents.DISPLAY_WORKSPACE_TRACE_COOKIE
- )
- }
- launcher.bindComplete(workspaceItemCount, isBindSync)
- launcher.rootView.viewTreeObserver.addOnDrawListener(
- object : OnDrawListener {
- override fun onDraw() {
- Executors.MAIN_EXECUTOR.handler.postAtFrontOfQueue {
- launcher.rootView.getViewTreeObserver().removeOnDrawListener(this)
- }
+ val executor =
+ ViewOnDrawExecutor(pendingTasks) {
+ if (pendingExecutor == it) {
+ pendingExecutor = null
}
}
- )
+ pendingExecutor = executor
+ executor.attachTo(launcher)
+ launcher.bindComplete(workspaceItemCount, isBindSync)
}
/**
@@ -178,7 +171,10 @@
val hadWorkApps = launcher.appsView.shouldShowTabs()
launcher.appsView.appsStore.setApps(apps, flags, packageUserKeytoUidMap)
PopupContainerWithArrow.dismissInvalidPopup(launcher)
- if (hadWorkApps != launcher.appsView.shouldShowTabs()) {
+ if (
+ hadWorkApps != launcher.appsView.shouldShowTabs() &&
+ launcher.stateManager.state == LauncherState.ALL_APPS
+ ) {
launcher.stateManager.goToState(LauncherState.NORMAL)
}
}
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index ca83245..1fede56 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1140,7 +1140,7 @@
mEdgeGlowLeft.onPullDistance(0f, 1f - displacement);
}
if (!mEdgeGlowRight.isFinished()) {
- mEdgeGlowRight.onPullDistance(0f, displacement);
+ mEdgeGlowRight.onPullDistance(0f, displacement, ev);
}
}
@@ -1320,10 +1320,10 @@
int consumed = 0;
if (delta < 0 && mEdgeGlowRight.getDistance() != 0f) {
consumed = Math.round(size *
- mEdgeGlowRight.onPullDistance(delta / size, displacement));
+ mEdgeGlowRight.onPullDistance(delta / size, displacement, ev));
} else if (delta > 0 && mEdgeGlowLeft.getDistance() != 0f) {
consumed = Math.round(-size *
- mEdgeGlowLeft.onPullDistance(-delta / size, 1 - displacement));
+ mEdgeGlowLeft.onPullDistance(-delta / size, 1 - displacement, ev));
}
delta -= consumed;
}
@@ -1341,14 +1341,14 @@
final float pulledToX = oldScroll + delta;
if (pulledToX < mMinScroll) {
- mEdgeGlowLeft.onPullDistance(-delta / size, 1.f - displacement);
+ mEdgeGlowLeft.onPullDistance(-delta / size, 1.f - displacement, ev);
if (!mEdgeGlowRight.isFinished()) {
- mEdgeGlowRight.onRelease();
+ mEdgeGlowRight.onRelease(ev);
}
} else if (pulledToX > mMaxScroll) {
- mEdgeGlowRight.onPullDistance(delta / size, displacement);
+ mEdgeGlowRight.onPullDistance(delta / size, displacement, ev);
if (!mEdgeGlowLeft.isFinished()) {
- mEdgeGlowLeft.onRelease();
+ mEdgeGlowLeft.onRelease(ev);
}
}
@@ -1356,7 +1356,6 @@
postInvalidateOnAnimation();
}
}
-
} else {
awakenScrollBars();
}
@@ -1456,10 +1455,11 @@
}
invalidate();
}
+ mEdgeGlowLeft.onFlingVelocity(velocity);
+ mEdgeGlowRight.onFlingVelocity(velocity);
}
-
- mEdgeGlowLeft.onRelease();
- mEdgeGlowRight.onRelease();
+ mEdgeGlowLeft.onRelease(ev);
+ mEdgeGlowRight.onRelease(ev);
// End any intermediate reordering states
resetTouchState();
break;
@@ -1468,8 +1468,8 @@
if (mIsBeingDragged) {
runOnPageScrollsInitialized(this::snapToDestination);
}
- mEdgeGlowLeft.onRelease();
- mEdgeGlowRight.onRelease();
+ mEdgeGlowLeft.onRelease(ev);
+ mEdgeGlowRight.onRelease(ev);
resetTouchState();
break;
diff --git a/src/com/android/launcher3/SessionCommitReceiver.java b/src/com/android/launcher3/SessionCommitReceiver.java
index d460ba8..6168e41 100644
--- a/src/com/android/launcher3/SessionCommitReceiver.java
+++ b/src/com/android/launcher3/SessionCommitReceiver.java
@@ -30,6 +30,7 @@
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.ItemInstallQueue;
import com.android.launcher3.pm.InstallSessionHelper;
+import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.Executors;
import java.util.Locale;
@@ -51,13 +52,13 @@
@WorkerThread
private static void processIntent(Context context, Intent intent) {
- if (!isEnabled(context)) {
+ UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
+ if (!isEnabled(context, user)) {
// User has decided to not add icons on homescreen.
return;
}
SessionInfo info = intent.getParcelableExtra(PackageInstaller.EXTRA_SESSION);
- UserHandle user = intent.getParcelableExtra(Intent.EXTRA_USER);
if (!PackageInstaller.ACTION_SESSION_COMMITTED.equals(intent.getAction())
|| info == null || user == null) {
// Invalid intent.
@@ -92,7 +93,17 @@
.queueItem(info.getAppPackageName(), user);
}
- public static boolean isEnabled(Context context) {
+ /**
+ * Returns whether adding Installed App Icons to home screen is allowed or not.
+ * Not allowed when:
+ * - User belongs to {@link com.android.launcher3.util.UserIconInfo.TYPE_PRIVATE} or
+ * - Home Settings preference to add App Icons on Home Screen is set as disabled
+ */
+ public static boolean isEnabled(Context context, UserHandle user) {
+ if (Flags.privateSpaceRestrictItemDrag() && user != null
+ && UserCache.getInstance(context).getUserInfo(user).isPrivate()) {
+ return false;
+ }
return LauncherPrefs.getPrefs(context).getBoolean(ADD_ICON_PREFERENCE_KEY, true);
}
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index ac0d7ce..55416af 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -125,8 +125,8 @@
import com.android.launcher3.widget.WidgetManagerHelper;
import com.android.launcher3.widget.dragndrop.AppWidgetHostViewDragListener;
import com.android.launcher3.widget.util.WidgetSizes;
-import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayCallbacks;
+import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
import java.util.ArrayList;
import java.util.Iterator;
@@ -1237,7 +1237,7 @@
mLauncher.onPageEndTransition();
}
- public void setLauncherOverlay(LauncherOverlay overlay) {
+ public void setLauncherOverlay(LauncherOverlayTouchProxy overlay) {
final EdgeEffectCompat newEffect;
if (overlay == null) {
newEffect = new EdgeEffectCompat(getContext());
@@ -2988,7 +2988,7 @@
}
public void animateWidgetDrop(ItemInfo info, CellLayout cellLayout, final DragView dragView,
- final Runnable onCompleteRunnable, int animationType, final View finalView,
+ final Runnable onCompleteRunnable, int animationType, @Nullable final View finalView,
boolean external) {
int[] finalPos = new int[2];
float scaleXY[] = new float[2];
diff --git a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
index 7067fa2..911612f 100644
--- a/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
+++ b/src/com/android/launcher3/allapps/AllAppsFastScrollHelper.java
@@ -71,7 +71,7 @@
@Override
protected int getVerticalSnapPreference() {
- return SNAP_TO_START;
+ return SNAP_TO_ANY;
}
@Override
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index 051cf50..009a2aa6 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -93,11 +93,14 @@
* Sets the current set of apps and sets mapping for {@link PackageUserKey} to Uid for
* the current set of apps.
*
- * <p> Note that shouldPreinflate param should be set to {@code false} for taskbar, because this
- * method is too late to preinflate all apps, as user will open all apps in the same frame.
+ * <p> Note that shouldPreinflate param should be set to {@code false} for taskbar, because
+ * this method is too late to preinflate all apps, as user will open all apps in the frame
+ *
+ * <p>Param: apps are required to be sorted using the comparator COMPONENT_KEY_COMPARATOR
+ * in order to enable binary search on the mApps store
*/
public void setApps(@Nullable AppInfo[] apps, int flags, Map<PackageUserKey, Integer> map,
- boolean shouldPreinflate) {
+ boolean shouldPreinflate) {
mApps = apps == null ? EMPTY_ARRAY : apps;
mModelFlags = flags;
notifyUpdate();
diff --git a/src/com/android/launcher3/allapps/AppInfoComparator.java b/src/com/android/launcher3/allapps/AppInfoComparator.java
index 311a40e..a0867db 100644
--- a/src/com/android/launcher3/allapps/AppInfoComparator.java
+++ b/src/com/android/launcher3/allapps/AppInfoComparator.java
@@ -43,9 +43,7 @@
@Override
public int compare(AppInfo a, AppInfo b) {
// Order by the title in the current locale
- int result = mLabelComparator.compare(
- a.title == null ? "" : a.title.toString(),
- b.title == null ? "" : b.title.toString());
+ int result = mLabelComparator.compare(getSortingTitle(a), getSortingTitle(b));
if (result != 0) {
return result;
}
@@ -64,4 +62,14 @@
return aUserSerial.compareTo(bUserSerial);
}
}
+
+ private String getSortingTitle(AppInfo info) {
+ if (info.appTitle != null) {
+ return info.appTitle.toString();
+ }
+ if (info.title != null) {
+ return info.title.toString();
+ }
+ return "";
+ }
}
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 28c87b6..27092f6 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -258,6 +258,7 @@
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
+ holder.itemView.setVisibility(View.VISIBLE);
switch (holder.getItemViewType()) {
case VIEW_TYPE_ICON: {
AdapterItem adapterItem = mApps.getAdapterItems().get(position);
diff --git a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
index fcdfaa6..91fcf80 100644
--- a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
+++ b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
@@ -16,7 +16,12 @@
package com.android.launcher3.allapps;
+import static android.view.View.GONE;
+import static android.view.View.VISIBLE;
+
+import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
+import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
import static com.android.launcher3.allapps.PrivateProfileManager.STATE_DISABLED;
import static com.android.launcher3.allapps.PrivateProfileManager.STATE_ENABLED;
import static com.android.launcher3.allapps.PrivateProfileManager.STATE_TRANSITION;
@@ -24,21 +29,37 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP;
-import android.view.View;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.LayoutTransition;
+import android.animation.ValueAnimator;
+import android.view.ViewGroup;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
+import android.widget.TextView;
+import androidx.recyclerview.widget.LinearSmoothScroller;
+import androidx.recyclerview.widget.RecyclerView;
+
+import com.android.app.animation.Interpolators;
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 java.util.List;
/**
* Controller which returns views to be added to Private Space Header based upon
* {@link UserProfileState}
*/
public class PrivateSpaceHeaderViewController {
- private static final int ANIMATION_DURATION = 2000;
+ 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;
private final PrivateProfileManager mPrivateProfileManager;
@@ -50,10 +71,17 @@
/** Add Private Space Header view elements based upon {@link UserProfileState} */
public void addPrivateSpaceHeaderViewElements(RelativeLayout parent) {
+ // Set the transition duration for the settings and lock button to animate.
+ ViewGroup settingsAndLockGroup = parent.findViewById(R.id.settingsAndLockGroup);
+ LayoutTransition settingsAndLockTransition = settingsAndLockGroup.getLayoutTransition();
+ settingsAndLockTransition.enableTransitionType(LayoutTransition.CHANGING);
+ settingsAndLockTransition.setDuration(EXPAND_COLLAPSE_DURATION);
+
//Add quietMode image and action for lock/unlock button
- ImageButton quietModeButton = parent.findViewById(R.id.ps_lock_unlock_button);
- assert quietModeButton != null;
- addQuietModeButton(quietModeButton);
+ ViewGroup lockButton =
+ parent.findViewById(R.id.ps_lock_unlock_button);
+ assert lockButton != null;
+ addLockButton(parent, lockButton);
//Trigger lock/unlock action from header.
addHeaderOnClickListener(parent);
@@ -69,74 +97,181 @@
addTransitionImage(transitionView);
}
- private void addQuietModeButton(ImageButton quietModeButton) {
+ /**
+ * Adds the quietModeButton and attach onClickListener for the header to animate different
+ * states when clicked.
+ */
+ private void addLockButton(ViewGroup psHeader, ViewGroup lockButton) {
+ TextView lockText = lockButton.findViewById(R.id.lock_text);
switch (mPrivateProfileManager.getCurrentState()) {
case STATE_ENABLED -> {
- quietModeButton.setVisibility(View.VISIBLE);
- quietModeButton.setImageResource(R.drawable.bg_ps_lock_button);
- quietModeButton.setOnClickListener(view -> lockAction());
+ lockText.setVisibility(VISIBLE);
+ lockButton.setVisibility(VISIBLE);
+ lockButton.setOnClickListener(view -> lockAction(psHeader));
}
case STATE_DISABLED -> {
- quietModeButton.setVisibility(View.VISIBLE);
- quietModeButton.setImageResource(R.drawable.bg_ps_unlock_button);
- quietModeButton.setOnClickListener(view -> unLockAction());
+ lockText.setVisibility(GONE);
+ lockButton.setVisibility(VISIBLE);
+ lockButton.setOnClickListener(view -> unlockAction(psHeader));
}
- default -> quietModeButton.setVisibility(View.GONE);
+ default -> lockButton.setVisibility(GONE);
}
}
private void addHeaderOnClickListener(RelativeLayout header) {
if (mPrivateProfileManager.getCurrentState() == STATE_DISABLED) {
- header.setOnClickListener(view -> unLockAction());
+ header.setOnClickListener(view -> unlockAction(header));
} else {
header.setOnClickListener(null);
}
}
- private void unLockAction() {
+ private void unlockAction(ViewGroup psHeader) {
mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP);
- mPrivateProfileManager.unlockPrivateProfile((this::onPrivateProfileUnlocked));
+ mPrivateProfileManager.unlockPrivateProfile((() -> onPrivateProfileUnlocked(psHeader)));
}
- private void lockAction() {
+ private void lockAction(ViewGroup psHeader) {
mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_LOCK_TAP);
- mPrivateProfileManager.lockPrivateProfile();
+ if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()) {
+ updatePrivateStateAnimator(false, psHeader);
+ } else {
+ mPrivateProfileManager.lockPrivateProfile();
+ }
}
private void addPrivateSpaceSettingsButton(ImageButton settingsButton) {
if (mPrivateProfileManager.getCurrentState() == STATE_ENABLED
&& mPrivateProfileManager.isPrivateSpaceSettingsAvailable()) {
- settingsButton.setVisibility(View.VISIBLE);
+ settingsButton.setVisibility(VISIBLE);
+ settingsButton.setAlpha(1f);
settingsButton.setOnClickListener(
view -> {
mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
mPrivateProfileManager.openPrivateSpaceSettings();
});
} else {
- settingsButton.setVisibility(View.GONE);
+ settingsButton.setVisibility(GONE);
}
}
private void addTransitionImage(ImageView transitionImage) {
if (mPrivateProfileManager.getCurrentState() == STATE_TRANSITION) {
- transitionImage.setVisibility(View.VISIBLE);
+ transitionImage.setVisibility(VISIBLE);
} else {
- transitionImage.setVisibility(View.GONE);
+ transitionImage.setVisibility(GONE);
}
}
- private void onPrivateProfileUnlocked() {
+ private void onPrivateProfileUnlocked(ViewGroup header) {
// If we are on main adapter view, we apply the PS Container expansion animation and
// then scroll down to load the entire container, making animation visible.
ActivityAllAppsContainerView<?>.AdapterHolder mainAdapterHolder =
(ActivityAllAppsContainerView<?>.AdapterHolder) mAllApps.mAH.get(MAIN);
if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()
&& mAllApps.getActiveRecyclerView() == mainAdapterHolder.mRecyclerView) {
- mAllApps.getActiveRecyclerView().scrollToBottomWithMotion(ANIMATION_DURATION);
+ // Animate the text and settings icon.
+ updatePrivateStateAnimator(true, header);
+ mAllApps.getActiveRecyclerView().scrollToBottomWithMotion(EXPAND_SCROLL_DURATION);
+ }
+ }
+
+ /** 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;
+ }
+ // Scroll to the private space header.
+ if (allAppsAdapters.get(adapterPosition).viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+ // Note: SmoothScroller is meant to be used once.
+ RecyclerView.SmoothScroller smoothScroller =
+ new LinearSmoothScroller(mAllApps.getContext()) {
+ @Override protected int getVerticalSnapPreference() {
+ return LinearSmoothScroller.SNAP_TO_END;
+ }
+ };
+ smoothScroller.setTargetPosition(adapterPosition);
+ RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
+ if (layoutManager != null) {
+ layoutManager.startSmoothScroll(smoothScroller);
+ }
+ break;
+ }
+ // Make the private space apps gone to "collapse".
+ if (allAppsAdapters.get(adapterPosition).decorationInfo != null) {
+ allAppsRecyclerView.getChildAt(i).setVisibility(GONE);
+ }
}
}
PrivateProfileManager getPrivateProfileManager() {
return mPrivateProfileManager;
}
+
+ /**
+ * Scrolls up to the private space header and animates the collapsing of the text.
+ */
+ private ValueAnimator animateCollapseAnimation(ViewGroup lockButton) {
+ float from = 1;
+ float to = 0;
+ ValueAnimator collapseAnim = ValueAnimator.ofFloat(from, to);
+ collapseAnim.setDuration(EXPAND_COLLAPSE_DURATION);
+ collapseAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // scroll up
+ collapse();
+ // Animate the collapsing of the text.
+ lockButton.findViewById(R.id.lock_text).setVisibility(GONE);
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ mPrivateProfileManager.lockPrivateProfile();
+ }
+ });
+ return collapseAnim;
+ }
+
+ /**
+ * Using PropertySetter{@link PropertySetter}, we can update the view's attributes within an
+ * animation. At the moment, collapsing, setting alpha changes, and animating the text is done
+ * here.
+ */
+ private void updatePrivateStateAnimator(boolean expand, ViewGroup psHeader) {
+ PropertySetter setter = new AnimatedPropertySetter();
+ ViewGroup lockButton = psHeader.findViewById(R.id.ps_lock_unlock_button);
+ ImageButton settingsButton = psHeader.findViewById(R.id.ps_settings_button);
+ updateSettingsGearAlpha(settingsButton, expand, setter);
+ AnimatorSet animatorSet = setter.buildAnim();
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // Animate the collapsing of the text at the same time while updating lock button.
+ lockButton.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
+ }
+ });
+ // Play the collapsing together of the stateAnimator to avoid being unable to scroll to the
+ // header. Otherwise the smooth scrolling will scroll higher when played with the state
+ // animator.
+ if (!expand) {
+ animatorSet.playTogether(animateCollapseAnimation(lockButton));
+ }
+ animatorSet.setDuration(EXPAND_COLLAPSE_DURATION);
+ animatorSet.start();
+ }
+
+ /** Change the settings gear alpha when expanded or collapsed. */
+ private void updateSettingsGearAlpha(ImageButton settingsButton, boolean expand,
+ PropertySetter setter) {
+ float toAlpha = expand ? 1 : 0;
+ setter.setFloat(settingsButton, VIEW_ALPHA, toAlpha, Interpolators.LINEAR)
+ .setDuration(SETTINGS_OPACITY_DURATION).setStartDelay(0);
+ }
}
diff --git a/src/com/android/launcher3/anim/AnimatedFloat.java b/src/com/android/launcher3/anim/AnimatedFloat.java
index 2f3fa63..b414ab6 100644
--- a/src/com/android/launcher3/anim/AnimatedFloat.java
+++ b/src/com/android/launcher3/anim/AnimatedFloat.java
@@ -109,6 +109,13 @@
public void cancelAnimation() {
if (mValueAnimator != null) {
mValueAnimator.cancel();
+ // Clears the property values, so further ObjectAnimator#setCurrentFraction from e.g.
+ // AnimatorPlaybackController calls would do nothing. The null check is necessary to
+ // avoid mValueAnimator being set to null in onAnimationEnd.
+ if (mValueAnimator != null) {
+ mValueAnimator.setValues();
+ mValueAnimator = null;
+ }
}
}
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index 586beb2..e58890f 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -83,6 +83,20 @@
add(anim);
}
+ /**
+ * Add an {@link AnimatedFloat} to the animation.
+ * <p>
+ * Different from {@link #addFloat}, this method use animator provided by
+ * {@link AnimatedFloat#animateToValue}, which tracks the animator inside the AnimatedFloat,
+ * allowing the animation to be canceled and animate again from AnimatedFloat side.
+ */
+ public void addAnimatedFloat(AnimatedFloat target, float from, float to,
+ TimeInterpolator interpolator) {
+ Animator anim = target.animateToValue(from, to);
+ anim.setInterpolator(interpolator);
+ add(anim);
+ }
+
/** If trace is enabled, add counter to trace animation progress. */
public void logAnimationProgressToTrace(String counterName) {
if (Trace.isEnabled()) {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index e2902e9..072a96c 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -31,6 +31,7 @@
import static com.android.launcher3.uioverrides.flags.FlagsFactory.getReleaseFlag;
import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification;
+import android.content.res.Resources;
import android.view.ViewConfiguration;
import androidx.annotation.VisibleForTesting;
@@ -222,7 +223,19 @@
TEAMFOOD, "Sends a notification whenever launcher encounters an uncaught exception.");
public static final boolean ENABLE_TASKBAR_NAVBAR_UNIFICATION =
- enableTaskbarNavbarUnification();
+ enableTaskbarNavbarUnification() && !isPhone();
+
+ private static boolean isPhone() {
+ final boolean isPhone;
+ int foldedDeviceStatesId = Resources.getSystem().getIdentifier(
+ "config_foldedDeviceStates", "array", "android");
+ if (foldedDeviceStatesId != 0) {
+ isPhone = Resources.getSystem().getIntArray(foldedDeviceStatesId).length == 0;
+ } else {
+ isPhone = true;
+ }
+ return isPhone;
+ }
// Aconfig migration complete for ENABLE_TASKBAR_NO_RECREATION.
public static final BooleanFlag ENABLE_TASKBAR_NO_RECREATION = getDebugFlag(299193589,
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index f18f900..db693f0 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -42,6 +42,8 @@
import android.view.accessibility.AccessibilityManager;
import android.view.animation.Interpolator;
+import androidx.annotation.Nullable;
+
import com.android.app.animation.Interpolators;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DropTargetBar;
@@ -388,7 +390,13 @@
mDropAnim.start();
}
- public void clearAnimatedView() {
+ /**
+ * Remove the drop view and end the drag animation.
+ *
+ * @return {@link DragView} that is removed.
+ */
+ @Nullable
+ public DragView clearAnimatedView() {
if (mDropAnim != null) {
mDropAnim.cancel();
}
@@ -396,8 +404,10 @@
if (mDropView != null) {
mDragController.onDeferredEndDrag(mDropView);
}
+ DragView ret = mDropView;
mDropView = null;
invalidate();
+ return ret;
}
public View getAnimatedView() {
diff --git a/src/com/android/launcher3/dragndrop/DragView.java b/src/com/android/launcher3/dragndrop/DragView.java
index 1f07352..bcee442 100644
--- a/src/com/android/launcher3/dragndrop/DragView.java
+++ b/src/com/android/launcher3/dragndrop/DragView.java
@@ -30,6 +30,7 @@
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
import android.annotation.TargetApi;
+import android.appwidget.AppWidgetHostView;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
@@ -563,6 +564,11 @@
return mContentViewParent;
}
+ /** Return true if {@link mContent} is a {@link AppWidgetHostView}. */
+ public boolean containsAppWidgetHostView() {
+ return mContent instanceof AppWidgetHostView;
+ }
+
private static class SpringFloatValue {
private static final FloatPropertyCompat<SpringFloatValue> VALUE =
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 2f7f51e..d8fa90a 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -219,7 +219,19 @@
CacheEntry entry = cacheLocked(application.componentName,
application.user, () -> null, mLauncherActivityInfoCachingLogic,
false, application.usingLowResIcon());
- if (entry.bitmap != null && !isDefaultIcon(entry.bitmap, application.user)) {
+ if (entry.bitmap == null || isDefaultIcon(entry.bitmap, application.user)) {
+ 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());
+ applyPackageEntry(packageEntry, application, entry);
+ } else {
applyCacheEntry(entry, application);
}
}
@@ -227,10 +239,14 @@
/**
* Fill in {@param info} with the icon and label for {@param activityInfo}
*/
+ @SuppressWarnings("NewApi")
public synchronized void getTitleAndIcon(ItemInfoWithIcon info,
LauncherActivityInfo activityInfo, boolean useLowResIcon) {
+ boolean isAppArchived = Utilities.enableSupportForArchiving() && activityInfo != null
+ && activityInfo.getActivityInfo().isArchived;
// If we already have activity info, no need to use package icon
- getTitleAndIcon(info, () -> activityInfo, false, useLowResIcon);
+ getTitleAndIcon(info, () -> activityInfo, isAppArchived, useLowResIcon,
+ isAppArchived);
}
/**
@@ -309,7 +325,7 @@
} else {
Intent intent = info.getIntent();
getTitleAndIcon(info, () -> mLauncherApps.resolveActivity(intent, info.user),
- true, useLowResIcon);
+ true, useLowResIcon, info.isArchived());
}
}
@@ -334,6 +350,28 @@
}
/**
+ * Fill in {@param mWorkspaceItemInfo} with the icon and label for {@param info}
+ */
+ public synchronized void getTitleAndIcon(
+ @NonNull ItemInfoWithIcon infoInOut,
+ @NonNull Supplier<LauncherActivityInfo> activityInfoProvider,
+ boolean usePkgIcon, boolean useLowResIcon, boolean preferPackageEntry) {
+ CacheEntry entry = cacheLocked(infoInOut.getTargetComponent(), infoInOut.user,
+ activityInfoProvider, mLauncherActivityInfoCachingLogic, usePkgIcon,
+ useLowResIcon);
+ if (preferPackageEntry) {
+ String packageName = infoInOut.getTargetPackage();
+ CacheEntry packageEntry = cacheLocked(
+ new ComponentName(packageName, packageName + EMPTY_CLASS_NAME),
+ infoInOut.user, activityInfoProvider, mLauncherActivityInfoCachingLogic,
+ usePkgIcon, useLowResIcon);
+ applyPackageEntry(packageEntry, infoInOut, entry);
+ } else {
+ applyCacheEntry(entry, infoInOut);
+ }
+ }
+
+ /**
* Creates an sql cursor for a query of a set of ItemInfoWithIcon icons and titles.
*
* @param iconRequestInfos List of IconRequestInfos representing titles and icons to query.
@@ -551,6 +589,19 @@
}
}
+ protected void applyPackageEntry(@NonNull final CacheEntry packageEntry,
+ @NonNull final ItemInfoWithIcon info, @NonNull final CacheEntry fallbackEntry) {
+ info.title = Utilities.trim(packageEntry.title);
+ info.appTitle = Utilities.trim(fallbackEntry.title);
+ info.contentDescription = packageEntry.contentDescription;
+ info.bitmap = packageEntry.bitmap;
+ if (packageEntry.bitmap == null) {
+ // TODO: entry.bitmap can never be null, so this should not happen at all.
+ Log.wtf(TAG, "Cannot find bitmap from the cache, default icon was loaded.");
+ info.bitmap = getDefaultIcon(info.user);
+ }
+ }
+
public Drawable getFullResIcon(LauncherActivityInfo info) {
return mIconProvider.getIcon(info, mIconDpi);
}
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 2a0f030..2aabb7c 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -636,6 +636,9 @@
@UiEvent(doc = "User tapped taskbar All Apps button.")
LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP(1057),
+ @UiEvent(doc = "User long pressed taskbar All Apps button.")
+ LAUNCHER_TASKBAR_ALLAPPS_BUTTON_LONG_PRESS(1607),
+
@UiEvent(doc = "User tapped on Share app system shortcut.")
LAUNCHER_SYSTEM_SHORTCUT_APP_SHARE_TAP(1075),
diff --git a/src/com/android/launcher3/model/ItemInstallQueue.java b/src/com/android/launcher3/model/ItemInstallQueue.java
index 59f453a..d350879 100644
--- a/src/com/android/launcher3/model/ItemInstallQueue.java
+++ b/src/com/android/launcher3/model/ItemInstallQueue.java
@@ -18,7 +18,6 @@
import static android.appwidget.AppWidgetManager.EXTRA_APPWIDGET_ID;
-import static com.android.launcher3.Flags.enableSupportForArchiving;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
@@ -45,6 +44,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherSettings.Favorites;
+import com.android.launcher3.Utilities;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -300,7 +300,8 @@
} else {
lai = laiList.get(0);
si.intent = makeLaunchIntent(lai);
- if (enableSupportForArchiving() && lai.getActivityInfo().isArchived) {
+ if (Utilities.enableSupportForArchiving()
+ && lai.getActivityInfo().isArchived) {
si.runtimeStatusFlags |= FLAG_ARCHIVED;
}
}
diff --git a/src/com/android/launcher3/model/WidgetItem.java b/src/com/android/launcher3/model/WidgetItem.java
index c99b889..ddf4023 100644
--- a/src/com/android/launcher3/model/WidgetItem.java
+++ b/src/com/android/launcher3/model/WidgetItem.java
@@ -1,5 +1,9 @@
package com.android.launcher3.model;
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD;
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX;
+
import static com.android.launcher3.Utilities.ATLEAST_S;
import android.annotation.SuppressLint;
@@ -7,13 +11,19 @@
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.Resources;
+import android.util.SparseArray;
+import android.widget.RemoteViews;
+import androidx.core.os.BuildCompat;
+
+import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Utilities;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.widget.WidgetManagerHelper;
/**
* An wrapper over various items displayed in a widget picker,
@@ -28,9 +38,11 @@
public final String label;
public final CharSequence description;
public final int spanX, spanY;
+ public final SparseArray<RemoteViews> generatedPreviews;
public WidgetItem(LauncherAppWidgetProviderInfo info,
- InvariantDeviceProfile idp, IconCache iconCache, Context context) {
+ InvariantDeviceProfile idp, IconCache iconCache, Context context,
+ WidgetManagerHelper helper) {
super(info.provider, info.getProfile());
label = iconCache.getTitleNoCache(info);
@@ -40,6 +52,27 @@
spanX = Math.min(info.spanX, idp.numColumns);
spanY = Math.min(info.spanY, idp.numRows);
+
+ if (BuildCompat.isAtLeastV() && Flags.enableGeneratedPreviews()) {
+ generatedPreviews = new SparseArray<>(3);
+ for (int widgetCategory : new int[] {
+ WIDGET_CATEGORY_HOME_SCREEN,
+ WIDGET_CATEGORY_KEYGUARD,
+ WIDGET_CATEGORY_SEARCHBOX,
+ }) {
+ if ((widgetCategory & widgetInfo.generatedPreviewCategories) != 0) {
+ generatedPreviews.put(widgetCategory,
+ helper.loadGeneratedPreview(widgetInfo, widgetCategory));
+ }
+ }
+ } else {
+ generatedPreviews = null;
+ }
+ }
+
+ public WidgetItem(LauncherAppWidgetProviderInfo info,
+ InvariantDeviceProfile idp, IconCache iconCache, Context context) {
+ this(info, idp, iconCache, context, new WidgetManagerHelper(context));
}
public WidgetItem(ShortcutConfigActivityInfo info, IconCache iconCache, PackageManager pm) {
@@ -50,6 +83,7 @@
widgetInfo = null;
activityInfo = info;
spanX = spanY = 1;
+ generatedPreviews = null;
}
/**
@@ -78,4 +112,15 @@
public boolean isShortcut() {
return activityInfo != null;
}
+
+ /**
+ * Returns whether this {@link WidgetItem} has a generated preview for the given widget
+ * category.
+ */
+ public boolean hasGeneratedPreview(int widgetCategory) {
+ if (!Flags.enableGeneratedPreviews() || generatedPreviews == null) {
+ return false;
+ }
+ return generatedPreviews.contains(widgetCategory);
+ }
}
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
index 88b98aa..287c29e 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -202,7 +202,7 @@
}
}
}
- pmHelper.isAppOnSdcard(targetPkg!!, c.user) -> {
+ pmHelper.isAppOnSdcard(targetPkg, c.user) -> {
// Package is present but not available.
disabledState =
disabledState or WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE
@@ -278,7 +278,7 @@
info = c.loadSimpleWorkspaceItem()
// Shortcuts are only available on the primary profile
- if (!TextUtils.isEmpty(targetPkg) && pmHelper.isAppSuspended(targetPkg!!, c.user)) {
+ if (!TextUtils.isEmpty(targetPkg) && pmHelper.isAppSuspended(targetPkg, c.user)) {
disabledState = disabledState or ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED
}
info.options = c.options
@@ -333,13 +333,12 @@
info.runtimeStatusFlags and
ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE.inv()
} else if (
- activityInfo ==
- null // For archived apps, include progress info in case there is
- // a pending install session post restart of device.
- ||
+ activityInfo == null ||
(Utilities.enableSupportForArchiving() &&
activityInfo.applicationInfo.isArchived)
) {
+ // For archived apps, include progress info in case there is
+ // a pending install session post restart of device.
val installProgress = (si.getProgress() * 100).toInt()
info.setProgressLevel(installProgress, PackageInstallInfo.STATUS_INSTALLING)
}
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index 86393a0..55849c2 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -160,6 +160,13 @@
public CharSequence title;
/**
+ * Optionally set: The appTitle might e.g. be different if {@code title} is used to
+ * display progress (e.g. Downloading..).
+ */
+ @Nullable
+ public CharSequence appTitle;
+
+ /**
* Content description of the item.
*/
@Nullable
diff --git a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
index df369c6..1b5abaa 100644
--- a/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
+++ b/src/com/android/launcher3/pageindicators/PageIndicatorDots.java
@@ -367,7 +367,7 @@
mNumPages = numMarkers;
// If the last page gets removed we want to go to the previous page.
- if (mNumPages == mActivePage) {
+ if (mNumPages > 0 && mNumPages == mActivePage) {
mActivePage--;
CURRENT_POSITION.set(this, (float) mActivePage);
}
diff --git a/src/com/android/launcher3/pm/InstallSessionHelper.java b/src/com/android/launcher3/pm/InstallSessionHelper.java
index 605ef16..2ec994e 100644
--- a/src/com/android/launcher3/pm/InstallSessionHelper.java
+++ b/src/com/android/launcher3/pm/InstallSessionHelper.java
@@ -211,7 +211,8 @@
*/
@WorkerThread
void tryQueuePromiseAppIcon(@Nullable final PackageInstaller.SessionInfo sessionInfo) {
- if (SessionCommitReceiver.isEnabled(mAppContext)
+ if (sessionInfo != null
+ && SessionCommitReceiver.isEnabled(mAppContext, getUserHandle(sessionInfo))
&& verifySessionInfo(sessionInfo)
&& !promiseIconAddedForId(sessionInfo.getSessionId())) {
FileLog.d(LOG, "Adding package name to install queue: "
diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java
index f1d837c..fb463f7 100644
--- a/src/com/android/launcher3/popup/PopupDataProvider.java
+++ b/src/com/android/launcher3/popup/PopupDataProvider.java
@@ -222,6 +222,7 @@
}
/** Returns the recommended widgets mapped by their category. */
+ @NonNull
public Map<WidgetRecommendationCategory, List<WidgetItem>> getCategorizedRecommendedWidgets() {
Map<ComponentKey, WidgetItem> allWidgetItems = mAllWidgets.stream()
.filter(entry -> entry instanceof WidgetsListContentEntry)
@@ -232,7 +233,8 @@
Function.identity()
));
return mRecommendedWidgets.stream()
- .filter(itemInfo -> itemInfo instanceof PendingAddWidgetInfo)
+ .filter(itemInfo -> itemInfo instanceof PendingAddWidgetInfo
+ && ((PendingAddWidgetInfo) itemInfo).recommendationCategory != null)
.collect(Collectors.groupingBy(
it -> ((PendingAddWidgetInfo) it).recommendationCategory,
Collectors.collectingAndThen(
diff --git a/src/com/android/launcher3/statemanager/StateManager.java b/src/com/android/launcher3/statemanager/StateManager.java
index e8b3066..51bc339 100644
--- a/src/com/android/launcher3/statemanager/StateManager.java
+++ b/src/com/android/launcher3/statemanager/StateManager.java
@@ -38,7 +38,6 @@
import com.android.launcher3.states.StateAnimationConfig;
import com.android.launcher3.states.StateAnimationConfig.AnimationFlags;
import com.android.launcher3.states.StateAnimationConfig.AnimationPropertyFlags;
-import com.android.launcher3.testing.shared.TestProtocol;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -52,6 +51,8 @@
public class StateManager<STATE_TYPE extends BaseState<STATE_TYPE>> {
public static final String TAG = "StateManager";
+ // b/279059025
+ private static final boolean DEBUG = true;
private final AnimationState mConfig = new AnimationState();
private final Handler mUiHandler;
@@ -158,6 +159,13 @@
/**
* @see #goToState(STATE_TYPE, boolean, AnimatorListener)
*/
+ public void goToState(STATE_TYPE state, AnimatorListener listener) {
+ goToState(state, shouldAnimateStateChange(), listener);
+ }
+
+ /**
+ * @see #goToState(STATE_TYPE, boolean, AnimatorListener)
+ */
public void goToState(STATE_TYPE state, boolean animated) {
goToState(state, animated, 0, null);
}
@@ -167,7 +175,7 @@
*
* @param animated false if the state should change immediately without any animation,
* true otherwise
- * @paras onCompleteRunnable any action to perform at the end of the transition, of null.
+ * @param listener any action to perform at the end of the transition, or null.
*/
public void goToState(STATE_TYPE state, boolean animated, AnimatorListener listener) {
goToState(state, animated, 0, listener);
@@ -231,15 +239,18 @@
private void goToState(
STATE_TYPE state, boolean animated, long delay, AnimatorListener listener) {
- String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
- String truncatedTrace =
- Arrays.stream(stackTrace.split("\\n"))
- .limit(5)
- .skip(1) // Removes the line "java.lang.Exception: tracing state transition"
- .filter(traceLine -> !traceLine.contains("StateManager.goToState"))
- .collect(Collectors.joining("\n"));
- Log.d(TestProtocol.OVERVIEW_OVER_HOME,
- "go to state " + state + " partial trace:\n" + truncatedTrace);
+ if (DEBUG) {
+ String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
+ String truncatedTrace =
+ Arrays.stream(stackTrace.split("\\n"))
+ .limit(5)
+ .skip(1) // Removes the line "java.lang.Exception: tracing state
+ // transition"
+ .filter(traceLine -> !traceLine.contains("StateManager.goToState"))
+ .collect(Collectors.joining("\n"));
+ Log.d(TAG, "goToState - fromState: " + mState + ", toState: " + state
+ + ", partial trace:\n" + truncatedTrace);
+ }
animated &= areAnimatorsEnabled();
if (mActivity.isInState(state)) {
@@ -324,6 +335,20 @@
*/
public AnimatorSet createAtomicAnimation(
STATE_TYPE fromState, STATE_TYPE toState, StateAnimationConfig config) {
+ if (DEBUG) {
+ String stackTrace = Log.getStackTraceString(new Exception("tracing state transition"));
+ String truncatedTrace =
+ Arrays.stream(stackTrace.split("\\n"))
+ .limit(5)
+ .skip(1) // Removes the line "java.lang.Exception: tracing state
+ // transition"
+ .filter(traceLine -> !traceLine.contains(
+ "StateManager.createAtomicAnimation"))
+ .collect(Collectors.joining("\n"));
+ Log.d(TAG, "createAtomicAnimation - fromState: " + fromState + ", toState: " + toState
+ + ", partial trace:\n" + truncatedTrace);
+ }
+
PendingAnimation builder = new PendingAnimation(config.duration);
prepareForAtomicAnimation(fromState, toState, config);
@@ -395,8 +420,9 @@
mState = state;
mActivity.onStateSetStart(mState);
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "Notifying listeners for state transition start"
- + " to state: " + state.toString());
+ if (DEBUG) {
+ Log.d(TAG, "onStateTransitionStart - state: " + state);
+ }
for (int i = mListeners.size() - 1; i >= 0; i--) {
mListeners.get(i).onStateTransitionStart(state);
}
@@ -414,8 +440,9 @@
setRestState(null);
}
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "Notifying " + mListeners.size() + " listeners "
- + "for end transition for state: " + state.toString());
+ if (DEBUG) {
+ Log.d(TAG, "onStateTransitionEnd - state: " + state);
+ }
for (int i = mListeners.size() - 1; i >= 0; i--) {
mListeners.get(i).onStateTransitionComplete(state);
}
@@ -453,7 +480,9 @@
* Cancels the current animation.
*/
public void cancelAnimation() {
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "current animation cancelled");
+ if (DEBUG && mConfig.currentAnimation != null) {
+ Log.d(TAG, "cancelAnimation - with ongoing animation");
+ }
mConfig.reset();
// It could happen that a new animation is set as a result of an endListener on the
// existing animation.
@@ -485,7 +514,6 @@
* @param toState The state we are animating towards.
*/
public void setCurrentAnimation(AnimatorSet anim, STATE_TYPE toState) {
- Log.d(TestProtocol.OVERVIEW_OVER_HOME, "setting animation to " + toState.toString());
cancelAnimation();
setCurrentAnimation(anim);
anim.addListener(createStateAnimationListener(toState));
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 1623ad8..1231cd7 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -17,6 +17,7 @@
import static com.android.launcher3.Flags.enableGridOnlyOverview;
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.enableSplitContextually;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
@@ -182,6 +183,11 @@
response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD, mDeviceProfile.isTablet);
return response;
+ case TestProtocol.REQUEST_ENABLE_TASKBAR_NAVBAR_UNIFICATION:
+ response.putBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD,
+ ENABLE_TASKBAR_NAVBAR_UNIFICATION);
+ return response;
+
case TestProtocol.REQUEST_NUM_ALL_APPS_COLUMNS:
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD,
mDeviceProfile.numShownAllAppsColumns);
diff --git a/src/com/android/launcher3/util/EdgeEffectCompat.java b/src/com/android/launcher3/util/EdgeEffectCompat.java
index 491582b..ca37259 100644
--- a/src/com/android/launcher3/util/EdgeEffectCompat.java
+++ b/src/com/android/launcher3/util/EdgeEffectCompat.java
@@ -16,6 +16,7 @@
package com.android.launcher3.util;
import android.content.Context;
+import android.view.MotionEvent;
import android.widget.EdgeEffect;
import com.android.launcher3.Utilities;
@@ -43,4 +44,14 @@
return deltaDistance;
}
}
+
+ public float onPullDistance(float deltaDistance, float displacement, MotionEvent ev) {
+ return onPullDistance(deltaDistance, displacement);
+ }
+
+ public void onFlingVelocity(int velocity) { }
+
+ public void onRelease(MotionEvent ev) {
+ onRelease();
+ }
}
diff --git a/src/com/android/launcher3/util/OverlayEdgeEffect.java b/src/com/android/launcher3/util/OverlayEdgeEffect.java
index 2ef1e1f..d09d801 100644
--- a/src/com/android/launcher3/util/OverlayEdgeEffect.java
+++ b/src/com/android/launcher3/util/OverlayEdgeEffect.java
@@ -17,10 +17,13 @@
import android.content.Context;
import android.graphics.Canvas;
+import android.os.SystemClock;
+import android.view.MotionEvent;
import android.widget.EdgeEffect;
+import com.android.launcher3.BuildConfig;
import com.android.launcher3.Utilities;
-import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlay;
+import com.android.systemui.plugins.shared.LauncherOverlayManager.LauncherOverlayTouchProxy;
/**
* Extension of {@link EdgeEffect} which shows the Launcher overlay
@@ -28,11 +31,11 @@
public class OverlayEdgeEffect extends EdgeEffectCompat {
protected float mDistance;
- protected final LauncherOverlay mOverlay;
+ protected final LauncherOverlayTouchProxy mOverlay;
protected boolean mIsScrolling;
protected final boolean mIsRtl;
- public OverlayEdgeEffect(Context context, LauncherOverlay overlay) {
+ public OverlayEdgeEffect(Context context, LauncherOverlayTouchProxy overlay) {
super(context);
mOverlay = overlay;
mIsRtl = Utilities.isRtl(context.getResources());
@@ -44,12 +47,30 @@
}
public float onPullDistance(float deltaDistance, float displacement) {
+ // Fallback implementation, will never actually get called
+ if (BuildConfig.IS_DEBUG_DEVICE) {
+ throw new RuntimeException("Wrong method called");
+ }
+ MotionEvent mv = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+ MotionEvent.ACTION_MOVE, displacement, 0, 0);
+ try {
+ return onPullDistance(deltaDistance, displacement, mv);
+ } finally {
+ mv.recycle();
+ }
+ }
+
+ @Override
+ public float onPullDistance(float deltaDistance, float displacement, MotionEvent ev) {
mDistance = Math.max(0f, deltaDistance + mDistance);
if (!mIsScrolling) {
- mOverlay.onScrollInteractionBegin();
+ int originalAction = ev.getAction();
+ ev.setAction(MotionEvent.ACTION_DOWN);
+ mOverlay.onOverlayMotionEvent(ev, 0);
+ ev.setAction(originalAction);
mIsScrolling = true;
}
- mOverlay.onScrollChange(mDistance, mIsRtl);
+ mOverlay.onOverlayMotionEvent(ev, mDistance);
return mDistance > 0 ? deltaDistance : 0;
}
@@ -63,9 +84,30 @@
@Override
public void onRelease() {
+ // Fallback implementation, will never actually get called
+ if (BuildConfig.IS_DEBUG_DEVICE) {
+ throw new RuntimeException("Wrong method called");
+ }
+ MotionEvent mv = MotionEvent.obtain(SystemClock.uptimeMillis(), SystemClock.uptimeMillis(),
+ MotionEvent.ACTION_UP, mDistance, 0, 0);
+ onRelease(mv);
+ mv.recycle();
+ }
+
+ @Override
+ public void onFlingVelocity(int velocity) {
+ mOverlay.onFlingVelocity(velocity);
+ }
+
+ @Override
+ public void onRelease(MotionEvent ev) {
if (mIsScrolling) {
+ int originalAction = ev.getAction();
+ ev.setAction(MotionEvent.ACTION_UP);
+ mOverlay.onOverlayMotionEvent(ev, mDistance);
+ ev.setAction(originalAction);
+
mDistance = 0;
- mOverlay.onScrollInteractionEnd();
mIsScrolling = false;
}
}
diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java
index 92288e1..11d8e97 100644
--- a/src/com/android/launcher3/util/PackageManagerHelper.java
+++ b/src/com/android/launcher3/util/PackageManagerHelper.java
@@ -16,8 +16,6 @@
package com.android.launcher3.util;
-import static com.android.launcher3.Flags.enableSupportForArchiving;
-
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
@@ -276,6 +274,6 @@
@SuppressWarnings("NewApi")
private boolean isPackageInstalledOrArchived(ApplicationInfo info) {
return (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0 || (
- enableSupportForArchiving() && info.isArchived);
+ Utilities.enableSupportForArchiving() && info.isArchived);
}
}
diff --git a/src/com/android/launcher3/util/ViewOnDrawExecutor.java b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
index fada4a3..26bfd36 100644
--- a/src/com/android/launcher3/util/ViewOnDrawExecutor.java
+++ b/src/com/android/launcher3/util/ViewOnDrawExecutor.java
@@ -20,6 +20,8 @@
import android.view.View.OnAttachStateChangeListener;
import android.view.ViewTreeObserver.OnDrawListener;
+import androidx.annotation.NonNull;
+
import com.android.launcher3.Launcher;
import java.util.function.Consumer;
@@ -31,26 +33,23 @@
OnAttachStateChangeListener {
private final RunnableList mTasks;
-
- private Consumer<ViewOnDrawExecutor> mOnClearCallback;
+ private final Consumer<ViewOnDrawExecutor> mOnClearCallback;
private View mAttachedView;
private boolean mCompleted;
- private boolean mLoadAnimationCompleted;
private boolean mFirstDrawCompleted;
private boolean mCancelled;
- public ViewOnDrawExecutor(RunnableList tasks) {
+ public ViewOnDrawExecutor(RunnableList tasks,
+ @NonNull Consumer<ViewOnDrawExecutor> onClearCallback) {
mTasks = tasks;
+ mOnClearCallback = onClearCallback;
}
public void attachTo(Launcher launcher) {
- mOnClearCallback = launcher::clearPendingExecutor;
mAttachedView = launcher.getWorkspace();
-
mAttachedView.addOnAttachStateChangeListener(this);
-
if (mAttachedView.isAttachedToWindow()) {
attachObserver();
}
@@ -77,17 +76,10 @@
mAttachedView.post(this);
}
- public void onLoadAnimationCompleted() {
- mLoadAnimationCompleted = true;
- if (mAttachedView != null) {
- mAttachedView.post(this);
- }
- }
-
@Override
public void run() {
- // Post the pending tasks after both onDraw and onLoadAnimationCompleted have been called.
- if (mLoadAnimationCompleted && mFirstDrawCompleted && !mCompleted) {
+ // Post the pending tasks after first draw
+ if (mFirstDrawCompleted && !mCompleted) {
markCompleted();
}
}
@@ -104,9 +96,8 @@
mAttachedView.getViewTreeObserver().removeOnDrawListener(this);
mAttachedView.removeOnAttachStateChangeListener(this);
}
- if (mOnClearCallback != null) {
- mOnClearCallback.accept(this);
- }
+
+ mOnClearCallback.accept(this);
}
public void cancel() {
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index 145ad80..54ce973 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -16,6 +16,7 @@
package com.android.launcher3.widget;
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.LauncherPrefs.WIDGETS_EDUCATION_TIP_SEEN;
@@ -62,8 +63,10 @@
protected final Rect mInsets = new Rect();
- @Px protected int mContentHorizontalMargin;
- @Px protected int mWidgetCellHorizontalPadding;
+ @Px
+ protected int mContentHorizontalMargin;
+ @Px
+ protected int mWidgetCellHorizontalPadding;
protected int mNavBarScrimHeight;
private final Paint mNavBarScrimPaint;
@@ -196,7 +199,7 @@
DeviceProfile deviceProfile = mActivityContext.getDeviceProfile();
int widthUsed;
if (deviceProfile.isTablet) {
- widthUsed = Math.max(2 * getTabletMargin(deviceProfile),
+ widthUsed = Math.max(2 * getTabletHorizontalMargin(deviceProfile),
2 * (mInsets.left + mInsets.right));
} else if (mInsets.bottom > 0) {
widthUsed = mInsets.left + mInsets.right;
@@ -212,7 +215,11 @@
MeasureSpec.getSize(heightMeasureSpec));
}
- private int getTabletMargin(DeviceProfile deviceProfile) {
+ private int getTabletHorizontalMargin(DeviceProfile deviceProfile) {
+ // All bottom-sheets showing widgets will be full-width across all devices.
+ if (enableCategorizedWidgetSuggestions()) {
+ return 0;
+ }
if (deviceProfile.isLandscape && !deviceProfile.isTwoPanels) {
return getResources().getDimensionPixelSize(
R.dimen.widget_picker_landscape_tablet_left_right_margin);
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 25979c2..adf85c7 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -16,13 +16,20 @@
package com.android.launcher3.widget;
+import static android.graphics.Paint.ANTI_ALIAS_FLAG;
+import static android.graphics.Paint.DITHER_FLAG;
+import static android.graphics.Paint.FILTER_BITMAP_FLAG;
+
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
import static com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import android.appwidget.AppWidgetProviderInfo;
import android.content.Context;
+import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
+import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.ColorDrawable;
@@ -85,8 +92,12 @@
private boolean mDrawableSizeChanged;
private final TextPaint mPaint;
+
+ private final Paint mPreviewPaint;
private Layout mSetupTextLayout;
+ @Nullable private Bitmap mPreviewBitmap;
+
public PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
@Nullable LauncherAppWidgetProviderInfo appWidget) {
this(context, info, appWidget,
@@ -116,6 +127,15 @@
mDrawableSizeChanged = true;
}
+ /** Set {@link Bitmap} of widget preview. */
+ public void setPreviewBitmap(@Nullable Bitmap previewBitmap) {
+ if (this.mPreviewBitmap == previewBitmap) {
+ return;
+ }
+ this.mPreviewBitmap = previewBitmap;
+ invalidate();
+ }
+
private PendingAppWidgetHostView(Context context, LauncherAppWidgetInfo info,
LauncherAppWidgetProviderInfo appwidget, CharSequence label) {
super(new ContextThemeWrapper(context, R.style.WidgetContainerTheme));
@@ -130,12 +150,17 @@
mPaint.setColor(Themes.getAttrColor(getContext(), android.R.attr.textColorPrimary));
mPaint.setTextSize(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,
mLauncher.getDeviceProfile().iconTextSizePx, getResources().getDisplayMetrics()));
-
+ mPreviewPaint = new Paint(ANTI_ALIAS_FLAG | DITHER_FLAG | FILTER_BITMAP_FLAG);
setWillNotDraw(false);
setBackgroundResource(R.drawable.pending_widget_bg);
}
@Override
+ public AppWidgetProviderInfo getAppWidgetInfo() {
+ return mAppwidget;
+ }
+
+ @Override
public void updateAppWidget(RemoteViews remoteViews) {
checkIfRestored();
}
@@ -393,6 +418,11 @@
@Override
protected void onDraw(Canvas canvas) {
+ if (mPreviewBitmap != null
+ && (mInfo.restoreStatus & LauncherAppWidgetInfo.FLAG_UI_NOT_READY) != 0) {
+ canvas.drawBitmap(mPreviewBitmap, 0, 0, mPreviewPaint);
+ return;
+ }
if (mCenterDrawable == null) {
// Nothing to draw
return;
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index 8f5e2b6..94c630a 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -16,6 +16,8 @@
package com.android.launcher3.widget;
+import static android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN;
+
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;
@@ -44,6 +46,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.CheckLongPressHelper;
+import com.android.launcher3.Flags;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.icons.FastBitmapDrawable;
@@ -241,6 +244,11 @@
mAppWidgetHostViewPreview = createAppWidgetHostView(context);
setAppWidgetHostViewPreview(mAppWidgetHostViewPreview, item.widgetInfo,
mRemoteViewsPreview);
+ } else if (Flags.enableGeneratedPreviews()
+ && item.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)) {
+ mAppWidgetHostViewPreview = createAppWidgetHostView(context);
+ setAppWidgetHostViewPreview(mAppWidgetHostViewPreview, item.widgetInfo,
+ item.generatedPreviews.get(WIDGET_CATEGORY_HOME_SCREEN));
} else if (item.hasPreviewLayout()) {
// If the context is a Launcher activity, DragView will show mAppWidgetHostViewPreview
// as a preview during drag & drop. And thus, we should use LauncherAppWidgetHostView,
@@ -359,6 +367,16 @@
}
}
+ /**
+ * Shows or hides the long description displayed below each widget.
+ *
+ * @param show a flag that shows the long description of the widget if {@code true}, hides it if
+ * {@code false}.
+ */
+ public void showDescription(boolean show) {
+ mWidgetDescription.setVisibility(show ? VISIBLE : GONE);
+ }
+
@Override
public boolean onTouchEvent(MotionEvent ev) {
super.onTouchEvent(ev);
diff --git a/src/com/android/launcher3/widget/WidgetManagerHelper.java b/src/com/android/launcher3/widget/WidgetManagerHelper.java
index 058523b..52767a4 100644
--- a/src/com/android/launcher3/widget/WidgetManagerHelper.java
+++ b/src/com/android/launcher3/widget/WidgetManagerHelper.java
@@ -24,8 +24,11 @@
import android.os.Build;
import android.os.Bundle;
import android.os.UserHandle;
+import android.widget.RemoteViews;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresApi;
import com.android.launcher3.model.WidgetsModel;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -130,6 +133,23 @@
appWidgetId).getBoolean(WIDGET_OPTION_RESTORE_COMPLETED);
}
+
+ /**
+ * Load RemoteViews preview for this provider if available.
+ *
+ * @param info The provider info for the widget you want to preview.
+ * @param widgetCategory The widget category for which you want to display previews.
+ *
+ * @return Returns the widget preview that matches selected category, if available.
+ */
+ @Nullable
+ @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
+ public RemoteViews loadGeneratedPreview(@NonNull AppWidgetProviderInfo info,
+ int widgetCategory) {
+ if (!android.appwidget.flags.Flags.generatedPreviews()) return null;
+ return mAppWidgetManager.getWidgetPreview(info.provider, info.getProfile(), widgetCategory);
+ }
+
private static Stream<AppWidgetProviderInfo> allWidgetsSteam(Context context) {
AppWidgetManager awm = context.getSystemService(AppWidgetManager.class);
return Stream.concat(
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index c347939..ceb0072 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -16,6 +16,7 @@
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;
@@ -187,7 +188,13 @@
mWidgetCellHorizontalPadding)
.forEach(row -> {
TableRow tableRow = new TableRow(getContext());
- tableRow.setGravity(Gravity.TOP);
+ 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);
+ }
row.forEach(widgetItem -> {
WidgetCell widget = addItemCell(tableRow);
widget.applyFromCellItem(widgetItem);
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
new file mode 100644
index 0000000..738d74e
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
@@ -0,0 +1,258 @@
+/*
+ * 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 static com.android.launcher3.widget.util.WidgetsTableUtils.groupWidgetItemsUsingRowPxWithoutReordering;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+import androidx.annotation.Px;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.PagedView;
+import com.android.launcher3.R;
+import com.android.launcher3.model.WidgetItem;
+import com.android.launcher3.pageindicators.PageIndicatorDots;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+/**
+ * A {@link PagedView} that displays widget recommendations in categories with dots as paged
+ * indicators.
+ */
+public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots> {
+ private @Px float mAvailableHeight = Float.MAX_VALUE;
+
+ private static final int MAX_CATEGORIES = 3;
+ private TextView mRecommendationPageTitle;
+ private final List<String> mCategoryTitles = new ArrayList<>();
+
+ @Nullable
+ private OnLongClickListener mWidgetCellOnLongClickListener;
+ @Nullable
+ private OnClickListener mWidgetCellOnClickListener;
+
+ public WidgetRecommendationsView(Context context) {
+ this(context, /* attrs= */ null);
+ }
+
+ public WidgetRecommendationsView(Context context, AttributeSet attrs) {
+ this(context, attrs, /* defStyleAttr= */ 0);
+ }
+
+ public WidgetRecommendationsView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ @Override
+ public void initParentViews(View parent) {
+ super.initParentViews(parent);
+ mRecommendationPageTitle = parent.findViewById(R.id.recommendations_page_title);
+ }
+
+ /** Sets a {@link android.view.View.OnLongClickListener} for all widget cells in this table. */
+ public void setWidgetCellLongClickListener(OnLongClickListener onLongClickListener) {
+ mWidgetCellOnLongClickListener = onLongClickListener;
+ }
+
+ /** Sets a {@link android.view.View.OnClickListener} for all widget cells in this table. */
+ public void setWidgetCellOnClickListener(OnClickListener widgetCellOnClickListener) {
+ mWidgetCellOnClickListener = widgetCellOnClickListener;
+ }
+
+ /**
+ * Displays all the provided recommendations in a single table if they fit.
+ *
+ * @param recommendedWidgets list of widgets to be displayed in recommendation section.
+ * @param availableHeight height in px that can be used to display the recommendations;
+ * recommendations that don't fit in this height won't be shown
+ * @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.
+ */
+ public boolean setRecommendations(
+ List<WidgetItem> recommendedWidgets, final @Px float availableHeight,
+ final @Px int availableWidth, final @Px int cellPadding) {
+ this.mAvailableHeight = availableHeight;
+ removeAllViews();
+
+ maybeDisplayInTable(recommendedWidgets, availableWidth, cellPadding);
+ updateTitleAndIndicator();
+ return getChildCount() > 0;
+ }
+
+ /**
+ * Displays the recommendations grouped by categories as pages.
+ * <p>In case of a single category, no title is displayed for it.</p>
+ *
+ * @param recommendations a map of widget items per recommendation category
+ * @param availableHeight height in px that can be used to display the recommendations;
+ * recommendations that don't fit in this height won't be shown
+ * @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.
+ */
+ public boolean setRecommendations(
+ Map<WidgetRecommendationCategory, List<WidgetItem>> recommendations,
+ final @Px float availableHeight, final @Px int availableWidth,
+ final @Px int cellPadding) {
+ this.mAvailableHeight = availableHeight;
+ Context context = getContext();
+ removeAllViews();
+
+ int displayedCategories = 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(), availableWidth, cellPadding)) {
+ mCategoryTitles.add(
+ context.getResources().getString(entry.getKey().categoryTitleRes));
+ displayedCategories++;
+ }
+
+ if (displayedCategories == MAX_CATEGORIES) {
+ break;
+ }
+ }
+
+ updateTitleAndIndicator();
+ return getChildCount() > 0;
+ }
+
+ /** Displays the page title and paging indicator if there are multiple pages. */
+ private void updateTitleAndIndicator() {
+ int titleAndIndicatorVisibility = getPageCount() > 1 ? View.VISIBLE : View.GONE;
+ mRecommendationPageTitle.setVisibility(titleAndIndicatorVisibility);
+ mPageIndicator.setVisibility(titleAndIndicatorVisibility);
+ }
+
+ @Override
+ protected void notifyPageSwitchListener(int prevPage) {
+ if (getPageCount() > 1) {
+ // Since the title is outside the paging scroll, we update the title on page switch.
+ mRecommendationPageTitle.setText(mCategoryTitles.get(getNextPage()));
+ super.notifyPageSwitchListener(prevPage);
+ requestLayout();
+ }
+ }
+
+ @Override
+ protected boolean canScroll(float absVScroll, float absHScroll) {
+ // Allow only horizontal scroll.
+ return (absHScroll > absVScroll) && super.canScroll(absVScroll, absHScroll);
+ }
+
+ @Override
+ protected void onScrollChanged(int l, int t, int oldl, int oldt) {
+ super.onScrollChanged(l, t, oldl, oldt);
+ mPageIndicator.setScroll(l, mMaxScroll);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ boolean hasMultiplePages = getChildCount() > 0;
+
+ if (hasMultiplePages) {
+ int finalWidth = MeasureSpec.getSize(widthMeasureSpec);
+ int desiredHeight = 0;
+
+ 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());
+ }
+ }
+
+ int finalHeight = resolveSizeAndState(desiredHeight, heightMeasureSpec, 0);
+ setMeasuredDimension(finalWidth, finalHeight);
+ } else {
+ super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+ }
+ }
+
+ /**
+ * Groups the provided recommendations into rows and displays them in a table if at least one
+ * fits.
+ * <p>Returns false if none of the recommendations could fit.</p>
+ */
+ private boolean maybeDisplayInTable(List<WidgetItem> recommendedWidgets,
+ final @Px int availableWidth, final @Px int cellPadding) {
+ Context context = getContext();
+ DeviceProfile deviceProfile = Launcher.getLauncher(context).getDeviceProfile();
+ LayoutInflater inflater = LayoutInflater.from(context);
+
+ List<ArrayList<WidgetItem>> rows = groupWidgetItemsUsingRowPxWithoutReordering(
+ recommendedWidgets,
+ context,
+ deviceProfile,
+ availableWidth,
+ cellPadding);
+
+ WidgetsRecommendationTableLayout recommendationsTable =
+ (WidgetsRecommendationTableLayout) inflater.inflate(
+ R.layout.widget_recommendations_table,
+ /* root=*/ this,
+ /* attachToRoot=*/ false);
+ recommendationsTable.setWidgetCellOnClickListener(mWidgetCellOnClickListener);
+ recommendationsTable.setWidgetCellLongClickListener(mWidgetCellOnLongClickListener);
+
+ boolean displayedAtLeastOne = recommendationsTable.setRecommendedWidgets(rows,
+ mAvailableHeight);
+ if (displayedAtLeastOne) {
+ addView(recommendationsTable);
+ }
+
+ return displayedAtLeastOne;
+ }
+
+ /** Returns location of a widget cell for displaying the "touch and hold" education tip. */
+ public View getViewForEducationTip() {
+ if (getChildCount() > 0) {
+ // first page (a table layout) -> first item (a widget cell).
+ return ((ViewGroup) getChildAt(0)).getChildAt(0);
+ }
+ return null;
+ }
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 28bae59..237078e 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -17,18 +17,20 @@
import static android.view.View.MeasureSpec.makeMeasureSpec;
+import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
import static com.android.launcher3.LauncherPrefs.WIDGETS_EDUCATION_DIALOG_SEEN;
+import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
import android.animation.Animator;
import android.content.Context;
-import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Build;
+import android.os.Parcelable;
import android.os.Process;
import android.os.UserHandle;
import android.os.UserManager;
@@ -44,6 +46,7 @@
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
import android.widget.Button;
+import android.widget.LinearLayout;
import android.widget.TextView;
import android.window.BackEvent;
@@ -64,7 +67,6 @@
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.model.UserManagerState;
-import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.pm.UserCache;
import com.android.launcher3.views.ArrowTipView;
import com.android.launcher3.views.RecyclerViewFastScroller;
@@ -75,7 +77,6 @@
import com.android.launcher3.widget.model.WidgetsListBaseEntry;
import com.android.launcher3.widget.picker.search.SearchModeListener;
import com.android.launcher3.widget.picker.search.WidgetsSearchBar;
-import com.android.launcher3.widget.util.WidgetsTableUtils;
import com.android.launcher3.workprofile.PersonalWorkPagedView;
import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePageChangedListener;
@@ -99,7 +100,6 @@
// resolution or landscape on phone. This ratio defines the max percentage of content area that
// the table can display.
private static final float RECOMMENDATION_TABLE_HEIGHT_RATIO = 0.75f;
-
private final UserCache mUserCache;
private final UserManagerState mUserManagerState = new UserManagerState();
private final UserHandle mCurrentUser = Process.myUserHandle();
@@ -162,12 +162,13 @@
@Nullable PersonalWorkPagedView mViewPager;
private boolean mIsInSearchMode;
private boolean mIsNoWidgetsViewNeeded;
- @Px private int mMaxSpanPerRow;
+ @Px protected int mMaxSpanPerRow;
protected DeviceProfile mDeviceProfile;
protected TextView mNoWidgetsView;
protected StickyHeaderLayout mSearchScrollView;
- protected WidgetsRecommendationTableLayout mRecommendedWidgetsTable;
+ protected WidgetRecommendationsView mWidgetRecommendationsView;
+ protected LinearLayout mWidgetRecommendationsContainer;
protected View mTabBar;
protected View mSearchBarContainer;
protected WidgetsSearchBar mSearchBar;
@@ -221,9 +222,14 @@
setupViews();
- mRecommendedWidgetsTable = mSearchScrollView.findViewById(R.id.recommended_widget_table);
- mRecommendedWidgetsTable.setWidgetCellLongClickListener(this);
- mRecommendedWidgetsTable.setWidgetCellOnClickListener(this);
+ mWidgetRecommendationsContainer = mSearchScrollView.findViewById(
+ R.id.widget_recommendations_container);
+ mWidgetRecommendationsView = mSearchScrollView.findViewById(
+ R.id.widget_recommendations_view);
+ mWidgetRecommendationsView.initParentViews(mWidgetRecommendationsContainer);
+ mWidgetRecommendationsView.setWidgetCellLongClickListener(this);
+ mWidgetRecommendationsView.setWidgetCellOnClickListener(this);
+
mHeaderTitle = mSearchScrollView.findViewById(R.id.title);
onRecommendedWidgetsBound();
@@ -522,11 +528,13 @@
}
@Override
- public void enterSearchMode() {
+ public void enterSearchMode(boolean shouldLog) {
if (mIsInSearchMode) return;
setViewVisibilityBasedOnSearch(/*isInSearchMode= */ true);
attachScrollbarToRecyclerView(mAdapters.get(AdapterHolder.SEARCH).mWidgetsRecyclerView);
- mActivityContext.getStatsLogManager().logger().log(LAUNCHER_WIDGETSTRAY_SEARCHED);
+ if (shouldLog) {
+ mActivityContext.getStatsLogManager().logger().log(LAUNCHER_WIDGETSTRAY_SEARCHED);
+ }
}
@Override
@@ -549,7 +557,7 @@
protected void setViewVisibilityBasedOnSearch(boolean isInSearchMode) {
mIsInSearchMode = isInSearchMode;
if (isInSearchMode) {
- mRecommendedWidgetsTable.setVisibility(GONE);
+ mWidgetRecommendationsContainer.setVisibility(GONE);
if (mHasWorkProfile) {
mViewPager.setVisibility(GONE);
mTabBar.setVisibility(GONE);
@@ -578,40 +586,44 @@
if (mIsInSearchMode) {
return;
}
- List<WidgetItem> recommendedWidgets =
- mActivityContext.getPopupDataProvider().getRecommendedWidgets();
- mHasRecommendedWidgets = recommendedWidgets.size() > 0;
- if (mHasRecommendedWidgets) {
- float noWidgetsViewHeight = 0;
- if (mIsNoWidgetsViewNeeded) {
- // Make sure recommended section leaves enough space for noWidgetsView.
- Rect noWidgetsViewTextBounds = new Rect();
- mNoWidgetsView.getPaint()
- .getTextBounds(mNoWidgetsView.getText().toString(), /* start= */ 0,
- mNoWidgetsView.getText().length(), noWidgetsViewTextBounds);
- noWidgetsViewHeight = noWidgetsViewTextBounds.height();
- }
- if (!isTwoPane()) {
- doMeasure(
- makeMeasureSpec(mActivityContext.getDeviceProfile().availableWidthPx,
- MeasureSpec.EXACTLY),
- makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx,
- MeasureSpec.EXACTLY));
- }
- float maxTableHeight = getMaxTableHeight(noWidgetsViewHeight);
- List<ArrayList<WidgetItem>> recommendedWidgetsInTable =
- WidgetsTableUtils.groupWidgetItemsUsingRowPxWithoutReordering(
- recommendedWidgets,
- mActivityContext,
- mActivityContext.getDeviceProfile(),
- mMaxSpanPerRow,
- mWidgetCellHorizontalPadding);
- mRecommendedWidgetsTable.setRecommendedWidgets(
- recommendedWidgetsInTable, maxTableHeight);
+ if (enableCategorizedWidgetSuggestions()) {
+ mHasRecommendedWidgets = mWidgetRecommendationsView.setRecommendations(
+ mActivityContext.getPopupDataProvider().getCategorizedRecommendedWidgets(),
+ /* availableHeight= */ getMaxAvailableHeightForRecommendations(),
+ /* availableWidth= */ mMaxSpanPerRow,
+ /* cellPadding= */ mWidgetCellHorizontalPadding
+ );
} else {
- mRecommendedWidgetsTable.setVisibility(GONE);
+ mHasRecommendedWidgets = mWidgetRecommendationsView.setRecommendations(
+ mActivityContext.getPopupDataProvider().getRecommendedWidgets(),
+ /* availableHeight= */ getMaxAvailableHeightForRecommendations(),
+ /* availableWidth= */ mMaxSpanPerRow,
+ /* cellPadding= */ mWidgetCellHorizontalPadding
+ );
}
+ mWidgetRecommendationsContainer.setVisibility(mHasRecommendedWidgets ? VISIBLE : GONE);
+ }
+
+ @Px
+ private float getMaxAvailableHeightForRecommendations() {
+ float noWidgetsViewHeight = 0;
+ if (mIsNoWidgetsViewNeeded) {
+ // Make sure recommended section leaves enough space for noWidgetsView.
+ Rect noWidgetsViewTextBounds = new Rect();
+ mNoWidgetsView.getPaint()
+ .getTextBounds(mNoWidgetsView.getText().toString(), /* start= */ 0,
+ mNoWidgetsView.getText().length(), noWidgetsViewTextBounds);
+ noWidgetsViewHeight = noWidgetsViewTextBounds.height();
+ }
+ if (!isTwoPane()) {
+ doMeasure(
+ makeMeasureSpec(mActivityContext.getDeviceProfile().availableWidthPx,
+ MeasureSpec.EXACTLY),
+ makeMeasureSpec(mActivityContext.getDeviceProfile().availableHeightPx,
+ MeasureSpec.EXACTLY));
+ }
+ return getMaxTableHeight(noWidgetsViewHeight);
}
/** b/209579563: "Widgets" header should be focused first. */
@@ -620,7 +632,8 @@
return mHeaderTitle;
}
- protected float getMaxTableHeight(float noWidgetsViewHeight) {
+ @Px
+ protected float getMaxTableHeight(@Px float noWidgetsViewHeight) {
return (mContent.getMeasuredHeight()
- mTabsHeight - getHeaderViewHeight()
- noWidgetsViewHeight)
@@ -697,7 +710,9 @@
private static int getWidgetSheetId(BaseActivity activity) {
boolean isTwoPane = (activity.getDeviceProfile().isTablet
- && activity.getDeviceProfile().isLandscape
+ // Enables two pane picker for tablets in all orientations when the
+ // enableCategorizedWidgetSuggestions flag is on.
+ && (activity.getDeviceProfile().isLandscape || enableCategorizedWidgetSuggestions())
&& !activity.getDeviceProfile().isTwoPanels)
// Enables two pane picker for unfolded foldables if the flag is on.
|| (activity.getDeviceProfile().isTwoPanels && enableUnfoldedTwoPanePicker());
@@ -789,32 +804,60 @@
+ marginLayoutParams.topMargin;
}
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {
- super.onConfigurationChanged(newConfig);
+ private int getCurrentAdapterHolderType() {
if (mIsInSearchMode) {
- mSearchBar.reset();
+ return SEARCH;
+ } else if (mViewPager != null) {
+ return mViewPager.getCurrentPage();
+ } else {
+ return AdapterHolder.PRIMARY;
+ }
+ }
+
+ private void restorePreviousAdapterHolderType(int previousAdapterHolderType) {
+ if (previousAdapterHolderType == AdapterHolder.WORK && mViewPager != null) {
+ mViewPager.setCurrentPage(previousAdapterHolderType);
+ } else if (previousAdapterHolderType == AdapterHolder.SEARCH) {
+ enterSearchMode(false);
}
}
@Override
public void onDeviceProfileChanged(DeviceProfile dp) {
- if (mDeviceProfile.isLandscape != dp.isLandscape && dp.isTablet && !dp.isTwoPanels) {
+ super.onDeviceProfileChanged(dp);
+
+ if (shouldRecreateLayout(/*oldDp=*/ mDeviceProfile, /*newDp=*/ dp)) {
+ SparseArray<Parcelable> widgetsState = new SparseArray<>();
+ saveHierarchyState(widgetsState);
handleClose(false);
- show(BaseActivity.fromContext(getContext()), false);
+ WidgetsFullSheet sheet = show(BaseActivity.fromContext(getContext()), false);
+ sheet.restoreHierarchyState(widgetsState);
+ sheet.restorePreviousAdapterHolderType(getCurrentAdapterHolderType());
} else if (!isTwoPane()) {
reset();
resetExpandedHeaders();
}
+ mDeviceProfile = dp;
+ }
+
+ /**
+ * Indicates if layout should be re-created on device profile change - so that a different
+ * layout can be displayed.
+ */
+ private static boolean shouldRecreateLayout(DeviceProfile oldDp, DeviceProfile newDp) {
// When folding/unfolding the foldables, we need to switch between the regular widget picker
// and the two pane picker, so we rebuild the picker with the correct layout.
- if (mDeviceProfile.isTwoPanels != dp.isTwoPanels && enableUnfoldedTwoPanePicker()) {
- handleClose(false);
- show(BaseActivity.fromContext(getContext()), false);
- }
+ boolean isFoldUnFold =
+ oldDp.isTwoPanels != newDp.isTwoPanels && enableUnfoldedTwoPanePicker();
+ // In tablets, on orientation change we switch between single and two pane picker unless the
+ // categorized suggestions flag was on. With the categorized suggestions feature, we use a
+ // two pane picker across all orientations.
+ boolean useDifferentLayoutOnOrientationChange =
+ (!enableCategorizedWidgetSuggestions() && (newDp.isTablet && !newDp.isTwoPanels
+ && oldDp.isLandscape != newDp.isLandscape));
- mDeviceProfile = dp;
+ return isFoldUnFold || useDifferentLayoutOnOrientationChange;
}
@Override
@@ -837,9 +880,8 @@
}
@Nullable private View getViewToShowEducationTip() {
- if (mRecommendedWidgetsTable.getVisibility() == VISIBLE
- && mRecommendedWidgetsTable.getChildCount() > 0) {
- return ((ViewGroup) mRecommendedWidgetsTable.getChildAt(0)).getChildAt(0);
+ if (mWidgetRecommendationsContainer.getVisibility() == VISIBLE) {
+ return mWidgetRecommendationsView.getViewForEducationTip();
}
AdapterHolder adapterHolder = mAdapters.get(mIsInSearchMode
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index c7d2aa3..f10ab48 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -15,6 +15,8 @@
*/
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;
@@ -147,7 +149,13 @@
tableRow = (TableRow) table.getChildAt(i);
} else {
tableRow = new TableRow(table.getContext());
- tableRow.setGravity(Gravity.TOP);
+ 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);
+ }
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 06cc65e..ce1f4e0 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.widget.picker;
+import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
import android.content.Context;
@@ -61,7 +62,7 @@
super(context, attrs);
// There are 1 row for title, 1 row for dimension and 2 rows for description.
mWidgetsRecommendationTableVerticalPadding = 2 * getResources()
- .getDimensionPixelSize(R.dimen.recommended_widgets_table_vertical_padding);
+ .getDimensionPixelSize(R.dimen.widget_recommendations_table_vertical_padding);
mWidgetCellVerticalPadding = 2 * getResources()
.getDimensionPixelSize(R.dimen.widget_cell_vertical_padding);
mWidgetCellTextViewsHeight = 4 * getResources().getDimension(R.dimen.widget_cell_font_size);
@@ -84,17 +85,20 @@
* <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.
+ *
+ * <p>Returns {@code false} if none of the widgets could fit</p>
*/
- public void setRecommendedWidgets(List<ArrayList<WidgetItem>> recommendedWidgets,
+ public boolean setRecommendedWidgets(List<ArrayList<WidgetItem>> recommendedWidgets,
float recommendationTableMaxHeight) {
mRecommendationTableMaxHeight = recommendationTableMaxHeight;
RecommendationTableData data = fitRecommendedWidgetsToTableSpace(/* previewScale= */ 1f,
recommendedWidgets);
bindData(data);
+ return !data.mRecommendationTable.isEmpty();
}
private void bindData(RecommendationTableData data) {
- if (data.mRecommendationTable.size() == 0) {
+ if (data.mRecommendationTable.isEmpty()) {
setVisibility(GONE);
return;
}
@@ -104,12 +108,20 @@
for (int i = 0; i < data.mRecommendationTable.size(); i++) {
List<WidgetItem> widgetItems = data.mRecommendationTable.get(i);
TableRow tableRow = new TableRow(getContext());
- tableRow.setGravity(Gravity.TOP);
-
+ 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);
+ }
for (WidgetItem widgetItem : widgetItems) {
WidgetCell widgetCell = addItemCell(tableRow);
widgetCell.applyFromCellItem(widgetItem, data.mPreviewScale);
widgetCell.showBadge();
+ if (enableCategorizedWidgetSuggestions()) {
+ widgetCell.showDescription(false);
+ }
}
addView(tableRow);
}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index 5a1ec87..165b2fe 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -15,10 +15,10 @@
*/
package com.android.launcher3.widget.picker;
+import static com.android.launcher3.Flags.enableCategorizedWidgetSuggestions;
import static com.android.launcher3.Flags.enableUnfoldedTwoPanePicker;
import android.content.Context;
-import android.content.res.Configuration;
import android.graphics.Outline;
import android.graphics.Rect;
import android.os.Process;
@@ -110,9 +110,15 @@
mWidgetsListTableViewHolderBinder =
new WidgetsListTableViewHolderBinder(mActivityContext, layoutInflater, this, this);
- mRecommendedWidgetsTable = mContent.findViewById(R.id.recommended_widget_table);
- mRecommendedWidgetsTable.setWidgetCellLongClickListener(this);
- mRecommendedWidgetsTable.setWidgetCellOnClickListener(this);
+
+ mWidgetRecommendationsContainer = mContent.findViewById(
+ R.id.widget_recommendations_container);
+ mWidgetRecommendationsView = mContent.findViewById(
+ R.id.widget_recommendations_view);
+ mWidgetRecommendationsView.initParentViews(mWidgetRecommendationsContainer);
+ mWidgetRecommendationsView.setWidgetCellLongClickListener(this);
+ mWidgetRecommendationsView.setWidgetCellOnClickListener(this);
+
mHeaderTitle = mContent.findViewById(R.id.title);
mRightPane = mContent.findViewById(R.id.right_pane);
mRightPane.setOutlineProvider(mViewOutlineProviderRightPane);
@@ -127,10 +133,6 @@
mFastScroller.setVisibility(GONE);
}
- /** Overrides onConfigurationChanged method from WidgetsFullSheet. Needed for b/319150904 */
- @Override
- protected void onConfigurationChanged(Configuration newConfig) {}
-
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
@@ -200,10 +202,14 @@
return false;
}
};
- packageItemInfo.title = getContext().getString(R.string.suggested_widgets_header_title);
+ String suggestionsHeaderTitle = getContext().getString(
+ R.string.suggested_widgets_header_title);
+ String suggestionsRightPaneTitle = getContext().getString(
+ R.string.widget_picker_right_pane_accessibility_title, suggestionsHeaderTitle);
+ packageItemInfo.title = suggestionsHeaderTitle;
WidgetsListHeaderEntry widgetsListHeaderEntry = WidgetsListHeaderEntry.create(
packageItemInfo,
- getContext().getString(R.string.suggested_widgets_header_title),
+ suggestionsHeaderTitle,
mActivityContext.getPopupDataProvider().getRecommendedWidgets())
.withWidgetListShown();
@@ -214,16 +220,19 @@
mSuggestedWidgetsHeader.setExpanded(true);
resetExpandedHeaders();
mRightPane.removeAllViews();
- mRightPane.addView(mRecommendedWidgetsTable);
+ mRightPane.addView(mWidgetRecommendationsContainer);
mRightPaneScrollView.setScrollY(0);
+ mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
mSuggestedWidgetsPackageUserKey = PackageUserKey.fromPackageItemInfo(packageItemInfo);
mSelectedHeader = mSuggestedWidgetsPackageUserKey;
});
mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader);
+ mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
}
@Override
- protected float getMaxTableHeight(float noWidgetsViewHeight) {
+ @Px
+ protected float getMaxTableHeight(@Px float noWidgetsViewHeight) {
return Float.MAX_VALUE;
}
@@ -307,21 +316,35 @@
if (mSuggestedWidgetsHeader != null) {
mSuggestedWidgetsHeader.setExpanded(false);
}
+
+ WidgetsListContentEntry contentEntryToBind;
+ if (enableCategorizedWidgetSuggestions()) {
+ // Setting max span size enables row to understand how to fit more than one item
+ // in a row.
+ contentEntryToBind = contentEntry.withMaxSpanSize(mMaxSpanPerRow);
+ } else {
+ contentEntryToBind = contentEntry;
+ }
+
WidgetsRowViewHolder widgetsRowViewHolder =
mWidgetsListTableViewHolderBinder.newViewHolder(mRightPane);
mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
- contentEntry,
+ contentEntryToBind,
ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
Collections.EMPTY_LIST);
widgetsRowViewHolder.mDataCallback = data -> {
mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
- contentEntry,
+ contentEntryToBind,
ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
Collections.singletonList(data));
};
mRightPane.removeAllViews();
mRightPane.addView(widgetsRowViewHolder.itemView);
mRightPaneScrollView.setScrollY(0);
+ mRightPane.setAccessibilityPaneTitle(
+ getContext().getString(
+ R.string.widget_picker_right_pane_accessibility_title,
+ contentEntry.mPkgItem.title));
}
};
}
diff --git a/src/com/android/launcher3/widget/picker/search/SearchModeListener.java b/src/com/android/launcher3/widget/picker/search/SearchModeListener.java
index cee7d67..b2620d0 100644
--- a/src/com/android/launcher3/widget/picker/search/SearchModeListener.java
+++ b/src/com/android/launcher3/widget/picker/search/SearchModeListener.java
@@ -26,7 +26,7 @@
/**
* Notifies the subscriber when user enters widget picker search mode.
*/
- void enterSearchMode();
+ void enterSearchMode(boolean shouldLog);
/**
* Notifies the subscriber when user exits widget picker search mode.
diff --git a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
index a15508a..2d96cbd 100644
--- a/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
+++ b/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarController.java
@@ -70,7 +70,7 @@
mCancelButton.setVisibility(GONE);
} else {
mSearchAlgorithm.cancel(/* interruptActiveRequests= */ false);
- mSearchModeListener.enterSearchMode();
+ mSearchModeListener.enterSearchMode(true);
mSearchAlgorithm.doSearch(mQuery, this);
mCancelButton.setVisibility(VISIBLE);
}
diff --git a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
index 54cc0bc..a940774 100644
--- a/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
+++ b/src_plugins/com/android/systemui/plugins/shared/LauncherOverlayManager.java
@@ -15,6 +15,8 @@
*/
package com.android.systemui.plugins.shared;
+import android.view.MotionEvent;
+
import java.io.PrintWriter;
/**
@@ -47,7 +49,11 @@
default void onActivityDestroyed() { }
- interface LauncherOverlay {
+ /**
+ * @deprecated use LauncherOverlayTouchProxy directly
+ */
+ @Deprecated
+ interface LauncherOverlay extends LauncherOverlayTouchProxy {
/**
* Touch interaction leading to overscroll has begun
@@ -70,6 +76,38 @@
* @param callbacks A set of callbacks provided by Launcher in relation to the overlay
*/
void setOverlayCallbacks(LauncherOverlayCallbacks callbacks);
+
+ @Override
+ default void onFlingVelocity(float velocity) { }
+
+ @Override
+ default void onOverlayMotionEvent(MotionEvent ev, float scrollProgress) {
+ switch (ev.getAction()) {
+ case MotionEvent.ACTION_DOWN -> onScrollInteractionBegin();
+ case MotionEvent.ACTION_MOVE -> onScrollChange(scrollProgress, false);
+ case MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> onScrollInteractionEnd();
+ }
+
+ }
+ }
+
+ interface LauncherOverlayTouchProxy {
+
+ /**
+ * Called just before finishing scroll interaction to indicate the fling velocity
+ */
+ void onFlingVelocity(float velocity);
+
+ /**
+ * Called to dispatch various motion events to the overlay
+ */
+ void onOverlayMotionEvent(MotionEvent ev, float scrollProgress);
+
+ /**
+ * Called when the launcher is ready to use the overlay
+ * @param callbacks A set of callbacks provided by Launcher in relation to the overlay
+ */
+ default void setOverlayCallbacks(LauncherOverlayCallbacks callbacks) { }
}
interface LauncherOverlayCallbacks {
diff --git a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
index 4c5bfd8..8b983fc 100644
--- a/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
+++ b/src_shortcuts_overrides/com/android/launcher3/model/WidgetsModel.java
@@ -147,7 +147,8 @@
LauncherAppWidgetProviderInfo.fromProviderInfo(context, widgetInfo);
widgetsAndShortcuts.add(new WidgetItem(
- launcherWidgetInfo, idp, app.getIconCache(), app.getContext()));
+ launcherWidgetInfo, idp, app.getIconCache(), app.getContext(),
+ widgetManager));
updatedItems.add(launcherWidgetInfo);
}
@@ -206,6 +207,7 @@
public void onPackageIconsUpdated(Set<String> packageNames, UserHandle user,
LauncherAppState app) {
+ WidgetManagerHelper widgetManager = new WidgetManagerHelper(app.getContext());
for (Entry<PackageItemInfo, List<WidgetItem>> entry : mWidgetsList.entrySet()) {
if (packageNames.contains(entry.getKey().packageName)) {
List<WidgetItem> items = entry.getValue();
@@ -219,7 +221,7 @@
} else {
items.set(i, new WidgetItem(item.widgetInfo,
app.getInvariantDeviceProfile(), app.getIconCache(),
- app.getContext()));
+ app.getContext(), widgetManager));
}
}
}
@@ -337,4 +339,4 @@
return mMap.values();
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/Android.bp b/tests/Android.bp
index ed8609e..9ce0777 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -127,6 +127,7 @@
"testables",
"com_android_launcher3_flags_lib",
"com_android_wm_shell_flags_lib",
+ "android.appwidget.flags-aconfig-java",
],
manifest: "AndroidManifest-common.xml",
platform_apis: true,
diff --git a/tests/Launcher3Tests.xml b/tests/Launcher3Tests.xml
index 0aed1e1..bcbe343 100644
--- a/tests/Launcher3Tests.xml
+++ b/tests/Launcher3Tests.xml
@@ -46,6 +46,6 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest" >
<option name="package" value="com.android.launcher3.tests" />
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
- <option name="instrumentation-arg" key="waitForActivitiesToComplete" value="false" />
+ <option name="hidden-api-checks" value="false" />
</test>
</configuration>
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 8d40ff2..4e1e9c8 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -119,6 +119,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_ENABLE_TASKBAR_NAVBAR_UNIFICATION =
+ "enable-taskbar-navbar-unification";
public static final String REQUEST_NUM_ALL_APPS_COLUMNS = "num-all-apps-columns";
public static final String REQUEST_IS_TWO_PANELS = "is-two-panel";
public static final String REQUEST_CELL_LAYOUT_BOARDER_HEIGHT = "cell-layout-boarder-height";
@@ -168,6 +170,8 @@
public static final String TWO_TASKBAR_LONG_CLICKS = "b/262282528";
public static final String ICON_MISSING = "b/282963545";
public static final String OVERVIEW_OVER_HOME = "b/279059025";
+ public static final String UIOBJECT_STALE_ELEMENT = "b/319501259";
+ public static final String ACTIVITY_NOT_RESUMED_AFTER_BACK = "b/322823209";
public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 978e1f2..679bd01 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -193,6 +193,7 @@
protected AbstractLauncherUiTest() {
mLauncher.enableCheckEventsForSuccessfulGestures();
+ mLauncher.setAnomalyChecker(AbstractLauncherUiTest::verifyKeyguardInvisible);
try {
mDevice.setOrientationNatural();
} catch (RemoteException e) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java b/tests/multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
index 8eebdb2..5ef63da 100644
--- a/tests/multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
+++ b/tests/multivalentTests/src/com/android/launcher3/ui/PortraitLandscapeRunner.java
@@ -14,6 +14,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.util.concurrent.TimeUnit;
public class PortraitLandscapeRunner implements TestRule {
private static final String TAG = "PortraitLandscapeRunner";
@@ -49,7 +50,8 @@
mTest.mDevice.pressHome();
mTest.waitForLauncherCondition("Launcher activity wasn't created",
- launcher -> launcher != null);
+ launcher -> launcher != null,
+ TimeUnit.SECONDS.toMillis(20));
mTest.executeOnLauncher(launcher ->
launcher.getRotationHelper().forceAllowRotationForTesting(
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index cdde605..326802f 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -204,6 +204,9 @@
private LogEventChecker mEventChecker;
+ // UI anomaly checker provided by the test.
+ private Runnable mTestAnomalyChecker;
+
private boolean mCheckEventsForSuccessfulGestures = false;
private Runnable mOnLauncherCrashed;
@@ -402,6 +405,11 @@
.getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
}
+ public boolean isTaskbarNavbarUnificationEnabled() {
+ return getTestInfo(TestProtocol.REQUEST_ENABLE_TASKBAR_NAVBAR_UNIFICATION)
+ .getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
+ }
+
public boolean isTwoPanels() {
return getTestInfo(TestProtocol.REQUEST_IS_TWO_PANELS)
.getBoolean(TestProtocol.TEST_INFO_RESPONSE_FIELD);
@@ -573,8 +581,31 @@
checkForAnomaly(false, false);
}
+ /**
+ * Allows the test to provide a pluggable anomaly checker. It’s supposed to throw an exception
+ * if the check fails. The test may provide its own anomaly checker, for example, if it wants to
+ * check for an anomaly that’s recognized by the standard TAPL anomaly checker, but wants a
+ * custom error message, such as adding information whether the keyguard is seen for the first
+ * time during the shard execution.
+ */
+ public void setAnomalyChecker(Runnable anomalyChecker) {
+ mTestAnomalyChecker = anomalyChecker;
+ }
+
+ /**
+ * Verifies that there are no visible UI anomalies. An "anomaly" is a state of UI that should
+ * never happen during the text execution. Anomaly is something different from just “regular”
+ * unexpected state of the Launcher such as when we see Workspace after swiping up to All Apps.
+ * Workspace is a normal state. We can contrast this with an anomaly, when, for example, we see
+ * a lock screen. Launcher tests can never bring the lock screen, so the very presence of the
+ * lock screen is an indication that something went very wrong, and perhaps is caused by reasons
+ * outside of the Launcher and its tests, perhaps, by a crash in System UI. Diagnosing anomalies
+ * helps to understand faster whether the problem is in the Launcher or its tests, or outside.
+ */
public void checkForAnomaly(
boolean ignoreNavmodeChangeStates, boolean ignoreOnlySystemUiViews) {
+ if (mTestAnomalyChecker != null) mTestAnomalyChecker.run();
+
final String systemAnomalyMessage =
getSystemAnomalyMessage(ignoreNavmodeChangeStates, ignoreOnlySystemUiViews);
if (systemAnomalyMessage != null) {
@@ -819,7 +850,8 @@
}
private String getNavigationButtonResPackage() {
- return isTablet() ? getLauncherPackageName() : SYSTEMUI_PACKAGE;
+ return isTablet() || isTaskbarNavbarUnificationEnabled()
+ ? getLauncherPackageName() : SYSTEMUI_PACKAGE;
}
UiObject2 verifyContainerType(ContainerType containerType) {
diff --git a/tests/multivalentTests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/multivalentTests/tapl/com/android/launcher3/tapl/Workspace.java
index a911de4..1029b78 100644
--- a/tests/multivalentTests/tapl/com/android/launcher3/tapl/Workspace.java
+++ b/tests/multivalentTests/tapl/com/android/launcher3/tapl/Workspace.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.testing.shared.TestProtocol.ALL_APPS_STATE_ORDINAL;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
+import static com.android.launcher3.testing.shared.TestProtocol.UIOBJECT_STALE_ELEMENT;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertTrue;
@@ -28,6 +29,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemClock;
+import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -315,8 +317,17 @@
return workspaceIcons.stream()
.collect(
Collectors.toMap(
- /* keyMapper= */ UiObject2::getText,
- /* valueMapper= */ UiObject2::getVisibleCenter,
+ /* keyMapper= */ uiObject21 -> {
+ Log.d(UIOBJECT_STALE_ELEMENT, "keyText: " +
+ uiObject21.getText());
+ return uiObject21.getText();
+ },
+ /* valueMapper= */ uiObject2 -> {
+ Log.d(UIOBJECT_STALE_ELEMENT, uiObject2.getText() +
+ " dispId" + uiObject2.getDisplayId() +
+ " parent" + uiObject2.getParent());
+ return uiObject2.getVisibleCenter();
+ },
/* mergeFunction= */ (p1, p2) -> p1.x < p2.x ? p1 : p2));
}
diff --git a/tests/res/layout/test_layout_appwidget_red.xml b/tests/res/layout/test_layout_appwidget_red.xml
index 48d3e81..0f2bda3 100644
--- a/tests/res/layout/test_layout_appwidget_red.xml
+++ b/tests/res/layout/test_layout_appwidget_red.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@android:id/content"
android:orientation="vertical"
android:background="#FFFF0000"
android:layout_width="match_parent"
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
index 92fff49..490cb47 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
@@ -24,6 +24,7 @@
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -33,8 +34,11 @@
import android.graphics.drawable.Drawable;
import android.view.LayoutInflater;
import android.view.View;
+import android.widget.ImageButton;
import android.widget.ImageView;
+import android.widget.LinearLayout;
import android.widget.RelativeLayout;
+import android.widget.TextView;
import androidx.test.filters.SmallTest;
import androidx.test.runner.AndroidJUnit4;
@@ -59,7 +63,6 @@
private static final int PS_TRANSITION_IMAGE_COUNT = 1;
private Context mContext;
- private LayoutInflater mLayoutInflater;
private PrivateSpaceHeaderViewController mPsHeaderViewController;
private RelativeLayout mPsHeaderLayout;
@Mock
@@ -71,16 +74,15 @@
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = new ActivityContextWrapper(getApplicationContext());
- mLayoutInflater = LayoutInflater.from(getApplicationContext());
mPsHeaderViewController = new PrivateSpaceHeaderViewController(mAllApps,
mPrivateProfileManager);
- mPsHeaderLayout = (RelativeLayout) mLayoutInflater.inflate(R.layout.private_space_header,
- null);
+ mPsHeaderLayout = (RelativeLayout) LayoutInflater.from(mContext).inflate(
+ R.layout.private_space_header, null);
}
@Test
public void privateProfileDisabled_psHeaderContainsLockedView() throws Exception {
- Bitmap unlockButton = getBitmap(mContext.getDrawable(R.drawable.bg_ps_unlock_button));
+ Bitmap unlockButton = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
@@ -93,11 +95,15 @@
if (view.getId() == R.id.ps_container_header) {
totalContainerHeaderView += 1;
assertEquals(View.VISIBLE, view.getVisibility());
- } else if (view.getId() == R.id.ps_lock_unlock_button
- && view instanceof ImageView imageView) {
+ } else if (view.getId() == R.id.settingsAndLockGroup) {
+ ImageView lockIcon = view.findViewById(R.id.lock_icon);
+ assertTrue(getBitmap(lockIcon.getDrawable()).sameAs(unlockButton));
+ assertEquals(View.VISIBLE, lockIcon.getVisibility());
+
+ // Verify textView shouldn't be showing when disabled.
+ TextView lockText = view.findViewById(R.id.lock_text);
+ assertEquals(View.GONE, lockText.getVisibility());
totalLockUnlockButtonView += 1;
- assertEquals(View.VISIBLE, view.getVisibility());
- getBitmap(imageView.getDrawable()).sameAs(unlockButton);
} else {
assertEquals(View.GONE, view.getVisibility());
}
@@ -108,8 +114,8 @@
@Test
public void privateProfileEnabled_psHeaderContainsUnlockedView() throws Exception {
- Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_lock_button));
- Bitmap settingsImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_settings_button));
+ Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
+ Bitmap settingsImage = getBitmap(mContext.getDrawable(R.drawable.ic_ps_settings));
when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
when(mPrivateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(true);
@@ -124,16 +130,20 @@
if (view.getId() == R.id.ps_container_header) {
totalContainerHeaderView += 1;
assertEquals(View.VISIBLE, view.getVisibility());
- } else if (view.getId() == R.id.ps_lock_unlock_button
- && view instanceof ImageView imageView) {
- totalLockUnlockButtonView += 1;
- assertEquals(View.VISIBLE, view.getVisibility());
- getBitmap(imageView.getDrawable()).sameAs(lockImage);
- } else if (view.getId() == R.id.ps_settings_button
- && view instanceof ImageView imageView) {
+ } else if (view.getId() == R.id.settingsAndLockGroup) {
+ // Look for settings button.
+ ImageButton settingsButton = view.findViewById(R.id.ps_settings_button);
+ assertEquals(View.VISIBLE, settingsButton.getVisibility());
totalSettingsImageView += 1;
- assertEquals(View.VISIBLE, view.getVisibility());
- getBitmap(imageView.getDrawable()).sameAs(settingsImage);
+ assertTrue(getBitmap(settingsButton.getDrawable()).sameAs(settingsImage));
+
+ // Look for lock_icon and lock_text.
+ ImageView lockIcon = view.findViewById(R.id.lock_icon);
+ assertTrue(getBitmap(lockIcon.getDrawable()).sameAs(lockImage));
+ assertEquals(View.VISIBLE, lockIcon.getVisibility());
+ TextView lockText = view.findViewById(R.id.lock_text);
+ assertEquals(View.VISIBLE, lockText.getVisibility());
+ totalLockUnlockButtonView += 1;
} else {
assertEquals(View.GONE, view.getVisibility());
}
@@ -146,7 +156,7 @@
@Test
public void privateProfileEnabledAndNoSettingsIntent_psHeaderContainsUnlockedView()
throws Exception {
- Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_lock_button));
+ Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
when(mPrivateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(false);
@@ -161,11 +171,18 @@
if (view.getId() == R.id.ps_container_header) {
totalContainerHeaderView += 1;
assertEquals(View.VISIBLE, view.getVisibility());
- } else if (view.getId() == R.id.ps_lock_unlock_button
- && view instanceof ImageView imageView) {
+ } else if (view.getId() == R.id.settingsAndLockGroup) {
+ // Ensure there is no settings button.
+ ImageButton settingsImage = view.findViewById(R.id.ps_settings_button);
+ assertEquals(View.GONE, settingsImage.getVisibility());
+
+ // Check lock icon and lock text is there.
+ ImageView lockIcon = view.findViewById(R.id.lock_icon);
+ assertTrue(getBitmap(lockIcon.getDrawable()).sameAs(lockImage));
+ assertEquals(View.VISIBLE, lockIcon.getVisibility());
+ TextView lockText = view.findViewById(R.id.lock_text);
+ assertEquals(View.VISIBLE, lockText.getVisibility());
totalLockUnlockButtonView += 1;
- assertEquals(View.VISIBLE, view.getVisibility());
- getBitmap(imageView.getDrawable()).sameAs(lockImage);
} else {
assertEquals(View.GONE, view.getVisibility());
}
@@ -194,7 +211,10 @@
&& view instanceof ImageView imageView) {
totalLockUnlockButtonView += 1;
assertEquals(View.VISIBLE, view.getVisibility());
- getBitmap(imageView.getDrawable()).sameAs(transitionImage);
+ assertTrue(getBitmap(imageView.getDrawable()).sameAs(transitionImage));
+ } else if (view.getId() == R.id.settingsAndLockGroup) {
+ LinearLayout lockUnlockButton = view.findViewById(R.id.ps_lock_unlock_button);
+ assertEquals(View.GONE, lockUnlockButton.getVisibility());
} else {
assertEquals(View.GONE, view.getVisibility());
}
diff --git a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
index 6fce4c6..848ae82 100644
--- a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
+++ b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
@@ -34,6 +34,7 @@
import com.android.launcher3.tapl.AllApps;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
+import com.android.launcher3.util.rule.ScreenRecordRule;
import org.junit.Before;
import org.junit.Test;
@@ -130,6 +131,7 @@
@Test
@PortraitLandscape
@PlatinumTest(focusArea = "launcher")
+ @ScreenRecordRule.ScreenRecord // b/322228038
public void testAllAppsFromHome() {
// Test opening all apps
assertNotNull("switchToAllApps() returned null",
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index 1e765c0..20ba04b 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -16,6 +16,8 @@
package com.android.launcher3.dragging;
import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
+import static com.android.launcher3.testing.shared.TestProtocol.UIOBJECT_STALE_ELEMENT;
+import static com.android.launcher3.ui.AbstractLauncherUiTest.initialize;
import static com.android.launcher3.util.TestConstants.AppNames.DUMMY_APP_NAME;
import static com.android.launcher3.util.TestConstants.AppNames.GMAIL_APP_NAME;
import static com.android.launcher3.util.TestConstants.AppNames.MAPS_APP_NAME;
@@ -154,6 +156,7 @@
0, Math.min(gridPositions.length, appNameCandidates.length));
for (int i = 0; i < appNames.length; ++i) {
+ Log.d(UIOBJECT_STALE_ELEMENT, "creatingShortcut for: " + appNames[i]);
createShortcutIfNotExist(appNames[i], gridPositions[i]);
}
@@ -166,6 +169,7 @@
DUMMY_APP_NAME + " was expected to disappear after uninstall.", DUMMY_APP_NAME);
if (!TestStabilityRule.isPresubmit()) { // b/315847371
+ Log.d(UIOBJECT_STALE_ELEMENT, "second getWorkspaceIconsPositions()");
Map<String, Point> finalPositions =
mLauncher.getWorkspace().getWorkspaceIconsPositions();
assertThat(finalPositions).doesNotContainKey(DUMMY_APP_NAME);
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index f771052..5283c6b 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -2,21 +2,35 @@
import static android.os.Process.myUserHandle;
+import static androidx.test.InstrumentationRegistry.getInstrumentation;
+
+import static com.android.launcher3.Flags.FLAG_ENABLE_SUPPORT_FOR_ARCHIVING;
+import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_ARCHIVED;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY;
import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY2;
import static com.android.launcher3.util.LauncherModelHelper.TEST_ACTIVITY3;
import static com.android.launcher3.util.LauncherModelHelper.TEST_PACKAGE;
+import static com.android.launcher3.util.TestUtil.DUMMY_CLASS_NAME;
+import static com.android.launcher3.util.TestUtil.DUMMY_PACKAGE;
import static com.android.launcher3.util.TestUtil.runOnExecutorSync;
+import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
+import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
+
+import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import android.content.Context;
+import android.platform.test.annotations.RequiresFlagsEnabled;
+import android.platform.test.flag.junit.CheckFlagsRule;
+import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
+import androidx.test.uiautomator.UiDevice;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.icons.BitmapInfo;
@@ -26,12 +40,16 @@
import com.android.launcher3.util.LauncherLayoutBuilder;
import com.android.launcher3.util.LauncherModelHelper;
import com.android.launcher3.util.PackageUserKey;
+import com.android.launcher3.util.rule.TestStabilityRule;
+import com.android.launcher3.util.TestUtil;
import org.junit.After;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
@@ -43,9 +61,18 @@
@RunWith(AndroidJUnit4.class)
public class CacheDataUpdatedTaskTest {
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule =
+ DeviceFlagsValueProvider.createCheckFlagsRule();
+
private static final String PENDING_APP_1 = TEST_PACKAGE + ".pending1";
private static final String PENDING_APP_2 = TEST_PACKAGE + ".pending2";
+ private static final String ARCHIVED_PACKAGE = DUMMY_PACKAGE;
+ private static final String ARCHIVED_CLASS_NAME = DUMMY_CLASS_NAME;
+ private static final String ARCHIVED_TITLE = "Aardwolf";
+
+
private LauncherModelHelper mModelHelper;
private Context mContext;
@@ -57,6 +84,7 @@
mContext = mModelHelper.sandboxContext;
mSession1 = mModelHelper.createInstallerSession(PENDING_APP_1);
mModelHelper.createInstallerSession(PENDING_APP_2);
+ TestUtil.installDummyApp();
LauncherLayoutBuilder builder = new LauncherLayoutBuilder()
.atHotseat(1).putFolder("MyFolder")
@@ -73,14 +101,22 @@
.addApp(PENDING_APP_2, TEST_ACTIVITY) // 8
.addApp(PENDING_APP_2, TEST_ACTIVITY2) // 9
.addApp(PENDING_APP_2, TEST_ACTIVITY3) // 10
+
+ // Dummy Test Package
+ .addApp(ARCHIVED_PACKAGE, ARCHIVED_CLASS_NAME) // 11
.build();
mModelHelper.setupDefaultLayoutProvider(builder);
mModelHelper.loadModelSync();
- assertEquals(10, mModelHelper.getBgDataModel().itemsIdMap.size());
+ assertEquals(11, mModelHelper.getBgDataModel().itemsIdMap.size());
+
+ UiDevice device = UiDevice.getInstance(getInstrumentation());
+ assertThat(device.executeShellCommand(String.format("pm archive %s", ARCHIVED_PACKAGE)))
+ .isEqualTo("Success\n");
}
@After
- public void tearDown() {
+ public void tearDown() throws IOException {
+ TestUtil.uninstallDummyApp();
mModelHelper.destroy();
}
@@ -90,6 +126,7 @@
}
@Test
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/325283522
public void testCacheUpdate_update_apps() {
// Run on model executor so that no other task runs in the middle.
runOnExecutorSync(MODEL_EXECUTOR, () -> {
@@ -138,6 +175,47 @@
});
}
+ @Test
+ @RequiresFlagsEnabled(FLAG_ENABLE_SUPPORT_FOR_ARCHIVING)
+ public void testSessionUpdate_archivedApps_sessionInfoPrioritized() {
+ // Run on model executor so that no other task runs in the middle.
+ runOnExecutorSync(MODEL_EXECUTOR, () -> {
+ // Clear all icons from apps list so that its easy to check what was updated
+ allItems().forEach(wi -> wi.bitmap = BitmapInfo.LOW_RES_INFO);
+ int mSession2 = mModelHelper.createInstallerSession(ARCHIVED_PACKAGE);
+ mModelHelper.getModel().enqueueModelUpdateTask(
+ newTask(CacheDataUpdatedTask.OP_CACHE_UPDATE, ARCHIVED_PACKAGE));
+ List<Integer> pendingArchivedAppIds = List.of(11);
+ // Mark the app items as archived.
+ allItems().forEach(wi -> {
+ if (pendingArchivedAppIds.contains(wi.id)) {
+ wi.runtimeStatusFlags |= FLAG_ARCHIVED;
+ }
+ });
+ // Before cache is updated with sessionInfo, confirm the title.
+ for (WorkspaceItemInfo info : allItems()) {
+ if (pendingArchivedAppIds.contains(info.id)) {
+ assertEquals(info.title, ARCHIVED_TITLE);
+ }
+ }
+
+ // Update the cache with session details.
+ LauncherAppState.getInstance(mContext).getIconCache().updateSessionCache(
+ new PackageUserKey(ARCHIVED_PACKAGE, myUserHandle()),
+ mContext.getPackageManager().getPackageInstaller().getSessionInfo(mSession2));
+
+ // Trigger a refresh for workspace itemInfo objects.
+ mModelHelper.getModel().enqueueModelUpdateTask(
+ newTask(CacheDataUpdatedTask.OP_SESSION_UPDATE, ARCHIVED_PACKAGE));
+ // Verify the new title from session is applied to the iconInfo.
+ for (WorkspaceItemInfo info : allItems()) {
+ if (pendingArchivedAppIds.contains(info.id)) {
+ assertEquals(info.title, ARCHIVED_PACKAGE);
+ }
+ }
+ });
+ }
+
private void verifyUpdate(int... idsUpdated) {
IntSet updates = IntSet.wrap(idsUpdated);
for (WorkspaceItemInfo info : allItems()) {
diff --git a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
index e94dc02..fc7caed 100644
--- a/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
+++ b/tests/src/com/android/launcher3/model/WorkspaceItemProcessorTest.kt
@@ -18,6 +18,7 @@
import android.appwidget.AppWidgetProviderInfo
import android.content.ComponentName
+import android.content.Context
import android.content.Intent
import android.content.pm.LauncherApps
import android.content.pm.PackageInstaller
@@ -27,245 +28,137 @@
import com.android.launcher3.LauncherAppState
import com.android.launcher3.LauncherSettings.Favorites
import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APPLICATION
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT
+import com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER
+import com.android.launcher3.Utilities.EMPTY_PERSON_ARRAY
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError.Companion.MISSING_INFO
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError.Companion.PROFILE_DELETED
+import com.android.launcher3.model.data.FolderInfo
import com.android.launcher3.model.data.IconRequestInfo
+import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.shortcuts.ShortcutKey
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.PackageManagerHelper
import com.android.launcher3.util.PackageUserKey
import com.android.launcher3.widget.WidgetInflater
+import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.Before
import org.junit.Test
+import org.mockito.Mock
import org.mockito.Mockito.RETURNS_DEEP_STUBS
import org.mockito.Mockito.mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.anyOrNull
import org.mockito.kotlin.doAnswer
import org.mockito.kotlin.mock
-import org.mockito.kotlin.times
-import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
class WorkspaceItemProcessorTest {
- private var itemProcessor = createTestWorkspaceItemProcessor()
+
+ @Mock private lateinit var mockIconRequestInfo: IconRequestInfo<WorkspaceItemInfo>
+ @Mock private lateinit var mockWorkspaceInfo: WorkspaceItemInfo
+ @Mock private lateinit var mockBgDataModel: BgDataModel
+ @Mock private lateinit var mockContext: Context
+ @Mock private lateinit var mockAppState: LauncherAppState
+ @Mock private lateinit var mockIntent: Intent
+ @Mock private lateinit var mockPmHelper: PackageManagerHelper
+ @Mock private lateinit var mockLauncherApps: LauncherApps
+ @Mock private lateinit var mockCursor: LoaderCursor
+ @Mock private lateinit var mockUserManagerState: UserManagerState
+ @Mock private lateinit var mockWidgetInflater: WidgetInflater
+
+ private lateinit var userHandle: UserHandle
+ private lateinit var iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>>
+ private lateinit var componentName: ComponentName
+ private lateinit var unlockedUsersArray: LongSparseArray<Boolean>
+ private lateinit var keyToPinnedShortcutsMap: MutableMap<ShortcutKey, ShortcutInfo>
+ private lateinit var installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo>
+ private lateinit var allDeepShortcuts: MutableList<ShortcutInfo>
+
+ private lateinit var itemProcessorUnderTest: WorkspaceItemProcessor
@Before
fun setup() {
- itemProcessor = createTestWorkspaceItemProcessor()
- }
-
- @Test
- fun `When user is null then mark item deleted`() {
- // Given
- val mockCursor = mock<LoaderCursor>().apply { id = 1 }
- val itemProcessor = createTestWorkspaceItemProcessor(cursor = mockCursor)
- // When
- itemProcessor.processItem()
- // Then
- verify(mockCursor).markDeleted("User has been deleted for item id=1", PROFILE_DELETED)
- }
-
- @Test
- fun `When app has null intent then mark deleted`() {
- // Given
- val mockCursor =
- mock<LoaderCursor>().apply {
- user = UserHandle(0)
- id = 1
- itemType = ITEM_TYPE_APPLICATION
- }
- val itemProcessor = createTestWorkspaceItemProcessor(cursor = mockCursor)
- // When
- itemProcessor.processItem()
- // Then
- verify(mockCursor).markDeleted("Null intent for item id=1", MISSING_INFO)
- }
-
- @Test
- fun `When app has null target package then mark deleted`() {
- // Given
- val mockCursor =
- mock<LoaderCursor>().apply {
- user = UserHandle(0)
- itemType = ITEM_TYPE_APPLICATION
- id = 1
- whenever(parseIntent()).thenReturn(Intent())
- }
- val itemProcessor = createTestWorkspaceItemProcessor(cursor = mockCursor)
- // When
- itemProcessor.processItem()
- // Then
- verify(mockCursor).markDeleted("No target package for item id=1", MISSING_INFO)
- }
-
- @Test
- fun `When app has empty String target package then mark deleted`() {
- // Given
- val mockIntent =
- mock<Intent>().apply {
- whenever(component).thenReturn(null)
- whenever(`package`).thenReturn("")
- }
- val mockCursor =
- mock<LoaderCursor>().apply {
- user = UserHandle(0)
- itemType = ITEM_TYPE_APPLICATION
- id = 1
- whenever(parseIntent()).thenReturn(mockIntent)
- }
- val itemProcessor = createTestWorkspaceItemProcessor(cursor = mockCursor)
- // When
- itemProcessor.processItem()
- // Then
- verify(mockCursor).markDeleted("No target package for item id=1", MISSING_INFO)
- }
-
- @Test
- fun `When valid app then mark restored`() {
- // Given
- val userHandle = UserHandle(0)
- val componentName = ComponentName("package", "class")
- val mockIntent =
+ userHandle = UserHandle(0)
+ mockIconRequestInfo = mock<IconRequestInfo<WorkspaceItemInfo>>()
+ iconRequestInfos = mutableListOf(mockIconRequestInfo)
+ mockWorkspaceInfo = mock<WorkspaceItemInfo>()
+ mockBgDataModel = mock<BgDataModel>()
+ componentName = ComponentName("package", "class")
+ unlockedUsersArray = LongSparseArray<Boolean>(1).apply { put(101, true) }
+ mockIntent =
mock<Intent>().apply {
whenever(component).thenReturn(componentName)
- whenever(`package`).thenReturn("")
+ whenever(`package`).thenReturn("pkg")
+ whenever(getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID)).thenReturn("")
}
- val mockLauncherApps =
- mock<LauncherApps>().apply {
- whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
- whenever(isActivityEnabled(componentName, userHandle)).thenReturn(true)
+ mockContext =
+ mock<Context>().apply {
+ whenever(packageManager).thenReturn(mock())
+ whenever(packageManager.getUserBadgedLabel(any(), any())).thenReturn("")
}
- val mockCursor =
- mock<LoaderCursor>().apply {
- user = userHandle
- itemType = ITEM_TYPE_APPLICATION
- id = 1
- restoreFlag = 1
- whenever(parseIntent()).thenReturn(mockIntent)
- whenever(markRestored()).doAnswer { restoreFlag = 0 }
+ mockAppState =
+ mock<LauncherAppState>().apply {
+ whenever(context).thenReturn(mockContext)
+ whenever(iconCache).thenReturn(mock())
+ whenever(iconCache.getShortcutIcon(any(), any(), any())).then {}
}
- val itemProcessor =
- createTestWorkspaceItemProcessor(cursor = mockCursor, launcherApps = mockLauncherApps)
- // When
- itemProcessor.processItem()
- // Then
- assertWithMessage("item restoreFlag should be set to 0")
- .that(mockCursor.restoreFlag)
- .isEqualTo(0)
- // currently gets marked restored twice, although markRestore() has check for restoreFlag
- verify(mockCursor, times(2)).markRestored()
- }
-
- @Test
- fun `When fallback Activity found for app then mark restored`() {
- // Given
- val userHandle = UserHandle(0)
- val componentName = ComponentName("package", "class")
- val mockIntent =
- mock<Intent>().apply {
- whenever(component).thenReturn(componentName)
- whenever(`package`).thenReturn("")
- whenever(toUri(0)).thenReturn("")
- }
- val mockLauncherApps =
- mock<LauncherApps>().apply {
- whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
- whenever(isActivityEnabled(componentName, userHandle)).thenReturn(false)
- }
- val mockPmHelper =
+ mockPmHelper =
mock<PackageManagerHelper>().apply {
whenever(getAppLaunchIntent(componentName.packageName, userHandle))
.thenReturn(mockIntent)
}
- val mockCursor =
+ mockLauncherApps =
+ mock<LauncherApps>().apply {
+ whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
+ whenever(isActivityEnabled(componentName, userHandle)).thenReturn(true)
+ }
+ mockCursor =
mock(LoaderCursor::class.java, RETURNS_DEEP_STUBS).apply {
user = userHandle
itemType = ITEM_TYPE_APPLICATION
id = 1
restoreFlag = 1
+ serialNumber = 101
whenever(parseIntent()).thenReturn(mockIntent)
whenever(markRestored()).doAnswer { restoreFlag = 0 }
whenever(updater().put(Favorites.INTENT, mockIntent.toUri(0)).commit())
.thenReturn(1)
+ whenever(getAppShortcutInfo(any(), any(), any(), any()))
+ .thenReturn(mockWorkspaceInfo)
+ whenever(createIconRequestInfo(any(), any())).thenReturn(mockIconRequestInfo)
}
- val itemProcessor =
- createTestWorkspaceItemProcessor(
- cursor = mockCursor,
- launcherApps = mockLauncherApps,
- pmHelper = mockPmHelper
- )
- // When
- itemProcessor.processItem()
- // Then
- assertWithMessage("item restoreFlag should be set to 0")
- .that(mockCursor.restoreFlag)
- .isEqualTo(0)
- verify(mockCursor.updater().put(Favorites.INTENT, mockIntent.toUri(0))).commit()
- }
-
- @Test
- fun `When app with disabled activity and no fallback found then mark deleted`() {
- // Given
- val userHandle = UserHandle(0)
- val componentName = ComponentName("package", "class")
- val mockIntent =
- mock<Intent>().apply {
- whenever(component).thenReturn(componentName)
- whenever(`package`).thenReturn("")
- }
- val mockLauncherApps =
- mock<LauncherApps>().apply {
- whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
- whenever(isActivityEnabled(componentName, userHandle)).thenReturn(false)
- }
- val mockPmHelper =
- mock<PackageManagerHelper>().apply {
- whenever(getAppLaunchIntent(componentName.packageName, userHandle)).thenReturn(null)
- }
- val mockCursor =
- mock<LoaderCursor>().apply {
- user = userHandle
- itemType = ITEM_TYPE_APPLICATION
- id = 1
- restoreFlag = 1
- whenever(parseIntent()).thenReturn(mockIntent)
- }
- val itemProcessor =
- createTestWorkspaceItemProcessor(
- cursor = mockCursor,
- launcherApps = mockLauncherApps,
- pmHelper = mockPmHelper
- )
- // When
- itemProcessor.processItem()
- // Then
- assertWithMessage("item restoreFlag should be unchanged")
- .that(mockCursor.restoreFlag)
- .isEqualTo(1)
- verify(mockCursor).markDeleted("Intent null, unable to find a launch target", MISSING_INFO)
+ mockUserManagerState = mock<UserManagerState>()
+ mockWidgetInflater = mock<WidgetInflater>()
+ keyToPinnedShortcutsMap = mutableMapOf()
+ installingPkgs = hashMapOf()
+ allDeepShortcuts = mutableListOf()
}
/**
* Helper to create WorkspaceItemProcessor with defaults. WorkspaceItemProcessor has a lot of
* dependencies, so this method can be used to inject concrete arguments while keeping the rest
- * as mocks/defaults.
+ * as mocks/defaults, or to recreate it after modifying the default vars.
*/
- private fun createTestWorkspaceItemProcessor(
- cursor: LoaderCursor = mock(),
+ private fun createWorkspaceItemProcessorUnderTest(
+ cursor: LoaderCursor = mockCursor,
memoryLogger: LoaderMemoryLogger? = null,
- userManagerState: UserManagerState = mock(),
- launcherApps: LauncherApps = mock(),
- shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = mapOf(),
- app: LauncherAppState = mock(),
- bgDataModel: BgDataModel = mock(),
+ userManagerState: UserManagerState = mockUserManagerState,
+ launcherApps: LauncherApps = mockLauncherApps,
+ shortcutKeyToPinnedShortcuts: Map<ShortcutKey, ShortcutInfo> = keyToPinnedShortcutsMap,
+ app: LauncherAppState = mockAppState,
+ bgDataModel: BgDataModel = mockBgDataModel,
widgetProvidersMap: MutableMap<ComponentKey, AppWidgetProviderInfo?> = mutableMapOf(),
- widgetInflater: WidgetInflater = mock(),
- pmHelper: PackageManagerHelper = mock(),
+ widgetInflater: WidgetInflater = mockWidgetInflater,
+ pmHelper: PackageManagerHelper = mockPmHelper,
iconRequestInfos: MutableList<IconRequestInfo<WorkspaceItemInfo>> = mutableListOf(),
isSdCardReady: Boolean = false,
pendingPackages: MutableSet<PackageUserKey> = mutableSetOf(),
- unlockedUsers: LongSparseArray<Boolean> = LongSparseArray(),
+ unlockedUsers: LongSparseArray<Boolean> = unlockedUsersArray,
installingPkgs: HashMap<PackageUserKey, PackageInstaller.SessionInfo> = hashMapOf(),
allDeepShortcuts: MutableList<ShortcutInfo> = mutableListOf()
) =
@@ -287,4 +180,244 @@
installingPkgs = installingPkgs,
allDeepShortcuts = allDeepShortcuts
)
+
+ @Test
+ fun `When user is null then mark item deleted`() {
+ // Given
+ mockCursor = mock<LoaderCursor>().apply { id = 1 }
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+ // When
+ itemProcessorUnderTest.processItem()
+ // Then
+ verify(mockCursor).markDeleted("User has been deleted for item id=1", PROFILE_DELETED)
+ verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
+ }
+
+ @Test
+ fun `When app has null intent then mark deleted`() {
+ // Given
+ mockCursor.apply { whenever(parseIntent()).thenReturn(null) }
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+ // When
+ itemProcessorUnderTest.processItem()
+ // Then
+ verify(mockCursor).markDeleted("Null intent for item id=1", MISSING_INFO)
+ verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
+ }
+
+ @Test
+ fun `When app has null target package then mark deleted`() {
+
+ // Given
+ mockIntent.apply {
+ whenever(component).thenReturn(null)
+ whenever(`package`).thenReturn(null)
+ }
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
+ // When
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ verify(mockCursor).markDeleted("No target package for item id=1", MISSING_INFO)
+ verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
+ }
+
+ @Test
+ fun `When app has empty String target package then mark deleted`() {
+
+ // Given
+ componentName = ComponentName("", "")
+ whenever(mockIntent.component).thenReturn(componentName)
+ whenever(mockCursor.parseIntent()).thenReturn(mockIntent)
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
+ // When
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ verify(mockCursor).markDeleted("No target package for item id=1", MISSING_INFO)
+ verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
+ }
+
+ @Test
+ fun `When valid app then mark restored`() {
+
+ // Given
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
+ // When
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ assertWithMessage("item restoreFlag should be set to 0")
+ .that(mockCursor.restoreFlag)
+ .isEqualTo(0)
+ // currently gets marked restored twice, although markRestore() has check for restoreFlag
+ verify(mockCursor, times(2)).markRestored()
+ assertThat(iconRequestInfos).containsExactly(mockIconRequestInfo)
+ verify(mockCursor).checkAndAddItem(mockWorkspaceInfo, mockBgDataModel, null)
+ }
+
+ @Test
+ fun `When fallback Activity found for app then mark restored`() {
+
+ // Given
+ mockLauncherApps =
+ mock<LauncherApps>().apply {
+ whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
+ whenever(isActivityEnabled(componentName, userHandle)).thenReturn(false)
+ }
+ mockPmHelper =
+ mock<PackageManagerHelper>().apply {
+ whenever(getAppLaunchIntent(componentName.packageName, userHandle))
+ .thenReturn(mockIntent)
+ }
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
+ // When
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ assertWithMessage("item restoreFlag should be set to 0")
+ .that(mockCursor.restoreFlag)
+ .isEqualTo(0)
+ verify(mockCursor.updater().put(Favorites.INTENT, mockIntent.toUri(0))).commit()
+ assertThat(iconRequestInfos).containsExactly(mockIconRequestInfo)
+ verify(mockCursor).checkAndAddItem(mockWorkspaceInfo, mockBgDataModel, null)
+ }
+
+ @Test
+ fun `When app with disabled activity and no fallback found then mark deleted`() {
+
+ // Given
+ mockLauncherApps =
+ mock<LauncherApps>().apply {
+ whenever(isPackageEnabled("package", userHandle)).thenReturn(true)
+ whenever(isActivityEnabled(componentName, userHandle)).thenReturn(false)
+ }
+ mockPmHelper =
+ mock<PackageManagerHelper>().apply {
+ whenever(getAppLaunchIntent(componentName.packageName, userHandle)).thenReturn(null)
+ }
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
+ // When
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ assertWithMessage("item restoreFlag should be unchanged")
+ .that(mockCursor.restoreFlag)
+ .isEqualTo(1)
+ verify(mockCursor).markDeleted("Intent null, unable to find a launch target", MISSING_INFO)
+ verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
+ }
+
+ @Test
+ fun `When valid Pinned Deep Shortcut then mark restored`() {
+
+ // Given
+ mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
+ val expectedShortcutInfo =
+ mock<ShortcutInfo>().apply {
+ whenever(id).thenReturn("")
+ whenever(`package`).thenReturn("")
+ whenever(activity).thenReturn(mock())
+ whenever(longLabel).thenReturn("")
+ whenever(isEnabled).thenReturn(true)
+ whenever(disabledMessage).thenReturn("")
+ whenever(disabledReason).thenReturn(0)
+ whenever(persons).thenReturn(EMPTY_PERSON_ARRAY)
+ }
+ val shortcutKey = ShortcutKey.fromIntent(mockIntent, mockCursor.user)
+ keyToPinnedShortcutsMap[shortcutKey] = expectedShortcutInfo
+ iconRequestInfos = mutableListOf()
+ itemProcessorUnderTest =
+ createWorkspaceItemProcessorUnderTest(allDeepShortcuts = allDeepShortcuts)
+
+ // When
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ assertWithMessage("item restoreFlag should be set to 0")
+ .that(mockCursor.restoreFlag)
+ .isEqualTo(0)
+ assertThat(iconRequestInfos).isEmpty()
+ assertThat(allDeepShortcuts).containsExactly(expectedShortcutInfo)
+ verify(mockCursor).markRestored()
+ verify(mockCursor).checkAndAddItem(any(), any(), anyOrNull())
+ }
+
+ @Test
+ fun `When Pinned Deep Shortcut not found then mark deleted`() {
+
+ // Given
+ mockCursor.itemType = ITEM_TYPE_DEEP_SHORTCUT
+ iconRequestInfos = mutableListOf()
+ keyToPinnedShortcutsMap = hashMapOf()
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
+ // When
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ assertWithMessage("item restoreFlag should be set to 0")
+ .that(mockCursor.restoreFlag)
+ .isEqualTo(0)
+ assertThat(iconRequestInfos).isEmpty()
+ verify(mockCursor, times(0)).checkAndAddItem(any(), any(), anyOrNull())
+ verify(mockCursor)
+ .markDeleted(
+ "Pinned shortcut not found from request. package=pkg, user=UserHandle{0}",
+ "shortcut_not_found"
+ )
+ }
+
+ @Test
+ fun `When processing Folder then create FolderInfo and mark restored`() {
+ val actualFolderInfo = FolderInfo()
+ mockBgDataModel =
+ mock<BgDataModel>().apply { whenever(findOrMakeFolder(1)).thenReturn(actualFolderInfo) }
+ mockCursor =
+ mock<LoaderCursor>().apply {
+ user = UserHandle(0)
+ itemType = ITEM_TYPE_FOLDER
+ id = 1
+ container = 100
+ restoreFlag = 1
+ serialNumber = 101
+ whenever(applyCommonProperties(any<ItemInfo>())).then {}
+ whenever(markRestored()).doAnswer { restoreFlag = 0 }
+ whenever(getColumnIndex(Favorites.TITLE)).thenReturn(4)
+ whenever(getString(4)).thenReturn("title")
+ whenever(options).thenReturn(5)
+ }
+ val expectedFolderInfo =
+ FolderInfo().apply {
+ itemType = ITEM_TYPE_FOLDER
+ spanX = 1
+ spanY = 1
+ options = 5
+ }
+ itemProcessorUnderTest = createWorkspaceItemProcessorUnderTest()
+
+ // When
+ itemProcessorUnderTest.processItem()
+
+ // Then
+ assertWithMessage("item restoreFlag should be set to 0")
+ .that(mockCursor.restoreFlag)
+ .isEqualTo(0)
+ verify(mockCursor).markRestored()
+ assertThat(actualFolderInfo.id).isEqualTo(expectedFolderInfo.id)
+ assertThat(actualFolderInfo.container).isEqualTo(expectedFolderInfo.container)
+ assertThat(actualFolderInfo.itemType).isEqualTo(expectedFolderInfo.itemType)
+ assertThat(actualFolderInfo.screenId).isEqualTo(expectedFolderInfo.screenId)
+ assertThat(actualFolderInfo.cellX).isEqualTo(expectedFolderInfo.cellX)
+ assertThat(actualFolderInfo.cellY).isEqualTo(expectedFolderInfo.cellY)
+ assertThat(actualFolderInfo.spanX).isEqualTo(expectedFolderInfo.spanX)
+ assertThat(actualFolderInfo.spanY).isEqualTo(expectedFolderInfo.spanY)
+ assertThat(actualFolderInfo.options).isEqualTo(expectedFolderInfo.options)
+ verify(mockCursor).checkAndAddItem(actualFolderInfo, mockBgDataModel, null)
+ }
}
diff --git a/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt b/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
new file mode 100644
index 0000000..11855e6
--- /dev/null
+++ b/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
@@ -0,0 +1,142 @@
+package com.android.launcher3.widget
+
+import android.appwidget.AppWidgetProviderInfo
+import android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN
+import android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_KEYGUARD
+import android.appwidget.AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX
+import android.content.ComponentName
+import android.content.Context
+import android.content.pm.ActivityInfo
+import android.content.pm.ApplicationInfo
+import android.platform.test.annotations.RequiresFlagsDisabled
+import android.platform.test.annotations.RequiresFlagsEnabled
+import android.platform.test.flag.junit.CheckFlagsRule
+import android.platform.test.flag.junit.DeviceFlagsValueProvider
+import android.view.LayoutInflater
+import android.widget.RemoteViews
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.Flags.FLAG_ENABLE_GENERATED_PREVIEWS
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.icons.IconCache
+import com.android.launcher3.icons.IconProvider
+import com.android.launcher3.model.WidgetItem
+import com.android.launcher3.tests.R
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.Executors
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class GeneratedPreviewTest {
+ @get:Rule val checkFlagsRule: CheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule()
+ private val providerName =
+ ComponentName(
+ "com.android.launcher3.tests",
+ "com.android.launcher3.testcomponent.AppWidgetNoConfig"
+ )
+ private val generatedPreviewLayout = R.layout.test_layout_appwidget_blue
+ private lateinit var context: Context
+ private lateinit var generatedPreview: RemoteViews
+ private lateinit var widgetCell: WidgetCell
+ private lateinit var helper: WidgetManagerHelper
+ private lateinit var appWidgetProviderInfo: LauncherAppWidgetProviderInfo
+ private lateinit var widgetItem: WidgetItem
+
+ @Before
+ fun setup() {
+ context = getApplicationContext()
+ generatedPreview = RemoteViews(context.packageName, generatedPreviewLayout)
+ widgetCell =
+ LayoutInflater.from(ActivityContextWrapper(context))
+ .inflate(com.android.launcher3.R.layout.widget_cell, null) as WidgetCell
+ appWidgetProviderInfo =
+ AppWidgetProviderInfo()
+ .apply {
+ generatedPreviewCategories = WIDGET_CATEGORY_HOME_SCREEN
+ provider = providerName
+ providerInfo = ActivityInfo().apply { applicationInfo = ApplicationInfo() }
+ }
+ .let { LauncherAppWidgetProviderInfo.fromProviderInfo(context, it) }
+ helper =
+ object : WidgetManagerHelper(context) {
+ override fun loadGeneratedPreview(
+ info: AppWidgetProviderInfo,
+ widgetCategory: Int
+ ) =
+ generatedPreview.takeIf {
+ info === appWidgetProviderInfo &&
+ widgetCategory == WIDGET_CATEGORY_HOME_SCREEN
+ }
+ }
+ createWidgetItem()
+ }
+
+ private fun createWidgetItem() {
+ Executors.MODEL_EXECUTOR.submit {
+ val idp = InvariantDeviceProfile()
+ widgetItem =
+ WidgetItem(
+ appWidgetProviderInfo,
+ idp,
+ IconCache(context, idp, null, IconProvider(context)),
+ context,
+ helper,
+ )
+ }
+ .get()
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+ fun widgetItem_hasGeneratedPreview() {
+ assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isTrue()
+ assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
+ assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+ fun widgetItem_hasGeneratedPreview_noPreview() {
+ appWidgetProviderInfo.generatedPreviewCategories = 0
+ createWidgetItem()
+ assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_HOME_SCREEN)).isFalse()
+ 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()
+ assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
+ assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
+ }
+ @Test
+ @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+ fun widgetItem_getGeneratedPreview() {
+ val preview = widgetItem.generatedPreviews.get(WIDGET_CATEGORY_HOME_SCREEN)
+ assertThat(preview).isEqualTo(generatedPreview)
+ }
+
+ @Test
+ @RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+ fun widgetCell_showGeneratedPreview() {
+ widgetCell.applyFromCellItem(widgetItem)
+ assertThat(widgetCell.appWidgetHostViewPreview).isNotNull()
+ assertThat(widgetCell.appWidgetHostViewPreview?.appWidgetInfo)
+ .isEqualTo(appWidgetProviderInfo)
+ }
+
+ @Test
+ @RequiresFlagsDisabled(FLAG_ENABLE_GENERATED_PREVIEWS)
+ fun widgetCell_showGeneratedPreview_flagDisabled() {
+ widgetCell.applyFromCellItem(widgetItem)
+ assertThat(widgetCell.appWidgetHostViewPreview).isNull()
+ }
+}
diff --git a/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
index 60590e7..0286279 100644
--- a/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinderTest.java
@@ -52,6 +52,7 @@
import com.android.launcher3.util.WidgetUtils;
import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
import com.android.launcher3.widget.WidgetCell;
+import com.android.launcher3.widget.WidgetManagerHelper;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import org.junit.Before;
@@ -137,6 +138,7 @@
}
private List<WidgetItem> generateWidgetItems(String packageName, int numOfWidgets) {
+ WidgetManagerHelper widgetManager = new WidgetManagerHelper(mContext);
ArrayList<WidgetItem> widgetItems = new ArrayList<>();
for (int i = 0; i < numOfWidgets; i++) {
ComponentName cn = ComponentName.createRelative(packageName, ".SampleWidget" + i);
@@ -144,7 +146,7 @@
widgetItems.add(new WidgetItem(
LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, widgetInfo),
- mTestProfile, mIconCache, mContext));
+ mTestProfile, mIconCache, mContext, widgetManager));
}
return widgetItems;
}
diff --git a/tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java b/tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
index 583d37f..8457ac6 100644
--- a/tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
+++ b/tests/src/com/android/launcher3/widget/picker/search/WidgetsSearchBarControllerTest.java
@@ -78,7 +78,7 @@
public void afterTextChanged_shouldInformSearchModeListenerToEnterSearch() {
mEditText.setText("abc");
- verify(mSearchModeListener).enterSearchMode();
+ verify(mSearchModeListener).enterSearchMode(true);
verifyNoMoreInteractions(mSearchModeListener);
}