Merge changes from topic "taskbar-pinning-preference-rule-fixes" into main
* changes:
Add subrule for controlling an individual Taskbar preference.
Taskbar Pinning Preference Rule fixes.
diff --git a/Android.bp b/Android.bp
index 13a926b..e358005 100644
--- a/Android.bp
+++ b/Android.bp
@@ -19,6 +19,17 @@
min_launcher3_sdk_version = "30"
+// Targets that don't inherit framework aconfig libs (i.e., those that don't set
+// `platform_apis: true`) must manually link them.
+java_defaults {
+ name: "launcher-non-platform-apis-defaults",
+ static_libs: [
+ "android.os.flags-aconfig-java",
+ "android.appwidget.flags-aconfig-java",
+ "com.android.window.flags.window-aconfig-java",
+ ]
+}
+
// Common source files used to build launcher (java and kotlin)
// All sources are split so they can be reused in many other libraries/apps in other folders
@@ -141,7 +152,6 @@
static_libs: [
"LauncherPluginLib",
"launcher_quickstep_log_protos_lite",
- "android.os.flags-aconfig-java",
"androidx-constraintlayout_constraintlayout",
"androidx.recyclerview_recyclerview",
"androidx.dynamicanimation_dynamicanimation",
@@ -163,8 +173,6 @@
"kotlinx_coroutines",
"com_android_launcher3_flags_lib",
"com_android_wm_shell_flags_lib",
- "android.appwidget.flags-aconfig-java",
- "com.android.window.flags.window-aconfig-java",
],
manifest: "AndroidManifest-common.xml",
sdk_version: "current",
@@ -179,6 +187,7 @@
//
android_app {
name: "Launcher3",
+ defaults: ["launcher-non-platform-apis-defaults"],
static_libs: [
"Launcher3ResLib",
@@ -190,7 +199,7 @@
],
optimize: {
- proguard_flags_files: ["proguard.flags"],
+ proguard_flags_files: [":launcher-proguard-rules"],
// Proguard is disable for testing. Derivarive prjects to keep proguard enabled
enabled: false,
},
@@ -302,7 +311,9 @@
static_libs: ["Launcher3QuickStepLib"],
optimize: {
- enabled: false,
+ proguard_flags_files: [":launcher-proguard-rules"],
+ enabled: true,
+ shrink_resources: true,
},
platform_apis: true,
@@ -349,6 +360,7 @@
optimize: {
proguard_flags_files: ["proguard.flags"],
enabled: true,
+ shrink_resources: true,
},
privileged: true,
@@ -385,6 +397,7 @@
optimize: {
proguard_flags_files: ["proguard.flags"],
enabled: true,
+ shrink_resources: true,
},
privileged: true,
diff --git a/go/quickstep/res/values-fr-rCA/strings.xml b/go/quickstep/res/values-fr-rCA/strings.xml
index 2cc9d8f..e48faeb 100644
--- a/go/quickstep/res/values-fr-rCA/strings.xml
+++ b/go/quickstep/res/values-fr-rCA/strings.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="app_share_drop_target_label" msgid="5804774105974539508">"Partager application"</string>
+ <string name="app_share_drop_target_label" msgid="5804774105974539508">"Partager appli"</string>
<string name="action_listen" msgid="2370304050784689486">"Écouter"</string>
<string name="action_translate" msgid="8028378961867277746">"Traduire"</string>
<string name="action_search" msgid="6269564710943755464">"Lentille"</string>
@@ -9,12 +9,12 @@
<string name="dialog_cancel" msgid="6464336969134856366">"ANNULER"</string>
<string name="dialog_settings" msgid="6564397136021186148">"PARAMÈTRES"</string>
<string name="niu_actions_confirmation_title" msgid="3863451714863526143">"Traduire ou écouter le texte à l\'écran"</string>
- <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"Des renseignements comme du texte sur votre écran, des adresses Web et des captures d\'écran peuvent être partagés avec Google.\n\nPour modifier les renseignements que vous partagez, accédez à "<b>"Paramètres > Applications > Applications par défaut > Application d\'assistant numérique"</b>"."</string>
+ <string name="niu_actions_confirmation_text" msgid="2105271481950866089">"Des renseignements comme du texte sur votre écran, des adresses Web et des captures d\'écran peuvent être partagés avec Google.\n\nPour modifier les renseignements que vous partagez, accédez à "<b>"Paramètres > Applis > Applis par défaut > Appli d\'assistant numérique"</b>"."</string>
<string name="assistant_not_selected_title" msgid="5017072974603345228">"Choisir un assistant pour utiliser cette fonctionnalité"</string>
- <string name="assistant_not_selected_text" msgid="3244613673884359276">"Pour écouter ou traduire le texte affiché sur votre écran, choisissez l\'application d\'un assistant numérique dans les paramètres"</string>
+ <string name="assistant_not_selected_text" msgid="3244613673884359276">"Pour écouter ou traduire le texte affiché sur votre écran, choisissez l\'appli d\'un assistant numérique dans les paramètres"</string>
<string name="assistant_not_supported_title" msgid="1675788067597484142">"Modifier votre assistant pour utiliser cette fonctionnalité"</string>
- <string name="assistant_not_supported_text" msgid="1708031078549268884">"Pour écouter ou traduire le texte affiché sur votre écran, modifiez l\'application de votre assistant numérique dans les paramètres"</string>
+ <string name="assistant_not_supported_text" msgid="1708031078549268884">"Pour écouter ou traduire le texte affiché sur votre écran, modifiez l\'appli de votre assistant numérique dans les paramètres"</string>
<string name="tooltip_listen" msgid="7634466447860989102">"Touchez ce bouton pour écouter le texte affiché sur cet écran"</string>
<string name="tooltip_translate" msgid="4184845868901542567">"Touchez ce bouton pour traduire le texte affiché sur cet écran"</string>
- <string name="toast_p2p_app_not_shareable" msgid="7229739094132131536">"Cette application ne peut pas être partagée"</string>
+ <string name="toast_p2p_app_not_shareable" msgid="7229739094132131536">"Cette appli ne peut pas être partagée"</string>
</resources>
diff --git a/quickstep/res/layout/task.xml b/quickstep/res/layout/task.xml
index cc3b30e..46c1332 100644
--- a/quickstep/res/layout/task.xml
+++ b/quickstep/res/layout/task.xml
@@ -28,7 +28,7 @@
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
- <include layout="@layout/task_thumbnail" />
+ <include layout="@layout/task_thumbnail_deprecated" />
<!-- Filtering affects only alpha instead of the visibility since visibility can be altered
separately through RecentsView#resetFromSplitSelectionState() -->
diff --git a/quickstep/res/layout/task_grouped.xml b/quickstep/res/layout/task_grouped.xml
index 87a0f70..708aa3c 100644
--- a/quickstep/res/layout/task_grouped.xml
+++ b/quickstep/res/layout/task_grouped.xml
@@ -33,9 +33,9 @@
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
- <include layout="@layout/task_thumbnail"/>
+ <include layout="@layout/task_thumbnail_deprecated"/>
- <include layout="@layout/task_thumbnail"
+ <include layout="@layout/task_thumbnail_deprecated"
android:id="@+id/bottomright_snapshot" />
<!-- Filtering affects only alpha instead of the visibility since visibility can be altered
diff --git a/quickstep/res/layout/task_thumbnail.xml b/quickstep/res/layout/task_thumbnail.xml
index f1a3d62..34640e6 100644
--- a/quickstep/res/layout/task_thumbnail.xml
+++ b/quickstep/res/layout/task_thumbnail.xml
@@ -13,8 +13,29 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.quickstep.views.TaskThumbnailViewDeprecated
+<com.android.quickstep.task.thumbnail.TaskThumbnailView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/snapshot"
android:layout_width="match_parent"
- android:layout_height="match_parent" />
\ No newline at end of file
+ android:layout_height="match_parent">
+
+ <ImageView
+ android:id="@+id/task_thumbnail"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:importantForAccessibility="no"
+ android:visibility="gone"/>
+
+ <com.android.quickstep.task.thumbnail.LiveTileView
+ android:id="@+id/task_thumbnail_live_tile"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:visibility="gone"/>
+
+ <View
+ android:id="@+id/task_thumbnail_scrim"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@color/overview_foreground_scrim_color"
+ android:alpha="0" />
+
+</com.android.quickstep.task.thumbnail.TaskThumbnailView>
\ No newline at end of file
diff --git a/quickstep/res/layout/task_thumbnail_deprecated.xml b/quickstep/res/layout/task_thumbnail_deprecated.xml
new file mode 100644
index 0000000..f1a3d62
--- /dev/null
+++ b/quickstep/res/layout/task_thumbnail_deprecated.xml
@@ -0,0 +1,20 @@
+<?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.quickstep.views.TaskThumbnailViewDeprecated
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:id="@+id/snapshot"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent" />
\ No newline at end of file
diff --git a/quickstep/res/raw-h480dp/all_set_page_bg.json b/quickstep/res/raw-h480dp/all_set_page_bg.json
deleted file mode 100644
index f2998a0..0000000
--- a/quickstep/res/raw-h480dp/all_set_page_bg.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.8.1","fr":60,"ip":0,"op":181,"w":701,"h":841,"nm":"SUW_WelcomeScreen_FoldableOpen_Portrait_Dynamic","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".primary","cl":"primary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":180,"s":[55]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.949},"o":{"x":0.167,"y":0.167},"t":0,"s":[181.172,148.425,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.038},"t":95,"s":[181.172,-68.377,0],"to":[0,0,0],"ti":[0,0,0]},{"t":180,"s":[181.172,148.425,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[21.6,21.6,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[100.594,-128.921],[118.85,-93.491],[148.984,-67.406],[148.684,-27.55],[163.244,9.552],[144.457,44.702],[140.106,84.321],[107.136,106.715],[84.872,139.773],[45.271,144.279],[10.194,163.205],[-26.964,148.792],[-66.818,149.249],[-93.023,119.218],[-128.524,101.101],[-137.771,62.332],[-160.786,29.793],[-150.957,-8.833],[-156.215,-48.341],[-129.561,-77.974],[-115.856,-115.401],[-78.484,-129.253],[-48.956,-156.023],[-9.427,-150.921],[29.159,-160.903],[61.789,-138.015]],"o":[[-100.594,128.921],[-118.85,93.491],[-148.984,67.406],[-148.684,27.55],[-163.244,-9.552],[-144.456,-44.702],[-140.106,-84.321],[-107.136,-106.715],[-84.872,-139.773],[-45.271,-144.279],[-10.194,-163.205],[26.964,-148.792],[66.818,-149.249],[93.023,-119.218],[128.524,-101.101],[137.771,-62.332],[160.786,-29.793],[150.957,8.833],[156.215,48.341],[129.561,77.974],[115.856,115.4],[78.484,129.253],[48.956,156.023],[9.427,150.921],[-29.159,160.903],[-61.789,138.015]],"v":[[975.226,761.299],[707.165,899.424],[509.8,1127.42],[208.253,1125.148],[-72.46,1235.308],[-338.41,1093.162],[-638.164,1060.25],[-807.592,810.792],[-1057.715,642.348],[-1091.808,342.727],[-1235.002,77.338],[-1125.948,-203.807],[-1129.407,-505.342],[-902.191,-703.604],[-765.123,-972.207],[-471.796,-1042.166],[-225.603,-1216.305],[66.637,-1141.935],[365.557,-1181.715],[589.761,-980.053],[872.928,-876.361],[977.734,-593.606],[1180.277,-370.197],[1141.675,-71.124],[1217.196,220.821],[1044.029,467.699]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.713725490196,0.556862745098,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":9.3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":181,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".tertiary","cl":"tertiary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[0.619]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[67]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[-0.263]},"t":95,"s":[82]},{"t":180,"s":[67]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[0.927]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[458.803]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[-0.05]},"t":95,"s":[536.803]},{"t":180,"s":[458.803]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[707.143]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.069]},"t":95,"s":[639.643]},{"t":180,"s":[707.143]}],"ix":4}},"a":{"k":[{"s":[164.438,1433.781,0],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[164.438,1433.781,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"s":{"a":0,"k":[-30,30,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[2361.125,4541.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.901960784314,0.764705882353,0.423529411765,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":181,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[350.5,420.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[420.5,-350.5],[-420.5,-350.5],[-420.5,350.5],[420.5,350.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":181,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/quickstep/res/raw-sw600dp-land/all_set_page_bg.json b/quickstep/res/raw-sw600dp-land/all_set_page_bg.json
deleted file mode 100644
index 63b64da..0000000
--- a/quickstep/res/raw-sw600dp-land/all_set_page_bg.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.8.1","fr":60,"ip":0,"op":181,"w":841,"h":701,"nm":"SUW_WelcomeScreen_FoldableOpen_Dynamic","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".primary","cl":"primary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":180,"s":[55]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.939},"o":{"x":0.167,"y":0.167},"t":0,"s":[140.975,228.318,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.045},"t":95,"s":[140.975,47.65,0],"to":[0,0,0],"ti":[0,0,0]},{"t":180,"s":[140.975,228.318,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[18,18,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[100.594,-128.921],[118.85,-93.491],[148.984,-67.406],[148.684,-27.55],[163.244,9.552],[144.457,44.702],[140.106,84.321],[107.136,106.715],[84.872,139.773],[45.271,144.279],[10.194,163.205],[-26.964,148.792],[-66.818,149.249],[-93.023,119.218],[-128.524,101.101],[-137.771,62.332],[-160.786,29.793],[-150.957,-8.833],[-156.215,-48.341],[-129.561,-77.974],[-115.856,-115.401],[-78.484,-129.253],[-48.956,-156.023],[-9.427,-150.921],[29.159,-160.903],[61.789,-138.015]],"o":[[-100.594,128.921],[-118.85,93.491],[-148.984,67.406],[-148.684,27.55],[-163.244,-9.552],[-144.456,-44.702],[-140.106,-84.321],[-107.136,-106.715],[-84.872,-139.773],[-45.271,-144.279],[-10.194,-163.205],[26.964,-148.792],[66.818,-149.249],[93.023,-119.218],[128.524,-101.101],[137.771,-62.332],[160.786,-29.793],[150.957,8.833],[156.215,48.341],[129.561,77.974],[115.856,115.4],[78.484,129.253],[48.956,156.023],[9.427,150.921],[-29.159,160.903],[-61.789,138.015]],"v":[[975.226,761.299],[707.165,899.424],[509.8,1127.42],[208.253,1125.148],[-72.46,1235.308],[-338.41,1093.162],[-638.164,1060.25],[-807.592,810.792],[-1057.715,642.348],[-1091.808,342.727],[-1235.002,77.338],[-1125.948,-203.807],[-1129.407,-505.342],[-902.191,-703.604],[-765.123,-972.207],[-471.796,-1042.166],[-225.603,-1216.305],[66.637,-1141.935],[365.557,-1181.715],[589.761,-980.053],[872.928,-876.361],[977.734,-593.606],[1180.277,-370.197],[1141.675,-71.124],[1217.196,220.821],[1044.029,467.699]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.713725490196,0.556862745098,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"k":[{"s":[11.111],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[11.111],"t":180,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":181,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".tertiary","cl":"tertiary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[0.619]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[67]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[-0.263]},"t":95,"s":[82]},{"t":180,"s":[67]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[0.913]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[639]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[-0.06]},"t":95,"s":[704]},{"t":180,"s":[639]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.12]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[527.25]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.083]},"t":95,"s":[471]},{"t":180,"s":[527.25]}],"ix":4}},"a":{"k":[{"s":[164.438,1433.781,0],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[164.438,1433.781,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"s":{"a":0,"k":[-25,25,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[2361.125,4541.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.901960784314,0.764705882353,0.423529411765,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"k":[{"s":[6],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[6],"t":180,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":181,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[420.5,350.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[420.5,-350.5],[-420.5,-350.5],[-420.5,350.5],[420.5,350.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":181,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/quickstep/res/raw-sw600dp/all_set_page_bg.json b/quickstep/res/raw-sw600dp/all_set_page_bg.json
deleted file mode 100644
index f2998a0..0000000
--- a/quickstep/res/raw-sw600dp/all_set_page_bg.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.8.1","fr":60,"ip":0,"op":181,"w":701,"h":841,"nm":"SUW_WelcomeScreen_FoldableOpen_Portrait_Dynamic","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".primary","cl":"primary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":180,"s":[55]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.949},"o":{"x":0.167,"y":0.167},"t":0,"s":[181.172,148.425,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.038},"t":95,"s":[181.172,-68.377,0],"to":[0,0,0],"ti":[0,0,0]},{"t":180,"s":[181.172,148.425,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[21.6,21.6,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[100.594,-128.921],[118.85,-93.491],[148.984,-67.406],[148.684,-27.55],[163.244,9.552],[144.457,44.702],[140.106,84.321],[107.136,106.715],[84.872,139.773],[45.271,144.279],[10.194,163.205],[-26.964,148.792],[-66.818,149.249],[-93.023,119.218],[-128.524,101.101],[-137.771,62.332],[-160.786,29.793],[-150.957,-8.833],[-156.215,-48.341],[-129.561,-77.974],[-115.856,-115.401],[-78.484,-129.253],[-48.956,-156.023],[-9.427,-150.921],[29.159,-160.903],[61.789,-138.015]],"o":[[-100.594,128.921],[-118.85,93.491],[-148.984,67.406],[-148.684,27.55],[-163.244,-9.552],[-144.456,-44.702],[-140.106,-84.321],[-107.136,-106.715],[-84.872,-139.773],[-45.271,-144.279],[-10.194,-163.205],[26.964,-148.792],[66.818,-149.249],[93.023,-119.218],[128.524,-101.101],[137.771,-62.332],[160.786,-29.793],[150.957,8.833],[156.215,48.341],[129.561,77.974],[115.856,115.4],[78.484,129.253],[48.956,156.023],[9.427,150.921],[-29.159,160.903],[-61.789,138.015]],"v":[[975.226,761.299],[707.165,899.424],[509.8,1127.42],[208.253,1125.148],[-72.46,1235.308],[-338.41,1093.162],[-638.164,1060.25],[-807.592,810.792],[-1057.715,642.348],[-1091.808,342.727],[-1235.002,77.338],[-1125.948,-203.807],[-1129.407,-505.342],[-902.191,-703.604],[-765.123,-972.207],[-471.796,-1042.166],[-225.603,-1216.305],[66.637,-1141.935],[365.557,-1181.715],[589.761,-980.053],[872.928,-876.361],[977.734,-593.606],[1180.277,-370.197],[1141.675,-71.124],[1217.196,220.821],[1044.029,467.699]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.713725490196,0.556862745098,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":9.3,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":181,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".tertiary","cl":"tertiary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[0.619]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[67]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[-0.263]},"t":95,"s":[82]},{"t":180,"s":[67]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[0.927]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[458.803]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[-0.05]},"t":95,"s":[536.803]},{"t":180,"s":[458.803]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.1]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[707.143]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.069]},"t":95,"s":[639.643]},{"t":180,"s":[707.143]}],"ix":4}},"a":{"k":[{"s":[164.438,1433.781,0],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[164.438,1433.781,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"s":{"a":0,"k":[-30,30,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[2361.125,4541.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.901960784314,0.764705882353,0.423529411765,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":5,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":181,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[350.5,420.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[420.5,-350.5],[-420.5,-350.5],[-420.5,350.5],[420.5,350.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":181,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/quickstep/res/raw-sw720dp-land/all_set_page_bg.json b/quickstep/res/raw-sw720dp-land/all_set_page_bg.json
deleted file mode 100644
index a994b0f..0000000
--- a/quickstep/res/raw-sw720dp-land/all_set_page_bg.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.8.1","fr":60,"ip":0,"op":180,"w":1280,"h":800,"nm":"SUW_WelcomeScreen_Tablet_Landscape_Dynamic","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[288,540,0],"ix":2,"l":2},"a":{"a":0,"k":[50,50,0],"ix":1,"l":2},"s":{"a":0,"k":[25,25,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".primary","cl":"primary","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":180,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[375.832,-1006.545,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":95,"s":[375.832,-1811,0],"to":[0,0,0],"ti":[0,0,0]},{"t":180,"s":[375.832,-1006.545,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[110,110,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.956862745098,0.729411764706,0.619607843137,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":720,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".tertiary","cl":"tertiary","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[57]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":95,"s":[75]},{"t":180,"s":[57]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[2618]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":95,"s":[2442]},{"t":180,"s":[2618]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[891]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":95,"s":[694]},{"t":180,"s":[891]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[120,120,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.752941176471,0.788235294118,0.752941176471,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/quickstep/res/raw-sw720dp/all_set_page_bg.json b/quickstep/res/raw-sw720dp/all_set_page_bg.json
deleted file mode 100644
index 1030ffa..0000000
--- a/quickstep/res/raw-sw720dp/all_set_page_bg.json
+++ /dev/null
@@ -1 +0,0 @@
-{"v":"5.8.1","fr":60,"ip":0,"op":180,"w":800,"h":1280,"nm":"SUW_WelcomeScreen_Tablet_Portrait_Dynamic","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[288,528,0],"ix":2,"l":2},"a":{"a":0,"k":[50,50,0],"ix":1,"l":2},"s":{"a":0,"k":[25,25,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".primary","cl":"primary","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":180,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[999.832,-2238.545,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":95,"s":[999.832,-3043,0],"to":[0,0,0],"ti":[0,0,0]},{"t":180,"s":[999.832,-2238.545,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[200,200,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.956862745098,0.729411764706,0.619607843137,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":720,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".tertiary","cl":"tertiary","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-39]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":95,"s":[-21]},{"t":180,"s":[-39]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1490]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":95,"s":[1314]},{"t":180,"s":[1490]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[2967]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":95,"s":[2770]},{"t":180,"s":[2967]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[168,168,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.752941176471,0.788235294118,0.752941176471,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/quickstep/res/raw-w600dp-h900dp/all_set_page_bg.json b/quickstep/res/raw-w600dp-h900dp/all_set_page_bg.json
new file mode 100644
index 0000000..b1a3bbe
--- /dev/null
+++ b/quickstep/res/raw-w600dp-h900dp/all_set_page_bg.json
@@ -0,0 +1 @@
+{"v":"5.8.1","fr":60,"ip":0,"op":180,"w":800,"h":1280,"nm":"SUW_WelcomeScreen_Portrait_Dynamic","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[288,528,0],"ix":2,"l":2},"a":{"a":0,"k":[50,50,0],"ix":1,"l":2},"s":{"a":0,"k":[25,25,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".primary","cl":"primary","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":180,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[999.832,-2238.545,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":95,"s":[999.832,-3043,0],"to":[0,0,0],"ti":[0,0,0]},{"t":180,"s":[999.832,-2238.545,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[200,200,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.956862745098,0.729411764706,0.619607843137,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":720,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".tertiary","cl":"tertiary","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[-39]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":95,"s":[-21]},{"t":180,"s":[-39]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[1490]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":95,"s":[1314]},{"t":180,"s":[1490]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[2967]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":95,"s":[2770]},{"t":180,"s":[2967]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[168,168,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.752941176471,0.788235294118,0.752941176471,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/quickstep/res/raw-w840dp-h480dp/all_set_page_bg.json b/quickstep/res/raw-w840dp-h480dp/all_set_page_bg.json
index ae1b560..81de7a2 100644
--- a/quickstep/res/raw-w840dp-h480dp/all_set_page_bg.json
+++ b/quickstep/res/raw-w840dp-h480dp/all_set_page_bg.json
@@ -1 +1 @@
-{"v":"5.8.1","fr":60,"ip":0,"op":181,"w":841,"h":701,"nm":"SUW_WelcomeScreen_FelixOpen_Dynamic","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":4,"nm":".primary","cl":"primary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":180,"s":[55]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.939},"o":{"x":0.167,"y":0.167},"t":0,"s":[140.975,228.318,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.045},"t":95,"s":[140.975,47.65,0],"to":[0,0,0],"ti":[0,0,0]},{"t":180,"s":[140.975,228.318,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[18,18,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[100.594,-128.921],[118.85,-93.491],[148.984,-67.406],[148.684,-27.55],[163.244,9.552],[144.457,44.702],[140.106,84.321],[107.136,106.715],[84.872,139.773],[45.271,144.279],[10.194,163.205],[-26.964,148.792],[-66.818,149.249],[-93.023,119.218],[-128.524,101.101],[-137.771,62.332],[-160.786,29.793],[-150.957,-8.833],[-156.215,-48.341],[-129.561,-77.974],[-115.856,-115.401],[-78.484,-129.253],[-48.956,-156.023],[-9.427,-150.921],[29.159,-160.903],[61.789,-138.015]],"o":[[-100.594,128.921],[-118.85,93.491],[-148.984,67.406],[-148.684,27.55],[-163.244,-9.552],[-144.456,-44.702],[-140.106,-84.321],[-107.136,-106.715],[-84.872,-139.773],[-45.271,-144.279],[-10.194,-163.205],[26.964,-148.792],[66.818,-149.249],[93.023,-119.218],[128.524,-101.101],[137.771,-62.332],[160.786,-29.793],[150.957,8.833],[156.215,48.341],[129.561,77.974],[115.856,115.4],[78.484,129.253],[48.956,156.023],[9.427,150.921],[-29.159,160.903],[-61.789,138.015]],"v":[[975.226,761.299],[707.165,899.424],[509.8,1127.42],[208.253,1125.148],[-72.46,1235.308],[-338.41,1093.162],[-638.164,1060.25],[-807.592,810.792],[-1057.715,642.348],[-1091.808,342.727],[-1235.002,77.338],[-1125.948,-203.807],[-1129.407,-505.342],[-902.191,-703.604],[-765.123,-972.207],[-471.796,-1042.166],[-225.603,-1216.305],[66.637,-1141.935],[365.557,-1181.715],[589.761,-980.053],[872.928,-876.361],[977.734,-593.606],[1180.277,-370.197],[1141.675,-71.124],[1217.196,220.821],[1044.029,467.699]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,0.713725490196,0.556862745098,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"k":[{"s":[11.111],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[11.111],"t":180,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":181,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".tertiary","cl":"tertiary","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[0.619]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[67]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[-0.263]},"t":95,"s":[82]},{"t":180,"s":[67]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[0.913]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[639]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[-0.06]},"t":95,"s":[704]},{"t":180,"s":[639]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.12]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[527.25]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.083]},"t":95,"s":[471]},{"t":180,"s":[527.25]}],"ix":4}},"a":{"k":[{"s":[164.438,1433.781,0],"t":0,"i":{"x":1,"y":1},"o":{"x":0,"y":0}},{"s":[164.438,1433.781,0],"t":180,"i":{"x":1,"y":1},"o":{"x":0,"y":0}}],"l":2},"s":{"a":0,"k":[-25,25,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[2361.125,4541.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":1,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.901960784314,0.764705882353,0.423529411765,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"k":[{"s":[6],"t":0,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}},{"s":[6],"t":180,"i":{"x":[1],"y":[1]},"o":{"x":[0],"y":[0]}}]},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false}],"ip":0,"op":181,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".black","cl":"black","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[420.5,350.5,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0]],"v":[[420.5,-350.5],[-420.5,-350.5],[-420.5,350.5],[420.5,350.5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0,0,0,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Vector","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":181,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
+{"v":"5.8.1","fr":60,"ip":0,"op":180,"w":1280,"h":800,"nm":"SUW_WelcomeScreen_Landscape_Dynamic","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 5","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[288,540,0],"ix":2,"l":2},"a":{"a":0,"k":[50,50,0],"ix":1,"l":2},"s":{"a":0,"k":[25,25,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":600,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".primary","cl":"primary","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[0]},{"t":180,"s":[56]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.07,"y":0.986},"o":{"x":0.167,"y":0.167},"t":0,"s":[375.832,-1006.545,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.773,"y":0.01},"t":95, "s":[375.832,-1811,0],"to":[0,0,0],"ti":[0,0,0]},{"t":180,"s":[375.832,-1006.545,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-3514.717,-358.642,0],"ix":1,"l":2},"s":{"a":0,"k":[110,110,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[75.615,-96.908],[89.338,-70.276],[111.99,-50.668],[111.764,-20.709],[122.709,7.18],[108.586,33.602],[105.316,63.383],[80.533,80.216],[63.797,105.066],[34.03,108.453],[7.663,122.679],[-20.269,111.845],[-50.226,112.189],[-69.924,89.614],[-96.61,75.997],[-103.56,46.854],[-120.861,22.395],[-113.472,-6.639],[-117.425,-36.337],[-97.389,-58.612],[-87.087,-86.745],[-58.996,-97.158],[-36.8,-117.281],[-7.086,-113.445],[21.918,-120.948],[46.446,-103.744]],"o":[[-75.615,96.909],[-89.338,70.276],[-111.99,50.668],[-111.764,20.709],[-122.709,-7.18],[-108.586,-33.602],[-105.316,-63.383],[-80.533,-80.216],[-63.797,-105.066],[-34.03,-108.453],[-7.663,-122.679],[20.269,-111.845],[50.226,-112.188],[69.924,-89.614],[96.61,-75.997],[103.56,-46.854],[120.861,-22.395],[113.472,6.64],[117.425,36.337],[97.389,58.612],[87.088,86.745],[58.995,97.158],[36.8,117.281],[7.087,113.445],[-21.918,120.948],[-46.446,103.744]],"v":[[733.209,572.105],[531.711,675.932],[383.354,847.313],[156.685,845.606],[-54.323,928.412],[-254.235,821.562],[-479.555,796.823],[-606.913,609.309],[-794.927,482.691],[-820.554,257.47],[-928.191,57.981],[-846.217,-153.353],[-848.817,-380.013],[-678.021,-529.044],[-574.99,-730.949],[-354.499,-783.537],[-169.439,-914.435],[50.234,-858.532],[274.928,-888.434],[443.46,-736.847],[656.313,-658.903],[735.094,-446.359],[887.344,-278.426],[858.327,-53.616],[915.095,165.835],[784.928,351.409]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.956862745098,0.729411764706,0.619607843137,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[-3509.952,-363.731],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Polystar 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":720,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".tertiary","cl":"tertiary","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.248]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[57]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.172]},"t":95,"s":[75]},{"t":180,"s":[57]}],"ix":10},"p":{"s":true,"x":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.032]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[2618]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.022]},"t":95,"s":[2442]},{"t":180,"s":[2618]}],"ix":3},"y":{"a":1,"k":[{"i":{"x":[0.07],"y":[1.034]},"o":{"x":[0.167],"y":[0.167]},"t":0,"s":[891]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.719],"y":[0.024]},"t":95,"s":[694]},{"t":180,"s":[891]}],"ix":4}},"a":{"a":0,"k":[164.438,1433.781,0],"ix":1,"l":2},"s":{"a":0,"k":[120,120,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[3079.125,4685.989],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.752941176471,0.788235294118,0.752941176471,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[164.438,1481.781],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":600,"st":0,"bm":0}],"markers":[]}
\ No newline at end of file
diff --git a/quickstep/res/raw-land/all_set_page_bg.json b/quickstep/res/raw-w840dp/all_set_page_bg.json
similarity index 100%
rename from quickstep/res/raw-land/all_set_page_bg.json
rename to quickstep/res/raw-w840dp/all_set_page_bg.json
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index edfb59e..9510494 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -23,34 +23,34 @@
<string name="recent_task_option_freeform" msgid="48863056265284071">"Forme libre"</string>
<string name="recent_task_option_desktop" msgid="8280879717125435668">"Ordinateur de bureau"</string>
<string name="recents_empty_message" msgid="7040467240571714191">"Aucun élément récent"</string>
- <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres d\'utilisation de l\'application"</string>
+ <string name="accessibility_app_usage_settings" msgid="6312864233673544149">"Paramètres d\'utilisation de l\'appli"</string>
<string name="recents_clear_all" msgid="5328176793634888831">"Tout effacer"</string>
- <string name="accessibility_recent_apps" msgid="4058661986695117371">"Applications récentes"</string>
+ <string name="accessibility_recent_apps" msgid="4058661986695117371">"Applis récentes"</string>
<string name="task_view_closed" msgid="9170038230110856166">"Tâche fermée"</string>
<string name="task_contents_description_with_remaining_time" msgid="4479688746574672685">"<xliff:g id="TASK_DESCRIPTION">%1$s</xliff:g> : <xliff:g id="REMAINING_TIME">%2$s</xliff:g>"</string>
<string name="shorter_duration_less_than_one_minute" msgid="4722015666335015336">"< 1 min"</string>
<string name="time_left_for_app" msgid="3111996412933644358">"Il reste <xliff:g id="TIME">%1$s</xliff:g> aujourd\'hui"</string>
- <string name="title_app_suggestions" msgid="4185902664111965088">"Suggestions d\'applications"</string>
- <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Vos prédictions d\'applications"</string>
- <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Obtenir des suggestions d\'applications dans la rangée du bas de votre écran d\'accueil"</string>
- <string name="hotseat_edu_title_migrate_landscape" msgid="3633942953997845243">"Retrouvez des suggestions d\'applications dans la rangée des favoris de votre écran d\'accueil"</string>
- <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Accédez facilement aux applications que vous utilisez le plus, directement à l\'écran d\'accueil. Les suggestions changeront en fonction de vos habitudes. Les applications dans la rangée du bas seront déplacées vers votre écran d\'accueil."</string>
- <string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Accédez facilement aux applications que vous utilisez le plus, directement à l\'écran d\'accueil. Les suggestions changeront en fonction de vos habitudes. Les applications dans la rangée des favoris seront déplacées vers votre écran d\'accueil."</string>
- <string name="hotseat_edu_accept" msgid="1611544083278999837">"Obtenir des suggestions d\'applications"</string>
+ <string name="title_app_suggestions" msgid="4185902664111965088">"Suggestions d\'applis"</string>
+ <string name="all_apps_prediction_tip" msgid="2672336544844936186">"Vos prédictions d\'applis"</string>
+ <string name="hotseat_edu_title_migrate" msgid="306578144424489980">"Obtenir des suggestions d\'applis dans la rangée du bas de votre écran d\'accueil"</string>
+ <string name="hotseat_edu_title_migrate_landscape" msgid="3633942953997845243">"Retrouvez des suggestions d\'applis dans la rangée des favoris de votre écran d\'accueil"</string>
+ <string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Accédez facilement aux applis que vous utilisez le plus, directement à l\'écran d\'accueil. Les suggestions changeront en fonction de vos habitudes. Les applis dans la rangée du bas seront déplacées vers votre écran d\'accueil."</string>
+ <string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Accédez facilement aux applis que vous utilisez le plus, directement à l\'écran d\'accueil. Les suggestions changeront en fonction de vos habitudes. Les applis dans la rangée des favoris seront déplacées vers votre écran d\'accueil."</string>
+ <string name="hotseat_edu_accept" msgid="1611544083278999837">"Obtenir des suggestions d\'applis"</string>
<string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Non merci"</string>
<string name="hotseat_prediction_settings" msgid="6246554993566070818">"Paramètres"</string>
- <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Les applications les plus utilisées s\'affichent ici et changent en fonction des habitudes"</string>
- <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Faites glisser des applications hors de la rangée du bas pour obtenir des suggestions d\'applications"</string>
- <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Applications suggérées ajoutées à l\'espace vide"</string>
- <string name="hotsaet_tip_prediction_enabled" msgid="2233554377501347650">"Les suggestions d\'applications sont activées"</string>
- <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"Les suggestions d\'applications sont désactivées"</string>
- <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Application prédite : <xliff:g id="TITLE">%1$s</xliff:g>"</string>
+ <string name="hotseat_auto_enrolled" msgid="522100018967146807">"Les applis les plus utilisées s\'affichent ici et changent en fonction des habitudes"</string>
+ <string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Faites glisser des applis hors de la rangée du bas pour obtenir des suggestions d\'applis"</string>
+ <string name="hotseat_tip_gaps_filled" msgid="3035673010274223538">"Applis suggérées ajoutées à l\'espace vide"</string>
+ <string name="hotsaet_tip_prediction_enabled" msgid="2233554377501347650">"Les suggestions d\'applis sont activées"</string>
+ <string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"Les suggestions d\'applis sont désactivées"</string>
+ <string name="hotseat_prediction_content_description" msgid="4582028296938078419">"Appli prédite : <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"Faites pivoter votre appareil"</string>
<string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"Veuillez faire pivoter votre appareil pour terminer le tutoriel de navigation par gestes"</string>
<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_with_follow_up" msgid="8653374779579748392">"Vous avez appris le geste de retour en arrière. Maintenant, apprenez comment changer d\'appli."</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>
@@ -74,11 +74,11 @@
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Essayez de tenir la fenêtre plus longtemps avant de relâcher"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Assurez-vous de balayer l\'écran vers le haut, puis de faire une pause"</string>
<string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Vous avez appris à utiliser les gestes. Pour les désactiver, accédez au menu Paramètres."</string>
- <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Vous avez appris le geste de changement d\'application"</string>
- <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Balayez pour basculer entre les applications"</string>
- <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Pour changer d\'application, balayez l\'écran de bas en haut, maintenez le doigt dessus, puis relâchez-le."</string>
+ <string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Vous avez appris le geste de changement d\'appli"</string>
+ <string name="overview_gesture_intro_title" msgid="2902054412868489378">"Balayez pour basculer entre les applis"</string>
+ <string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Pour changer d\'appli, balayez l\'écran de bas en haut, maintenez le doigt dessus, puis relâchez-le."</string>
<string name="overview_gesture_spoken_intro_subtitle" msgid="3853371838260201751">"Pour changer d\'appli, balayez l\'écran de bas en haut avec deux doigts, maintenez-les et relâchez-les."</string>
- <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Changer d\'application"</string>
+ <string name="overview_gesture_tutorial_title" msgid="4125835002668708720">"Changer d\'appli"</string>
<string name="overview_gesture_tutorial_subtitle" msgid="5253549754058973071">"Balayez l\'écran de bas en haut, maintenez le doigt en place, puis relâchez-le"</string>
<string name="overview_gesture_tutorial_success" msgid="1910267697807973076">"Bien joué!"</string>
<string name="gesture_tutorial_confirm_title" msgid="6201516182040074092">"Terminé"</string>
@@ -98,14 +98,14 @@
<string name="action_split" msgid="2098009717623550676">"Partager"</string>
<string name="action_save_app_pair" msgid="5974823919237645229">"Enr. paire d\'applis"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Toucher une autre appli pour partager l\'écran"</string>
- <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choisir une autre application pour utiliser l\'Écran divisé"</string>
+ <string name="toast_contextual_split_select_app" msgid="433510957123687090">"Choisir une autre appli pour utiliser l\'Écran divisé"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Annuler"</b></string>
<string name="toast_split_select_cont_desc" msgid="2119685056059607602">"Quitter la sélection d\'écran divisé"</string>
- <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choisir une autre application pour utiliser l\'écran partagé"</string>
- <string name="blocked_by_policy" msgid="2071401072261365546">"L\'application ou votre organisation n\'autorise pas cette action"</string>
- <string name="split_widgets_not_supported" msgid="1355743038053053866">"Les widgets ne sont actuellement pas pris en charge. Veuillez sélectionner une autre application"</string>
+ <string name="toast_split_app_unsupported" msgid="2360229567007828914">"Choisir une autre appli pour utiliser l\'écran partagé"</string>
+ <string name="blocked_by_policy" msgid="2071401072261365546">"L\'appli ou votre organisation n\'autorise pas cette action"</string>
+ <string name="split_widgets_not_supported" msgid="1355743038053053866">"Les widgets ne sont actuellement pas pris en charge. Veuillez sélectionner une autre appli"</string>
<string name="skip_tutorial_dialog_title" msgid="2725643161260038458">"Ignorer le tutoriel sur la navigation?"</string>
- <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Vous trouverez le tutoriel dans l\'application <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="skip_tutorial_dialog_subtitle" msgid="544063326241955662">"Vous trouverez le tutoriel dans l\'appli <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_action_button_label_cancel" msgid="3809842569351264108">"Annuler"</string>
<string name="gesture_tutorial_action_button_label_skip" msgid="394452764989751960">"Ignorer"</string>
<string name="accessibility_rotate_button" msgid="4771825231336502943">"Faire pivoter l\'écran"</string>
@@ -137,7 +137,7 @@
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Séparateur de la barre des tâches"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Déplacer vers le coin supérieur gauche de l\'écran"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Déplacer vers le coin inférieur droit de l\'écran"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre application.}one{Afficher # autre application.}other{Afficher # autres applications.}}"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli.}one{Afficher # autre appli.}other{Afficher # autres applis.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # appli de bureau.}one{Afficher # appli de bureau.}other{Afficher # applis de bureau.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
<string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index dd3d16e..6aa755a 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -94,7 +94,7 @@
<string name="default_device_name" msgid="6660656727127422487">"enheten"</string>
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Innstillinger for systemnavigasjon"</annotation></string>
<string name="action_share" msgid="2648470652637092375">"Del"</string>
- <string name="action_screenshot" msgid="8171125848358142917">"Skjermdump"</string>
+ <string name="action_screenshot" msgid="8171125848358142917">"Skjermbilde"</string>
<string name="action_split" msgid="2098009717623550676">"Del opp"</string>
<string name="action_save_app_pair" msgid="5974823919237645229">"Lagre apptilkobling"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Trykk på en annen app for å bruke delt skjerm"</string>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index ed3ebee..47d8055 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -122,7 +122,7 @@
<string name="taskbar_edu_close" msgid="887022990168191073">"மூடுக"</string>
<string name="taskbar_edu_done" msgid="6880178093977704569">"முடிந்தது"</string>
<string name="taskbar_button_home" msgid="2151398979630664652">"முகப்பு"</string>
- <string name="taskbar_button_a11y" msgid="5241161324875094465">"அணுகல்தன்மை"</string>
+ <string name="taskbar_button_a11y" msgid="5241161324875094465">"மாற்றுத்திறன் வசதி"</string>
<string name="taskbar_button_back" msgid="8558862226461164514">"பின்செல்லும்"</string>
<string name="taskbar_button_ime_switcher" msgid="1730244360907588541">"IME சுவிட்ச்சர்"</string>
<string name="taskbar_button_recents" msgid="7273376136216613134">"சமீபத்தியவை"</string>
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index 8984086..44d8a5c 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -20,6 +20,7 @@
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
+import static com.android.launcher3.Flags.enablePredictiveBackGesture;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
@@ -33,6 +34,9 @@
import android.view.View;
import android.view.WindowInsetsController;
import android.view.WindowManager;
+import android.window.BackEvent;
+import android.window.OnBackAnimationCallback;
+import android.window.OnBackInvokedDispatcher;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -124,6 +128,8 @@
/** A set of user ids that should be filtered out from the selected widgets. */
@NonNull
Set<Integer> mFilteredUserIds = new HashSet<>();
+ @Nullable
+ private WidgetsFullSheet mWidgetSheet;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -148,6 +154,18 @@
refreshAndBindWidgets();
}
+ @Override
+ protected void registerBackDispatcher() {
+ if (!enablePredictiveBackGesture()) {
+ super.registerBackDispatcher();
+ return;
+ }
+
+ getOnBackInvokedDispatcher().registerOnBackInvokedCallback(
+ OnBackInvokedDispatcher.PRIORITY_DEFAULT,
+ new BackAnimationCallback());
+ }
+
private void parseIntentExtras() {
mTitle = getIntent().getStringExtra(EXTRA_PICKER_TITLE);
mDescription = getIntent().getStringExtra(EXTRA_PICKER_DESCRIPTION);
@@ -293,12 +311,12 @@
MAIN_EXECUTOR.execute(() -> mPopupDataProvider.setAllWidgets(widgets));
}
- private void openWidgetsSheet() {
+ private void openWidgetsSheet() {
MAIN_EXECUTOR.execute(() -> {
- WidgetsFullSheet widgetSheet = WidgetsFullSheet.show(this, true);
- widgetSheet.mayUpdateTitleAndDescription(mTitle, mDescription);
- widgetSheet.disableNavBarScrim(true);
- widgetSheet.addOnCloseListener(this::finish);
+ mWidgetSheet = WidgetsFullSheet.show(this, true);
+ mWidgetSheet.mayUpdateTitleAndDescription(mTitle, mDescription);
+ mWidgetSheet.disableNavBarScrim(true);
+ mWidgetSheet.addOnCloseListener(this::finish);
});
}
@@ -317,6 +335,51 @@
}
}
+ /**
+ * Animation callback for different predictive back animation states for the widget picker.
+ */
+ private class BackAnimationCallback implements OnBackAnimationCallback {
+ @Nullable
+ OnBackAnimationCallback mActiveOnBackAnimationCallback;
+
+ @Override
+ public void onBackStarted(@NonNull BackEvent backEvent) {
+ if (mActiveOnBackAnimationCallback != null) {
+ mActiveOnBackAnimationCallback.onBackCancelled();
+ }
+ if (mWidgetSheet != null) {
+ mActiveOnBackAnimationCallback = mWidgetSheet;
+ mActiveOnBackAnimationCallback.onBackStarted(backEvent);
+ }
+ }
+
+ @Override
+ public void onBackInvoked() {
+ if (mActiveOnBackAnimationCallback == null) {
+ return;
+ }
+ mActiveOnBackAnimationCallback.onBackInvoked();
+ mActiveOnBackAnimationCallback = null;
+ }
+
+ @Override
+ public void onBackProgressed(@NonNull BackEvent backEvent) {
+ if (mActiveOnBackAnimationCallback == null) {
+ return;
+ }
+ mActiveOnBackAnimationCallback.onBackProgressed(backEvent);
+ }
+
+ @Override
+ public void onBackCancelled() {
+ if (mActiveOnBackAnimationCallback == null) {
+ return;
+ }
+ mActiveOnBackAnimationCallback.onBackCancelled();
+ mActiveOnBackAnimationCallback = null;
+ }
+ };
+
private WidgetAcceptabilityVerdict isWidgetAcceptable(WidgetItem widget) {
final AppWidgetProviderInfo info = widget.widgetInfo;
if (info == null) {
diff --git a/quickstep/src/com/android/launcher3/model/WellbeingModel.java b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
index 28bc01c..fb17f15 100644
--- a/quickstep/src/com/android/launcher3/model/WellbeingModel.java
+++ b/quickstep/src/com/android/launcher3/model/WellbeingModel.java
@@ -83,10 +83,8 @@
private final Handler mWorkerHandler;
private final ContentObserver mContentObserver;
- private final SimpleBroadcastReceiver mWellbeingAppChangeReceiver =
- new SimpleBroadcastReceiver(t -> restartObserver());
- private final SimpleBroadcastReceiver mAppAddRemoveReceiver =
- new SimpleBroadcastReceiver(this::onAppPackageChanged);
+ private final SimpleBroadcastReceiver mWellbeingAppChangeReceiver;
+ private final SimpleBroadcastReceiver mAppAddRemoveReceiver;
private final Object mModelLock = new Object();
// Maps the action Id to the corresponding RemoteAction
@@ -101,6 +99,11 @@
mWorkerHandler = new Handler(TextUtils.isEmpty(mWellbeingProviderPkg)
? Executors.UI_HELPER_EXECUTOR.getLooper()
: Executors.getPackageExecutor(mWellbeingProviderPkg).getLooper());
+ mWellbeingAppChangeReceiver =
+ new SimpleBroadcastReceiver(mWorkerHandler, t -> restartObserver());
+ mAppAddRemoveReceiver =
+ new SimpleBroadcastReceiver(mWorkerHandler, this::onAppPackageChanged);
+
mContentObserver = new ContentObserver(mWorkerHandler) {
@Override
@@ -135,8 +138,8 @@
public void close() {
if (!TextUtils.isEmpty(mWellbeingProviderPkg)) {
mWorkerHandler.post(() -> {
- mWellbeingAppChangeReceiver.unregisterReceiverSafelySync(mContext);
- mAppAddRemoveReceiver.unregisterReceiverSafelySync(mContext);
+ mWellbeingAppChangeReceiver.unregisterReceiverSafely(mContext);
+ mAppAddRemoveReceiver.unregisterReceiverSafely(mContext);
mContext.getContentResolver().unregisterContentObserver(mContentObserver);
});
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 7b90aa6..78c6d4b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -800,6 +800,11 @@
*/
public void setUIController(@NonNull TaskbarUIController uiController) {
mControllers.setUiController(uiController);
+ if (mControllers.bubbleControllers.isEmpty()) {
+ // if the bubble bar was visible in a previous configuration of taskbar and is being
+ // recreated now without bubbles, clean up any bubble bar adjustments from hotseat
+ bubbleBarVisibilityChanged(/* isVisible= */ false);
+ }
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 58c5e83..0645972 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -282,6 +282,11 @@
}
uiController.dumpLogs(prefix + "\t", pw);
rotationButtonController.dumpLogs(prefix + "\t", pw);
+ if (bubbleControllers.isPresent()) {
+ bubbleControllers.get().dump(pw);
+ } else {
+ pw.println(String.format("%s\t%s", prefix, "Bubble controllers are empty."));
+ }
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index b90e5fd..f411e79 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -39,7 +39,6 @@
import android.content.ComponentCallbacks;
import android.content.Context;
import android.content.Intent;
-import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
@@ -120,7 +119,7 @@
private final ComponentCallbacks mComponentCallbacks;
private final SimpleBroadcastReceiver mShutdownReceiver =
- new SimpleBroadcastReceiver(i -> destroyExistingTaskbar());
+ new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, i -> destroyExistingTaskbar());
// The source for this provider is set when Launcher is available
// We use 'non-destroyable' version here so the original provider won't be destroyed
@@ -157,7 +156,7 @@
private boolean mUserUnlocked = false;
private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver =
- new SimpleBroadcastReceiver(this::showTaskbarFromBroadcast);
+ new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, this::showTaskbarFromBroadcast);
private final AllAppsActionManager mAllAppsActionManager;
@@ -306,17 +305,15 @@
.register(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
Log.d(TASKBAR_NOT_DESTROYED_TAG, "registering component callbacks from constructor.");
mContext.registerComponentCallbacks(mComponentCallbacks);
- mShutdownReceiver.registerAsync(mContext, Intent.ACTION_SHUTDOWN);
+ mShutdownReceiver.register(mContext, Intent.ACTION_SHUTDOWN);
UI_HELPER_EXECUTOR.execute(() -> {
mSharedState.taskbarSystemActionPendingIntent = PendingIntent.getBroadcast(
mContext,
SYSTEM_ACTION_ID_TASKBAR,
new Intent(ACTION_SHOW_TASKBAR).setPackage(mContext.getPackageName()),
PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
- mContext.registerReceiver(
- mTaskbarBroadcastReceiver,
- new IntentFilter(ACTION_SHOW_TASKBAR),
- RECEIVER_NOT_EXPORTED);
+ mTaskbarBroadcastReceiver.register(
+ mContext, RECEIVER_NOT_EXPORTED, ACTION_SHOW_TASKBAR);
});
debugWhyTaskbarNotDestroyed("TaskbarManager created");
@@ -623,7 +620,7 @@
public void destroy() {
debugWhyTaskbarNotDestroyed("TaskbarManager#destroy()");
removeActivityCallbacksAndListeners();
- mTaskbarBroadcastReceiver.unregisterReceiverSafelyAsync(mContext);
+ mTaskbarBroadcastReceiver.unregisterReceiverSafely(mContext);
destroyExistingTaskbar();
removeTaskbarRootViewFromWindow();
if (mUserUnlocked) {
@@ -635,7 +632,7 @@
.unregister(NAV_BAR_KIDS_MODE, mOnSettingsChangeListener);
Log.d(TASKBAR_NOT_DESTROYED_TAG, "unregistering component callbacks from destroy().");
mContext.unregisterComponentCallbacks(mComponentCallbacks);
- mShutdownReceiver.unregisterReceiverSafelyAsync(mContext);
+ mShutdownReceiver.unregisterReceiverSafely(mContext);
}
public @Nullable TaskbarActivityContext getCurrentActivityContext() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
index ea091ca..872a4d0 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java
@@ -24,6 +24,7 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_BACK_BUTTON_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_HOME_BUTTON_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_HOME_BUTTON_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_OVERVIEW_BUTTON_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_OVERVIEW_BUTTON_TAP;
@@ -37,6 +38,7 @@
import android.util.Log;
import android.view.HapticFeedbackConstants;
import android.view.View;
+import android.view.inputmethod.Flags;
import androidx.annotation.IntDef;
import androidx.annotation.Nullable;
@@ -147,7 +149,7 @@
break;
case BUTTON_IME_SWITCH:
logEvent(LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_TAP);
- showIMESwitcher();
+ onImeSwitcherPress();
break;
case BUTTON_A11Y:
logEvent(LAUNCHER_TASKBAR_A11Y_BUTTON_TAP);
@@ -190,6 +192,12 @@
backRecentsLongpress(buttonType);
return true;
case BUTTON_IME_SWITCH:
+ if (Flags.imeSwitcherRevamp()) {
+ logEvent(LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_LONGPRESS);
+ onImeSwitcherLongPress();
+ return true;
+ }
+ return false;
default:
return false;
}
@@ -305,10 +313,14 @@
mSystemUiProxy.onBackPressed();
}
- private void showIMESwitcher() {
+ private void onImeSwitcherPress() {
mSystemUiProxy.onImeSwitcherPressed();
}
+ private void onImeSwitcherLongPress() {
+ mSystemUiProxy.onImeSwitcherLongPress();
+ }
+
private void notifyA11yClick(boolean longClick) {
if (longClick) {
mSystemUiProxy.notifyAccessibilityButtonLongClicked();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 170e018..a2278ec 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -270,7 +270,7 @@
foundTask,
taskContainer.getIconView().getDrawable(),
taskContainer.getSnapshotView(),
- taskContainer.getThumbnail(),
+ taskContainer.getSplitAnimationThumbnail(),
null /* intent */,
null /* user */,
info);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
index 4100e51..7426dc7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java
@@ -356,6 +356,13 @@
}
}
+ // if a bubble was updated upstream, but removed before the update was received, add it back
+ if (update.updatedBubble != null && !mBubbles.containsKey(update.updatedBubble.getKey())) {
+ mBubbles.put(update.updatedBubble.getKey(), update.updatedBubble);
+ mBubbleBarViewController.addBubble(
+ update.updatedBubble, isExpanding, suppressAnimation);
+ }
+
if (update.addedBubble != null && isCollapsed) {
// If we're collapsed, the most recently added bubble will be selected.
bubbleToSelect = update.addedBubble;
@@ -394,7 +401,8 @@
BubbleBarBubble bb = mBubbles.get(update.updatedBubble.getKey());
// If we're not stashed, we're visible so animate
bb.getView().updateDotVisibility(!mBubbleStashController.isStashed() /* animate */);
- mBubbleBarViewController.animateBubbleNotification(bb, /* isExpanding= */ false);
+ mBubbleBarViewController.animateBubbleNotification(
+ bb, /* isExpanding= */ false, /* isUpdate= */ true);
}
if (update.bubbleKeysInOrder != null && !update.bubbleKeysInOrder.isEmpty()) {
// Create the new list
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 9be898d..fd989b1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -46,9 +46,10 @@
import com.android.launcher3.anim.SpringAnimationBuilder;
import com.android.launcher3.taskbar.bubbles.animation.BubbleAnimator;
import com.android.launcher3.util.DisplayController;
-import com.android.wm.shell.Flags;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import java.io.PrintWriter;
+import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
@@ -258,10 +259,6 @@
if (!isIconSizeOrPaddingUpdated(newIconSize, newBubbleBarPadding)) {
return;
}
- if (!Flags.animateBubbleSizeChange()) {
- setIconSizeAndPadding(newIconSize, newBubbleBarPadding);
- return;
- }
if (mScalePaddingAnimator != null && mScalePaddingAnimator.isRunning()) {
mScalePaddingAnimator.cancel();
}
@@ -899,6 +896,13 @@
float fullElevationForChild = (MAX_BUBBLES * mBubbleElevation) - i;
bv.setZ(fullElevationForChild * elevationState);
+ // only update the dot scale if we're expanding or collapsing
+ // TODO b/351904597: update the dot for the first bubble after removal and reorder
+ // since those might happen when the bar is collapsed and will need their dot back
+ if (mWidthAnimator.isRunning()) {
+ bv.setDotScale(widthState);
+ }
+
if (mIsBarExpanded) {
// If bar is on the right, account for bubble bar expanding and shifting left
final float expandedBarShift = onLeft ? 0 : currentWidth - expandedWidth;
@@ -907,7 +911,6 @@
bv.setTranslationX(widthState * (targetX - collapsedX) + collapsedX);
// When we're expanded, the badge is visible for all bubbles
bv.updateBadgeVisibility(/* show= */ true);
- bv.setDotScale(widthState);
bv.setAlpha(1);
} else {
// If bar is on the right, account for bubble bar expanding and shifting left
@@ -916,7 +919,6 @@
bv.setTranslationX(widthState * (expandedX - targetX) + targetX);
// The badge is always visible for the first bubble
bv.updateBadgeVisibility(/* show= */ i == 0);
- bv.setDotScale(widthState);
// If we're fully collapsed, hide all bubbles except for the first 2. If there are
// only 2 bubbles, hide the second bubble as well because it's the overflow.
if (widthState == 0) {
@@ -1310,6 +1312,37 @@
});
}
+ /** Dumps the current state of BubbleBarView. */
+ public void dump(PrintWriter pw) {
+ pw.println("BubbleBarView state:");
+ pw.println(" visibility: " + getVisibility());
+ pw.println(" translation Y: " + getTranslationY());
+ pw.println(" bubbles in bar (childCount = " + getChildCount() + ")");
+ for (BubbleView bubbleView: getBubbles()) {
+ BubbleBarItem bubble = bubbleView.getBubble();
+ String key = bubble == null ? "null" : bubble.getKey();
+ pw.println(" bubble key: " + key);
+ }
+ pw.println(" isExpanded: " + isExpanded());
+ pw.println(" mIsAnimatingNewBubble: " + mIsAnimatingNewBubble);
+ if (mBubbleAnimator != null) {
+ pw.println(" mBubbleAnimator.isRunning(): " + mBubbleAnimator.isRunning());
+ pw.println(" mBubbleAnimator is null");
+ }
+ pw.println(" mDragging: " + mDragging);
+ }
+
+ private List<BubbleView> getBubbles() {
+ List<BubbleView> bubbles = new ArrayList<>();
+ for (int i = 0; i < getChildCount(); i++) {
+ View child = getChildAt(i);
+ if (child instanceof BubbleView bubble) {
+ bubbles.add(bubble);
+ }
+ }
+ return bubbles;
+ }
+
/** Interface for BubbleBarView to communicate with its controller. */
interface Controller {
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
index 40e5b64..24b9139 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -43,6 +43,7 @@
import com.android.quickstep.SystemUiProxy;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;
import java.util.function.Consumer;
@@ -88,6 +89,8 @@
private BubbleBarViewAnimator mBubbleBarViewAnimator;
+ private TimeSource mTimeSource = System::currentTimeMillis;
+
@Nullable
private BubbleBarBoundsChangeListener mBoundsChangeListener;
@@ -399,7 +402,7 @@
addedBubble.getView().setOnClickListener(mBubbleClickListener);
mBubbleDragController.setupBubbleView(addedBubble.getView());
if (!suppressAnimation) {
- animateBubbleNotification(addedBubble, isExpanding);
+ animateBubbleNotification(addedBubble, isExpanding, /* isUpdate= */ false);
}
}
@@ -427,18 +430,19 @@
}
return;
}
- animateBubbleNotification(bubble, isExpanding);
+ animateBubbleNotification(bubble, isExpanding, /* isUpdate= */ false);
} else {
Log.w(TAG, "addBubble, bubble was null!");
}
}
/** Animates the bubble bar to notify the user about a bubble change. */
- public void animateBubbleNotification(BubbleBarBubble bubble, boolean isExpanding) {
+ public void animateBubbleNotification(BubbleBarBubble bubble, boolean isExpanding,
+ boolean isUpdate) {
boolean isInApp = mTaskbarStashController.isInApp();
// if this is the first bubble, animate to the initial state. one bubble is the overflow
// so check for at most 2 children.
- if (mBarView.getChildCount() <= 2) {
+ if (mBarView.getChildCount() <= 2 && !isUpdate) {
mBubbleBarViewAnimator.animateToInitialState(bubble, isInApp, isExpanding);
return;
}
@@ -574,7 +578,7 @@
* @param bubble dismissed bubble item
*/
public void onDismissBubbleWhileDragging(@NonNull BubbleBarItem bubble) {
- mSystemUiProxy.dragBubbleToDismiss(bubble.getKey());
+ mSystemUiProxy.dragBubbleToDismiss(bubble.getKey(), mTimeSource.currentTimeMillis());
}
/**
@@ -598,4 +602,24 @@
/** Called when bounds have changed */
void onBoundsChanged();
}
+
+ /** Interface for getting the current timestamp. */
+ interface TimeSource {
+ long currentTimeMillis();
+ }
+
+ /** Dumps the state of BubbleBarViewController. */
+ public void dump(PrintWriter pw) {
+ pw.println("Bubble bar view controller state:");
+ pw.println(" mHiddenForSysui: " + mHiddenForSysui);
+ pw.println(" mHiddenForNoBubbles: " + mHiddenForNoBubbles);
+ pw.println(" mShouldShowEducation: " + mShouldShowEducation);
+ pw.println(" mBubbleBarTranslationY.value: " + mBubbleBarTranslationY.value);
+ pw.println(" mBubbleBarSwipeUpTranslationY: " + mBubbleBarSwipeUpTranslationY);
+ if (mBarView != null) {
+ mBarView.dump(pw);
+ } else {
+ pw.println(" Bubble bar view is null!");
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
index 32d6375..03140fe 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
@@ -18,6 +18,8 @@
import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.util.RunnableList;
+import java.io.PrintWriter;
+
/**
* Hosts various bubble controllers to facilitate passing between one another.
*/
@@ -94,4 +96,9 @@
bubbleStashedHandleViewController.onDestroy();
bubbleBarController.onDestroy();
}
+
+ /** Dumps bubble controllers state. */
+ public void dump(PrintWriter pw) {
+ bubbleBarViewController.dump(pw);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
index 185f85f..74f58ac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
@@ -36,6 +36,8 @@
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
+import java.io.PrintWriter;
+
/**
* Coordinates between controllers such as BubbleBarView and BubbleHandleViewController to
* create a cohesive animation between stashed/unstashed states.
@@ -456,4 +458,13 @@
public void setHandleTranslationY(float ty) {
mHandleViewController.setTranslationYForSwipe(ty);
}
+
+ /** Dumps the state of BubbleStashController. */
+ public void dump(PrintWriter pw) {
+ pw.println("Bubble stash controller state:");
+ pw.println(" mIsStashed: " + mIsStashed);
+ pw.println(" mBubblesShowingOnOverview: " + mBubblesShowingOnOverview);
+ pw.println(" mBubblesShowingOnHome: " + mBubblesShowingOnHome);
+ pw.println(" mIsSysuiLocked: " + mIsSysuiLocked);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index 0e26c54..4c468bb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -20,6 +20,7 @@
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Outline;
+import android.graphics.Path;
import android.graphics.Rect;
import android.text.TextUtils;
import android.util.AttributeSet;
@@ -47,7 +48,7 @@
private final ImageView mBubbleIcon;
private final ImageView mAppIcon;
- private final int mBubbleSize;
+ private int mBubbleSize;
private float mDragTranslationX;
private float mOffsetX;
@@ -89,8 +90,6 @@
setLayoutDirection(LAYOUT_DIRECTION_LTR);
LayoutInflater.from(context).inflate(R.layout.bubble_view, this);
-
- mBubbleSize = getResources().getDimensionPixelSize(R.dimen.bubblebar_icon_size);
mBubbleIcon = findViewById(R.id.icon_view);
mAppIcon = findViewById(R.id.app_icon_view);
@@ -107,11 +106,21 @@
}
private void getOutline(Outline outline) {
+ updateBubbleSizeAndDotRender();
final int normalizedSize = IconNormalizer.getNormalizedCircleSize(mBubbleSize);
final int inset = (mBubbleSize - normalizedSize) / 2;
outline.setOval(inset, inset, inset + normalizedSize, inset + normalizedSize);
}
+ private void updateBubbleSizeAndDotRender() {
+ int updatedBubbleSize = Math.min(getWidth(), getHeight());
+ if (updatedBubbleSize == mBubbleSize) return;
+ mBubbleSize = updatedBubbleSize;
+ if (mBubble == null || mBubble instanceof BubbleBarOverflow) return;
+ Path dotPath = ((BubbleBarBubble) mBubble).getDotPath();
+ mDotRenderer = new DotRenderer(mBubbleSize, dotPath, DEFAULT_PATH_SIZE);
+ }
+
/**
* Set translation-x while this bubble is being dragged.
* Translation applied to the view is a sum of {@code translationX} and offset defined by
@@ -141,6 +150,12 @@
applyDragTranslation();
}
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ super.onLayout(changed, left, top, right, bottom);
+ updateBubbleSizeAndDotRender();
+ }
+
private void applyDragTranslation() {
setTranslationX(mDragTranslationX + mOffsetX);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 0368f3a..3a39cf2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -110,6 +110,7 @@
// taskbar icons disappearing before hotseat icons show up.
float scrimUpperBoundFromSplit =
QuickstepTransitionManager.getTaskbarToHomeDuration() / (float) config.duration;
+ scrimUpperBoundFromSplit = Math.min(scrimUpperBoundFromSplit, 1f);
config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR, 0, 0.25f));
config.setInterpolator(ANIM_SCRIM_FADE,
fromState == OVERVIEW_SPLIT_SELECT
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index b1d511c..3a8c141 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -42,6 +42,7 @@
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.taskbar.TaskbarUIController;
import com.android.launcher3.util.DisplayController;
+import com.android.launcher3.util.WindowBounds;
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.quickstep.util.ActivityInitListener;
@@ -51,6 +52,7 @@
import com.android.systemui.shared.recents.model.ThumbnailData;
import java.util.HashMap;
+import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -269,8 +271,11 @@
} else {
Rect portraitInsets = dp.getInsets();
DisplayController displayController = DisplayController.INSTANCE.get(context);
- Rect deviceRotationInsets = displayController.getInfo().getCurrentBounds().get(
- orientationHandler.getRotation()).insets;
+ @Nullable List<WindowBounds> windowBounds =
+ displayController.getInfo().getCurrentBounds();
+ Rect deviceRotationInsets = windowBounds != null
+ ? windowBounds.get(orientationHandler.getRotation()).insets
+ : new Rect();
// Obtain the landscape/seascape insets, and rotate it to portrait perspective.
orientationHandler.rotateInsets(deviceRotationInsets, outRect);
// Then combine with portrait's insets to leave space for status bar/nav bar in
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 1048ea1..b564fa7 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -212,6 +212,9 @@
if (launcher.isStarted() && (isInLiveTileMode() || launcher.hasBeenResumed())) {
return launcher;
}
+ if (isInMinusOne()) {
+ return launcher;
+ }
return null;
}
@@ -289,6 +292,15 @@
&& TopTaskTracker.INSTANCE.get(launcher).getCachedTopTask(false).isHomeTask();
}
+ private boolean isInMinusOne() {
+ QuickstepLauncher launcher = getCreatedContainer();
+
+ return launcher != null
+ && launcher.getStateManager().getState() == NORMAL
+ && !launcher.isStarted()
+ && TopTaskTracker.INSTANCE.get(launcher).getCachedTopTask(false).isHomeTask();
+ }
+
@Override
public void onLaunchTaskFailed() {
QuickstepLauncher launcher = getCreatedContainer();
diff --git a/quickstep/src/com/android/quickstep/OrientationRectF.java b/quickstep/src/com/android/quickstep/OrientationRectF.java
index aa01b05..2b7ecb2 100644
--- a/quickstep/src/com/android/quickstep/OrientationRectF.java
+++ b/quickstep/src/com/android/quickstep/OrientationRectF.java
@@ -67,13 +67,15 @@
}
public boolean applyTransform(MotionEvent event, int deltaRotation, boolean forceTransform) {
+ if (deltaRotation == 0) {
+ return contains(event.getX(), event.getY());
+ }
mTmpMatrix.reset();
postDisplayRotation(deltaRotation, mHeight, mWidth, mTmpMatrix);
if (forceTransform) {
if (DEBUG) {
Log.d(TAG, "Transforming rotation due to forceTransform, "
+ "deltaRotation: " + deltaRotation
- + "mRotation: " + mRotation
+ " this: " + this);
}
event.applyTransform(mTmpMatrix);
diff --git a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
index 9c64576..d82426f 100644
--- a/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
+++ b/quickstep/src/com/android/quickstep/OverviewComponentObserver.java
@@ -21,6 +21,7 @@
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
+import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.systemui.shared.system.PackageManagerWrapper.ACTION_PREFERRED_ACTIVITY_CHANGED;
import android.content.ActivityNotFoundException;
@@ -55,10 +56,11 @@
public final class OverviewComponentObserver {
private static final String TAG = "OverviewComponentObserver";
+ // We register broadcast receivers on main thread to avoid missing updates.
private final SimpleBroadcastReceiver mUserPreferenceChangeReceiver =
- new SimpleBroadcastReceiver(this::updateOverviewTargets);
+ new SimpleBroadcastReceiver(MAIN_EXECUTOR, this::updateOverviewTargets);
private final SimpleBroadcastReceiver mOtherHomeAppUpdateReceiver =
- new SimpleBroadcastReceiver(this::updateOverviewTargets);
+ new SimpleBroadcastReceiver(MAIN_EXECUTOR, this::updateOverviewTargets);
private final Context mContext;
private final RecentsAnimationDeviceState mDeviceState;
@@ -102,7 +104,7 @@
mConfigChangesMap.append(fallbackComponent.hashCode(), fallbackInfo.configChanges);
} catch (PackageManager.NameNotFoundException ignored) { /* Impossible */ }
- mUserPreferenceChangeReceiver.registerAsync(mContext, ACTION_PREFERRED_ACTIVITY_CHANGED);
+ mUserPreferenceChangeReceiver.register(mContext, ACTION_PREFERRED_ACTIVITY_CHANGED);
updateOverviewTargets();
}
@@ -191,7 +193,7 @@
unregisterOtherHomeAppUpdateReceiver();
mUpdateRegisteredPackage = defaultHome.getPackageName();
- mOtherHomeAppUpdateReceiver.registerPkgActionsAsync(
+ mOtherHomeAppUpdateReceiver.registerPkgActions(
mContext, mUpdateRegisteredPackage, ACTION_PACKAGE_ADDED,
ACTION_PACKAGE_CHANGED, ACTION_PACKAGE_REMOVED);
}
@@ -203,13 +205,13 @@
* Clean up any registered receivers.
*/
public void onDestroy() {
- mUserPreferenceChangeReceiver.unregisterReceiverSafelyAsync(mContext);
+ mUserPreferenceChangeReceiver.unregisterReceiverSafely(mContext);
unregisterOtherHomeAppUpdateReceiver();
}
private void unregisterOtherHomeAppUpdateReceiver() {
if (mUpdateRegisteredPackage != null) {
- mOtherHomeAppUpdateReceiver.unregisterReceiverSafelyAsync(mContext);
+ mOtherHomeAppUpdateReceiver.unregisterReceiverSafely(mContext);
mUpdateRegisteredPackage = null;
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index f902284..cd62265 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -33,7 +33,6 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BUBBLES_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DIALOG_SHOWING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
@@ -417,8 +416,7 @@
| SYSUI_STATE_QUICK_SETTINGS_EXPANDED
| SYSUI_STATE_MAGNIFICATION_OVERLAP
| SYSUI_STATE_DEVICE_DREAMING
- | SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION
- | SYSUI_STATE_DISABLE_GESTURE_PIP_ANIMATING;
+ | SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
return (gestureDisablingStates & mSystemUiStateFlags) == 0 && homeOrOverviewEnabled;
}
diff --git a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
index 29a57fc..5264643 100644
--- a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
@@ -34,12 +34,18 @@
private final Context mContext;
private OrientationRectF mOrientationRectF;
+ private OrientationRectF mTouchingOrientationRectF;
+ private int mViewRotation;
public SimpleOrientationTouchTransformer(Context context) {
+ this(context, DisplayController.INSTANCE.get(context));
+ }
+
+ @androidx.annotation.VisibleForTesting
+ public SimpleOrientationTouchTransformer(Context context, DisplayController displayController) {
mContext = context;
- DisplayController.INSTANCE.get(context).addChangeListener(this);
- onDisplayInfoChanged(context, DisplayController.INSTANCE.get(context).getInfo(),
- CHANGE_ALL);
+ displayController.addChangeListener(this);
+ onDisplayInfoChanged(context, displayController.getInfo(), CHANGE_ALL);
}
@Override
@@ -56,7 +62,29 @@
info.rotation);
}
+ /**
+ * Called when the touch is started. This preserves the touching orientation until the touch is
+ * done (i.e. ACTION_CANCEL or ACTION_UP). So the transform won't produce inconsistent position
+ * if display is changed during the touch.
+ */
+ public void updateTouchingOrientation(int viewRotation) {
+ mViewRotation = viewRotation;
+ mTouchingOrientationRectF = new OrientationRectF(mOrientationRectF.left,
+ mOrientationRectF.top, mOrientationRectF.right, mOrientationRectF.bottom,
+ mOrientationRectF.getRotation());
+ }
+
+ /** Called when the touch is finished. */
+ public void clearTouchingOrientation() {
+ mTouchingOrientationRectF = null;
+ }
+
public void transform(MotionEvent ev, int rotation) {
+ if (mTouchingOrientationRectF != null) {
+ mTouchingOrientationRectF.applyTransformToRotation(ev, mViewRotation,
+ true /* forceTransform */);
+ return;
+ }
mOrientationRectF.applyTransformToRotation(ev, rotation, true /* forceTransform */);
}
}
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 433baa9..66aa897 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -229,6 +229,17 @@
}
@Override
+ public void onImeSwitcherLongPress() {
+ if (mSystemUiProxy != null) {
+ try {
+ mSystemUiProxy.onImeSwitcherLongPress();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Failed call onImeSwitcherLongPress");
+ }
+ }
+ }
+
+ @Override
public void setHomeRotationEnabled(boolean enabled) {
if (mSystemUiProxy != null) {
try {
@@ -831,12 +842,14 @@
/**
* Tells SysUI to dismiss the bubble with the provided key.
+ *
* @param key the key of the bubble to dismiss.
+ * @param timestamp the timestamp when the removal happened.
*/
- public void dragBubbleToDismiss(String key) {
+ public void dragBubbleToDismiss(String key, long timestamp) {
if (mBubbles == null) return;
try {
- mBubbles.dragBubbleToDismiss(key);
+ mBubbles.dragBubbleToDismiss(key, timestamp);
} catch (RemoteException e) {
Log.w(TAG, "Failed call dragBubbleToDismiss");
}
diff --git a/quickstep/src/com/android/quickstep/TaskIconCache.java b/quickstep/src/com/android/quickstep/TaskIconCache.java
index b3a9199..1f6c02c 100644
--- a/quickstep/src/com/android/quickstep/TaskIconCache.java
+++ b/quickstep/src/com/android/quickstep/TaskIconCache.java
@@ -33,6 +33,7 @@
import android.text.TextUtils;
import android.util.SparseArray;
+import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import com.android.launcher3.R;
@@ -48,6 +49,7 @@
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.FlagOp;
import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.task.thumbnail.data.TaskIconDataSource;
import com.android.quickstep.util.TaskKeyLruCache;
import com.android.quickstep.util.TaskVisualsChangeListener;
import com.android.systemui.shared.recents.model.Task;
@@ -59,7 +61,7 @@
/**
* Manages the caching of task icons and related data.
*/
-public class TaskIconCache implements DisplayInfoChangeListener {
+public class TaskIconCache implements TaskIconDataSource, DisplayInfoChangeListener {
private final Executor mBgExecutor;
@@ -102,7 +104,8 @@
* @param callback The callback to receive the task after its data has been populated.
* @return A cancelable handle to the request
*/
- public CancellableTask getIconInBackground(Task task, GetTaskIconCallback callback) {
+ @Override
+ public CancellableTask getIconInBackground(Task task, @NonNull GetTaskIconCallback callback) {
Preconditions.assertUIThread();
if (task.icon != null) {
// Nothing to load, the icon is already loaded
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 0d450c6..13b6447 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -70,6 +70,9 @@
*/
public class OtherActivityInputConsumer extends ContextWrapper implements InputConsumer {
+ private static final String TAG = "OtherActivityInputConsumer";
+ private static final boolean DEBUG = true;
+
public static final String DOWN_EVT = "OtherActivityInputConsumer.DOWN";
private static final String UP_EVT = "OtherActivityInputConsumer.UP";
@@ -230,6 +233,9 @@
// Start the window animation on down to give more time for launcher to draw if the
// user didn't start the gesture over the back button
+ if (DEBUG) {
+ Log.d(TAG, "ACTION_DOWN: mIsDeferredDownTarget=" + mIsDeferredDownTarget);
+ }
if (!mIsDeferredDownTarget) {
startTouchTrackingForWindowAnimation(ev.getEventTime());
}
@@ -284,9 +290,18 @@
float horizontalDist = Math.abs(displacementX);
float upDist = -displacement;
- boolean passedSlop = mGestureState.isTrackpadGesture()
- || (squaredHypot(displacementX, displacementY) >= mSquaredTouchSlop
- && !mGestureState.isInExtendedSlopRegion());
+ boolean isTrackpadGesture = mGestureState.isTrackpadGesture();
+ float squaredHypot = squaredHypot(displacementX, displacementY);
+ boolean isInExtendedSlopRegion = !mGestureState.isInExtendedSlopRegion();
+ boolean passedSlop = isTrackpadGesture
+ || (squaredHypot >= mSquaredTouchSlop
+ && isInExtendedSlopRegion);
+ if (DEBUG) {
+ Log.d(TAG, "ACTION_MOVE: passedSlop=" + passedSlop
+ + " ( " + isTrackpadGesture
+ + " || (" + squaredHypot + " >= " + mSquaredTouchSlop
+ + " && " + isInExtendedSlopRegion + " ))");
+ }
if (!mPassedSlopOnThisGesture && passedSlop) {
mPassedSlopOnThisGesture = true;
@@ -306,6 +321,9 @@
boolean isLikelyToStartNewTask =
haveNotPassedSlopOnContinuedGesture || swipeWithinQuickSwitchRange;
+ if (DEBUG) {
+ Log.d(TAG, "ACTION_MOVE: mPassedPilferInputSlop=" + mPassedPilferInputSlop);
+ }
if (!mPassedPilferInputSlop) {
if (passedSlop) {
// Horizontal gesture is not allowed in this region
@@ -394,6 +412,10 @@
mInteractionHandler.initWhenReady(
"OtherActivityInputConsumer.startTouchTrackingForWindowAnimation");
+ if (DEBUG) {
+ Log.d(TAG, "startTouchTrackingForWindowAnimation: isRecentsAnimationRunning="
+ + mTaskAnimationManager.isRecentsAnimationRunning());
+ }
if (mTaskAnimationManager.isRecentsAnimationRunning()) {
mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState);
mActiveCallbacks.removeListener(mCleanupHandler);
@@ -422,6 +444,11 @@
*/
private void finishTouchTracking(MotionEvent ev) {
TraceHelper.INSTANCE.beginSection(UP_EVT);
+ if (DEBUG) {
+ Log.d(TAG, "finishTouchTracking: mPassedWindowMoveSlop=" + mPassedWindowMoveSlop);
+ Log.d(TAG, "finishTouchTracking: mInteractionHandler=" + mInteractionHandler);
+ Log.d(TAG, "finishTouchTracking: ev=" + ev);
+ }
boolean isCanceled = ev.getActionMasked() == ACTION_CANCEL;
if (mPassedWindowMoveSlop && mInteractionHandler != null) {
@@ -444,7 +471,14 @@
// Since we start touch tracking on DOWN, we may reach this state without actually
// starting the gesture. In that case, we need to clean-up an unfinished or un-started
// animation.
+ if (DEBUG) {
+ Log.d(TAG, "finishTouchTracking: mActiveCallbacks=" + mActiveCallbacks);
+ }
if (mActiveCallbacks != null && mInteractionHandler != null) {
+ if (DEBUG) {
+ Log.d(TAG, "finishTouchTracking: isRecentsAnimationRunning="
+ + mTaskAnimationManager.isRecentsAnimationRunning());
+ }
if (mTaskAnimationManager.isRecentsAnimationRunning()) {
// The animation started, but with no movement, in this case, there will be no
// animateToProgress so we have to manually finish here. In the case of
@@ -535,7 +569,13 @@
public void onRecentsAnimationStart(RecentsAnimationController controller,
RecentsAnimationTargets targets) {
+ if (DEBUG) {
+ Log.d(TAG, "FinishImmediatelyHandler: queuing callback");
+ }
Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> {
+ if (DEBUG) {
+ Log.d(TAG, "FinishImmediatelyHandler: running callback");
+ }
controller.finish(false /* toRecents */, null);
});
}
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
index c1eef0b..9c4248c 100644
--- a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
@@ -17,6 +17,7 @@
package com.android.quickstep.recents.data
import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
import kotlinx.coroutines.flow.Flow
interface RecentTasksRepository {
@@ -25,11 +26,17 @@
/**
* Gets the data associated with a task that has id [taskId]. Flow will settle on null if the
- * task was not found.
+ * task was not found. [Task.thumbnail] will settle on null if task is invisible.
*/
fun getTaskDataById(taskId: Int): Flow<Task?>
/**
+ * Gets the [ThumbnailData] associated with a task that has id [taskId]. Flow will settle on
+ * null if the task was not found or is invisible.
+ */
+ fun getThumbnailById(taskId: Int): Flow<ThumbnailData?>
+
+ /**
* Sets the tasks that are visible, indicating that properties relating to visuals need to be
* populated e.g. icons/thumbnails etc.
*/
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
index 9f3ef4a..f73db5a 100644
--- a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -16,7 +16,8 @@
package com.android.quickstep.recents.data
-import com.android.quickstep.TaskIconCache
+import android.graphics.drawable.Drawable
+import com.android.quickstep.task.thumbnail.data.TaskIconDataSource
import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource
import com.android.quickstep.util.GroupTask
import com.android.systemui.shared.recents.model.Task
@@ -27,6 +28,7 @@
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
@@ -37,7 +39,7 @@
class TasksRepository(
private val recentsModel: RecentTasksDataSource,
private val taskThumbnailDataSource: TaskThumbnailDataSource,
- private val taskIconCache: TaskIconCache,
+ private val taskIconDataSource: TaskIconDataSource,
) : RecentTasksRepository {
private val groupedTaskData = MutableStateFlow(emptyList<GroupTask>())
private val _taskData =
@@ -45,10 +47,19 @@
private val visibleTaskIds = MutableStateFlow(emptySet<Int>())
private val taskData: Flow<List<Task>> =
- combine(_taskData, getThumbnailQueryResults()) { tasks, results ->
+ combine(_taskData, getThumbnailQueryResults(), getIconQueryResults()) {
+ tasks,
+ thumbnailQueryResults,
+ iconQueryResults ->
tasks.forEach { task ->
// Add retrieved thumbnails + remove unnecessary thumbnails
- task.thumbnail = results[task.key.id]
+ task.thumbnail = thumbnailQueryResults[task.key.id]
+
+ // TODO(b/352331675) don't load icons for DesktopTaskView
+ // Add retrieved icons + remove unnecessary icons
+ task.icon = iconQueryResults[task.key.id]?.icon
+ task.titleDescription = iconQueryResults[task.key.id]?.contentDescription
+ task.title = iconQueryResults[task.key.id]?.title
}
tasks
}
@@ -63,6 +74,9 @@
override fun getTaskDataById(taskId: Int): Flow<Task?> =
taskData.map { taskList -> taskList.firstOrNull { it.key.id == taskId } }
+ override fun getThumbnailById(taskId: Int): Flow<ThumbnailData?> =
+ getTaskDataById(taskId).map { it?.thumbnail }.distinctUntilChangedBy { it?.snapshotId }
+
override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
this.visibleTaskIds.value = visibleTaskIdList.toSet()
}
@@ -75,7 +89,6 @@
suspendCancellableCoroutine { continuation ->
val cancellableTask =
taskThumbnailDataSource.getThumbnailInBackground(task) {
- task.thumbnail = it
continuation.resume(it)
}
continuation.invokeOnCancellation { cancellableTask?.cancel() }
@@ -105,6 +118,59 @@
}
}
}
+
+ /** Flow wrapper for [TaskThumbnailDataSource.getThumbnailInBackground] api */
+ private fun getIconDataRequest(task: Task): IconDataRequest =
+ flow {
+ emit(task.key.id to task.getTaskIconQueryResponse())
+ val iconDataResponse: TaskIconQueryResponse? =
+ suspendCancellableCoroutine { continuation ->
+ val cancellableTask =
+ taskIconDataSource.getIconInBackground(task) {
+ icon,
+ contentDescription,
+ title ->
+ continuation.resume(
+ TaskIconQueryResponse(icon, contentDescription, title)
+ )
+ }
+ continuation.invokeOnCancellation { cancellableTask?.cancel() }
+ }
+ emit(task.key.id to iconDataResponse)
+ }
+ .distinctUntilChanged()
+
+ private fun getIconQueryResults(): Flow<Map<Int, TaskIconQueryResponse?>> {
+ val visibleTasks =
+ combine(_taskData, visibleTaskIds) { tasks, visibleIds ->
+ tasks.filter { it.key.id in visibleIds }
+ }
+ val visibleIconDataRequests: Flow<List<IconDataRequest>> =
+ visibleTasks.map { visibleTasksList -> visibleTasksList.map(::getIconDataRequest) }
+ return visibleIconDataRequests.flatMapLatest { iconRequestFlows: List<IconDataRequest> ->
+ if (iconRequestFlows.isEmpty()) {
+ flowOf(emptyMap())
+ } else {
+ combine(iconRequestFlows) { it.toMap() }
+ }
+ }
+ }
}
-typealias ThumbnailDataRequest = Flow<Pair<Int, ThumbnailData?>>
+private data class TaskIconQueryResponse(
+ val icon: Drawable,
+ val contentDescription: String,
+ val title: String
+)
+
+private fun Task.getTaskIconQueryResponse(): TaskIconQueryResponse? {
+ val iconVal = icon ?: return null
+ val titleDescriptionVal = titleDescription ?: return null
+ val titleVal = title ?: return null
+
+ return TaskIconQueryResponse(iconVal, titleDescriptionVal, titleVal)
+}
+
+private typealias ThumbnailDataRequest = Flow<Pair<Int, ThumbnailData?>>
+
+private typealias IconDataRequest = Flow<Pair<Int, TaskIconQueryResponse?>>
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/LiveTileView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/LiveTileView.kt
new file mode 100644
index 0000000..45b3687
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/LiveTileView.kt
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.thumbnail
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.PorterDuff
+import android.graphics.PorterDuffXfermode
+import android.util.AttributeSet
+import android.view.View
+
+class LiveTileView : View {
+ constructor(context: Context) : super(context)
+
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
+
+ constructor(
+ context: Context,
+ attrs: AttributeSet?,
+ defStyleAttr: Int,
+ ) : super(context, attrs, defStyleAttr)
+
+ override fun onDraw(canvas: Canvas) {
+ canvas.drawRect(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat(), CLEAR_PAINT)
+ }
+
+ companion object {
+ private val CLEAR_PAINT =
+ Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index 20a081b..d22fc94 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -18,17 +18,17 @@
import android.content.Context
import android.content.res.Configuration
-import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Outline
-import android.graphics.Paint
-import android.graphics.PorterDuff
-import android.graphics.PorterDuffXfermode
import android.graphics.Rect
import android.util.AttributeSet
import android.view.View
import android.view.ViewOutlineProvider
+import android.widget.FrameLayout
+import android.widget.ImageView
import androidx.annotation.ColorInt
+import androidx.core.view.isVisible
+import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.util.ViewPool
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
@@ -40,10 +40,15 @@
import com.android.quickstep.views.RecentsViewContainer
import com.android.quickstep.views.TaskView
import com.android.systemui.shared.system.QuickStepContract
-import kotlinx.coroutines.MainScope
-import kotlinx.coroutines.launch
+import kotlinx.coroutines.CoroutineName
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.SupervisorJob
+import kotlinx.coroutines.cancel
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
-class TaskThumbnailView : View, ViewPool.Reusable {
+class TaskThumbnailView : FrameLayout, ViewPool.Reusable {
// TODO(b/335649589): Ideally create and obtain this from DI. This ViewModel should be scoped
// to [TaskView], and also shared between [TaskView] and [TaskThumbnailView]
// This is using a lazy for now because the dependencies cannot be obtained without DI.
@@ -52,19 +57,20 @@
RecentsViewContainer.containerFromContext<RecentsViewContainer>(context)
.getOverviewPanel<RecentsView<*, *>>()
TaskThumbnailViewModel(
- recentsView.mRecentsViewData,
+ recentsView.mRecentsViewData!!,
(parent as TaskView).taskViewData,
(parent as TaskView).getTaskContainerForTaskThumbnailView(this)!!.taskContainerData,
- recentsView.mTasksRepository,
+ recentsView.mTasksRepository!!,
)
}
+ private lateinit var viewAttachedScope: CoroutineScope
- private var uiState: TaskThumbnailUiState = Uninitialized
+ private val scrimView: View by lazy { findViewById(R.id.task_thumbnail_scrim) }
+ private val liveTileView: LiveTileView by lazy { findViewById(R.id.task_thumbnail_live_tile) }
+ private val thumbnail: ImageView by lazy { findViewById(R.id.task_thumbnail) }
+
private var inheritedScale: Float = 1f
- private var dimProgress: Float = 0f
- private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG)
- private val scrimPaint = Paint().apply { color = Color.BLACK }
private val _measuredBounds = Rect()
private val measuredBounds: Rect
get() {
@@ -75,39 +81,44 @@
private var overviewCornerRadius: Float = TaskCornerRadius.get(context)
private var fullscreenCornerRadius: Float = QuickStepContract.getWindowCornerRadius(context)
- constructor(context: Context?) : super(context)
+ constructor(context: Context) : super(context)
- constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
+ constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(
- context: Context?,
+ context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
) : super(context, attrs, defStyleAttr)
override fun onAttachedToWindow() {
super.onAttachedToWindow()
- // TODO(b/335396935) replace MainScope with shorter lifecycle.
- MainScope().launch {
- viewModel.uiState.collect { viewModelUiState ->
- uiState = viewModelUiState
- invalidate()
+ viewAttachedScope =
+ CoroutineScope(SupervisorJob() + Dispatchers.Main + CoroutineName("TaskThumbnailView"))
+ viewModel.uiState
+ .onEach { viewModelUiState ->
+ resetViews()
+ when (viewModelUiState) {
+ is Uninitialized -> {}
+ is LiveTile -> drawLiveWindow()
+ is Snapshot -> drawSnapshot(viewModelUiState)
+ is BackgroundOnly -> drawBackground(viewModelUiState.backgroundColor)
+ }
}
- }
- MainScope().launch {
- viewModel.dimProgress.collect { dimProgress ->
+ .launchIn(viewAttachedScope)
+ viewModel.dimProgress
+ .onEach { dimProgress ->
// TODO(b/348195366) Add fade in/out for scrim
- this@TaskThumbnailView.dimProgress = dimProgress
- invalidate()
+ scrimView.alpha = dimProgress * MAX_SCRIM_ALPHA
}
- }
- MainScope().launch { viewModel.cornerRadiusProgress.collect { invalidateOutline() } }
- MainScope().launch {
- viewModel.inheritedScale.collect { viewModelInheritedScale ->
+ .launchIn(viewAttachedScope)
+ viewModel.cornerRadiusProgress.onEach { invalidateOutline() }.launchIn(viewAttachedScope)
+ viewModel.inheritedScale
+ .onEach { viewModelInheritedScale ->
inheritedScale = viewModelInheritedScale
invalidateOutline()
}
- }
+ .launchIn(viewAttachedScope)
clipToOutline = true
outlineProvider =
@@ -118,27 +129,13 @@
}
}
+ override fun onDetachedFromWindow() {
+ super.onDetachedFromWindow()
+ viewAttachedScope.cancel("TaskThumbnailView detaching from window")
+ }
+
override fun onRecycle() {
// Do nothing
- uiState = Uninitialized
- }
-
- override fun onDraw(canvas: Canvas) {
- when (val uiStateVal = uiState) {
- is Uninitialized -> drawBackgroundOnly(canvas, Color.BLACK)
- is LiveTile -> drawTransparentUiState(canvas)
- is Snapshot -> drawSnapshotState(canvas, uiStateVal)
- is BackgroundOnly -> drawBackgroundOnly(canvas, uiStateVal.backgroundColor)
- }
-
- if (dimProgress > 0) {
- drawScrim(canvas)
- }
- }
-
- private fun drawBackgroundOnly(canvas: Canvas, @ColorInt backgroundColor: Int) {
- backgroundPaint.color = backgroundColor
- canvas.drawRect(measuredBounds, backgroundPaint)
}
override fun onConfigurationChanged(newConfig: Configuration?) {
@@ -149,18 +146,25 @@
invalidateOutline()
}
- private fun drawTransparentUiState(canvas: Canvas) {
- canvas.drawRect(measuredBounds, CLEAR_PAINT)
+ private fun resetViews() {
+ liveTileView.isVisible = false
+ thumbnail.isVisible = false
+ scrimView.alpha = 0f
+ setBackgroundColor(Color.BLACK)
}
- private fun drawSnapshotState(canvas: Canvas, snapshot: Snapshot) {
- drawBackgroundOnly(canvas, snapshot.backgroundColor)
- canvas.drawBitmap(snapshot.bitmap, snapshot.drawnRect, measuredBounds, null)
+ private fun drawBackground(@ColorInt background: Int) {
+ setBackgroundColor(background)
}
- private fun drawScrim(canvas: Canvas) {
- scrimPaint.alpha = (dimProgress * MAX_SCRIM_ALPHA).toInt()
- canvas.drawRect(measuredBounds, scrimPaint)
+ private fun drawLiveWindow() {
+ liveTileView.isVisible = true
+ }
+
+ private fun drawSnapshot(snapshot: Snapshot) {
+ drawBackground(snapshot.backgroundColor)
+ thumbnail.setImageBitmap(snapshot.bitmap)
+ thumbnail.isVisible = true
}
private fun getCurrentCornerRadius() =
@@ -170,9 +174,7 @@
fullscreenCornerRadius
) / inheritedScale
- companion object {
- private val CLEAR_PAINT =
- Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }
- private const val MAX_SCRIM_ALPHA = (0.4f * 255).toInt()
+ private companion object {
+ const val MAX_SCRIM_ALPHA = 0.4f
}
}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/data/TaskIconDataSource.kt b/quickstep/src/com/android/quickstep/task/thumbnail/data/TaskIconDataSource.kt
new file mode 100644
index 0000000..ab699c6
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/data/TaskIconDataSource.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.thumbnail.data
+
+import com.android.launcher3.util.CancellableTask
+import com.android.quickstep.TaskIconCache.GetTaskIconCallback
+import com.android.systemui.shared.recents.model.Task
+
+interface TaskIconDataSource {
+ fun getIconInBackground(task: Task, callback: GetTaskIconCallback): CancellableTask<*>?
+}
diff --git a/quickstep/src/com/android/quickstep/task/util/GetThumbnailUseCase.kt b/quickstep/src/com/android/quickstep/task/util/GetThumbnailUseCase.kt
new file mode 100644
index 0000000..e8dd04c3
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/util/GetThumbnailUseCase.kt
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.util
+
+import android.graphics.Bitmap
+import com.android.quickstep.recents.data.RecentTasksRepository
+import kotlinx.coroutines.flow.firstOrNull
+import kotlinx.coroutines.runBlocking
+
+/** Use case for retrieving thumbnail. */
+class GetThumbnailUseCase(private val taskRepository: RecentTasksRepository) {
+ /** Returns the latest thumbnail associated with [taskId] if loaded, or null otherwise */
+ fun run(taskId: Int): Bitmap? = runBlocking {
+ taskRepository.getThumbnailById(taskId).firstOrNull()?.thumbnail
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt b/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
index de39584..5e55e2e 100644
--- a/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
+++ b/quickstep/src/com/android/quickstep/task/util/TaskOverlayHelper.kt
@@ -46,7 +46,7 @@
overlay.taskView.context
)
.getOverviewPanel<RecentsView<*, *>>()
- TaskOverlayViewModel(task, recentsView.mRecentsViewData, recentsView.mTasksRepository)
+ TaskOverlayViewModel(task, recentsView.mRecentsViewData!!, recentsView.mTasksRepository!!)
}
// TODO(b/331753115): TaskOverlay should listen for state changes and react.
diff --git a/quickstep/src/com/android/quickstep/task/viewmodel/TaskOverlayViewModel.kt b/quickstep/src/com/android/quickstep/task/viewmodel/TaskOverlayViewModel.kt
index 4682323..47f32fb 100644
--- a/quickstep/src/com/android/quickstep/task/viewmodel/TaskOverlayViewModel.kt
+++ b/quickstep/src/com/android/quickstep/task/viewmodel/TaskOverlayViewModel.kt
@@ -24,7 +24,6 @@
import com.android.systemui.shared.recents.model.Task
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.map
/** View model for TaskOverlay */
@@ -37,10 +36,7 @@
combine(
recentsViewData.overlayEnabled,
recentsViewData.settledFullyVisibleTaskIds.map { it.contains(task.key.id) },
- tasksRepository
- .getTaskDataById(task.key.id)
- .map { it?.thumbnail }
- .distinctUntilChangedBy { it?.snapshotId }
+ tasksRepository.getThumbnailById(task.key.id)
) { isOverlayEnabled, isFullyVisible, thumbnailData ->
if (isOverlayEnabled && isFullyVisible) {
Enabled(
diff --git a/quickstep/src/com/android/quickstep/util/AsyncClockEventDelegate.java b/quickstep/src/com/android/quickstep/util/AsyncClockEventDelegate.java
index c26fc0c5..38ae303 100644
--- a/quickstep/src/com/android/quickstep/util/AsyncClockEventDelegate.java
+++ b/quickstep/src/com/android/quickstep/util/AsyncClockEventDelegate.java
@@ -18,6 +18,8 @@
import static android.content.Intent.ACTION_TIMEZONE_CHANGED;
import static android.content.Intent.ACTION_TIME_CHANGED;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -50,7 +52,7 @@
private final Context mContext;
private final SimpleBroadcastReceiver mReceiver =
- new SimpleBroadcastReceiver(this::onClockEventReceived);
+ new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, this::onClockEventReceived);
private final ArrayMap<BroadcastReceiver, Handler> mTimeEventReceivers = new ArrayMap<>();
private final List<ContentObserver> mFormatObservers = new ArrayList<>();
@@ -62,7 +64,7 @@
private AsyncClockEventDelegate(Context context) {
super(context);
mContext = context;
- mReceiver.registerAsync(mContext, ACTION_TIME_CHANGED, ACTION_TIMEZONE_CHANGED);
+ mReceiver.register(mContext, ACTION_TIME_CHANGED, ACTION_TIMEZONE_CHANGED);
}
@Override
@@ -123,6 +125,6 @@
public void close() {
mDestroyed = true;
SettingsCache.INSTANCE.get(mContext).unregister(mFormatUri, this);
- mReceiver.unregisterReceiverSafelyAsync(mContext);
+ mReceiver.unregisterReceiverSafely(mContext);
}
}
diff --git a/quickstep/src/com/android/quickstep/util/BorderAnimator.kt b/quickstep/src/com/android/quickstep/util/BorderAnimator.kt
index 85238ed..7e51fcf 100644
--- a/quickstep/src/com/android/quickstep/util/BorderAnimator.kt
+++ b/quickstep/src/com/android/quickstep/util/BorderAnimator.kt
@@ -50,7 +50,7 @@
private val disappearanceDurationMs: Long,
private val interpolator: Interpolator,
) {
- private val borderAnimationProgress = AnimatedFloat { updateOutline() }
+ private val borderAnimationProgress = AnimatedFloat { _ -> updateOutline() }
private val borderPaint =
Paint(Paint.ANTI_ALIAS_FLAG).apply {
color = borderColor
@@ -224,6 +224,7 @@
val borderWidth: Float
get() = borderWidthPx * animationProgress
+
val alignmentAdjustment: Float
// Outset the border by half the width to create an outwards-growth animation
get() = -borderWidth / 2f + alignmentAdjustmentInset
diff --git a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
index cb44a1a..fcf9ab1 100644
--- a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
@@ -108,19 +108,28 @@
return false;
}
+ final SimpleOrientationTouchTransformer touchTransformer =
+ SimpleOrientationTouchTransformer.INSTANCE.get(mContext);
+ final int viewRotation = mRotationSupplier.get();
+ final boolean needTransform = viewRotation != ev.getSurfaceRotation();
if (action == ACTION_DOWN) {
mTouchInProgress = true;
+ if (needTransform) {
+ touchTransformer.updateTouchingOrientation(viewRotation);
+ }
initInputConsumerIfNeeded(/* isFromTouchDown= */ true);
} else if (action == ACTION_CANCEL || action == ACTION_UP) {
// Finish any pending actions
mTouchInProgress = false;
+ touchTransformer.clearTouchingOrientation();
if (mDestroyPending) {
destroy();
}
}
if (mInputConsumer != null) {
- SimpleOrientationTouchTransformer.INSTANCE.get(mContext).transform(ev,
- mRotationSupplier.get());
+ if (needTransform) {
+ touchTransformer.transform(ev, viewRotation);
+ }
mInputConsumer.onMotionEvent(ev);
}
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 0cd36f4..e31a828 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -122,7 +122,7 @@
val drawable = getDrawable(container.iconView, splitSelectSource)
return SplitAnimInitProps(
container.snapshotView,
- container.thumbnail,
+ container.splitAnimationThumbnail,
drawable,
fadeWithThumbnail = true,
isStagedTask = true,
@@ -141,7 +141,7 @@
val drawable = getDrawable(it.iconView, splitSelectSource)
return SplitAnimInitProps(
it.snapshotView,
- it.thumbnail,
+ it.splitAnimationThumbnail,
drawable,
fadeWithThumbnail = true,
isStagedTask = true,
@@ -536,8 +536,13 @@
val appPairLaunchingAppIndex = hasChangesForBothAppPairs(launchingIconView, info)
if (appPairLaunchingAppIndex == -1) {
// Launch split app pair animation
- composeIconSplitLaunchAnimator(launchingIconView, info, t, finishCallback,
- cornerRadius)
+ composeIconSplitLaunchAnimator(
+ launchingIconView,
+ info,
+ t,
+ finishCallback,
+ cornerRadius
+ )
} else {
composeFullscreenIconSplitLaunchAnimator(
launchingIconView,
@@ -554,8 +559,14 @@
"unexpected null"
}
- composeFadeInSplitLaunchAnimator(initialTaskId, secondTaskId, info, t, finishCallback,
- cornerRadius)
+ composeFadeInSplitLaunchAnimator(
+ initialTaskId,
+ secondTaskId,
+ info,
+ t,
+ finishCallback,
+ cornerRadius
+ )
}
}
@@ -701,7 +712,7 @@
val launchAnimation = AnimatorSet()
val splitRoots: Pair<Change, List<Change>>? =
- SplitScreenUtils.extractTopParentAndChildren(transitionInfo)
+ SplitScreenUtils.extractTopParentAndChildren(transitionInfo)
check(splitRoots != null) { "Could not find split roots" }
// Will point to change (0) in diagram above
@@ -711,10 +722,11 @@
// Find the place where our left/top app window meets the divider (used for the
// launcher side animation)
- val leftTopApp = leafRoots.single { change ->
- (dp.isLeftRightSplit && change.endAbsBounds.left == 0) ||
+ val leftTopApp =
+ leafRoots.single { change ->
+ (dp.isLeftRightSplit && change.endAbsBounds.left == 0) ||
(!dp.isLeftRightSplit && change.endAbsBounds.top == 0)
- }
+ }
val dividerPos =
if (dp.isLeftRightSplit) leftTopApp.endAbsBounds.right
else leftTopApp.endAbsBounds.bottom
@@ -736,17 +748,24 @@
)
floatingView.bringToFront()
- val iconLaunchValueAnimator = getIconLaunchValueAnimator(t, dp, finishCallback, launcher,
- floatingView, mainRootCandidate)
+ val iconLaunchValueAnimator =
+ getIconLaunchValueAnimator(
+ t,
+ dp,
+ finishCallback,
+ launcher,
+ floatingView,
+ mainRootCandidate
+ )
iconLaunchValueAnimator.addListener(
- object : AnimatorListenerAdapter() {
- override fun onAnimationStart(animation: Animator, isReverse: Boolean) {
- for (c in leafRoots) {
- t.setCornerRadius(c.leash, windowRadius)
- t.apply()
- }
+ object : AnimatorListenerAdapter() {
+ override fun onAnimationStart(animation: Animator, isReverse: Boolean) {
+ for (c in leafRoots) {
+ t.setCornerRadius(c.leash, windowRadius)
+ t.apply()
}
}
+ }
)
launchAnimation.play(iconLaunchValueAnimator)
launchAnimation.start()
@@ -1017,12 +1036,12 @@
*/
@VisibleForTesting
fun composeFadeInSplitLaunchAnimator(
- initialTaskId: Int,
- secondTaskId: Int,
- transitionInfo: TransitionInfo,
- t: Transaction,
- finishCallback: Runnable,
- cornerRadius: Float
+ initialTaskId: Int,
+ secondTaskId: Int,
+ transitionInfo: TransitionInfo,
+ t: Transaction,
+ finishCallback: Runnable,
+ cornerRadius: Float
) {
var splitRoot1: Change? = null
var splitRoot2: Change? = null
@@ -1100,7 +1119,7 @@
override fun onAnimationStart(animation: Animator) {
for (leash in openingTargets) {
animTransaction.show(leash).setAlpha(leash, 0.0f)
- animTransaction.setCornerRadius(leash, cornerRadius);
+ animTransaction.setCornerRadius(leash, cornerRadius)
}
animTransaction.apply()
}
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 48ed67b..56e91ed 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -139,6 +139,10 @@
final float aspectRatio = destinationBounds.width() / (float) destinationBounds.height();
String reasonForCreateOverlay = null; // For debugging purpose.
+
+ // Slightly larger app bounds to allow for off by 1 pixel source-rect-hint errors.
+ Rect overflowAppBounds = new Rect(appBounds.left - 1, appBounds.top - 1,
+ appBounds.right + 1, appBounds.bottom + 1);
if (sourceRectHint.isEmpty()) {
reasonForCreateOverlay = "Source rect hint is empty";
} else if (sourceRectHint.width() < destinationBounds.width()
@@ -149,7 +153,7 @@
// animation in this case.
reasonForCreateOverlay = "Source rect hint is too small " + sourceRectHint;
sourceRectHint.setEmpty();
- } else if (!appBounds.contains(sourceRectHint)) {
+ } else if (!overflowAppBounds.contains(sourceRectHint)) {
// This is a situation in which the source hint rect is outside the app bounds, so it is
// not a valid rectangle to use for cropping app surface
reasonForCreateOverlay = "Source rect hint exceeds display bounds " + sourceRectHint;
diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
index 4333c8b..9ce2277 100644
--- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.kt
@@ -24,6 +24,7 @@
import android.graphics.drawable.shapes.RoundRectShape
import android.util.AttributeSet
import android.util.Log
+import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.updateLayoutParams
@@ -36,7 +37,6 @@
import com.android.launcher3.util.rects.set
import com.android.quickstep.BaseContainerInterface
import com.android.quickstep.TaskOverlayFactory
-import com.android.quickstep.task.thumbnail.TaskThumbnailView
import com.android.quickstep.util.RecentsOrientedState
import com.android.systemui.shared.recents.model.Task
@@ -54,7 +54,7 @@
ViewPool<TaskThumbnailViewDeprecated>(
context,
this,
- R.layout.task_thumbnail,
+ R.layout.task_thumbnail_deprecated,
VIEW_POOL_MAX_SIZE,
VIEW_POOL_INITIAL_SIZE
)
@@ -108,22 +108,21 @@
tasks.map { task ->
val snapshotView =
if (enableRefactorTaskThumbnail()) {
- TaskThumbnailView(context)
- } else {
- taskThumbnailViewDeprecatedPool.view
- }
- .also { snapshotView ->
- addView(
- snapshotView,
- // Add snapshotView to the front after initial views e.g. icon and
- // background.
- childCountAtInflation,
- LayoutParams(
- ViewGroup.LayoutParams.WRAP_CONTENT,
- ViewGroup.LayoutParams.WRAP_CONTENT
- )
- )
- }
+ LayoutInflater.from(context).inflate(R.layout.task_thumbnail, this, false)
+ } else {
+ taskThumbnailViewDeprecatedPool.view
+ }
+
+ addView(
+ snapshotView,
+ // Add snapshotView to the front after initial views e.g. icon and
+ // background.
+ childCountAtInflation,
+ LayoutParams(
+ ViewGroup.LayoutParams.WRAP_CONTENT,
+ ViewGroup.LayoutParams.WRAP_CONTENT
+ )
+ )
TaskContainer(
this,
task,
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 7b6d383..3273809 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -461,7 +461,9 @@
private static final float FOREGROUND_SCRIM_TINT = 0.32f;
+ @Nullable
public final RecentsViewData mRecentsViewData = new RecentsViewData();
+ @Nullable
public final TasksRepository mTasksRepository;
protected final RecentsOrientedState mOrientationState;
@@ -793,6 +795,13 @@
private int mOffsetMidpointIndexOverride = INVALID_PAGE;
+ /**
+ * Whether or not any task has been dismissed i.e. swiped away by the user, in the lifetime of
+ * RecentsView being open and displayed to the user. It is reset in the {@link #reset()} method
+ * i.e. when RecentsView closes.
+ */
+ private boolean mAnyTaskHasBeenDismissed;
+
public RecentsView(Context context, @Nullable AttributeSet attrs, int defStyleAttr,
BaseContainerInterface sizeStrategy) {
super(context, attrs, defStyleAttr);
@@ -2179,15 +2188,6 @@
* Updates TaskView scaling and translation required to support variable width.
*/
private void updateTaskSize() {
- updateTaskSize(false);
- }
-
- /**
- * Updates TaskView scaling and translation required to support variable width.
- *
- * @param isTaskDismissal indicates if update was called due to task dismissal
- */
- private void updateTaskSize(boolean isTaskDismissal) {
final int taskCount = getTaskViewCount();
if (taskCount == 0) {
return;
@@ -2214,7 +2214,7 @@
mClearAllButton.setFullscreenTranslationPrimary(accumulatedTranslationX);
- updateGridProperties(isTaskDismissal);
+ updateGridProperties();
}
public void getTaskSize(Rect outRect) {
@@ -2514,6 +2514,7 @@
mIgnoreResetTaskId = -1;
mTaskListChangeId = -1;
mFocusedTaskViewId = -1;
+ mAnyTaskHasBeenDismissed = false;
Log.d(TAG, "reset - mEnableDrawingLiveTile: " + mEnableDrawingLiveTile
+ ", mRecentsAnimationController: " + mRecentsAnimationController);
@@ -2989,22 +2990,11 @@
/**
* Updates TaskView and ClearAllButtion scaling and translation required to turn into grid
* layout.
- * This method is used when no task dismissal has occurred.
+ *
+ * Skips rebalance.
*/
private void updateGridProperties() {
- updateGridProperties(false, Integer.MAX_VALUE);
- }
-
- /**
- * Updates TaskView and ClearAllButtion scaling and translation required to turn into grid
- * layout.
- *
- * This method is used when task dismissal has occurred, but rebalance is not needed.
- *
- * @param isTaskDismissal indicates if update was called due to task dismissal
- */
- private void updateGridProperties(boolean isTaskDismissal) {
- updateGridProperties(isTaskDismissal, Integer.MAX_VALUE);
+ updateGridProperties(Integer.MAX_VALUE);
}
/**
@@ -3014,11 +3004,10 @@
* This method only calculates the potential position and depends on {@link #setGridProgress} to
* apply the actual scaling and translation.
*
- * @param isTaskDismissal indicates if update was called due to task dismissal
* @param startRebalanceAfter which view index to start rebalancing from. Use Integer.MAX_VALUE
- * to skip rebalance
+ * to skip rebalance
*/
- private void updateGridProperties(boolean isTaskDismissal, int startRebalanceAfter) {
+ private void updateGridProperties(int startRebalanceAfter) {
int taskCount = getTaskViewCount();
if (taskCount == 0) {
return;
@@ -3049,7 +3038,8 @@
TaskView homeTaskView = getHomeTaskView();
TaskView nextFocusedTaskView = null;
- if (!isTaskDismissal) {
+ // Don't clear the top row, if the user has dismissed a task, to maintain the task order.
+ if (!mAnyTaskHasBeenDismissed) {
mTopRowIdSet.clear();
}
for (int i = 0; i < taskCount; i++) {
@@ -3089,7 +3079,7 @@
// Rebalance the grid starting after a certain index
boolean isTopRow;
- if (isTaskDismissal) {
+ if (mAnyTaskHasBeenDismissed) {
if (i > startRebalanceAfter) {
mTopRowIdSet.remove(taskViewId);
isTopRow = topRowWidth <= bottomRowWidth;
@@ -3814,7 +3804,7 @@
anim.setFloat(taskView, taskView.getSecondaryDismissTranslationProperty(),
secondaryTranslation, clampToProgress(LINEAR, animationStartProgress,
dismissTranslationInterpolationEnd));
- anim.setFloat(taskView, TaskView.SCALE_AND_DIM_OUT, 0f,
+ anim.add(taskView.getFocusTransitionScaleAndDimOutAnimator(),
clampToProgress(LINEAR, 0f, ANIMATION_DISMISS_PROGRESS_MIDPOINT));
} else {
float primaryTranslation =
@@ -3870,6 +3860,7 @@
resetTaskVisuals();
if (success) {
+ mAnyTaskHasBeenDismissed = true;
if (shouldRemoveTask) {
if (dismissedTaskView.isRunningTask()) {
finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
@@ -3978,7 +3969,7 @@
mTopRowIdSet.remove(mFocusedTaskViewId);
finalNextFocusedTaskView.animateIconScaleAndDimIntoView();
}
- updateTaskSize(/*isTaskDismissal=*/ true);
+ updateTaskSize();
updateChildTaskOrientations();
// Update scroll and snap to page.
updateScrollSynchronously();
@@ -4014,8 +4005,7 @@
}
if (shouldRebalance) {
- updateGridProperties(/*isTaskDismissal=*/ true,
- highestVisibleTaskIndex);
+ updateGridProperties(highestVisibleTaskIndex);
updateScrollSynchronously();
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskContainer.kt b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
index 0648986..74d120f 100644
--- a/quickstep/src/com/android/quickstep/views/TaskContainer.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskContainer.kt
@@ -31,6 +31,7 @@
import com.android.quickstep.TaskUtils
import com.android.quickstep.task.thumbnail.TaskThumbnail
import com.android.quickstep.task.thumbnail.TaskThumbnailView
+import com.android.quickstep.task.util.GetThumbnailUseCase
import com.android.quickstep.task.viewmodel.TaskContainerData
import com.android.systemui.shared.recents.model.Task
@@ -56,6 +57,16 @@
val overlay: TaskOverlayFactory.TaskOverlay<*> = taskOverlayFactory.createOverlay(this)
val taskContainerData = TaskContainerData()
+ private val getThumbnailUseCase by lazy {
+ // TODO(b/335649589): Ideally create and obtain this from DI.
+ val recentsView =
+ RecentsViewContainer.containerFromContext<RecentsViewContainer>(
+ overlay.taskView.context
+ )
+ .getOverviewPanel<RecentsView<*, *>>()
+ GetThumbnailUseCase(recentsView.mTasksRepository!!)
+ }
+
init {
if (enableRefactorTaskThumbnail()) {
require(snapshotView is TaskThumbnailView)
@@ -64,6 +75,14 @@
}
}
+ val splitAnimationThumbnail: Bitmap?
+ get() =
+ if (enableRefactorTaskThumbnail()) {
+ getThumbnailUseCase.run(task.key.id)
+ } else {
+ thumbnailViewDeprecated.thumbnail
+ }
+
val thumbnailView: TaskThumbnailView
get() {
require(enableRefactorTaskThumbnail())
@@ -76,10 +95,6 @@
return snapshotView as TaskThumbnailViewDeprecated
}
- // TODO(b/349120849): Extract ThumbnailData from TaskContainerData/TaskThumbnailViewModel
- val thumbnail: Bitmap?
- get() = if (enableRefactorTaskThumbnail()) null else thumbnailViewDeprecated.thumbnail
-
// TODO(b/334826842): Support shouldShowSplashView for new TTV.
val shouldShowSplashView: Boolean
get() =
@@ -114,6 +129,15 @@
}
}
+ fun bind() {
+ if (enableRefactorTaskThumbnail()) {
+ bindThumbnailView()
+ } else {
+ thumbnailViewDeprecated.bind(task, overlay)
+ }
+ overlay.init()
+ }
+
fun destroy() {
digitalWellBeingToast?.destroy()
if (enableRefactorTaskThumbnail()) {
@@ -122,15 +146,6 @@
overlay.destroy()
}
- fun bind() {
- if (enableRefactorTaskThumbnail()) {
- bindThumbnailView()
- overlay.init()
- } else {
- thumbnailViewDeprecated.bind(task, overlay)
- }
- }
-
// TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
// so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
fun bindThumbnailView() {
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 2e07e36..004003c 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -31,6 +31,7 @@
import android.util.FloatProperty
import android.util.Log
import android.view.Display
+import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.View.OnClickListener
@@ -51,6 +52,7 @@
import com.android.launcher3.Flags.enableRefactorTaskThumbnail
import com.android.launcher3.R
import com.android.launcher3.Utilities
+import com.android.launcher3.anim.AnimatedFloat
import com.android.launcher3.config.FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH
import com.android.launcher3.logging.StatsLogManager.LauncherEvent
import com.android.launcher3.model.data.ItemInfo
@@ -419,17 +421,17 @@
focusTransitionPropertyFactory.get(FOCUS_TRANSITION_INDEX_FULLSCREEN)
private val focusTransitionScaleAndDim =
focusTransitionPropertyFactory.get(FOCUS_TRANSITION_INDEX_SCALE_AND_DIM)
+
/**
- * Variant of [focusTransitionScaleAndDim] that has a built-in interpolator, to be used with
- * [com.android.launcher3.anim.PendingAnimation] via [SCALE_AND_DIM_OUT] only. PendingAnimation
- * doesn't support interpolator per animation, so we'll have to interpolate inside the property.
+ * Returns an animator of [focusTransitionScaleAndDim] that transition out with a built-in
+ * interpolator.
*/
- private var focusTransitionScaleAndDimOut = focusTransitionScaleAndDim.value
- set(value) {
- field = value
- focusTransitionScaleAndDim.value =
- FOCUS_TRANSITION_FAST_OUT_INTERPOLATOR.getInterpolation(field)
- }
+ fun getFocusTransitionScaleAndDimOutAnimator(): ObjectAnimator =
+ AnimatedFloat { v ->
+ focusTransitionScaleAndDim.value =
+ FOCUS_TRANSITION_FAST_OUT_INTERPOLATOR.getInterpolation(v)
+ }
+ .animateToValue(1f, 0f)
private var iconAndDimAnimator: ObjectAnimator? = null
// The current background requests to load the task thumbnail and icon
@@ -665,9 +667,8 @@
if (enableRefactorTaskThumbnail()) {
thumbnailViewDeprecated.visibility = GONE
val indexOfSnapshotView = indexOfChild(thumbnailViewDeprecated)
- TaskThumbnailView(context).apply {
- layoutParams = thumbnailViewDeprecated.layoutParams
- addView(this, indexOfSnapshotView)
+ LayoutInflater.from(context).inflate(R.layout.task_thumbnail, this, false).also {
+ addView(it, indexOfSnapshotView, thumbnailViewDeprecated.layoutParams)
}
} else {
thumbnailViewDeprecated
@@ -1179,7 +1180,7 @@
container.task,
container.iconView.drawable,
container.snapshotView,
- container.thumbnail,
+ container.splitAnimationThumbnail,
/* intent */ null,
/* user */ null,
container.itemInfo
@@ -1615,16 +1616,6 @@
override fun get(taskView: TaskView) = taskView.focusTransitionProgress
}
- @JvmField
- val SCALE_AND_DIM_OUT: FloatProperty<TaskView> =
- object : FloatProperty<TaskView>("scaleAndDimFastOut") {
- override fun setValue(taskView: TaskView, v: Float) {
- taskView.focusTransitionScaleAndDimOut = v
- }
-
- override fun get(taskView: TaskView) = taskView.focusTransitionScaleAndDimOut
- }
-
private val SPLIT_SELECT_TRANSLATION_X: FloatProperty<TaskView> =
object : FloatProperty<TaskView>("splitSelectTranslationX") {
override fun setValue(taskView: TaskView, v: Float) {
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
index 0f06d98..399aea6 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarNavButtonControllerTest.java
@@ -4,6 +4,8 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_BACK_BUTTON_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_HOME_BUTTON_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_HOME_BUTTON_TAP;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_LONGPRESS;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_OVERVIEW_BUTTON_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_OVERVIEW_BUTTON_TAP;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
@@ -26,6 +28,7 @@
import android.os.Handler;
import android.view.View;
+import android.view.inputmethod.Flags;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
@@ -109,8 +112,27 @@
@Test
public void testPressImeSwitcher() {
+ mNavButtonController.init(mockTaskbarControllers);
mNavButtonController.onButtonClick(BUTTON_IME_SWITCH, mockView);
+ verify(mockStatsLogger, times(1)).log(LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_TAP);
+ verify(mockStatsLogger, never()).log(LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_LONGPRESS);
verify(mockSystemUiProxy, times(1)).onImeSwitcherPressed();
+ verify(mockSystemUiProxy, never()).onImeSwitcherLongPress();
+ }
+
+ @Test
+ public void testLongPressImeSwitcher() {
+ mNavButtonController.init(mockTaskbarControllers);
+ mNavButtonController.onButtonLongClick(BUTTON_IME_SWITCH, mockView);
+ verify(mockStatsLogger, never()).log(LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_TAP);
+ verify(mockSystemUiProxy, never()).onImeSwitcherPressed();
+ if (Flags.imeSwitcherRevamp()) {
+ verify(mockStatsLogger, times(1)).log(LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_LONGPRESS);
+ verify(mockSystemUiProxy, times(1)).onImeSwitcherLongPress();
+ } else {
+ verify(mockStatsLogger, never()).log(LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_LONGPRESS);
+ verify(mockSystemUiProxy, never()).onImeSwitcherLongPress();
+ }
}
@Test
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt
new file mode 100644
index 0000000..242bc73
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskIconDataSource.kt
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.recents.data
+
+import android.graphics.drawable.Drawable
+import com.android.launcher3.util.CancellableTask
+import com.android.quickstep.TaskIconCache
+import com.android.quickstep.task.thumbnail.data.TaskIconDataSource
+import com.android.systemui.shared.recents.model.Task
+import com.google.common.truth.Truth.assertThat
+import org.mockito.kotlin.mock
+
+class FakeTaskIconDataSource : TaskIconDataSource {
+
+ val taskIdToDrawable: Map<Int, Drawable> = (0..10).associateWith { mock() }
+ val taskIdToUpdatingTask: MutableMap<Int, () -> Unit> = mutableMapOf()
+ var shouldLoadSynchronously: Boolean = true
+
+ /** Retrieves and sets an icon on [task] from [taskIdToDrawable]. */
+ override fun getIconInBackground(
+ task: Task,
+ callback: TaskIconCache.GetTaskIconCallback
+ ): CancellableTask<*>? {
+ val wrappedCallback = {
+ callback.onTaskIconReceived(
+ taskIdToDrawable.getValue(task.key.id),
+ "content desc ${task.key.id}",
+ "title ${task.key.id}"
+ )
+ }
+ if (shouldLoadSynchronously) {
+ wrappedCallback()
+ } else {
+ taskIdToUpdatingTask[task.key.id] = wrappedCallback
+ }
+ return null
+ }
+}
+
+fun Task.assertHasIconDataFromSource(fakeTaskIconDataSource: FakeTaskIconDataSource) {
+ assertThat(icon).isEqualTo(fakeTaskIconDataSource.taskIdToDrawable[key.id])
+ assertThat(titleDescription).isEqualTo("content desc ${key.id}")
+ assertThat(title).isEqualTo("title ${key.id}")
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
index e160627..19990a8 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
@@ -32,6 +32,9 @@
override fun getTaskDataById(taskId: Int): Flow<Task?> =
getAllTaskData().map { taskList -> taskList.firstOrNull { it.key.id == taskId } }
+ override fun getThumbnailById(taskId: Int): Flow<ThumbnailData?> =
+ getTaskDataById(taskId).map { it?.thumbnail }
+
override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
visibleTasks.value = visibleTaskIdList
tasks.value = tasks.value.map { it.apply { thumbnail = thumbnailDataMap[it.key.id] } }
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
index c28a85a..88fa190 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
@@ -18,7 +18,6 @@
import android.content.ComponentName
import android.content.Intent
-import com.android.quickstep.TaskIconCache
import com.android.quickstep.util.DesktopTask
import com.android.quickstep.util.GroupTask
import com.android.systemui.shared.recents.model.Task
@@ -31,7 +30,6 @@
import kotlinx.coroutines.test.UnconfinedTestDispatcher
import kotlinx.coroutines.test.runTest
import org.junit.Test
-import org.mockito.kotlin.mock
@OptIn(ExperimentalCoroutinesApi::class)
class TasksRepositoryTest {
@@ -44,10 +42,10 @@
)
private val recentsModel = FakeRecentTasksDataSource()
private val taskThumbnailDataSource = FakeTaskThumbnailDataSource()
- private val taskIconCache = mock<TaskIconCache>()
+ private val taskIconDataSource = FakeTaskIconDataSource()
private val systemUnderTest =
- TasksRepository(recentsModel, taskThumbnailDataSource, taskIconCache)
+ TasksRepository(recentsModel, taskThumbnailDataSource, taskIconDataSource)
@Test
fun getAllTaskDataReturnsFlattenedListOfTasks() = runTest {
@@ -81,6 +79,22 @@
}
@Test
+ fun setVisibleTasksPopulatesIcons() = runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ // .drop(1) to ignore initial null content before from thumbnail was loaded.
+ systemUnderTest
+ .getTaskDataById(1)
+ .drop(1)
+ .first()!!
+ .assertHasIconDataFromSource(taskIconDataSource)
+ systemUnderTest.getTaskDataById(2).first()!!.assertHasIconDataFromSource(taskIconDataSource)
+ }
+
+ @Test
fun changingVisibleTasksContainsAlreadyPopulatedThumbnails() = runTest {
recentsModel.seedTasks(defaultTaskList)
val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
@@ -101,7 +115,28 @@
}
@Test
- fun retrievedThumbnailsAreDiscardedWhenTaskBecomesInvisible() = runTest {
+ fun changingVisibleTasksContainsAlreadyPopulatedIcons() = runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ // .drop(1) to ignore initial null content before from icon was loaded.
+ systemUnderTest
+ .getTaskDataById(2)
+ .drop(1)
+ .first()!!
+ .assertHasIconDataFromSource(taskIconDataSource)
+
+ // Prevent new loading of Drawables
+ taskThumbnailDataSource.shouldLoadSynchronously = false
+ systemUnderTest.setVisibleTasks(listOf(2, 3))
+
+ systemUnderTest.getTaskDataById(2).first()!!.assertHasIconDataFromSource(taskIconDataSource)
+ }
+
+ @Test
+ fun retrievedImagesAreDiscardedWhenTaskBecomesInvisible() = runTest {
recentsModel.seedTasks(defaultTaskList)
val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
systemUnderTest.getAllTaskData(forceRefresh = true)
@@ -109,14 +144,20 @@
systemUnderTest.setVisibleTasks(listOf(1, 2))
// .drop(1) to ignore initial null content before from thumbnail was loaded.
- assertThat(systemUnderTest.getTaskDataById(2).drop(1).first()!!.thumbnail!!.thumbnail)
- .isEqualTo(bitmap2)
+ val task2 = systemUnderTest.getTaskDataById(2).drop(1).first()!!
+ assertThat(task2.thumbnail!!.thumbnail).isEqualTo(bitmap2)
+ task2.assertHasIconDataFromSource(taskIconDataSource)
// Prevent new loading of Bitmaps
taskThumbnailDataSource.shouldLoadSynchronously = false
+ taskIconDataSource.shouldLoadSynchronously = false
systemUnderTest.setVisibleTasks(listOf(0, 1))
- assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail).isNull()
+ val task2AfterVisibleTasksChanged = systemUnderTest.getTaskDataById(2).first()!!
+ assertThat(task2AfterVisibleTasksChanged.thumbnail).isNull()
+ assertThat(task2AfterVisibleTasksChanged.icon).isNull()
+ assertThat(task2AfterVisibleTasksChanged.titleDescription).isNull()
+ assertThat(task2AfterVisibleTasksChanged.title).isNull()
}
@Test
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/util/GetThumbnailUseCaseTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/util/GetThumbnailUseCaseTest.kt
new file mode 100644
index 0000000..414f8ca
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/util/GetThumbnailUseCaseTest.kt
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.util
+
+import android.content.ComponentName
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.Color
+import com.android.quickstep.recents.data.FakeTasksRepository
+import com.android.quickstep.task.viewmodel.TaskOverlayViewModelTest
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+/** Test for [GetThumbnailUseCase] */
+class GetThumbnailUseCaseTest {
+ private val task =
+ Task(Task.TaskKey(TASK_ID, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+ colorBackground = Color.BLACK
+ }
+ private val thumbnailData =
+ ThumbnailData(
+ thumbnail =
+ mock<Bitmap>().apply {
+ whenever(width).thenReturn(THUMBNAIL_WIDTH)
+ whenever(height).thenReturn(THUMBNAIL_HEIGHT)
+ }
+ )
+
+ private val tasksRepository = FakeTasksRepository()
+ private val systemUnderTest = GetThumbnailUseCase(tasksRepository)
+
+ @Test
+ fun taskNotSeeded_returnsNull() {
+ assertThat(systemUnderTest.run(TASK_ID)).isNull()
+ }
+
+ @Test
+ fun taskNotLoaded_returnsNull() {
+ tasksRepository.seedTasks(listOf(task))
+
+ assertThat(systemUnderTest.run(TASK_ID)).isNull()
+ }
+
+ @Test
+ fun taskNotVisible_returnsNull() {
+ tasksRepository.seedTasks(listOf(task))
+ tasksRepository.seedThumbnailData(mapOf(TaskOverlayViewModelTest.TASK_ID to thumbnailData))
+
+ assertThat(systemUnderTest.run(TASK_ID)).isNull()
+ }
+
+ @Test
+ fun taskVisible_returnsThumbnail() {
+ tasksRepository.seedTasks(listOf(task))
+ tasksRepository.seedThumbnailData(mapOf(TaskOverlayViewModelTest.TASK_ID to thumbnailData))
+ tasksRepository.setVisibleTasks(listOf(TaskOverlayViewModelTest.TASK_ID))
+
+ assertThat(systemUnderTest.run(TASK_ID)).isEqualTo(thumbnailData.thumbnail)
+ }
+
+ companion object {
+ const val TASK_ID = 0
+ const val THUMBNAIL_WIDTH = 100
+ const val THUMBNAIL_HEIGHT = 200
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
index a9f5dcd..f3cde52 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitAnimationControllerTest.kt
@@ -87,7 +87,7 @@
@Before
fun setup() {
whenever(mockTaskContainer.snapshotView).thenReturn(mockSnapshotView)
- whenever(mockTaskContainer.thumbnail).thenReturn(mockBitmap)
+ whenever(mockTaskContainer.splitAnimationThumbnail).thenReturn(mockBitmap)
whenever(mockTaskContainer.iconView).thenReturn(mockIconView)
whenever(mockIconView.drawable).thenReturn(mockTaskViewDrawable)
whenever(mockTaskView.taskContainers).thenReturn(List(1) { mockTaskContainer })
diff --git a/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java b/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
index 298dd6c..f5d082d 100644
--- a/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
@@ -21,6 +21,7 @@
import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.any;
@@ -288,6 +289,34 @@
assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion2.getX(), inRegion2.getY()));
}
+ @Test
+ public void testSimpleOrientationTouchTransformer() {
+ final DisplayController displayController = mock(DisplayController.class);
+ doReturn(mInfo).when(displayController).getInfo();
+ final SimpleOrientationTouchTransformer transformer =
+ new SimpleOrientationTouchTransformer(getApplicationContext(), displayController);
+ final MotionEvent move1 = generateMotionEvent(MotionEvent.ACTION_MOVE, 100, 10);
+ transformer.transform(move1, Surface.ROTATION_90);
+ // The position is transformed to 90 degree.
+ assertEquals(10, move1.getX(), 0f /* delta */);
+ assertEquals(NORMAL_SCREEN_SIZE.getWidth() - 100, move1.getY(), 0f /* delta */);
+
+ // If the touching state is specified, the position is still transformed to 90 degree even
+ // if the given rotation is changed.
+ final MotionEvent move2 = generateMotionEvent(MotionEvent.ACTION_MOVE, 100, 10);
+ transformer.updateTouchingOrientation(Surface.ROTATION_90);
+ transformer.transform(move2, Surface.ROTATION_0);
+ assertEquals(move1.getX(), move2.getX(), 0f /* delta */);
+ assertEquals(move1.getY(), move2.getY(), 0f /* delta */);
+
+ // If the touching state is cleared, it restores to use the given rotation.
+ final MotionEvent move3 = generateMotionEvent(MotionEvent.ACTION_MOVE, 100, 10);
+ transformer.clearTouchingOrientation();
+ transformer.transform(move3, Surface.ROTATION_0);
+ assertEquals(100, move3.getX(), 0f /* delta */);
+ assertEquals(10, move3.getY(), 0f /* delta */);
+ }
+
private DisplayController.Info createDisplayInfo(Size screenSize, int rotation) {
Point displaySize = new Point(screenSize.getWidth(), screenSize.getHeight());
RotationUtils.rotateSize(displaySize, rotation);
diff --git a/res/anim-v33/shared_x_axis_activity_close_enter.xml b/res/anim-v33/shared_x_axis_activity_close_enter.xml
deleted file mode 100644
index 3d7ad2b..0000000
--- a/res/anim-v33/shared_x_axis_activity_close_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 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.
- -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:showBackdrop="true">
-
- <alpha
- android:fromAlpha="0.0"
- android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/standard_decelerate_interpolator"
- android:startOffset="100"
- android:duration="350" />
-
- <translate
- android:fromXDelta="-25%"
- android:toXDelta="0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/emphasized_interpolator"
- android:startOffset="0"
- android:duration="450" />
-
-</set>
\ No newline at end of file
diff --git a/res/anim-v33/shared_x_axis_activity_close_exit.xml b/res/anim-v33/shared_x_axis_activity_close_exit.xml
deleted file mode 100644
index fb63602..0000000
--- a/res/anim-v33/shared_x_axis_activity_close_exit.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 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.
- -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
-
- <alpha
- android:fromAlpha="1.0"
- android:toAlpha="0.0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/standard_accelerate_interpolator"
- android:startOffset="0"
- android:duration="100" />
-
- <translate
- android:fromXDelta="0"
- android:toXDelta="25%"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/emphasized_interpolator"
- android:startOffset="0"
- android:duration="450" />
-
-</set>
\ No newline at end of file
diff --git a/res/anim-v33/shared_x_axis_activity_open_enter.xml b/res/anim-v33/shared_x_axis_activity_open_enter.xml
deleted file mode 100644
index cba74ba..0000000
--- a/res/anim-v33/shared_x_axis_activity_open_enter.xml
+++ /dev/null
@@ -1,42 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 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.
- -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false"
- android:showBackdrop="true">
-
- <alpha
- android:fromAlpha="0.0"
- android:toAlpha="1.0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/standard_decelerate_interpolator"
- android:startOffset="100"
- android:duration="350" />
-
- <translate
- android:fromXDelta="25%"
- android:toXDelta="0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/emphasized_interpolator"
- android:startOffset="0"
- android:duration="450" />
-
-</set>
\ No newline at end of file
diff --git a/res/anim-v33/shared_x_axis_activity_open_exit.xml b/res/anim-v33/shared_x_axis_activity_open_exit.xml
deleted file mode 100644
index 22e878d..0000000
--- a/res/anim-v33/shared_x_axis_activity_open_exit.xml
+++ /dev/null
@@ -1,41 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 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.
- -->
-
-<set xmlns:android="http://schemas.android.com/apk/res/android"
- android:shareInterpolator="false">
-
- <alpha
- android:fromAlpha="1.0"
- android:toAlpha="0.0"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/standard_accelerate_interpolator"
- android:startOffset="0"
- android:duration="100" />
-
- <translate
- android:fromXDelta="0"
- android:toXDelta="-25%"
- android:fillEnabled="true"
- android:fillBefore="true"
- android:fillAfter="true"
- android:interpolator="@interpolator/emphasized_interpolator"
- android:startOffset="0"
- android:duration="450" />
-
-</set>
\ No newline at end of file
diff --git a/res/drawable/ic_close_work_edu.xml b/res/drawable/ic_close_work_edu.xml
new file mode 100644
index 0000000..f336eea
--- /dev/null
+++ b/res/drawable/ic_close_work_edu.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="960"
+ android:viewportHeight="960">
+ <path
+ android:fillColor="@color/material_color_on_surface"
+ android:pathData="M256,760L200,704L424,480L200,256L256,200L480,424L704,200L760,256L536,480L760,704L704,760L480,536L256,760Z"/>
+</vector>
diff --git a/res/drawable/rounded_action_button.xml b/res/drawable/rounded_action_button.xml
index 81e94f7..e283d3f 100644
--- a/res/drawable/rounded_action_button.xml
+++ b/res/drawable/rounded_action_button.xml
@@ -18,11 +18,11 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurfaceVariant" />
+ <solid android:color="@color/material_color_surface_container_low" />
<corners android:radius="@dimen/rounded_button_radius" />
<stroke
android:width="1dp"
- android:color="?androidprv:attr/colorSurfaceVariant" />
+ android:color="@color/material_color_surface_container_low" />
<padding
android:left="@dimen/rounded_button_padding"
android:right="@dimen/rounded_button_padding" />
diff --git a/res/drawable/work_card.xml b/res/drawable/work_card.xml
index 4a66cac..9bf2b8d 100644
--- a/res/drawable/work_card.xml
+++ b/res/drawable/work_card.xml
@@ -16,9 +16,8 @@
<shape xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
android:shape="rectangle">
- <solid android:color="?androidprv:attr/colorSurface" />
+ <solid android:color="@color/material_color_surface_container_highest" />
<corners android:radius="@dimen/work_edu_card_radius" />
</shape>
diff --git a/res/layout/work_apps_edu.xml b/res/layout/work_apps_edu.xml
index 99db8c6..c581ae3 100644
--- a/res/layout/work_apps_edu.xml
+++ b/res/layout/work_apps_edu.xml
@@ -54,7 +54,7 @@
android:layout_gravity="center"
android:contentDescription="@string/accessibility_close"
android:background="@android:color/transparent"
- android:src="@drawable/ic_remove_no_shadow" />
+ android:src="@drawable/ic_close_work_edu" />
</FrameLayout>
</LinearLayout>
</com.android.launcher3.allapps.WorkEduCard>
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 90e784d..1a8f8e2 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Legstukke gedeaktiveer in Veiligmodus"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Kortpad is nie beskikbaar nie"</string>
<string name="home_screen" msgid="5629429142036709174">"Tuis"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Stel <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> as verstektuisskermapp in Instellings"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Verdeelde skerm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Programinligting vir %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Gebruikinstellings vir %1$s"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 1289b8c..80447c5 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"ምግብሮች በደህንነቱ የተጠበቀ ሁኔታ ተሰናክለዋል"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"አቋራጭ አይገኝም"</string>
<string name="home_screen" msgid="5629429142036709174">"መነሻ"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"በቅንብሮች ውስጥ <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>ን እንደ ነባሪ የHome መተግበሪያ ያቀናብሩ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"የተከፈለ ማያ ገፅ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"የመተግበሪያ መረጃ ለ%1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"የ%1$s የአጠቃቀም ቅንብሮች"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 37d6fba..4eee121 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"الأدوات غير مفعّلة في الوضع الآمن"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"الاختصار غير متاح"</string>
<string name="home_screen" msgid="5629429142036709174">"الشاشة الرئيسية"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"يمكن ضبط \"<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>\" كتطبيق الشاشة الرئيسية التلقائي من خلال \"الإعدادات\""</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"تقسيم الشاشة"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"معلومات تطبيق %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"إعدادات استخدام \"%1$s\""</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index e983ce8..52ec7ea 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"ৱিজেটবোৰক সুৰক্ষিত ম\'ডত অক্ষম কৰা হ’ল"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"শ্বৰ্টকাট নাই"</string>
<string name="home_screen" msgid="5629429142036709174">"গৃহ স্ক্ৰীন"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"ছেটিঙত <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>ক ডিফ’ল্ট গৃহপৃষ্ঠা এপ্ হিচাপে ছেট কৰক"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"বিভাজিত স্ক্ৰীন"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$sৰ বাবে এপৰ তথ্য"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$sৰ বাবে ব্যৱহাৰৰ ছেটিং"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index f390c7c..6c1cc46 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Vidcetlər Güvənli rejimdə deaktiv edilib"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Qısayol əlçatan deyil"</string>
<string name="home_screen" msgid="5629429142036709174">"Əsas səhifə"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Ayarlarda <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> tətbiqini defolt əsas ekran tətbiqi kimi ayarlayın"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ekran bölünməsi"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ilə bağlı tətbiq məlumatı"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s üzrə istifadə ayarları"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index fc71eeb..24328cf 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Vidžeti su onemogućeni u Bezbednom režimu"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Prečica nije dostupna"</string>
<string name="home_screen" msgid="5629429142036709174">"Početni ekran"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Podesite <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> kao podrazumevanu početnu aplikaciju u Podešavanjima"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podeljeni ekran"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji za: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Podešavanja potrošnje za %1$s"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 4589125..ebbb378 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Віджэты адключаны ў Бяспечным рэжыме"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Ярлык недаступны"</string>
<string name="home_screen" msgid="5629429142036709174">"Галоўны экран"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Зрабіць <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> стандартнай праграмай для галоўнага экрана, перайшоўшы ў Налады"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Падзелены экран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Інфармацыя пра праграму для: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s: налады выкарыстання"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 643c24e..d5d948e 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Приспособленията са деактивирани в безопасния режим"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Няма достъп до прекия път"</string>
<string name="home_screen" msgid="5629429142036709174">"Начален екран"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"От настройките задайте <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> като основното приложение за начален екран"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Разделен екран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Информация за приложението за %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Настройки за използването на %1$s"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 7e10a0e..cf75fb58 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"সুরক্ষিত মোডে উইজেট নিষ্ক্রিয় থাকে"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"শর্টকাটগুলি অনুপলব্ধ"</string>
<string name="home_screen" msgid="5629429142036709174">"হোম"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"সেটিংসে গিয়ে <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> অ্যাপকে ডিফল্ট হোম অ্যাপ হিসেবে সেট করুন"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"স্প্লিট স্ক্রিন"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-এর জন্য অ্যাপ সম্পর্কিত তথ্য"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s-এর জন্য ব্যবহারের সেটিংস"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 10aa86a..1758c39 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Vidžeti su onemogućeni u sigurnom načinu rada."</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Prečica nije dostupna"</string>
<string name="home_screen" msgid="5629429142036709174">"Početni ekran"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Postavite <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> kao zadanu aplikaciju za početni ekran u Postavkama"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podijeljeni ekran"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Postavke korištenja za: %1$s"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 3d2ff4a..bf578f5 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"En Mode segur, els widgets estan desactivats."</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"La drecera no està disponible"</string>
<string name="home_screen" msgid="5629429142036709174">"Inici"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Defineix <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> com a aplicació d\'inici predeterminada a Configuració"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informació de l\'aplicació %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Configuració d\'ús de %1$s"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 14a3583..9a8fc6f 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"V nouzovém režimu jsou widgety zakázány."</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Zkratka není k dispozici"</string>
<string name="home_screen" msgid="5629429142036709174">"Domů"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Nastavit <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> jako výchozí vstupní aplikaci v Nastavení"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Rozdělit obrazovku"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informace o aplikaci %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Nastavení využití pro aplikaci %1$s"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index f18e1e8..208c2ef 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets er deaktiveret i Beskyttet tilstand"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Genvejen er ikke tilgængelig"</string>
<string name="home_screen" msgid="5629429142036709174">"Startskærm"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Angiv <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> som standardstartapp i Indstillinger"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Opdel skærm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinfo for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Indstillinger for brug af %1$s"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 9a4e5e2..380030b 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets im abgesicherten Modus deaktiviert"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Verknüpfung nicht verfügbar"</string>
<string name="home_screen" msgid="5629429142036709174">"Startbildschirm"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> in den Einstellungen als Stand-Start-App festlegen"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Splitscreen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App-Info für %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Nutzungseinstellungen für %1$s"</string>
@@ -37,7 +36,7 @@
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Dieses App-Paar wird auf diesem Gerät nicht unterstützt"</string>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"Gerät aufklappen, um dieses App-Paar zu verwenden"</string>
<string name="app_pair_not_available" msgid="3556767440808032031">"App-Paar nicht verfügbar"</string>
- <string name="long_press_widget_to_add" msgid="3587712543577675817">"Zum Verschieben des Widgets berühren und halten"</string>
+ <string name="long_press_widget_to_add" msgid="3587712543577675817">"Zum Verschieben des Widgets gedrückt halten"</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Doppeltippen und halten, um ein Widget zu bewegen oder benutzerdefinierte Aktionen zu nutzen."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breit und %2$d hoch"</string>
@@ -75,7 +74,7 @@
<string name="label_application" msgid="8531721983832654978">"App"</string>
<string name="all_apps_label" msgid="5015784846527570951">"Alle Apps"</string>
<string name="notifications_header" msgid="1404149926117359025">"Benachrichtigungen"</string>
- <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Zum Verschieben einer Verknüpfung berühren und halten"</string>
+ <string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Zum Verschieben einer Verknüpfung gedrückt halten"</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Doppeltippen und halten, um eine Verknüpfung zu bewegen oder benutzerdefinierte Aktionen zu nutzen."</string>
<string name="out_of_space" msgid="6455557115204099579">"Auf diesem Startbildschirm ist kein Platz mehr vorhanden"</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Ablage \"Favoriten\" ist voll."</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 840ff5b..e86ebae 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Τα γραφικά στοιχεία απενεργοποιήθηκαν στην ασφαλή λειτουργία"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Η συντόμευση δεν είναι διαθέσιμη"</string>
<string name="home_screen" msgid="5629429142036709174">"Αρχική οθόνη"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Ορίστε το <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> ως την προεπιλεγμένη εφαρμογή αρχικής οθόνης στις Ρυθμίσεις"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Διαχωρισμός οθόνης"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Πληροφορίες εφαρμογής για %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Ρυθμίσεις χρήσης για %1$s"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 4deacb6..50c5976 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets disabled in Safe mode"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Shortcut isn\'t available"</string>
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Set <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> as the default home app in Settings"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Usage settings for %1$s"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 4deacb6..50c5976 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets disabled in Safe mode"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Shortcut isn\'t available"</string>
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Set <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> as the default home app in Settings"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Usage settings for %1$s"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 4deacb6..50c5976 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets disabled in Safe mode"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Shortcut isn\'t available"</string>
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Set <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> as the default home app in Settings"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App info for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Usage settings for %1$s"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index e734744..5879129 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets inhabilitados en modo seguro"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"El acceso directo no está disponible"</string>
<string name="home_screen" msgid="5629429142036709174">"Pantalla principal"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Establece <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> como la app de inicio predeterminada en Configuración"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la app de %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Configuración del uso de %1$s"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 3e0e516..8d384ac 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets inhabilitados en modo Seguro"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Acceso directo no disponible"</string>
<string name="home_screen" msgid="5629429142036709174">"Inicio"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Define <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> como aplicación de inicio predeterminada en Ajustes"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información de la aplicación %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Ajustes de uso para %1$s"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index bab7da3..44448a6 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Turvarežiimis on vidinad keelatud"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Otsetee pole saadaval"</string>
<string name="home_screen" msgid="5629429142036709174">"Avakuva"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Määrake rakendus <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> seadetes avakuva vaikerakenduseks"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Jagatud ekraanikuva"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Rakenduse teave: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Kasutuse seaded: %1$s"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index b8017d6..6fc4cf4 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgetak desgaitu egin dira modu seguruan"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Lasterbideak ez daude erabilgarri"</string>
<string name="home_screen" msgid="5629429142036709174">"Orri nagusia"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Ezarri <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> hasierako aplikazio lehenetsi gisa ezarpenetan"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantaila zatitzea"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s aplikazioari buruzko informazioa"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s aplikazioaren erabilera-ezarpenak"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 27ce075..fffce13 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"ابزارکها در حالت ایمن غیرفعال هستند"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"میانبر دردسترس نیست"</string>
<string name="home_screen" msgid="5629429142036709174">"صفحه اصلی"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"تنظیم <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> بهعنوان برنامه صفحه اصلی پیشفرض در «تنظیمات»"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"صفحهٔ دونیمه"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"اطلاعات برنامه %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"تنظیمات مصرف برای %1$s"</string>
@@ -38,7 +37,7 @@
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"برای استفاده از این جفت برنامه، دستگاه را باز کنید"</string>
<string name="app_pair_not_available" msgid="3556767440808032031">"جفت برنامه دردسترس نیست"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"برای جابهجا کردن ابزارک، لمس کنید و نگه دارید."</string>
- <string name="long_accessible_way_to_add" msgid="2733588281439571974">"برای جابهجا کردن ابزارک یا استفاده از کنشهای سفارشی، دوضربه بزنید و نگه دارید."</string>
+ <string name="long_accessible_way_to_add" msgid="2733588281439571974">"برای جابهجا کردن ابزارک یا استفاده از کنشهای سفارشی، دو تکضرب بزنید و نگه دارید."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d عرض در %2$d طول"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"ابزارک <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
@@ -76,7 +75,7 @@
<string name="all_apps_label" msgid="5015784846527570951">"همه برنامهها"</string>
<string name="notifications_header" msgid="1404149926117359025">"اعلانها"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"برای جابهجا کردن میانبر، لمس کنید و نگه دارید."</string>
- <string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"برای جابهجا کردن میانبر یا استفاده از کنشهای سفارشی، دوضربه بزنید و نگه دارید."</string>
+ <string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"برای جابهجا کردن میانبر یا استفاده از کنشهای سفارشی، دو تکضرب بزنید و نگه دارید."</string>
<string name="out_of_space" msgid="6455557115204099579">"فضای خالی در این صفحه اصلی وجود ندارد"</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"فضای بیشتری در سینی موارد دلخواه وجود ندارد"</string>
<string name="all_apps_button_label" msgid="8130441508702294465">"فهرست برنامهها"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 181c89e..310053e 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgetit poistettu käytöstä vikasietotilassa"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Pikakuvake ei ole käytettävissä."</string>
<string name="home_screen" msgid="5629429142036709174">"Etusivu"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Valitse <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> oletusaloitusnäyttösovellukseksi asetuksissa"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Jaettu näyttö"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Sovellustiedot: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Käyttöasetus tälle: %1$s"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index f3b08cb..11b2c01 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -21,22 +21,21 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="app_name" msgid="649227358658669779">"Lanceur3"</string>
<string name="work_folder_name" msgid="3753320833950115786">"Travail"</string>
- <string name="activity_not_found" msgid="8071924732094499514">"L\'application n\'est pas installée."</string>
- <string name="activity_not_available" msgid="7456344436509528827">"Application indisponible"</string>
- <string name="safemode_shortcut_error" msgid="9160126848219158407">"L\'application téléchargée est désactivée en mode sans échec."</string>
+ <string name="activity_not_found" msgid="8071924732094499514">"L\'appli n\'est pas installée."</string>
+ <string name="activity_not_available" msgid="7456344436509528827">"Appli indisponible"</string>
+ <string name="safemode_shortcut_error" msgid="9160126848219158407">"L\'appli téléchargée est désactivée en mode sans échec."</string>
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets désactivés en mode sans échec"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Le raccourci n\'est pas disponible"</string>
<string name="home_screen" msgid="5629429142036709174">"Accueil"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Définissez <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> comme appli d\'accueil par défaut dans les paramètres"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran divisé"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Renseignements sur l\'appli pour %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Paramètres d\'utilisation pour %1$s"</string>
<string name="save_app_pair" msgid="5647523853662686243">"Enr. paire d\'applis"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
- <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applications n\'est pas prise en charge sur cet appareil"</string>
- <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Déplier l\'appareil pour utiliser cette paire d\'applications"</string>
- <string name="app_pair_not_available" msgid="3556767440808032031">"La Paire d\'applications n\'est pas offerte"</string>
+ <string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applis n\'est pas prise en charge sur cet appareil"</string>
+ <string name="app_pair_needs_unfold" msgid="4588897528143807002">"Déplier l\'appareil pour utiliser cette paire d\'applis"</string>
+ <string name="app_pair_not_available" msgid="3556767440808032031">"La Paire d\'applis n\'est pas offerte"</string>
<string name="long_press_widget_to_add" msgid="3587712543577675817">"Maintenez le doigt sur un widget pour le déplacer."</string>
<string name="long_accessible_way_to_add" msgid="2733588281439571974">"Touchez 2x un widget et maintenez le doigt dessus pour le déplacer ou utiliser des actions personnalisées."</string>
<string name="widget_dims_format" msgid="2370757736025621599">"%1$d × %2$d"</string>
@@ -69,20 +68,20 @@
<string name="widget_add_button_content_description" msgid="1810530016360039643">"Ajoutez le widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="reconfigurable_widget_education_tip" msgid="6336962690888067057">"Touchez pour modifier les paramètres du widget"</string>
<string name="widget_reconfigure_button_content_description" msgid="8811472721881205250">"Modifier les paramètres du widget"</string>
- <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Rechercher dans les applications"</string>
- <string name="all_apps_loading_message" msgid="5813968043155271636">"Chargement des applications en cours…"</string>
- <string name="all_apps_no_search_results" msgid="3200346862396363786">"Aucune application trouvée correspondant à « <xliff:g id="QUERY">%1$s</xliff:g> »"</string>
- <string name="label_application" msgid="8531721983832654978">"Application"</string>
- <string name="all_apps_label" msgid="5015784846527570951">"Toutes les applications"</string>
+ <string name="all_apps_search_bar_hint" msgid="1390553134053255246">"Rechercher dans les applis"</string>
+ <string name="all_apps_loading_message" msgid="5813968043155271636">"Chargement des applis en cours…"</string>
+ <string name="all_apps_no_search_results" msgid="3200346862396363786">"Aucune appli trouvée correspondant à « <xliff:g id="QUERY">%1$s</xliff:g> »"</string>
+ <string name="label_application" msgid="8531721983832654978">"Appli"</string>
+ <string name="all_apps_label" msgid="5015784846527570951">"Toutes les applis"</string>
<string name="notifications_header" msgid="1404149926117359025">"Notifications"</string>
<string name="long_press_shortcut_to_add" msgid="5405328730817637737">"Maintenez le doigt sur un raccourci pour le déplacer."</string>
<string name="long_accessible_way_to_add_shortcut" msgid="2199537273817090740">"Touchez deux fois un raccourci et maintenez le doigt dessus pour le déplacer ou utiliser des actions personnalisées."</string>
<string name="out_of_space" msgid="6455557115204099579">"Pas d\'espace libre sur cet écran d\'accueil"</string>
<string name="hotseat_out_of_space" msgid="7448809638125333693">"Il n\'y a plus d\'espace dans la zone des favoris"</string>
- <string name="all_apps_button_label" msgid="8130441508702294465">"Liste des applications"</string>
+ <string name="all_apps_button_label" msgid="8130441508702294465">"Liste des applis"</string>
<string name="all_apps_search_results" msgid="5889367432531296759">"Résultats de recherche"</string>
- <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Liste des applications personnelles"</string>
- <string name="all_apps_button_work_label" msgid="7270707118948892488">"Liste des applications professionnelles"</string>
+ <string name="all_apps_button_personal_label" msgid="1315764287305224468">"Liste des applis personnelles"</string>
+ <string name="all_apps_button_work_label" msgid="7270707118948892488">"Liste des applis professionnelles"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Supprimer"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Désinstaller"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Détails de l\'appli"</string>
@@ -92,17 +91,17 @@
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'appli"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"installer des raccourcis"</string>
- <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet à une application d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string>
+ <string name="permdesc_install_shortcut" msgid="923466509822011139">"Permet à une appli d\'ajouter des raccourcis sans l\'intervention de l\'utilisateur."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"lire les paramètres et les raccourcis de la page d\'accueil"</string>
- <string name="permdesc_read_settings" msgid="4208061150510996676">"Permet à l\'application de lire les paramètres et les raccourcis de l\'écran d\'accueil."</string>
+ <string name="permdesc_read_settings" msgid="4208061150510996676">"Permet à l\'appli de lire les paramètres et les raccourcis de l\'écran d\'accueil."</string>
<string name="permlab_write_settings" msgid="4820028712156303762">"modifier les paramètres et les raccourcis de la page d\'accueil"</string>
- <string name="permdesc_write_settings" msgid="726859348127868466">"Permet à l\'application de modifier les paramètres et les raccourcis de l\'écran d\'accueil."</string>
+ <string name="permdesc_write_settings" msgid="726859348127868466">"Permet à l\'appli de modifier les paramètres et les raccourcis de l\'écran d\'accueil."</string>
<string name="gadget_error_text" msgid="740356548025791839">"Impossible de charger le widget"</string>
<string name="gadget_setup_text" msgid="8348374825537681407">"Paramètres du widget"</string>
<string name="gadget_complete_setup_text" msgid="309040266978007925">"Touchez pour terminer la configuration"</string>
- <string name="uninstall_system_app_text" msgid="4172046090762920660">"Impossible de désinstaller cette application, car il s\'agit d\'une application système."</string>
+ <string name="uninstall_system_app_text" msgid="4172046090762920660">"Impossible de désinstaller cette appli, car il s\'agit d\'une appli système."</string>
<string name="folder_hint_text" msgid="5174843001373488816">"Modifier le nom"</string>
- <string name="disabled_app_label" msgid="6673129024321402780">"L\'application <xliff:g id="APP_NAME">%1$s</xliff:g> est désactivée"</string>
+ <string name="disabled_app_label" msgid="6673129024321402780">"L\'appli <xliff:g id="APP_NAME">%1$s</xliff:g> est désactivée"</string>
<string name="dotted_app_label" msgid="1865617679843363410">"{count,plural, =1{{app_name} a # notification}one{{app_name} a # notification}other{{app_name} a # notifications}}"</string>
<string name="default_scroll_format" msgid="7475544710230993317">"Page %1$d sur %2$d"</string>
<string name="workspace_scroll_format" msgid="8458889198184077399">"Écran d\'accueil %1$d sur %2$d"</string>
@@ -114,7 +113,7 @@
<string name="folder_renamed" msgid="1794088362165669656">"Nouveau nom du dossier : <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="folder_name_format_exact" msgid="8626242716117004803">"Dossier : <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> élément(s)"</string>
<string name="folder_name_format_overflow" msgid="4270108890534995199">"Dossier : <xliff:g id="NAME">%1$s</xliff:g>, <xliff:g id="SIZE">%2$d</xliff:g> éléments ou plus"</string>
- <string name="app_pair_name_format" msgid="8134106404716224054">"Paire d\'applications : <xliff:g id="APP1">%1$s</xliff:g> et <xliff:g id="APP2">%2$s</xliff:g>"</string>
+ <string name="app_pair_name_format" msgid="8134106404716224054">"Paire d\'applis : <xliff:g id="APP1">%1$s</xliff:g> et <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="styles_wallpaper_button_text" msgid="8216961355289236794">"Fond d\'écran et style"</string>
<string name="edit_home_screen" msgid="8947858375782098427">"Modifier l\'écran d\'accueil"</string>
<string name="settings_button_text" msgid="8873672322605444408">"Paramètres d\'accueil"</string>
@@ -125,23 +124,23 @@
<string name="notification_dots_desc_on" msgid="1679848116452218908">"Activé"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Désactivé"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"L\'accès aux notifications est requis"</string>
- <string name="msg_missing_notification_access" msgid="281113995110910548">"Pour afficher les points de notification, activez les notifications d\'application pour <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="msg_missing_notification_access" msgid="281113995110910548">"Pour afficher les points de notification, activez les notifications d\'appli pour <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="title_change_settings" msgid="1376365968844349552">"Modifier les paramètres"</string>
<string name="notification_dots_service_title" msgid="4284221181793592871">"Afficher les points de notification"</string>
<string name="developer_options_title" msgid="700788437593726194">"Options pour les développeurs"</string>
- <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Ajouter les icônes des applications à l\'écran d\'accueil"</string>
- <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pour les nouvelles applications"</string>
+ <string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Ajouter les icônes des applis à l\'écran d\'accueil"</string>
+ <string name="auto_add_shortcuts_description" msgid="7117251166066978730">"Pour les nouvelles applis"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"Inconnu"</string>
<string name="abandoned_clean_this" msgid="7610119707847920412">"Supprimer"</string>
<string name="abandoned_search" msgid="891119232568284442">"Rechercher"</string>
- <string name="abandoned_promises_title" msgid="7096178467971716750">"Cette application n\'est pas installée"</string>
- <string name="abandoned_promise_explanation" msgid="3990027586878167529">"L\'application liée à cette icône n\'est pas installée. Vous pouvez la supprimer ou rechercher l\'application et l\'installer manuellement."</string>
- <string name="app_installing_title" msgid="5864044122733792085">"Installation de l\'application <xliff:g id="NAME">%1$s</xliff:g> en cours, <xliff:g id="PROGRESS">%2$s</xliff:g> terminée"</string>
+ <string name="abandoned_promises_title" msgid="7096178467971716750">"Cette appli n\'est pas installée"</string>
+ <string name="abandoned_promise_explanation" msgid="3990027586878167529">"L\'appli liée à cette icône n\'est pas installée. Vous pouvez la supprimer ou rechercher l\'appli et l\'installer manuellement."</string>
+ <string name="app_installing_title" msgid="5864044122733792085">"Installation de l\'appli <xliff:g id="NAME">%1$s</xliff:g> en cours, <xliff:g id="PROGRESS">%2$s</xliff:g> terminée"</string>
<string name="app_downloading_title" msgid="8336702962104482644">"Téléchargement de <xliff:g id="NAME">%1$s</xliff:g> : <xliff:g id="PROGRESS">%2$s</xliff:g>"</string>
<string name="app_waiting_download_title" msgid="7053938513995617849">"<xliff:g id="NAME">%1$s</xliff:g> en attente d\'installation"</string>
<string name="app_archived_title" msgid="7717956158562544081">"L\'appli <xliff:g id="NAME">%1$s</xliff:g> est archivée. Touchez le bouton pour télécharger et restaurer l\'appli."</string>
- <string name="dialog_update_title" msgid="114234265740994042">"Mise à jour de l\'application requise"</string>
- <string name="dialog_update_message" msgid="4176784553982226114">"L\'application pour cette icône n\'est pas à jour. Vous pouvez soit la mettre à jour manuellement pour réactiver ce raccourci, soit retirer l\'icône."</string>
+ <string name="dialog_update_title" msgid="114234265740994042">"Mise à jour de l\'appli requise"</string>
+ <string name="dialog_update_message" msgid="4176784553982226114">"L\'appli pour cette icône n\'est pas à jour. Vous pouvez soit la mettre à jour manuellement pour réactiver ce raccourci, soit retirer l\'icône."</string>
<string name="dialog_update" msgid="2178028071796141234">"Mettre à jour"</string>
<string name="dialog_remove" msgid="6510806469849709407">"Retirer"</string>
<string name="widgets_list" msgid="796804551140113767">"Liste des widgets"</string>
@@ -174,15 +173,15 @@
<string name="all_apps_personal_tab" msgid="4190252696685155002">"Personnel"</string>
<string name="all_apps_work_tab" msgid="4884822796154055118">"Travail"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Profil professionnel"</string>
- <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Les applications professionnelles sont indiquées par un badge et elles sont visibles pour votre administrateur informatique"</string>
+ <string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Les applis professionnelles sont indiquées par un badge et elles sont visibles pour votre administrateur informatique"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"OK"</string>
- <string name="work_apps_paused_title" msgid="3040901117349444598">"Les applications professionnelles sont interrompues"</string>
- <string name="work_apps_paused_info_body" msgid="1687828929959237477">"Vous ne recevrez pas de notifications de vos applications professionnelles"</string>
- <string name="work_apps_paused_body" msgid="261634750995824906">"Les applications professionnelles ne peuvent ni vous envoyer de notifications, ni utiliser la pile, ni accéder à votre position"</string>
- <string name="work_apps_paused_telephony_unavailable_body" msgid="8358872357502756790">"Vous ne recevrez pas d\'appels téléphoniques, de messages texte ni de notifications de vos applications professionnelles"</string>
- <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"Les applications professionnelles sont indiquées par un badge et sont visibles pour votre administrateur informatique"</string>
+ <string name="work_apps_paused_title" msgid="3040901117349444598">"Les applis professionnelles sont interrompues"</string>
+ <string name="work_apps_paused_info_body" msgid="1687828929959237477">"Vous ne recevrez pas de notifications de vos applis professionnelles"</string>
+ <string name="work_apps_paused_body" msgid="261634750995824906">"Les applis professionnelles ne peuvent ni vous envoyer de notifications, ni utiliser la pile, ni accéder à votre position"</string>
+ <string name="work_apps_paused_telephony_unavailable_body" msgid="8358872357502756790">"Vous ne recevrez pas d\'appels téléphoniques, de messages texte ni de notifications de vos applis professionnelles"</string>
+ <string name="work_apps_paused_edu_banner" msgid="8872412121608402058">"Les applis professionnelles sont indiquées par un badge et sont visibles pour votre administrateur informatique"</string>
<string name="work_apps_paused_edu_accept" msgid="6377476824357318532">"OK"</string>
- <string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Mettre en pause les applications professionnelles"</string>
+ <string name="work_apps_pause_btn_text" msgid="4669288269140620646">"Mettre en pause les applis professionnelles"</string>
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Réactiver"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrer"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
@@ -195,5 +194,5 @@
<string name="ps_container_lock_title" msgid="2640257399982364682">"Verrouiller"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Transition vers l\'Espace privé"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Installer"</string>
- <string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer des applications dans l\'Espace privé"</string>
+ <string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer des applis dans l\'Espace privé"</string>
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 4a7c7fb..b4c5ec6 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Les widgets sont désactivés en mode sécurisé."</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Raccourci non disponible"</string>
<string name="home_screen" msgid="5629429142036709174">"Accueil"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Définissez <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> comme application d\'accueil par défaut dans Paramètres"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Écran partagé"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Infos sur l\'appli pour %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Paramètres d\'utilisation pour %1$s"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 0430a9a..ac72802 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Os widgets están desactivados no modo seguro"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"O atallo non está dispoñible"</string>
<string name="home_screen" msgid="5629429142036709174">"Inicio"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Define <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> como aplicación de inicio predeterminada en Configuración"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Pantalla dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Información da aplicación para %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Configuración de uso para %1$s"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index 3c248db..74747d0 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"સુરક્ષિત મોડમાં વિજેટ્સ અક્ષમ કર્યા"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"શૉર્ટકટ ઉપલબ્ધ નથી"</string>
<string name="home_screen" msgid="5629429142036709174">"હોમ સ્ક્રીન"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"સેટિંગમાં <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>ને ડિફૉલ્ટ હોમ ઍપ તરીકે સેટ કરો"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"સ્ક્રીનને વિભાજિત કરો"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s માટે ઍપ માહિતી"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$sના વપરાશ સંબંધિત સેટિંગ"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 50d4762..6071935 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"विजेट सुरक्षित मोड में अक्षम हैं"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"शॉर्टकट उपलब्ध नहीं है"</string>
<string name="home_screen" msgid="5629429142036709174">"होम स्क्रीन"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"सेटिंग में जाकर, <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> को डिफ़ॉल्ट होम ऐप्लिकेशन के तौर पर सेट करें"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रीन"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s के लिए ऐप्लिकेशन की जानकारी"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s के लिए खर्च की सेटिंग"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 7a1fd94..cf7a91a 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgeti su onemogućeni u Sigurnom načinu rada"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Prečac nije dostupan"</string>
<string name="home_screen" msgid="5629429142036709174">"Početni zaslon"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Postavite aplikaciju <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> kao zadanu aplikaciju početnog zaslona u postavkama"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podijeljeni zaslon"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacije o aplikaciji %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Postavke upotrebe za %1$s"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 3b556da..f306110 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"A modulok ki vannak kapcsolva Csökkentett módban"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"A gyorsparancs nem áll rendelkezésre"</string>
<string name="home_screen" msgid="5629429142036709174">"Kezdőképernyő"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"A(z) <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> appot a Beállításokban adhatja meg alapértelmezett kezdőalkalmazásként."</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Osztott képernyő"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Alkalmazásinformáció a következőhöz: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"A(z) %1$s használati beállításai"</string>
@@ -188,7 +187,7 @@
<string name="remote_action_failed" msgid="1383965239183576790">"Sikertelen: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privát terület"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Koppintson a beállításhoz vagy a megnyitáshoz"</string>
- <string name="ps_container_title" msgid="4391796149519594205">"Privát terület"</string>
+ <string name="ps_container_title" msgid="4391796149519594205">"Privát"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Privát terület beállításai"</string>
<string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privát, feloldott."</string>
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privát, zárolt."</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 491ba05..2d345f2 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Վիջեթներն անջատված են անվտանգ ռեժիմում"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Դյուրանցումն անհասանելի է"</string>
<string name="home_screen" msgid="5629429142036709174">"Հիմնական էկրան"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Սահմանել <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> գործարկիչը որպես մեկնարկի կանխադրված հավելված Կարգավորումներում"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Տրոհել էկրանը"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Տեղեկություններ %1$s հավելվածի մասին"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Օգտագործման կարգավորումներ (%1$s)"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 1335385..9ced9f4 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widget dinonaktifkan dalam mode Aman"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Pintasan tidak tersedia"</string>
<string name="home_screen" msgid="5629429142036709174">"Layar utama"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Jadikan <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> sebagai aplikasi layar utama default di Setelan"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Layar terpisah"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Info aplikasi untuk %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Setelan penggunaan untuk %1$s"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 4865264..2ab7817 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Græjur eru óvirkar í öruggri stillingu"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Flýtileið er ekki tiltæk"</string>
<string name="home_screen" msgid="5629429142036709174">"Heim"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Stilltu <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> sem sjálfgefið heimaforrit í stillingunum"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Skipta skjá"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Upplýsingar um forrit fyrir %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Notkunarstillingar fyrir %1$s"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index 41b4b60..a59de6c 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widget disabilitati in modalità provvisoria"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"La scorciatoia non è disponibile"</string>
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Imposta <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> come app iniziale predefinita nelle Impostazioni"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Schermo diviso"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informazioni sull\'app %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Impostazioni di utilizzo per %1$s"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index ae71edd..89a0c8a 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"ווידג\'טים מושבתים במצב בטוח"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"קיצור הדרך אינו זמין"</string>
<string name="home_screen" msgid="5629429142036709174">"בית"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"הגדרה של <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> כאפליקציית הבית ב\'הגדרות\'"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"מסך מפוצל"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"פרטים על האפליקציה %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"הגדרות שימוש ב-%1$s"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index c64d335..b48c7be 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"セーフモードではウィジェットは無効です"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"ショートカットは使用できません"</string>
<string name="home_screen" msgid="5629429142036709174">"ホーム"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"[設定] で <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> をデフォルトのホームアプリに設定します"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割画面"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s のアプリ情報"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s の使用設定"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index bcced9a..76b8b5d 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"უსაფრთხო რეჟიმში ვიჯეტი გამორთულია"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"მალსახმობი მიუწვდომელია"</string>
<string name="home_screen" msgid="5629429142036709174">"მთავარი გვერდი"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>-ის დაყენება ნაგულისხმევ Home აპად პარამეტრებში"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ეკრანის გაყოფა"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-ის აპის ინფო"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"გამოყენების პარამეტრები %1$s-ისთვის"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index 62bb983..95d4420 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Қауіпсіз режимде виджеттер өшіріледі"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Таңбаша қолжетімді емес"</string>
<string name="home_screen" msgid="5629429142036709174">"Негізгі экран"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Параметрлерден <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> қолданбасын әдепкі негізгі экран қолданбасы ретінде орнатыңыз."</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Экранды бөлу"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s қолданбасы туралы ақпарат"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s пайдалану параметрлері"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index b733699..5c71276 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"បានបិទធាតុក្រាហ្វិកក្នុងរបៀបសុវត្ថិភាព"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"ផ្លូវកាត់មិនអាចប្រើបានទេ"</string>
<string name="home_screen" msgid="5629429142036709174">"អេក្រង់ដើម"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"កំណត់ <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> ជាកម្មវិធីអេក្រង់ដើមលំនាំដើមនៅក្នុង \"ការកំណត់\""</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"មុខងារបំបែកអេក្រង់"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"ព័ត៌មានកម្មវិធីសម្រាប់ %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"ការកំណត់ការប្រើប្រាស់សម្រាប់ %1$s"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index 16b39f8..931ca30 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"ಸುರಕ್ಷಿತ ಮೋಡ್ನಲ್ಲಿ ವಿಜೆಟ್ಗಳನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"ಶಾರ್ಟ್ಕಟ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="home_screen" msgid="5629429142036709174">"ಹೋಮ್"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"ಸೆಟ್ಟಿಂಗ್ಗಳಲ್ಲಿ <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> ಅನ್ನು ಡೀಫಾಲ್ಟ್ ಹೋಮ್ ಆ್ಯಪ್ ಆಗಿ ಸೆಟ್ ಮಾಡಿ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ಸ್ಪ್ಲಿಟ್ ಸ್ಕ್ರೀನ್"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ಗಾಗಿ ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s ಗೆ ಸಂಬಂಧಿಸಿದ ಬಳಕೆಯ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index 1d5c58f..9f64cfb 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"안전 모드에서 위젯 사용 중지됨"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"바로가기를 사용할 수 없음"</string>
<string name="home_screen" msgid="5629429142036709174">"홈"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"설정에서 <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> 런처를 기본 홈 앱으로 설정하세요."</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"화면 분할"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 앱 정보"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s의 사용량 설정"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 6f01db3..3e67c36 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Виджеттер Коопсуз режимде өчүрүлгөн"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Кыска жол жок"</string>
<string name="home_screen" msgid="5629429142036709174">"Башкы экран"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Параметрлерден <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> жүргүзгүчүн демейки башкы бет колдонмосу катары коюу"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Экранды бөлүү"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s колдонмосу жөнүндө маалымат"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s колдонмосун пайдалануу параметрлери"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 7ec103b..e0cd3ee 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"ວິດເຈັດຖືກປິດໃນ Safe mode"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"ບໍ່ສາມາດໃຊ້ທາງລັດໄດ້"</string>
<string name="home_screen" msgid="5629429142036709174">"ໂຮມສະກຣີນ"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"ຕັ້ງ <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> ເປັນແອັບໂຮມເລີ່ມຕົ້ນໃນການຕັ້ງຄ່າ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ແບ່ງໜ້າຈໍ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"ຂໍ້ມູນແອັບສຳລັບ %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"ການຕັ້ງຄ່າການນຳໃຊ້ສຳລັບ %1$s"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 1112474..9846525 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Valdikliai išjungti Saugiame režime"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Sparčiojo klavišo negalima naudoti"</string>
<string name="home_screen" msgid="5629429142036709174">"Pagrindinis"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Nustatykite „<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>“ kaip numatytąją pagrindinę programą skiltyje „Nustatymai“"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Išskaidyto ekrano režimas"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Programos „%1$s“ informacija"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"„%1$s“ naudojimo nustatymai"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 4f1a92c..49f7ffe 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Logrīki atspējoti drošajā režīmā"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Saīsne nav pieejama."</string>
<string name="home_screen" msgid="5629429142036709174">"Sākums"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Iestatiet <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> kā noklusējuma sākuma lietotni iestatījumos."</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Sadalīt ekrānu"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s: informācija par lietotni"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Lietojuma iestatījumi: %1$s"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index d984ca0..2bfa089 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Додатоците се оневозможени во безбеден режим"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Кратенката не е достапна"</string>
<string name="home_screen" msgid="5629429142036709174">"Почетен екран"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Поставете <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> да биде стандардна апликација за почетен екран во „Поставки“"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Поделен екран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Податоци за апликација за %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Поставки за користење за %1$s"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index ea8849e..a2babd5 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"സുരക്ഷിത മോഡിൽ വിജറ്റുകൾ പ്രവർത്തനരഹിതമാക്കി"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"കുറുക്കുവഴി ലഭ്യമല്ല"</string>
<string name="home_screen" msgid="5629429142036709174">"ഹോം"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"ക്രമീകരണത്തിൽ <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> എന്നത് ഡിഫോൾട്ട് ഹോം ആപ്പായി സജ്ജീകരിക്കുക"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"സ്ക്രീൻ വിഭജന മോഡ്"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s എന്നതിന്റെ ആപ്പ് വിവരങ്ങൾ"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s എന്നതിനുള്ള ഉപയോഗ ക്രമീകരണം"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 8554717..93a1c9c 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Safe горимд виджетүүдийг идэвхгүйжүүлсэн"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Товчлол алга"</string>
<string name="home_screen" msgid="5629429142036709174">"Нүүр"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>-г Тохиргоонд өгөгдмөл үндсэн аппаар тохируулна уу"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Дэлгэцийг хуваах"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s-н аппын мэдээлэл"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s-н ашиглалтын тохиргоо"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index dcdf25c..c084fab 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"विजेट सुरक्षित मोडमध्ये अक्षम झाले"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"शॉर्टकट उपलब्ध नाही"</string>
<string name="home_screen" msgid="5629429142036709174">"होम"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"सेटिंग्ज मध्ये <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> हे डीफॉल्ट होम अॅप म्हणून सेट करा"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रीन"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s साठी ॲपशी संबंधित माहिती"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s साठी वापरासंबंधित सेटिंग्ज"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 22ee2cb..72d92e2 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widget dilumpuhkan dalam mod Selamat"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Pintasan tidak tersedia"</string>
<string name="home_screen" msgid="5629429142036709174">"Rumah"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Tetapkan <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> sebagai apl skrin utama lalai dalam Tetapan"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Skrin pisah"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Maklumat apl untuk %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Tetapan penggunaan sebanyak %1$s"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index bca1c6e..194ece7 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"လုံခြုံရေး မုဒ်ထဲမှာ ဝီဂျက်များကို ပိတ်ထား"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"ဖြတ်လမ်း မရနိုင်ပါ"</string>
<string name="home_screen" msgid="5629429142036709174">"ပင်မစာမျက်နှာ"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"ဆက်တင်များတွင် <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> ကို မူရင်းပင်မစာမျက်နှာအက်ပ်အဖြစ် သတ်မှတ်ရန်"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"မျက်နှာပြင် ခွဲ၍ပြသခြင်း"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s အတွက် အက်ပ်အချက်အလက်"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s အတွက် အသုံးပြုမှုဆက်တင်များ"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index 1440443..a9e6c5d 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Moduler er deaktivert i sikker modus"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Snarveien er ikke tilgjengelig"</string>
<string name="home_screen" msgid="5629429142036709174">"Startskjerm"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Angi <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> som standard startsideapp i innstillingene"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Delt skjerm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformasjon for %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Bruksinnstillinger for %1$s"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index 52613cb..7880c36 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"सुरक्षित मोडमा विगेटहरू अक्षम गरियो"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"सर्टकट उपलब्ध छैन"</string>
<string name="home_screen" msgid="5629429142036709174">"होम"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"सेटिङमा गई <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> लाई डिफल्ट होम एपका रूपमा सेट गर्नुहोस्"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"स्प्लिट स्क्रिन"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s का हकमा एपसम्बन्धी जानकारी"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s को प्रयोगसम्बन्धी सेटिङ"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 90dcd46..7b3f563 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets uitgezet in veilige modus"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Snelkoppeling is niet beschikbaar"</string>
<string name="home_screen" msgid="5629429142036709174">"Startscherm"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Stel <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> in als de standaard startscherm-app in Instellingen"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Gesplitst scherm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"App-info voor %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Gebruiksinstellingen voor %1$s"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 6d2f87e..33b7664 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"ନିରାପଦ ମୋଡରେ ୱିଜେଟ୍ ଅକ୍ଷମ କରାଗଲା"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"ଶର୍ଟକଟ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="home_screen" msgid="5629429142036709174">"ହୋମ"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"ସେଟିଂସରେ <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>କୁ ଡିଫଲ୍ଟ Home ଆପ ଭାବରେ ସେଟ କରନ୍ତୁ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ସ୍କ୍ରିନକୁ ସ୍ପ୍ଲିଟ କରନ୍ତୁ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ପାଇଁ ଆପ ସୂଚନା"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s ପାଇଁ ବ୍ୟବହାର ସେଟିଂସ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index b287b2f..71c25eb 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"ਵਿਜੇਟ ਸੁਰੱਖਿਅਤ ਮੋਡ ਵਿੱਚ ਅਸਮਰਥਿਤ"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"ਸ਼ਾਰਟਕੱਟ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="home_screen" msgid="5629429142036709174">"ਮੁੱਖ ਪੰਨਾ"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਜਾ ਕੇ <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> ਨੂੰ ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਹੋਮ ਐਪ ਵਜੋਂ ਸੈੱਟ ਕਰੋ"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ਲਈ ਐਪ ਜਾਣਕਾਰੀ"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s ਲਈ ਵਰਤੋਂ ਸੈਟਿੰਗਾਂ"</string>
@@ -186,14 +185,14 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"ਰੋਕ ਹਟਾਓ"</string>
<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>
+ <string name="private_space_label" msgid="2359721649407947001">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"ਸੈੱਟਅੱਪ ਕਰਨ ਜਾਂ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ"</string>
<string name="ps_container_title" msgid="4391796149519594205">"ਨਿੱਜੀ"</string>
- <string name="ps_container_settings" msgid="6059734123353320479">"ਨਿੱਜੀ ਸਪੇਸ ਸੰਬੰਧੀ ਸੈਟਿੰਗਾਂ"</string>
+ <string name="ps_container_settings" msgid="6059734123353320479">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ ਸੰਬੰਧੀ ਸੈਟਿੰਗਾਂ"</string>
<string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"ਨਿੱਜੀ, ਅਣਲਾਕ ਕੀਤਾ ਗਿਆ।"</string>
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"ਨਿੱਜੀ, ਲਾਕ ਕੀਤਾ ਗਿਆ।"</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"ਲਾਕ ਕਰੋ"</string>
- <string name="ps_container_transition" msgid="8667331812048014412">"ਨਿੱਜੀ ਸਪੇਸ ਨੂੰ ਤਬਦੀਲ ਕਰਨਾ"</string>
+ <string name="ps_container_transition" msgid="8667331812048014412">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ ਨੂੰ ਤਬਦੀਲ ਕਰਨਾ"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"ਸਥਾਪਤ ਕਰੋ"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"ਪ੍ਰਾਈਵੇਟ ਸਪੇਸ ਵਿੱਚ ਐਪਾਂ ਸਥਾਪਤ ਕਰੋ"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 685b7d9..587c40f 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widżety są wyłączone w trybie bezpiecznym"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Skrót nie jest dostępny"</string>
<string name="home_screen" msgid="5629429142036709174">"Ekran główny"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Otwórz Ustawienia i ustaw aplikację <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> jako domyślną aplikację ekranu głównego"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Podziel ekran"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacje o aplikacji: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s – ustawienia użycia"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 14a3cf5..67d93de 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets desativados no Modo de segurança"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"O atalho não está disponível"</string>
<string name="home_screen" msgid="5629429142036709174">"Página inicial"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Defina a app <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> como a app inicial predefinida nas Definições"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ecrã dividido"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informações da app para %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Definições de utilização para %1$s"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 4c4b13b..4302588 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets desativados no modo de segurança"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"O atalho não está disponível"</string>
<string name="home_screen" msgid="5629429142036709174">"Início"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Definir <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> como app de início padrão nas Configurações"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Tela dividida"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informações do app %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Configurações de uso de %1$s"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 256fa60..d9e0413 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgeturile sunt dezactivate în modul de siguranță"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Comanda rapidă nu este disponibilă"</string>
<string name="home_screen" msgid="5629429142036709174">"Pagina de pornire"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Setează <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> drept aplicație ecran de pornire prestabilită, în Setări"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ecran împărțit"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informații despre aplicație pentru %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Setări de utilizare pentru %1$s"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 402143d..64a21f7 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Виджеты отключены в безопасном режиме"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Ярлык недоступен"</string>
<string name="home_screen" msgid="5629429142036709174">"Главный экран"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Установить \"<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>\" в качестве приложения главного экрана по умолчанию в настройках"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Разделить экран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Сведения о приложении \"%1$s\""</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Настройки использования приложения \"%1$s\""</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 455f18b..71efc03 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"සුරක්ෂිත ආකාරය තුළ විජටය අබල කරන ලදි"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"කෙටි මග ලබා ගත නොහැකිය"</string>
<string name="home_screen" msgid="5629429142036709174">"මුල් පිටුව"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> සැකසීම් තුළ පෙරනිමි මුල් පිටුව යෙදුම ලෙස සකසන්න"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"බෙදුම් තිරය"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s සඳහා යෙදුම් තතු"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s සඳහා භාවිත සැකසීම්"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 7771cf7..43bc29c 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Miniaplikácie sú v núdzovom režime zakázané"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Skratky nie sú k dispozícii"</string>
<string name="home_screen" msgid="5629429142036709174">"Domov"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Nastaviť aplikáciu <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> ako predvolenú vstupnú aplikáciu v Nastaveniach"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Rozdeliť obrazovku"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informácie o aplikácii pre %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Nastavenia používania pre %1$s"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 2e75b17..5d423ca 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Pripomočki so onemogočeni v varnem načinu"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Bližnjica ni na voljo"</string>
<string name="home_screen" msgid="5629429142036709174">"Začetni zaslon"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Nastavitev zaganjalnika <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> kot privzete aplikacije za začetni zaslon v nastavitvah"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Razdeljen zaslon"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Podatki o aplikaciji za: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Nastavitve uporabe za »%1$s«"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index a00f11a..8f4133d 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Miniaplikacionet janë të çaktivizuara në modalitetin e sigurt"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Shkurtorja nuk është e disponueshme"</string>
<string name="home_screen" msgid="5629429142036709174">"Ekrani bazë"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Cakto <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> si aplikacionin e parazgjedhur të ekranit bazë te \"Cilësimet\""</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ekrani i ndarë"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Informacioni i aplikacionit për %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Cilësimet e përdorimit për \"%1$s\""</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 97d3ff4..cd6523c 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Виџети су онемогућени у Безбедном режиму"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Пречица није доступна"</string>
<string name="home_screen" msgid="5629429142036709174">"Почетни екран"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Подесите <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> као подразумевану почетну апликацију у Подешавањима"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Подељени екран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Информације о апликацији за: %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Подешавања потрошње за %1$s"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index 8a8524e..4f95c67 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Widgets är inaktiverade i felsäkert läge"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Genvägen är inte tillgänglig"</string>
<string name="home_screen" msgid="5629429142036709174">"Startskärm"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Ställ in <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> som standardstartskärmsapp i Inställningar"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Delad skärm"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Appinformation för %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Användningsinställningar för %1$s"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 64f6296..53a9abe 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Wijeti zimezimwa katika hali ya Usalama"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Hakuna njia ya mkato"</string>
<string name="home_screen" msgid="5629429142036709174">"Skrini ya kwanza"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Weka <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> iwe programu chaguomsingi ya mwanzo kwenye Mipangilio"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Gawa skrini"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Maelezo ya programu ya %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Mipangilio ya matumizi ya %1$s"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 189f4ce..738f85c 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"பாதுகாப்புப் பயன்முறையில் விட்ஜெட்கள் முடக்கப்பட்டுள்ளன"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"ஷார்ட்கட் இல்லை"</string>
<string name="home_screen" msgid="5629429142036709174">"முகப்பு"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"அமைப்புகளில் <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> என்பதை இயல்பு முகப்பு ஆப்ஸாக அமையுங்கள்"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"திரைப் பிரிப்பு"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$sக்கான ஆப்ஸ் தகவல்கள்"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$sக்கான உபயோக அமைப்புகள்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index d789baa..0520ebf 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"సురక్షిత మోడ్లో విడ్జెట్లు నిలిపివేయబడ్డాయి"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"షార్ట్కట్ అందుబాటులో లేదు"</string>
<string name="home_screen" msgid="5629429142036709174">"మొదటి ట్యాబ్"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"సెట్టింగ్లలో <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>ను ఆటోమేటిక్ సెట్టింగ్ మొదటి స్క్రీన్ యాప్గా సెట్ చేయండి"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"స్ప్లిట్ స్క్రీన్"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s కోసం యాప్ సమాచారం"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$sకు సంబంధించిన వినియోగ సెట్టింగ్లు"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index f89638d..554fd94 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"มีการปิดใช้งานวิดเจ็ตในเซฟโหมด"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"ทางลัดไม่พร้อมใช้งาน"</string>
<string name="home_screen" msgid="5629429142036709174">"หน้าแรก"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"ตั้ง <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> เป็นแอปหน้าแรกเริ่มต้นในการตั้งค่า"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"แยกหน้าจอ"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"ข้อมูลแอปสำหรับ %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"การตั้งค่าการใช้งานสำหรับ %1$s"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 8754a12..cb6fe66 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Naka-disable ang mga widget sa Safe mode"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Hindi available ang shortcut"</string>
<string name="home_screen" msgid="5629429142036709174">"Home"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Itakda ang <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> bilang default na home app sa Mga Setting"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Split screen"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Impormasyon ng app para sa %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Mga setting ng paggamit para sa %1$s"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 761ce56..b12ec27 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Güvenli modda widget\'lar devre dışı"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Kısayol kullanılamıyor"</string>
<string name="home_screen" msgid="5629429142036709174">"Ana ekran"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> başlatıcısını Ayarlar\'da varsayılan ana ekran uygulaması olarak ayarlayın"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Bölünmüş ekran"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s uygulama bilgileri"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s ile ilgili kullanım ayarları"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index 2c85d5a..2a01dae 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"У безпечному режимі віджети вимкнено"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Ярлик недоступний"</string>
<string name="home_screen" msgid="5629429142036709174">"Головний екран"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Зробити <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> додатком головного екрана за умовчанням у налаштуваннях"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Розділити екран"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Інформація про додаток для %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Параметри використання (%1$s)"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 09f4304..544357e 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"ویجیٹس کو محفوظ وضع میں غیر فعال کر دیا گیا"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"شارٹ کٹ دستیاب نہیں ہے"</string>
<string name="home_screen" msgid="5629429142036709174">"ہوم"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"ترتیبات میں <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> کو بطور ڈیفالٹ ہوم ایپ سیٹ کریں"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"اسپلٹ اسکرین"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s کے لیے ایپ کی معلومات"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s کیلئے استعمال کی ترتیبات"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index d8dea69..5038d4f 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Xavfsiz rejimda vidjetlar o‘chirib qo‘yilgan"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Tezkor tugmadan foydalanib bo‘lmaydi"</string>
<string name="home_screen" msgid="5629429142036709174">"Bosh ekran"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Sozlamalar orqali <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> ilovasini birlamchi bosh ekran ilovasi sifatida belgilash"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Ekranni ikkiga ajratish"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s ilovasi axboroti"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s uchun sarf sozlamalari"</string>
diff --git a/res/values-v33/style.xml b/res/values-v33/style.xml
deleted file mode 100644
index 1261b23..0000000
--- a/res/values-v33/style.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-* Copyright (C) 2022 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>
- <style name="HomeSettings.Theme" parent="@android:style/Theme.DeviceDefault.Settings">
- <item name="android:listPreferredItemPaddingEnd">16dp</item>
- <item name="android:listPreferredItemPaddingStart">24dp</item>
- <item name="android:navigationBarColor">@android:color/transparent</item>
- <item name="android:statusBarColor">@android:color/transparent</item>
- <item name="android:switchStyle">@style/SwitchStyle</item>
- <item name="android:textAppearanceListItem">@style/HomeSettings.PreferenceTitle</item>
- <item name="android:windowActionBar">false</item>
- <item name="android:windowNoTitle">true</item>
- <item name="preferenceTheme">@style/HomeSettings.PreferenceTheme</item>
- <item name="android:windowAnimationStyle">@style/Animation.SharedBackground</item>
- </style>
-
- <style name="Animation.SharedBackground" parent="@android:style/Animation.Activity">
- <item name="android:activityOpenEnterAnimation">@anim/shared_x_axis_activity_open_enter</item>
- <item name="android:activityOpenExitAnimation">@anim/shared_x_axis_activity_open_exit</item>
- <item name="android:activityCloseEnterAnimation">@anim/shared_x_axis_activity_close_enter</item>
- <item name="android:activityCloseExitAnimation">@anim/shared_x_axis_activity_close_exit</item>
- </style>
-</resources>
\ No newline at end of file
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 172c995..e5252b1 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Tiện ích bị vô hiệu hóa ở chế độ an toàn"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Lối tắt không khả dụng"</string>
<string name="home_screen" msgid="5629429142036709174">"Màn hình chính"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Đặt <xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> làm trình chạy mặc định trong phần Cài đặt"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Chia đôi màn hình"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Thông tin ứng dụng cho %1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Chế độ cài đặt mức sử dụng %1$s"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 9c658dc..7a76158 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"安全模式下不允许使用微件"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"无法使用快捷方式"</string>
<string name="home_screen" msgid="5629429142036709174">"主屏幕"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"在“设置”中将“<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>”设为默认主屏幕应用"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分屏"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的应用信息"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"%1$s的使用设置"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index af32638..ed6e52f 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"在安全模式中無法使用小工具"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"沒有可用的捷徑"</string>
<string name="home_screen" msgid="5629429142036709174">"主畫面"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"前往「設定」將「<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>」設為預設主畫面應用程式"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割螢幕"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"%1$s 的應用程式資料"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"「%1$s」的用量設定"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 54a1c5d..264d607 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"在安全模式下無法使用小工具"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"目前無法使用捷徑"</string>
<string name="home_screen" msgid="5629429142036709174">"主畫面"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"前往「設定」將「<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g>」設為預設主畫面應用程式"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"分割畫面"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"「%1$s」的應用程式資訊"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"「%1$s」的用量設定"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 9752e18..be6cd49 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -27,8 +27,7 @@
<string name="safemode_widget_error" msgid="4863470563535682004">"Amawijethi akhutshaziwe kwimodi yokuphepha"</string>
<string name="shortcut_not_available" msgid="2536503539825726397">"Isinqamuleli asitholakali"</string>
<string name="home_screen" msgid="5629429142036709174">"Ikhaya"</string>
- <!-- no translation found for set_default_home_app (5808906607627586381) -->
- <skip />
+ <string name="set_default_home_app" msgid="5808906607627586381">"Setha i-<xliff:g id="LAUNCHER_NAME">%1$s</xliff:g> njenge-app yasekhaya ezenzakalelayo Kumasethingi"</string>
<string name="recent_task_option_split_screen" msgid="6690461455618725183">"Hlukanisa isikrini"</string>
<string name="split_app_info_accessibility" msgid="5475288491241414932">"Ulwazi lwe-App ye-%1$s"</string>
<string name="split_app_usage_settings" msgid="7214375263347964093">"Amasethingi okusetshenziswa ka-%1$s"</string>
diff --git a/src/com/android/launcher3/AppWidgetResizeFrame.java b/src/com/android/launcher3/AppWidgetResizeFrame.java
index b51e850..ef56246 100644
--- a/src/com/android/launcher3/AppWidgetResizeFrame.java
+++ b/src/com/android/launcher3/AppWidgetResizeFrame.java
@@ -37,6 +37,8 @@
import com.android.launcher3.celllayout.CellLayoutLayoutParams;
import com.android.launcher3.celllayout.CellPosMapper.CellPos;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.debug.TestEvent;
+import com.android.launcher3.debug.TestEventEmitter;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.logging.InstanceId;
@@ -221,6 +223,9 @@
dl.addView(frame);
frame.mIsOpen = true;
frame.post(() -> frame.snapToWidget(false));
+ TestEventEmitter.INSTANCE.get(widget.getContext()).sendEvent(
+ TestEvent.RESIZE_FRAME_SHOWING
+ );
}
private void setCornerRadiusFromWidget() {
diff --git a/src/com/android/launcher3/FastScrollRecyclerView.java b/src/com/android/launcher3/FastScrollRecyclerView.java
index eff748a..960d77a 100644
--- a/src/com/android/launcher3/FastScrollRecyclerView.java
+++ b/src/com/android/launcher3/FastScrollRecyclerView.java
@@ -20,6 +20,7 @@
import android.content.Context;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
@@ -27,8 +28,8 @@
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
-import com.android.app.animation.Interpolators;
import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.views.RecyclerViewFastScroller;
@@ -188,6 +189,10 @@
* Scrolls this recycler view to the top.
*/
public void scrollToTop() {
+ if (TestProtocol.sDebugTracing) {
+ Log.d(TestProtocol.PRIVATE_SPACE_SCROLL_FAILURE, "FastScrollRecyclerView#scrollToTop",
+ new Exception());
+ }
if (mScrollbar != null) {
mScrollbar.reattachThumbToScroll();
}
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 5c052b2..cb897dc 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -166,7 +166,6 @@
import androidx.core.os.BuildCompat;
import androidx.window.embedding.RuleController;
-import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
@@ -181,6 +180,8 @@
import com.android.launcher3.celllayout.CellPosMapper.TwoPanelCellPosMapper;
import com.android.launcher3.compat.AccessibilityManagerCompat;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.debug.TestEvent;
+import com.android.launcher3.debug.TestEventEmitter;
import com.android.launcher3.dot.DotInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
@@ -595,6 +596,7 @@
RuleController.getInstance(this).setRules(
RuleController.parseRules(this, R.xml.split_configuration));
}
+ TestEventEmitter.INSTANCE.get(this).sendEvent(TestEvent.LAUNCHER_ON_CREATE);
}
protected ModelCallbacks createModelCallbacks() {
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index 239967d..85c8b57 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -24,6 +24,7 @@
import static com.android.launcher3.LauncherPrefs.THEMED_ICONS;
import static com.android.launcher3.model.LoaderTask.SMARTSPACE_ON_HOME_SCREEN;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SettingsCache.NOTIFICATION_BADGING_URI;
import static com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI;
@@ -63,6 +64,9 @@
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.widget.custom.CustomWidgetManager;
+import java.util.Locale;
+import java.util.Objects;
+
public class LauncherAppState implements SafeCloseable {
public static final String ACTION_FORCE_ROLOAD = "force-reload-launcher";
@@ -115,14 +119,25 @@
}
SimpleBroadcastReceiver modelChangeReceiver =
- new SimpleBroadcastReceiver(mModel::onBroadcastIntent);
- modelChangeReceiver.registerAsync(mContext, Intent.ACTION_LOCALE_CHANGED,
+ new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, mModel::onBroadcastIntent);
+ final Locale oldLocale = mContext.getResources().getConfiguration().locale;
+ modelChangeReceiver.register(
+ mContext,
+ () -> {
+ // if local has changed before receiver is registered on bg thread,
+ // mModel needs to reload.
+ Locale newLocale = mContext.getResources().getConfiguration().locale;
+ if (!Objects.equals(oldLocale, newLocale)) {
+ mModel.forceReload();
+ }
+ },
+ Intent.ACTION_LOCALE_CHANGED,
ACTION_DEVICE_POLICY_RESOURCE_UPDATED);
if (BuildConfig.IS_STUDIO_BUILD) {
mContext.registerReceiver(modelChangeReceiver, new IntentFilter(ACTION_FORCE_ROLOAD),
RECEIVER_EXPORTED);
}
- mOnTerminateCallback.add(() -> modelChangeReceiver.unregisterReceiverSafelyAsync(mContext));
+ mOnTerminateCallback.add(() -> modelChangeReceiver.unregisterReceiverSafely(mContext));
SafeCloseable userChangeListener = UserCache.INSTANCE.get(mContext)
.addUserEventListener(mModel::onUserEvent);
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index 13062b6..83c34ce 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -11,6 +11,8 @@
import com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID
import com.android.launcher3.allapps.AllAppsStore
import com.android.launcher3.config.FeatureFlags
+import com.android.launcher3.debug.TestEvent
+import com.android.launcher3.debug.TestEventEmitter
import com.android.launcher3.model.BgDataModel
import com.android.launcher3.model.StringCache
import com.android.launcher3.model.data.AppInfo
@@ -156,6 +158,7 @@
/*pause=*/ false,
deviceProfile.isTwoPanels
)
+ TestEventEmitter.INSTANCE.get(launcher).sendEvent(TestEvent.WORKSPACE_FINISH_LOADING)
}
/**
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index e601a3e..2995e8a 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -80,6 +80,8 @@
import com.android.launcher3.celllayout.CellPosMapper;
import com.android.launcher3.celllayout.CellPosMapper.CellPos;
import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.debug.TestEvent;
+import com.android.launcher3.debug.TestEventEmitter;
import com.android.launcher3.dot.FolderDotInfo;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
@@ -314,7 +316,6 @@
*/
public Workspace(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
-
mLauncher = Launcher.getLauncher(context);
mStateTransitionAnimation = new WorkspaceStateTransitionAnimation(mLauncher, this);
mWallpaperManager = WallpaperManager.getInstance(context);
@@ -2218,6 +2219,7 @@
if (d.stateAnnouncer != null && !droppedOnOriginalCell) {
d.stateAnnouncer.completeAction(R.string.item_moved);
}
+ TestEventEmitter.INSTANCE.get(getContext()).sendEvent(TestEvent.WORKSPACE_ON_DROP);
}
@Nullable
diff --git a/src/com/android/launcher3/allapps/AllAppsStore.java b/src/com/android/launcher3/allapps/AllAppsStore.java
index 9623709..89e6adc 100644
--- a/src/com/android/launcher3/allapps/AllAppsStore.java
+++ b/src/com/android/launcher3/allapps/AllAppsStore.java
@@ -42,6 +42,7 @@
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
+import java.util.Locale;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
@@ -260,8 +261,12 @@
public void dump(String prefix, PrintWriter writer) {
writer.println(prefix + "\tAllAppsStore Apps[] size: " + mApps.length);
for (int i = 0; i < mApps.length; i++) {
- writer.println(String.format("%s\tPackage index and name: %d/%s", prefix, i,
- mApps[i].componentName.getPackageName()));
+ writer.println(String.format(Locale.getDefault(),
+ "%s\tPackage index, name, and class: " + "%d/%s:%s",
+ prefix,
+ i,
+ mApps[i].componentName.getPackageName(),
+ mApps[i].componentName.getClassName()));
}
}
}
diff --git a/src/com/android/launcher3/anim/AnimatedFloat.java b/src/com/android/launcher3/anim/AnimatedFloat.java
index b414ab6..4441164 100644
--- a/src/com/android/launcher3/anim/AnimatedFloat.java
+++ b/src/com/android/launcher3/anim/AnimatedFloat.java
@@ -20,6 +20,8 @@
import android.animation.ObjectAnimator;
import android.util.FloatProperty;
+import java.util.function.Consumer;
+
/**
* A mutable float which allows animating the value
*/
@@ -38,9 +40,9 @@
}
};
- private static final Runnable NO_OP = () -> { };
+ private static final Consumer<Float> NO_OP = t -> { };
- private final Runnable mUpdateCallback;
+ private final Consumer<Float> mUpdateCallback;
private ObjectAnimator mValueAnimator;
// Only non-null when an animation is playing to this value.
private Float mEndValue;
@@ -52,6 +54,10 @@
}
public AnimatedFloat(Runnable updateCallback) {
+ this(v -> updateCallback.run());
+ }
+
+ public AnimatedFloat(Consumer<Float> updateCallback) {
mUpdateCallback = updateCallback;
}
@@ -60,6 +66,11 @@
value = initialValue;
}
+ public AnimatedFloat(Consumer<Float> updateCallback, float initialValue) {
+ this(updateCallback);
+ value = initialValue;
+ }
+
/**
* Returns an animation from the current value to the given value.
*/
@@ -99,7 +110,7 @@
public void updateValue(float v) {
if (Float.compare(v, value) != 0) {
value = v;
- mUpdateCallback.run();
+ mUpdateCallback.accept(value);
}
}
diff --git a/src/com/android/launcher3/anim/PendingAnimation.java b/src/com/android/launcher3/anim/PendingAnimation.java
index e58890f..47a2bdd 100644
--- a/src/com/android/launcher3/anim/PendingAnimation.java
+++ b/src/com/android/launcher3/anim/PendingAnimation.java
@@ -59,6 +59,13 @@
add(anim, springProperty);
}
+ /**
+ * Utility method to sent an interpolator on an animation and add it to the list
+ */
+ public void add(Animator anim, TimeInterpolator interpolator) {
+ add(anim, interpolator, SpringProperty.DEFAULT);
+ }
+
@Override
public void add(Animator anim) {
add(anim, SpringProperty.DEFAULT);
diff --git a/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt b/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt
new file mode 100644
index 0000000..650df5a
--- /dev/null
+++ b/src/com/android/launcher3/debug/TestEventsEmitterProduction.kt
@@ -0,0 +1,54 @@
+/*
+ * 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.debug
+
+import android.content.Context
+import com.android.launcher3.util.MainThreadInitializedObject
+import com.android.launcher3.util.SafeCloseable
+
+/** Events fired by the launcher. */
+enum class TestEvent(val event: String) {
+ LAUNCHER_ON_CREATE("LAUNCHER_ON_CREATE"),
+ WORKSPACE_ON_DROP("WORKSPACE_ON_DROP"),
+ RESIZE_FRAME_SHOWING("RESIZE_FRAME_SHOWING"),
+ WORKSPACE_FINISH_LOADING("WORKSPACE_FINISH_LOADING"),
+}
+
+/** Interface to create TestEventEmitters. */
+interface TestEventEmitter : SafeCloseable {
+
+ companion object {
+ @JvmField
+ val INSTANCE =
+ MainThreadInitializedObject<TestEventEmitter> { _: Context? ->
+ TestEventsEmitterProduction()
+ }
+ }
+
+ fun sendEvent(event: TestEvent)
+}
+
+/**
+ * TestEventsEmitterProduction shouldn't do anything since it runs on the launcher code and not on
+ * tests. This is just a placeholder and test should override this class.
+ */
+class TestEventsEmitterProduction : TestEventEmitter {
+
+ override fun close() {}
+
+ override fun sendEvent(event: TestEvent) {}
+}
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index bc5a164..c50c008 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -27,6 +27,7 @@
import android.view.View;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.app.animation.Interpolators;
import com.android.launcher3.DragSource;
@@ -69,8 +70,9 @@
*/
protected DragDriver mDragDriver = null;
+ @VisibleForTesting
/** Options controlling the drag behavior. */
- protected DragOptions mOptions;
+ public DragOptions mOptions;
/** Coordinate for motion down event */
protected final Point mMotionDown = new Point();
@@ -79,7 +81,8 @@
protected final Point mTmpPoint = new Point();
- protected DropTarget.DragObject mDragObject;
+ @VisibleForTesting
+ public DropTarget.DragObject mDragObject;
/** Who can receive drop events */
private final ArrayList<DropTarget> mDropTargets = new ArrayList<>();
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index ae8f1d5..6088941 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -508,6 +508,7 @@
&& !SHOULD_SHOW_FIRST_PAGE_WIDGET) {
CellLayout firstScreen = mWorkspaceScreens.get(FIRST_SCREEN_ID);
View qsb = mHomeElementInflater.inflate(R.layout.qsb_preview, firstScreen, false);
+ // TODO: set bgHandler on qsb when it is BaseTemplateCard, which requires API changes.
CellLayoutLayoutParams lp = new CellLayoutLayoutParams(
0, 0, firstScreen.getCountX(), 1);
lp.canReorder = false;
diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java
index 861631d..fbd24d8 100644
--- a/src/com/android/launcher3/logging/StatsLogManager.java
+++ b/src/com/android/launcher3/logging/StatsLogManager.java
@@ -795,6 +795,9 @@
@UiEvent(doc = "User launches Overview from meta+tab keyboard shortcut")
LAUNCHER_OVERVIEW_SHOW_OVERVIEW_FROM_KEYBOARD_SHORTCUT(1765),
+ @UiEvent(doc = "User long pressed on the taskbar IME switcher button")
+ LAUNCHER_TASKBAR_IME_SWITCHER_BUTTON_LONGPRESS(1798),
+
// ADD MORE
;
diff --git a/src/com/android/launcher3/pm/UserCache.java b/src/com/android/launcher3/pm/UserCache.java
index cf03462..7339111 100644
--- a/src/com/android/launcher3/pm/UserCache.java
+++ b/src/com/android/launcher3/pm/UserCache.java
@@ -75,7 +75,7 @@
private final List<BiConsumer<UserHandle, String>> mUserEventListeners = new ArrayList<>();
private final SimpleBroadcastReceiver mUserChangeReceiver =
- new SimpleBroadcastReceiver(this::onUsersChanged);
+ new SimpleBroadcastReceiver(MODEL_EXECUTOR, this::onUsersChanged);
private final Context mContext;
@@ -93,12 +93,12 @@
@Override
public void close() {
- MODEL_EXECUTOR.execute(() -> mUserChangeReceiver.unregisterReceiverSafelySync(mContext));
+ MODEL_EXECUTOR.execute(() -> mUserChangeReceiver.unregisterReceiverSafely(mContext));
}
@WorkerThread
private void initAsync() {
- mUserChangeReceiver.registerSync(mContext,
+ mUserChangeReceiver.register(mContext,
Intent.ACTION_MANAGED_PROFILE_AVAILABLE,
Intent.ACTION_MANAGED_PROFILE_UNAVAILABLE,
Intent.ACTION_MANAGED_PROFILE_REMOVED,
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 5b2f737..b1e82bb 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -49,6 +49,7 @@
import android.view.Display;
import androidx.annotation.AnyThread;
+import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
import androidx.annotation.VisibleForTesting;
@@ -110,7 +111,10 @@
private DisplayInfoChangeListener mPriorityListener;
private final ArrayList<DisplayInfoChangeListener> mListeners = new ArrayList<>();
- private final SimpleBroadcastReceiver mReceiver = new SimpleBroadcastReceiver(this::onIntent);
+ // We will register broadcast receiver on main thread to ensure not missing changes on
+ // TARGET_OVERLAY_PACKAGE and ACTION_OVERLAY_CHANGED.
+ private final SimpleBroadcastReceiver mReceiver =
+ new SimpleBroadcastReceiver(MAIN_EXECUTOR, this::onIntent);
private Info mInfo;
private boolean mDestroyed = false;
@@ -133,11 +137,11 @@
mWindowContext.registerComponentCallbacks(this);
} else {
mWindowContext = null;
- mReceiver.registerAsync(mContext, ACTION_CONFIGURATION_CHANGED);
+ mReceiver.register(mContext, ACTION_CONFIGURATION_CHANGED);
}
// Initialize navigation mode change listener
- mReceiver.registerPkgActionsAsync(mContext, TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED);
+ mReceiver.registerPkgActions(mContext, TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED);
WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(context);
Context displayInfoContext = getDisplayInfoContext(display);
@@ -232,7 +236,7 @@
} else {
// TODO: unregister broadcast receiver
}
- mReceiver.unregisterReceiverSafelyAsync(mContext);
+ mReceiver.unregisterReceiverSafely(mContext);
}
/**
@@ -522,9 +526,8 @@
return Collections.unmodifiableSet(mPerDisplayBounds.keySet());
}
- /**
- * Returns all {@link WindowBounds}s for the current display.
- */
+ /** Returns all {@link WindowBounds}s for the current display. */
+ @Nullable
public List<WindowBounds> getCurrentBounds() {
return mPerDisplayBounds.get(normalizedDisplayInfo);
}
diff --git a/src/com/android/launcher3/util/LockedUserState.kt b/src/com/android/launcher3/util/LockedUserState.kt
index 2737249..10559f3 100644
--- a/src/com/android/launcher3/util/LockedUserState.kt
+++ b/src/com/android/launcher3/util/LockedUserState.kt
@@ -20,21 +20,28 @@
import android.os.Process
import android.os.UserManager
import androidx.annotation.VisibleForTesting
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
+import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
class LockedUserState(private val mContext: Context) : SafeCloseable {
val isUserUnlockedAtLauncherStartup: Boolean
- var isUserUnlocked: Boolean
- private set
+ var isUserUnlocked = false
+ private set(value) {
+ field = value
+ if (value) {
+ notifyUserUnlocked()
+ }
+ }
private val mUserUnlockedActions: RunnableList = RunnableList()
@VisibleForTesting
- val mUserUnlockedReceiver = SimpleBroadcastReceiver {
- if (Intent.ACTION_USER_UNLOCKED == it.action) {
- isUserUnlocked = true
- notifyUserUnlocked()
+ val mUserUnlockedReceiver =
+ SimpleBroadcastReceiver(UI_HELPER_EXECUTOR) {
+ if (Intent.ACTION_USER_UNLOCKED == it.action) {
+ isUserUnlocked = true
+ }
}
- }
init {
// 1) when user reboots devices, launcher process starts at lock screen and both
@@ -43,26 +50,34 @@
// yet isUserUnlockedAtLauncherStartup will remains as false.
// 2) when launcher process restarts after user has unlocked screen, both variable are
// init as true and will not change.
- isUserUnlocked =
- mContext
- .getSystemService(UserManager::class.java)!!
- .isUserUnlocked(Process.myUserHandle())
+ isUserUnlocked = checkIsUserUnlocked()
isUserUnlockedAtLauncherStartup = isUserUnlocked
- if (isUserUnlocked) {
- notifyUserUnlocked()
- } else {
- mUserUnlockedReceiver.registerAsync(mContext, Intent.ACTION_USER_UNLOCKED)
+ if (!isUserUnlocked) {
+ mUserUnlockedReceiver.register(
+ mContext,
+ {
+ // If user is unlocked while registering broadcast receiver, we should update
+ // [isUserUnlocked], which will call [notifyUserUnlocked] in setter
+ if (checkIsUserUnlocked()) {
+ MAIN_EXECUTOR.execute { isUserUnlocked = true }
+ }
+ },
+ Intent.ACTION_USER_UNLOCKED
+ )
}
}
+ private fun checkIsUserUnlocked() =
+ mContext.getSystemService(UserManager::class.java)!!.isUserUnlocked(Process.myUserHandle())
+
private fun notifyUserUnlocked() {
mUserUnlockedActions.executeAllAndDestroy()
- mUserUnlockedReceiver.unregisterReceiverSafelyAsync(mContext)
+ mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
}
/** Stops the receiver from listening for ACTION_USER_UNLOCK broadcasts. */
override fun close() {
- mUserUnlockedReceiver.unregisterReceiverSafelyAsync(mContext)
+ mUserUnlockedReceiver.unregisterReceiverSafely(mContext)
}
/**
diff --git a/src/com/android/launcher3/util/ScreenOnTracker.java b/src/com/android/launcher3/util/ScreenOnTracker.java
index c1d192c..12eff61 100644
--- a/src/com/android/launcher3/util/ScreenOnTracker.java
+++ b/src/com/android/launcher3/util/ScreenOnTracker.java
@@ -19,6 +19,8 @@
import static android.content.Intent.ACTION_SCREEN_ON;
import static android.content.Intent.ACTION_USER_PRESENT;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
+
import android.content.Context;
import android.content.Intent;
@@ -32,7 +34,8 @@
public static final MainThreadInitializedObject<ScreenOnTracker> INSTANCE =
new MainThreadInitializedObject<>(ScreenOnTracker::new);
- private final SimpleBroadcastReceiver mReceiver = new SimpleBroadcastReceiver(this::onReceive);
+ private final SimpleBroadcastReceiver mReceiver =
+ new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, this::onReceive);
private final CopyOnWriteArrayList<ScreenOnListener> mListeners = new CopyOnWriteArrayList<>();
private final Context mContext;
@@ -42,12 +45,12 @@
// Assume that the screen is on to begin with
mContext = context;
mIsScreenOn = true;
- mReceiver.registerAsync(context, ACTION_SCREEN_ON, ACTION_SCREEN_OFF, ACTION_USER_PRESENT);
+ mReceiver.register(context, ACTION_SCREEN_ON, ACTION_SCREEN_OFF, ACTION_USER_PRESENT);
}
@Override
public void close() {
- mReceiver.unregisterReceiverSafelyAsync(mContext);
+ mReceiver.unregisterReceiverSafely(mContext);
}
private void onReceive(Intent intent) {
diff --git a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java
index 5f39cce..539a7cb 100644
--- a/src/com/android/launcher3/util/SimpleBroadcastReceiver.java
+++ b/src/com/android/launcher3/util/SimpleBroadcastReceiver.java
@@ -15,21 +15,17 @@
*/
package com.android.launcher3.util;
-import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.os.Handler;
import android.os.Looper;
import android.os.PatternMatcher;
import android.text.TextUtils;
+import androidx.annotation.AnyThread;
import androidx.annotation.Nullable;
-import androidx.annotation.UiThread;
-import androidx.annotation.WorkerThread;
-
-import com.android.launcher3.BuildConfig;
import java.util.function.Consumer;
@@ -37,8 +33,16 @@
private final Consumer<Intent> mIntentConsumer;
- public SimpleBroadcastReceiver(Consumer<Intent> intentConsumer) {
+ // Handler to register/unregister broadcast receiver
+ private final Handler mHandler;
+
+ public SimpleBroadcastReceiver(LooperExecutor looperExecutor, Consumer<Intent> intentConsumer) {
+ this(looperExecutor.getHandler(), intentConsumer);
+ }
+
+ public SimpleBroadcastReceiver(Handler handler, Consumer<Intent> intentConsumer) {
mIntentConsumer = intentConsumer;
+ mHandler = handler;
}
@Override
@@ -46,55 +50,104 @@
mIntentConsumer.accept(intent);
}
- /** Helper method to register multiple actions. Caller should be on main thread. */
- @UiThread
- public void registerAsync(Context context, String... actions) {
- assertOnMainThread();
- UI_HELPER_EXECUTOR.execute(() -> registerSync(context, actions));
+ /** Calls {@link #register(Context, Runnable, String...)} with null completionCallback. */
+ @AnyThread
+ public void register(Context context, String... actions) {
+ register(context, null, actions);
}
- /** Helper method to register multiple actions. Caller should be on main thread. */
- @WorkerThread
- public void registerSync(Context context, String... actions) {
- assertOnBgThread();
+ /**
+ * Calls {@link #register(Context, Runnable, int, String...)} with null completionCallback.
+ */
+ @AnyThread
+ public void register(Context context, int flags, String... actions) {
+ register(context, null, flags, actions);
+ }
+
+ /**
+ * Register broadcast receiver. If this method is called on the same looper with mHandler's
+ * looper, then register will be called synchronously. Otherwise asynchronously. This ensures
+ * register happens on {@link #mHandler}'s looper.
+ *
+ * @param completionCallback callback that will be triggered after registration is completed,
+ * caller usually pass this callback to check if states has changed
+ * while registerReceiver() is executed on a binder call.
+ */
+ @AnyThread
+ public void register(
+ Context context, @Nullable Runnable completionCallback, String... actions) {
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ registerInternal(context, completionCallback, actions);
+ } else {
+ mHandler.post(() -> registerInternal(context, completionCallback, actions));
+ }
+ }
+
+ /** Register broadcast receiver and run completion callback if passed. */
+ @AnyThread
+ private void registerInternal(
+ Context context, @Nullable Runnable completionCallback, String... actions) {
context.registerReceiver(this, getFilter(actions));
+ if (completionCallback != null) {
+ completionCallback.run();
+ }
}
/**
- * Helper method to register multiple actions associated with a action. Caller should be from
- * main thread.
+ * Same as {@link #register(Context, Runnable, String...)} above but with additional flags
+ * params.
*/
- @UiThread
- public void registerPkgActionsAsync(Context context, @Nullable String pkg, String... actions) {
- assertOnMainThread();
- UI_HELPER_EXECUTOR.execute(() -> registerPkgActionsSync(context, pkg, actions));
+ @AnyThread
+ public void register(
+ Context context, @Nullable Runnable completionCallback, int flags, String... actions) {
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ registerInternal(context, completionCallback, flags, actions);
+ } else {
+ mHandler.post(() -> registerInternal(context, completionCallback, flags, actions));
+ }
+ }
+
+ /** Register broadcast receiver and run completion callback if passed. */
+ @AnyThread
+ private void registerInternal(
+ Context context, @Nullable Runnable completionCallback, int flags, String... actions) {
+ context.registerReceiver(this, getFilter(actions), flags);
+ if (completionCallback != null) {
+ completionCallback.run();
+ }
+ }
+
+ /** Same as {@link #register(Context, Runnable, String...)} above but with pkg name. */
+ @AnyThread
+ public void registerPkgActions(Context context, @Nullable String pkg, String... actions) {
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ context.registerReceiver(this, getPackageFilter(pkg, actions));
+ } else {
+ mHandler.post(() -> {
+ context.registerReceiver(this, getPackageFilter(pkg, actions));
+ });
+ }
}
/**
- * Helper method to register multiple actions associated with a action. Caller should be from
- * bg thread.
+ * Unregister broadcast receiver. If this method is called on the same looper with mHandler's
+ * looper, then unregister will be called synchronously. Otherwise asynchronously. This ensures
+ * unregister happens on {@link #mHandler}'s looper.
*/
- @WorkerThread
- public void registerPkgActionsSync(Context context, @Nullable String pkg, String... actions) {
- assertOnBgThread();
- context.registerReceiver(this, getPackageFilter(pkg, actions));
+ @AnyThread
+ public void unregisterReceiverSafely(Context context) {
+ if (Looper.myLooper() == mHandler.getLooper()) {
+ unregisterReceiverSafelyInternal(context);
+ } else {
+ mHandler.post(() -> {
+ unregisterReceiverSafelyInternal(context);
+ });
+ }
}
- /**
- * Unregisters the receiver ignoring any errors on bg thread. Caller should be on main thread.
- */
- @UiThread
- public void unregisterReceiverSafelyAsync(Context context) {
- assertOnMainThread();
- UI_HELPER_EXECUTOR.execute(() -> unregisterReceiverSafelySync(context));
- }
-
- /**
- * Unregisters the receiver ignoring any errors on bg thread. Caller should be on bg thread.
- */
- @WorkerThread
- public void unregisterReceiverSafelySync(Context context) {
- assertOnBgThread();
+ /** Unregister broadcast receiver ignoring any errors. */
+ @AnyThread
+ private void unregisterReceiverSafelyInternal(Context context) {
try {
context.unregisterReceiver(this);
} catch (IllegalArgumentException e) {
@@ -121,20 +174,4 @@
}
return filter;
}
-
- private static void assertOnBgThread() {
- if (BuildConfig.IS_STUDIO_BUILD && isMainThread()) {
- throw new IllegalStateException("Should not be called from main thread!");
- }
- }
-
- private static void assertOnMainThread() {
- if (BuildConfig.IS_STUDIO_BUILD && !isMainThread()) {
- throw new IllegalStateException("Should not be called from bg thread!");
- }
- }
-
- private static boolean isMainThread() {
- return Thread.currentThread() == Looper.getMainLooper().getThread();
- }
}
diff --git a/src/com/android/launcher3/util/ViewCache.java b/src/com/android/launcher3/util/ViewCache.java
index 98e6822..b98e977 100644
--- a/src/com/android/launcher3/util/ViewCache.java
+++ b/src/com/android/launcher3/util/ViewCache.java
@@ -21,6 +21,8 @@
import android.view.View;
import android.view.ViewGroup;
+import androidx.annotation.VisibleForTesting;
+
import com.android.launcher3.R;
/**
@@ -67,7 +69,8 @@
}
}
- private static class CacheEntry {
+ @VisibleForTesting
+ static class CacheEntry {
final int mMaxSize;
final View[] mViews;
diff --git a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
index a2277a0..f8cbe0d 100644
--- a/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
+++ b/src/com/android/launcher3/util/WallpaperOffsetInterpolator.java
@@ -32,7 +32,7 @@
private static final int MIN_PARALLAX_PAGE_SPAN = 4;
private final SimpleBroadcastReceiver mWallpaperChangeReceiver =
- new SimpleBroadcastReceiver(i -> onWallpaperChanged());
+ new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, i -> onWallpaperChanged());
private final Workspace<?> mWorkspace;
private final boolean mIsRtl;
private final Handler mHandler;
@@ -198,10 +198,10 @@
public void setWindowToken(IBinder token) {
mWindowToken = token;
if (mWindowToken == null && mRegistered) {
- mWallpaperChangeReceiver.unregisterReceiverSafelyAsync(mWorkspace.getContext());
+ mWallpaperChangeReceiver.unregisterReceiverSafely(mWorkspace.getContext());
mRegistered = false;
} else if (mWindowToken != null && !mRegistered) {
- mWallpaperChangeReceiver.registerAsync(
+ mWallpaperChangeReceiver.register(
mWorkspace.getContext(), ACTION_WALLPAPER_CHANGED);
onWallpaperChanged();
mRegistered = true;
diff --git a/src/com/android/launcher3/widget/LauncherWidgetHolder.java b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
index 1fb8c83..3016c9a 100644
--- a/src/com/android/launcher3/widget/LauncherWidgetHolder.java
+++ b/src/com/android/launcher3/widget/LauncherWidgetHolder.java
@@ -37,6 +37,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import androidx.annotation.WorkerThread;
import com.android.launcher3.BaseActivity;
@@ -484,7 +485,8 @@
* Sets or unsets a flag the can change whether the widget host should be in the listening
* state.
*/
- private void setShouldListenFlag(int flag, boolean on) {
+ @VisibleForTesting
+ void setShouldListenFlag(int flag, boolean on) {
if (on) {
mFlags.updateAndGet(old -> old | flag);
} else {
diff --git a/tests/assets/ReorderWidgets/full_reorder_case b/tests/assets/ReorderWidgets/full_reorder_case
index 850e4fd..2890b79 100644
--- a/tests/assets/ReorderWidgets/full_reorder_case
+++ b/tests/assets/ReorderWidgets/full_reorder_case
@@ -17,12 +17,12 @@
# Test 4x4
board: 4x4
xxxx
-bbmm
+bbaa
iimm
-iiaa
+iimm
arguments: 0 2
board: 4x4
xxxx
-bbii
+bbaa
mmii
-mmaa
\ No newline at end of file
+mmii
\ No newline at end of file
diff --git a/tests/assets/ReorderWidgets/push_reorder_case b/tests/assets/ReorderWidgets/push_reorder_case
index 8e845a2..1eacfae 100644
--- a/tests/assets/ReorderWidgets/push_reorder_case
+++ b/tests/assets/ReorderWidgets/push_reorder_case
@@ -17,28 +17,28 @@
#Test 5x5
board: 5x5
xxxxx
-bbbm-
+bbb--
--ccc
--ddd
------
-arguments: 2 1
+----m
+arguments: 2 2
board: 5x5
xxxxx
---m--
bbb--
+--m--
--ccc
--ddd
#6x5 Test
board: 6x5
xxxxxx
-bbbbm-
+bbbb--
--aaa-
--ddd-
-------
-arguments: 2 1
+-----m
+arguments: 2 2
board: 6x5
xxxxxx
---m---
bbbb--
+--m---
--aaa-
--ddd-
\ No newline at end of file
diff --git a/tests/assets/ReorderWidgets/simple_reorder_case b/tests/assets/ReorderWidgets/simple_reorder_case
index 2c50ce4..991ccb5 100644
--- a/tests/assets/ReorderWidgets/simple_reorder_case
+++ b/tests/assets/ReorderWidgets/simple_reorder_case
@@ -21,7 +21,7 @@
--mm-
-----
-----
-arguments: 0 4
+arguments: 0 3
board: 5x5
xxxxx
-----
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 59d0de6..fab3015 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -174,6 +174,7 @@
public static final String TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE = "b/326908466";
public static final String WIDGET_CONFIG_NULL_EXTRA_INTENT = "b/324419890";
public static final String OVERVIEW_SELECT_TOOLTIP_MISALIGNED = "b/332485341";
+ public static final String PRIVATE_SPACE_SCROLL_FAILURE = "b/339737008";
public static final String REQUEST_FLAG_ENABLE_GRID_ONLY_OVERVIEW = "enable-grid-only-overview";
public static final String REQUEST_FLAG_ENABLE_APP_PAIRS = "enable-app-pairs";
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
index 419cb3d..f1403e5 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/CellLayoutTestCaseReader.java
@@ -54,7 +54,7 @@
}
public static class Arguments extends TestSection {
- String[] arguments;
+ public String[] arguments;
public Arguments(String[] arguments) {
super(State.ARGUMENTS);
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/LauncherWidgetHolderTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/LauncherWidgetHolderTest.kt
new file mode 100644
index 0000000..1a659e2
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/LauncherWidgetHolderTest.kt
@@ -0,0 +1,149 @@
+/*
+ * 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
+
+import androidx.test.annotation.UiThreadTest
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.BuildConfig.WIDGETS_ENABLED
+import com.android.launcher3.util.ActivityContextWrapper
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.widget.LauncherWidgetHolder.FLAG_ACTIVITY_RESUMED
+import com.android.launcher3.widget.LauncherWidgetHolder.FLAG_ACTIVITY_STARTED
+import com.android.launcher3.widget.LauncherWidgetHolder.FLAG_STATE_IS_NORMAL
+import org.junit.After
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertSame
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+import org.mockito.Mockito.times
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(LauncherMultivalentJUnit::class)
+class LauncherWidgetHolderTest {
+ private lateinit var widgetHolder: LauncherWidgetHolder
+
+ @Before
+ fun setUp() {
+ assertTrue(WIDGETS_ENABLED)
+ widgetHolder =
+ LauncherWidgetHolder(ActivityContextWrapper(getInstrumentation().targetContext)) {}
+ }
+
+ @After
+ fun tearDown() {
+ widgetHolder.destroy()
+ }
+
+ @Test
+ fun widget_holder_start_listening() {
+ val testView = mock(PendingAppWidgetHostView::class.java)
+ widgetHolder.mViews[0] = testView
+ widgetHolder.setListeningFlag(false)
+ assertFalse(widgetHolder.isListening)
+ widgetHolder.startListening()
+ widgetHolder.widgetHolderExecutor.submit {}.get()
+ getInstrumentation().waitForIdleSync()
+ assertTrue(widgetHolder.isListening)
+ verify(testView, times(1)).reInflate()
+ widgetHolder.clearWidgetViews()
+ }
+
+ @Test
+ fun holder_start_listening_after_activity_start() {
+ widgetHolder.setShouldListenFlag(FLAG_STATE_IS_NORMAL or FLAG_ACTIVITY_RESUMED, true)
+ widgetHolder.setActivityStarted(false)
+ widgetHolder.widgetHolderExecutor.submit {}.get()
+ assertFalse(widgetHolder.shouldListen(widgetHolder.mFlags.get()))
+ widgetHolder.setActivityStarted(true)
+ widgetHolder.widgetHolderExecutor.submit {}.get()
+ assertTrue(widgetHolder.shouldListen(widgetHolder.mFlags.get()))
+ }
+
+ @Test
+ fun holder_start_listening_after_activity_resume() {
+ widgetHolder.setShouldListenFlag(FLAG_STATE_IS_NORMAL or FLAG_ACTIVITY_STARTED, true)
+ widgetHolder.setActivityResumed(false)
+ widgetHolder.widgetHolderExecutor.submit {}.get()
+ assertFalse(widgetHolder.shouldListen(widgetHolder.mFlags.get()))
+ widgetHolder.setActivityResumed(true)
+ widgetHolder.widgetHolderExecutor.submit {}.get()
+ assertTrue(widgetHolder.shouldListen(widgetHolder.mFlags.get()))
+ }
+
+ @Test
+ fun holder_start_listening_after_state_normal() {
+ widgetHolder.setShouldListenFlag(FLAG_ACTIVITY_RESUMED or FLAG_ACTIVITY_STARTED, true)
+ widgetHolder.setStateIsNormal(false)
+ widgetHolder.widgetHolderExecutor.submit {}.get()
+ assertFalse(widgetHolder.shouldListen(widgetHolder.mFlags.get()))
+ widgetHolder.setStateIsNormal(true)
+ widgetHolder.widgetHolderExecutor.submit {}.get()
+ assertTrue(widgetHolder.shouldListen(widgetHolder.mFlags.get()))
+ }
+
+ @Test
+ @UiThreadTest
+ fun widget_holder_create_view() {
+ val mockProviderInfo = mock(LauncherAppWidgetProviderInfo::class.java)
+ doReturn(false).whenever(mockProviderInfo).isCustomWidget
+ assertEquals(0, widgetHolder.mViews.size())
+ widgetHolder.createView(APP_WIDGET_ID, mockProviderInfo)
+ assertEquals(1, widgetHolder.mViews.size())
+ assertEquals(APP_WIDGET_ID, widgetHolder.mViews.get(0).appWidgetId)
+ widgetHolder.deleteAppWidgetId(APP_WIDGET_ID)
+ assertEquals(0, widgetHolder.mViews.size())
+ }
+
+ @Test
+ fun holder_add_provider_change_listener() {
+ val listener = LauncherWidgetHolder.ProviderChangedListener {}
+ widgetHolder.addProviderChangeListener(listener)
+ getInstrumentation().waitForIdleSync()
+ assertEquals(1, widgetHolder.mProviderChangedListeners.size)
+ assertSame(widgetHolder.mProviderChangedListeners.first(), listener)
+ widgetHolder.removeProviderChangeListener(listener)
+ }
+
+ @Test
+ fun holder_remove_provider_change_listener() {
+ val listener = LauncherWidgetHolder.ProviderChangedListener {}
+ widgetHolder.addProviderChangeListener(listener)
+ widgetHolder.removeProviderChangeListener(listener)
+ getInstrumentation().waitForIdleSync()
+ assertEquals(0, widgetHolder.mProviderChangedListeners.size)
+ }
+
+ @Test
+ fun widget_holder_stop_listening() {
+ widgetHolder.setListeningFlag(true)
+ assertTrue(widgetHolder.isListening)
+ widgetHolder.stopListening()
+ widgetHolder.widgetHolderExecutor.submit {}.get()
+ assertFalse(widgetHolder.isListening)
+ }
+
+ companion object {
+ private const val APP_WIDGET_ID = 0
+ }
+}
diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
index 57117cb..430e496 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -22,8 +22,6 @@
import static com.android.launcher3.allapps.UserProfileManager.STATE_ENABLED;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
-import static com.android.launcher3.util.rule.TestStabilityRule.LOCAL;
-import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -202,7 +200,6 @@
}
@Test
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/339109319
public void openPrivateSpaceSettings_triggersCorrectIntent() {
Intent expectedIntent = ApiWrapper.INSTANCE.get(mContext).getPrivateSpaceSettingsIntent();
ArgumentCaptor<Intent> acIntent = ArgumentCaptor.forClass(Intent.class);
diff --git a/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java b/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
deleted file mode 100644
index 28a1325..0000000
--- a/tests/src/com/android/launcher3/celllayout/TaplReorderWidgetsTest.java
+++ /dev/null
@@ -1,312 +0,0 @@
-/*
- * Copyright (C) 2022 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.celllayout;
-
-import static android.platform.uiautomator_helpers.DeviceHelpers.getContext;
-
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.graphics.Point;
-import android.net.Uri;
-import android.util.Log;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.SmallTest;
-
-import com.android.launcher3.InvariantDeviceProfile;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.MultipageCellLayout;
-import com.android.launcher3.celllayout.board.CellLayoutBoard;
-import com.android.launcher3.celllayout.board.TestWorkspaceBuilder;
-import com.android.launcher3.celllayout.board.WidgetRect;
-import com.android.launcher3.tapl.Widget;
-import com.android.launcher3.tapl.WidgetResizeFrame;
-import com.android.launcher3.ui.AbstractLauncherUiTest;
-import com.android.launcher3.util.ModelTestExtensions;
-import com.android.launcher3.util.rule.ShellCommandRule;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Assume;
-import org.junit.Before;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
-@SmallTest
-@RunWith(AndroidJUnit4.class)
-public class TaplReorderWidgetsTest extends AbstractLauncherUiTest<Launcher> {
-
- @Rule
- public ShellCommandRule mGrantWidgetRule = ShellCommandRule.grantWidgetBind();
-
- private static final String TAG = TaplReorderWidgetsTest.class.getSimpleName();
-
- private static final List<String> FOLDABLE_GRIDS = List.of("normal", "practical", "reasonable");
-
- TestWorkspaceBuilder mWorkspaceBuilder;
-
- @Before
- public void setup() throws Throwable {
- mWorkspaceBuilder = new TestWorkspaceBuilder(mTargetContext);
- super.setUp();
- }
-
- @After
- public void tearDown() {
- ModelTestExtensions.INSTANCE.clearModelDb(
- LauncherAppState.getInstance(getContext()).getModel()
- );
- }
-
- /**
- * Validate if the given board represent the current CellLayout
- **/
- private boolean validateBoard(List<CellLayoutBoard> testBoards) {
- ArrayList<CellLayoutBoard> workspaceBoards = workspaceToBoards();
- if (workspaceBoards.size() < testBoards.size()) {
- return false;
- }
- for (int i = 0; i < testBoards.size(); i++) {
- if (testBoards.get(i).compareTo(workspaceBoards.get(i)) != 0) {
- return false;
- }
- }
- return true;
- }
-
- private FavoriteItemsTransaction buildWorkspaceFromBoards(List<CellLayoutBoard> boards,
- FavoriteItemsTransaction transaction) {
- for (int i = 0; i < boards.size(); i++) {
- CellLayoutBoard board = boards.get(i);
- mWorkspaceBuilder.buildFromBoard(board, transaction, i);
- }
- return transaction;
- }
-
- private void printCurrentWorkspace() {
- InvariantDeviceProfile idp = InvariantDeviceProfile.INSTANCE.get(mTargetContext);
- ArrayList<CellLayoutBoard> boards = workspaceToBoards();
- for (int i = 0; i < boards.size(); i++) {
- Log.d(TAG, "Screen number " + i);
- Log.d(TAG, ".\n" + boards.get(i).toString(idp.numColumns, idp.numRows));
- }
- }
-
- private ArrayList<CellLayoutBoard> workspaceToBoards() {
- return getFromLauncher(CellLayoutTestUtils::workspaceToBoards);
- }
-
- private WidgetRect getWidgetClosestTo(Point point) {
- ArrayList<CellLayoutBoard> workspaceBoards = workspaceToBoards();
- int maxDistance = 9999;
- WidgetRect bestRect = null;
- for (int i = 0; i < workspaceBoards.get(0).getWidgets().size(); i++) {
- WidgetRect widget = workspaceBoards.get(0).getWidgets().get(i);
- if (widget.getCellX() == 0 && widget.getCellY() == 0) {
- continue;
- }
- int distance = Math.abs(point.x - widget.getCellX())
- + Math.abs(point.y - widget.getCellY());
- if (distance == 0) {
- break;
- }
- if (distance < maxDistance) {
- maxDistance = distance;
- bestRect = widget;
- }
- }
- return bestRect;
- }
-
- /**
- * This function might be odd, its function is to select a widget and leave it in its place.
- * The idea is to make the test broader and also test after a widgets resized because the
- * underlying code does different things in that case
- */
- private void triggerWidgetResize(ReorderTestCase testCase) {
- WidgetRect widgetRect = getWidgetClosestTo(testCase.moveMainTo);
- if (widgetRect == null) {
- // Some test doesn't have a widget in the final position, in those cases we will ignore
- // them
- return;
- }
- Widget widget = mLauncher.getWorkspace().getWidgetAtCell(widgetRect.getCellX(),
- widgetRect.getCellY());
- WidgetResizeFrame resizeFrame = widget.dragWidgetToWorkspace(widgetRect.getCellX(),
- widgetRect.getCellY(), widgetRect.getSpanX(), widgetRect.getSpanY());
- resizeFrame.dismiss();
- }
-
- private void runTestCase(ReorderTestCase testCase) {
- WidgetRect mainWidgetCellPos = CellLayoutBoard.getMainFromList(
- testCase.mStart);
-
- FavoriteItemsTransaction transaction =
- new FavoriteItemsTransaction(mTargetContext);
- transaction = buildWorkspaceFromBoards(testCase.mStart, transaction);
- transaction.commit();
- mLauncher.waitForLauncherInitialized();
- // resetLoaderState triggers the launcher to start loading the workspace which allows
- // waitForLauncherCondition to wait for that condition, otherwise the condition would
- // always be true and it wouldn't wait for the changes to be applied.
- waitForLauncherCondition("Workspace didn't finish loading", l -> !l.isWorkspaceLoading());
-
- triggerWidgetResize(testCase);
-
- Widget widget = mLauncher.getWorkspace().getWidgetAtCell(mainWidgetCellPos.getCellX(),
- mainWidgetCellPos.getCellY());
- assertNotNull(widget);
- WidgetResizeFrame resizeFrame = widget.dragWidgetToWorkspace(testCase.moveMainTo.x,
- testCase.moveMainTo.y, mainWidgetCellPos.getSpanX(), mainWidgetCellPos.getSpanY());
- resizeFrame.dismiss();
-
- boolean isValid = false;
- for (List<CellLayoutBoard> boards : testCase.mEnd) {
- isValid |= validateBoard(boards);
- if (isValid) break;
- }
- printCurrentWorkspace();
- assertTrue("Non of the valid boards match with the current state", isValid);
- }
-
- /**
- * Run only the test define for the current grid size if such test exist
- *
- * @param testCaseMap map containing all the tests per grid size (Point)
- */
- private boolean runTestCaseMap(Map<Point, ReorderTestCase> testCaseMap, String testName) {
- Point iconGridDimensions = mLauncher.getWorkspace().getIconGridDimensions();
- Log.d(TAG, "Running test " + testName + " for grid " + iconGridDimensions);
- if (!testCaseMap.containsKey(iconGridDimensions)) {
- Log.d(TAG, "The test " + testName + " doesn't support " + iconGridDimensions
- + " grid layout");
- return false;
- }
- runTestCase(testCaseMap.get(iconGridDimensions));
-
- return true;
- }
-
- private void runTestCaseMapForAllGrids(Map<Point, ReorderTestCase> testCaseMap,
- String testName) {
- boolean runAtLeastOnce = false;
- for (String grid : FOLDABLE_GRIDS) {
- applyGridOption(grid);
- mLauncher.waitForLauncherInitialized();
- runAtLeastOnce |= runTestCaseMap(testCaseMap, testName);
- }
- Assume.assumeTrue("None of the grids are supported", runAtLeastOnce);
- }
-
- private void applyGridOption(Object argValue) {
- String testProviderAuthority = mTargetContext.getPackageName() + ".grid_control";
- Uri gridUri = new Uri.Builder()
- .scheme(ContentResolver.SCHEME_CONTENT)
- .authority(testProviderAuthority)
- .appendPath("default_grid")
- .build();
- ContentValues values = new ContentValues();
- values.putObject("name", argValue);
- Assert.assertEquals(1,
- mTargetContext.getContentResolver().update(gridUri, values, null, null));
- }
-
- @Test
- public void simpleReorder() throws Exception {
- runTestCaseMap(getTestMap("ReorderWidgets/simple_reorder_case"),
- "push_reorder_case");
- }
-
- @Test
- public void pushTest() throws Exception {
- runTestCaseMap(getTestMap("ReorderWidgets/push_reorder_case"),
- "push_reorder_case");
- }
-
- @Test
- public void fullReorder() throws Exception {
- runTestCaseMap(getTestMap("ReorderWidgets/full_reorder_case"),
- "full_reorder_case");
- }
-
- @Test
- public void moveOutReorder() throws Exception {
- runTestCaseMap(getTestMap("ReorderWidgets/move_out_reorder_case"),
- "move_out_reorder_case");
- }
-
- @Test
- public void multipleCellLayoutsSimpleReorder() throws Exception {
- Assume.assumeTrue("Test doesn't support foldables", getFromLauncher(
- l -> l.getWorkspace().getScreenWithId(0) instanceof MultipageCellLayout));
- runTestCaseMapForAllGrids(getTestMap("ReorderWidgets/multiple_cell_layouts_simple_reorder"),
- "multiple_cell_layouts_simple_reorder");
- }
-
- @Test
- public void multipleCellLayoutsNoSpaceReorder() throws Exception {
- Assume.assumeTrue("Test doesn't support foldables", getFromLauncher(
- l -> l.getWorkspace().getScreenWithId(0) instanceof MultipageCellLayout));
- runTestCaseMapForAllGrids(
- getTestMap("ReorderWidgets/multiple_cell_layouts_no_space_reorder"),
- "multiple_cell_layouts_no_space_reorder");
- }
-
- @Test
- public void multipleCellLayoutsReorderToOtherSide() throws Exception {
- Assume.assumeTrue("Test doesn't support foldables", getFromLauncher(
- l -> l.getWorkspace().getScreenWithId(0) instanceof MultipageCellLayout));
- runTestCaseMapForAllGrids(
- getTestMap("ReorderWidgets/multiple_cell_layouts_reorder_other_side"),
- "multiple_cell_layouts_reorder_other_side");
- }
-
- private void addTestCase(Iterator<CellLayoutTestCaseReader.TestSection> sections,
- Map<Point, ReorderTestCase> testCaseMap) {
- CellLayoutTestCaseReader.Board startBoard =
- ((CellLayoutTestCaseReader.Board) sections.next());
- CellLayoutTestCaseReader.Arguments point =
- ((CellLayoutTestCaseReader.Arguments) sections.next());
- CellLayoutTestCaseReader.Board endBoard =
- ((CellLayoutTestCaseReader.Board) sections.next());
- Point moveTo = new Point(Integer.parseInt(point.arguments[0]),
- Integer.parseInt(point.arguments[1]));
- testCaseMap.put(endBoard.gridSize,
- new ReorderTestCase(startBoard.board, moveTo, endBoard.board));
- }
-
- private Map<Point, ReorderTestCase> getTestMap(String testPath) throws IOException {
- Map<Point, ReorderTestCase> testCaseMap = new HashMap<>();
- Iterator<CellLayoutTestCaseReader.TestSection> iterableSection =
- CellLayoutTestCaseReader.readFromFile(testPath).parse().iterator();
- while (iterableSection.hasNext()) {
- addTestCase(iterableSection, testCaseMap);
- }
- return testCaseMap;
- }
-}
diff --git a/tests/src/com/android/launcher3/celllayout/integrationtest/TestUtils.kt b/tests/src/com/android/launcher3/celllayout/integrationtest/TestUtils.kt
new file mode 100644
index 0000000..4cecb5a
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/integrationtest/TestUtils.kt
@@ -0,0 +1,72 @@
+/*
+ * 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.celllayout.integrationtest
+
+import android.graphics.Point
+import android.graphics.Rect
+import android.view.View
+import android.view.ViewGroup
+import com.android.launcher3.CellLayout
+import com.android.launcher3.Workspace
+import com.android.launcher3.util.CellAndSpan
+import com.android.launcher3.widget.LauncherAppWidgetHostView
+
+object TestUtils {
+ fun <T> searchChildren(viewGroup: ViewGroup, type: Class<T>): T? where T : View {
+ for (i in 0..<viewGroup.childCount) {
+ val child = viewGroup.getChildAt(i)
+ if (type.isInstance(child)) {
+ return type.cast(child)
+ }
+ if (child is ViewGroup) {
+ val result = searchChildren(child, type)
+ if (result != null) {
+ return result
+ }
+ }
+ }
+ return null
+ }
+
+ fun getWidgetAtCell(
+ workspace: Workspace<*>,
+ cellX: Int,
+ cellY: Int
+ ): LauncherAppWidgetHostView {
+ val view =
+ (workspace.getPageAt(workspace.currentPage) as CellLayout).getChildAt(cellX, cellY)
+ assert(view != null) { "There is no view at $cellX , $cellY" }
+ assert(view is LauncherAppWidgetHostView) { "The view at $cellX , $cellY is not a widget" }
+ return view as LauncherAppWidgetHostView
+ }
+
+ fun getCellTopLeftRelativeToCellLayout(
+ workspace: Workspace<*>,
+ cellAndSpan: CellAndSpan
+ ): Point {
+ val target = Rect()
+ val cellLayout = workspace.getPageAt(workspace.currentPage) as CellLayout
+ cellLayout.cellToRect(
+ cellAndSpan.cellX,
+ cellAndSpan.cellY,
+ cellAndSpan.spanX,
+ cellAndSpan.spanY,
+ target
+ )
+ return Point(target.left, target.top)
+ }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/integrationtest/events/EventsRule.kt b/tests/src/com/android/launcher3/celllayout/integrationtest/events/EventsRule.kt
new file mode 100644
index 0000000..fb61ced
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/integrationtest/events/EventsRule.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.celllayout.integrationtest.events
+
+import android.content.Context
+import com.android.launcher3.debug.TestEvent
+import com.android.launcher3.debug.TestEventEmitter
+import org.junit.rules.TestRule
+import org.junit.runner.Description
+import org.junit.runners.model.Statement
+
+/**
+ * Rule to create EventWaiters to wait for events that happens on the Launcher. For reference look
+ * at [TestEvent] for existing events.
+ *
+ * Waiting for event should be used to prevent race conditions, it provides a more precise way of
+ * waiting for events compared to [AbstractLauncherUiTest#waitForLauncherCondition].
+ *
+ * This class overrides the [TestEventEmitter] with [TestEventsEmitterImplementation] and makes sure
+ * to return the [TestEventEmitter] to the previous value when finished.
+ */
+class EventsRule(val context: Context) : TestRule {
+
+ private var prevEventEmitter: TestEventEmitter? = null
+
+ private val eventEmitter = TestEventsEmitterImplementation()
+
+ override fun apply(base: Statement, description: Description?): Statement {
+ return object : Statement() {
+ override fun evaluate() {
+ beforeTest()
+ base.evaluate()
+ afterTest()
+ }
+ }
+ }
+
+ fun createEventWaiter(expectedEvent: TestEvent): EventWaiter {
+ return eventEmitter.createEventWaiter(expectedEvent)
+ }
+
+ private fun beforeTest() {
+ prevEventEmitter = TestEventEmitter.INSTANCE.get(context)
+ TestEventEmitter.INSTANCE.initializeForTesting(eventEmitter)
+ }
+
+ private fun afterTest() {
+ TestEventEmitter.INSTANCE.initializeForTesting(prevEventEmitter)
+ }
+}
diff --git a/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt b/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt
new file mode 100644
index 0000000..365ad4b
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/integrationtest/events/TestEventsEmitterImplementation.kt
@@ -0,0 +1,89 @@
+/*
+ * 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.celllayout.integrationtest.events
+
+import android.util.Log
+import com.android.launcher3.debug.TestEvent
+import com.android.launcher3.debug.TestEventEmitter
+import java.util.concurrent.TimeUnit
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withTimeoutOrNull
+
+enum class EventStatus() {
+ SUCCESS,
+ FAILURE,
+ TIMEOUT,
+}
+
+class EventWaiter(val eventToWait: TestEvent) {
+ private val deferrable = CompletableDeferred<EventStatus>()
+
+ companion object {
+ private const val TAG = "EventWaiter"
+ }
+
+ fun waitForSignal(timeout: Long = TimeUnit.SECONDS.toMillis(10)) = runBlocking {
+ var status = withTimeoutOrNull(timeout) { deferrable.await() }
+ if (status == null) {
+ status = EventStatus.TIMEOUT
+ }
+ if (status != EventStatus.SUCCESS) {
+ throw Exception("Failure waiting for event $eventToWait, failure = $status")
+ }
+ }
+
+ fun terminate() {
+ deferrable.complete(EventStatus.SUCCESS)
+ }
+}
+
+class TestEventsEmitterImplementation() : TestEventEmitter {
+ companion object {
+ private const val TAG = "TestEvents"
+ }
+
+ private val expectedEvents: ArrayDeque<EventWaiter> = ArrayDeque()
+
+ fun createEventWaiter(expectedEvent: TestEvent): EventWaiter {
+ val eventWaiter = EventWaiter(expectedEvent)
+ expectedEvents.add(eventWaiter)
+ return eventWaiter
+ }
+
+ private fun clearQueue() {
+ expectedEvents.clear()
+ }
+
+ override fun sendEvent(event: TestEvent) {
+ Log.d(TAG, "Signal received $event")
+ Log.d(TAG, "Total expected events ${expectedEvents.size}")
+ if (expectedEvents.isEmpty()) return
+ val eventWaiter = expectedEvents.last()
+ if (eventWaiter.eventToWait == event) {
+ Log.d(TAG, "Removing $event")
+ expectedEvents.removeLast()
+ eventWaiter.terminate()
+ } else {
+ Log.d(TAG, "Not matching $event")
+ }
+ }
+
+ override fun close() {
+ clearQueue()
+ }
+}
diff --git a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
index 405dae7..46cafa7 100644
--- a/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplUninstallRemoveTest.java
@@ -177,8 +177,6 @@
*/
@Test
@PortraitLandscape
- @ScreenRecordRule.ScreenRecord // b/338869019
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/338869019
public void testAddDeleteShortcutOnHotseat() {
mLauncher.getWorkspace()
.deleteAppIcon(mLauncher.getWorkspace().getHotseatAppIcon(0))
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 6e01f9e..3d253b4 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -22,6 +22,7 @@
import static com.android.launcher3.testing.shared.TestProtocol.ICON_MISSING;
import static com.android.launcher3.testing.shared.TestProtocol.WIDGET_CONFIG_NULL_EXTRA_INTENT;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
+import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
@@ -238,9 +239,9 @@
protected void clearPackageData(String pkg) throws IOException, InterruptedException {
final CountDownLatch count = new CountDownLatch(2);
final SimpleBroadcastReceiver broadcastReceiver =
- new SimpleBroadcastReceiver(i -> count.countDown());
+ new SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, i -> count.countDown());
// We OK to make binder calls on main thread in test.
- broadcastReceiver.registerPkgActionsSync(mTargetContext, pkg,
+ broadcastReceiver.registerPkgActions(mTargetContext, pkg,
Intent.ACTION_PACKAGE_RESTARTED, Intent.ACTION_PACKAGE_DATA_CLEARED);
mDevice.executeShellCommand("pm clear " + pkg);
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
index ae24a57..eb05000 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
@@ -113,8 +113,6 @@
@Test
@PortraitLandscape
- @ScreenRecordRule.ScreenRecord // b/329935119
- @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/329935119
public void testSinglePageDragIconWhenMultiplePageScrollingIsPossible() {
Workspace workspace = mLauncher.getWorkspace();
@@ -169,6 +167,7 @@
@Test
@PortraitLandscape
+ @ScreenRecordRule.ScreenRecord // b/352130094
public void testDragIconToPage2() {
Workspace workspace = mLauncher.getWorkspace();
diff --git a/tests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt b/tests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt
new file mode 100644
index 0000000..1de99c5
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/SimpleBroadcastReceiverTest.kt
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Handler
+import android.os.Looper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
+import com.google.common.truth.Truth.assertThat
+import java.util.function.Consumer
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.ArgumentMatchers.same
+import org.mockito.Captor
+import org.mockito.Mock
+import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SimpleBroadcastReceiverTest {
+
+ private lateinit var underTest: SimpleBroadcastReceiver
+
+ @Mock private lateinit var intentConsumer: Consumer<Intent>
+ @Mock private lateinit var context: Context
+ @Mock private lateinit var completionRunnable: Runnable
+ @Captor private lateinit var intentFilterCaptor: ArgumentCaptor<IntentFilter>
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+ underTest = SimpleBroadcastReceiver(UI_HELPER_EXECUTOR, intentConsumer)
+ if (Looper.getMainLooper() == null) {
+ Looper.prepareMainLooper()
+ }
+ }
+
+ @Test
+ fun async_register() {
+ underTest.register(context, "test_action_1", "test_action_2")
+ awaitTasksCompleted()
+
+ verify(context).registerReceiver(same(underTest), intentFilterCaptor.capture())
+ val intentFilter = intentFilterCaptor.value
+ assertThat(intentFilter.countActions()).isEqualTo(2)
+ assertThat(intentFilter.getAction(0)).isEqualTo("test_action_1")
+ assertThat(intentFilter.getAction(1)).isEqualTo("test_action_2")
+ }
+
+ @Test
+ fun async_register_withCompletionRunnable() {
+ underTest.register(context, completionRunnable, "test_action_1", "test_action_2")
+ awaitTasksCompleted()
+
+ verify(context).registerReceiver(same(underTest), intentFilterCaptor.capture())
+ verify(completionRunnable).run()
+ val intentFilter = intentFilterCaptor.value
+ assertThat(intentFilter.countActions()).isEqualTo(2)
+ assertThat(intentFilter.getAction(0)).isEqualTo("test_action_1")
+ assertThat(intentFilter.getAction(1)).isEqualTo("test_action_2")
+ }
+
+ @Test
+ fun async_register_withCompletionRunnable_and_flag() {
+ underTest.register(context, completionRunnable, 1, "test_action_1", "test_action_2")
+ awaitTasksCompleted()
+
+ verify(context).registerReceiver(same(underTest), intentFilterCaptor.capture(), eq(1))
+ verify(completionRunnable).run()
+ val intentFilter = intentFilterCaptor.value
+ assertThat(intentFilter.countActions()).isEqualTo(2)
+ assertThat(intentFilter.getAction(0)).isEqualTo("test_action_1")
+ assertThat(intentFilter.getAction(1)).isEqualTo("test_action_2")
+ }
+
+ @Test
+ fun async_register_with_package() {
+ underTest.registerPkgActions(context, "pkg", "test_action_1", "test_action_2")
+
+ awaitTasksCompleted()
+ verify(context).registerReceiver(same(underTest), intentFilterCaptor.capture())
+ val intentFilter = intentFilterCaptor.value
+ assertThat(intentFilter.getDataScheme(0)).isEqualTo("package")
+ assertThat(intentFilter.getDataSchemeSpecificPart(0).path).isEqualTo("pkg")
+ assertThat(intentFilter.countActions()).isEqualTo(2)
+ assertThat(intentFilter.getAction(0)).isEqualTo("test_action_1")
+ assertThat(intentFilter.getAction(1)).isEqualTo("test_action_2")
+ }
+
+ @Test
+ fun sync_register_withCompletionRunnable_and_flag() {
+ underTest = SimpleBroadcastReceiver(Handler(Looper.getMainLooper()), intentConsumer)
+
+ underTest.register(context, completionRunnable, 1, "test_action_1", "test_action_2")
+
+ verify(context).registerReceiver(same(underTest), intentFilterCaptor.capture(), eq(1))
+ verify(completionRunnable).run()
+ val intentFilter = intentFilterCaptor.value
+ assertThat(intentFilter.countActions()).isEqualTo(2)
+ assertThat(intentFilter.getAction(0)).isEqualTo("test_action_1")
+ assertThat(intentFilter.getAction(1)).isEqualTo("test_action_2")
+ }
+
+ @Test
+ fun async_unregister() {
+ underTest.unregisterReceiverSafely(context)
+
+ awaitTasksCompleted()
+ verify(context).unregisterReceiver(same(underTest))
+ }
+
+ @Test
+ fun sync_unregister() {
+ underTest = SimpleBroadcastReceiver(Handler(Looper.getMainLooper()), intentConsumer)
+
+ underTest.unregisterReceiverSafely(context)
+
+ verify(context).unregisterReceiver(same(underTest))
+ }
+
+ @Test
+ fun getPackageFilter() {
+ val intentFilter =
+ SimpleBroadcastReceiver.getPackageFilter("pkg", "test_action_1", "test_action_2")
+
+ assertThat(intentFilter.getDataScheme(0)).isEqualTo("package")
+ assertThat(intentFilter.getDataSchemeSpecificPart(0).path).isEqualTo("pkg")
+ assertThat(intentFilter.countActions()).isEqualTo(2)
+ assertThat(intentFilter.getAction(0)).isEqualTo("test_action_1")
+ assertThat(intentFilter.getAction(1)).isEqualTo("test_action_2")
+ }
+
+ private fun awaitTasksCompleted() {
+ UI_HELPER_EXECUTOR.submit<Any> { null }.get()
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/ViewCacheTest.kt b/tests/src/com/android/launcher3/util/ViewCacheTest.kt
new file mode 100644
index 0000000..bad21c9
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/ViewCacheTest.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.util
+
+import android.view.View
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.R
+import com.android.launcher3.util.ViewCache.CacheEntry
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class ViewCacheTest {
+
+ private lateinit var underTest: ViewCache
+
+ private val context = InstrumentationRegistry.getInstrumentation().context
+ private val layoutId =
+ context.run { resources.getIdentifier("test_layout_appwidget_blue", "layout", packageName) }
+
+ @Before
+ fun setUp() {
+ underTest = ViewCache()
+ underTest.setCacheSize(layoutId, 5)
+ }
+
+ @Test
+ fun get_view_from_empty_cache() {
+ val view: View = underTest.getView(layoutId, context, null)
+
+ val cacheEntry = view.getTag(R.id.cache_entry_tag_id) as ViewCache.CacheEntry
+ assertThat(cacheEntry).isNotNull()
+ assertThat(cacheEntry.mMaxSize).isEqualTo(5)
+ assertThat(cacheEntry.mCurrentSize).isEqualTo(0)
+ assertThat(cacheEntry.mViews[0]).isNull()
+ }
+
+ @Test
+ fun recyclerView() {
+ val view: View = underTest.getView(layoutId, context, null)
+ val cacheEntry = view.getTag(R.id.cache_entry_tag_id) as ViewCache.CacheEntry
+
+ underTest.recycleView(layoutId, view)
+
+ assertThat(cacheEntry.mMaxSize).isEqualTo(5)
+ assertThat(cacheEntry.mCurrentSize).isEqualTo(1)
+ assertThat(cacheEntry.mViews[0]).isSameInstanceAs(view)
+ }
+
+ @Test
+ fun get_view_from_cache() {
+ val view: View = underTest.getView(layoutId, context, null)
+ underTest.recycleView(layoutId, view)
+
+ val newView = underTest.getView<View>(layoutId, context, null)
+
+ assertThat(view).isSameInstanceAs(newView)
+ }
+
+ @Test
+ fun change_tag_id_recyclerView_noOp() {
+ val view: View = underTest.getView(layoutId, context, null)
+ val cacheEntry = view.getTag(R.id.cache_entry_tag_id) as ViewCache.CacheEntry
+
+ view.setTag(R.id.cache_entry_tag_id, CacheEntry(3))
+ underTest.recycleView(layoutId, view)
+
+ assertThat(cacheEntry.mMaxSize).isEqualTo(5)
+ assertThat(cacheEntry.mCurrentSize).isEqualTo(0)
+ assertThat(cacheEntry.mViews[0]).isNull()
+ }
+}