Merge "Fix gesture tutorial regression on tablets when rotating the screen" into main
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 3d15e77..9051ca8 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -1,6 +1,13 @@
+[Builtin Hooks]
+ktfmt = true
+
+[Builtin Hooks Options]
+ktfmt = --kotlinlang-style
+
+[Tool Paths]
+ktfmt = ${REPO_ROOT}/external/ktfmt/ktfmt.sh
+
[Hook Scripts]
checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --config_xml tools/checkstyle.xml --sha ${PREUPLOAD_COMMIT}
-ktfmt_hook = ${REPO_ROOT}/external/ktfmt/ktfmt.py --check ${PREUPLOAD_FILES}
-
flag_hook = ${REPO_ROOT}/frameworks/base/packages/SystemUI/flag_check.py --msg=${PREUPLOAD_COMMIT_MESSAGE} --files=${PREUPLOAD_FILES} --project=${REPO_PATH}
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 8682e5d..9c945b9 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -286,8 +286,26 @@
}
flag {
- name: "enable_tiny_taskbar"
+ name: "enable_recents_in_taskbar"
namespace: "launcher"
- description: "Enables Taskbar on phones"
- bug: "341784466"
+ description: "Replace hybrid hotseat app predictions with strictly Recent Apps"
+ bug: "315354060"
+}
+
+flag {
+ name: "enable_first_screen_broadcast_archiving_extras"
+ namespace: "launcher"
+ description: "adds Extras to first screen broadcast for archived apps"
+ bug: "322314760"
+ is_fixed_read_only: true
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
+}
+
+flag {
+ name: "floating_search_bar"
+ namespace: "launcher"
+ description: "Search bar persists at the bottom of the screen across Launcher states"
+ bug: "346408388"
}
diff --git a/aconfig/launcher_search.aconfig b/aconfig/launcher_search.aconfig
index b243922..b98eee6 100644
--- a/aconfig/launcher_search.aconfig
+++ b/aconfig/launcher_search.aconfig
@@ -45,8 +45,11 @@
flag {
- name: "private_space_floating_mask_view"
+ name: "private_space_add_floating_mask_view"
namespace: "launcher_search"
description: "This flag enables the floating mask view as part of the Private Space animation. "
bug: "339850589"
+ metadata {
+ purpose: PURPOSE_BUGFIX
+ }
}
diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
index b1a6202..e31f462 100644
--- a/go/quickstep/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -124,23 +124,15 @@
</LinearLayout>
<!-- Unused. Included only for compatibility with parent class. -->
- <LinearLayout
- android:id="@+id/group_action_buttons"
- android:layout_width="match_parent"
- android:layout_height="@dimen/overview_actions_height"
+ <Button
+ android:id="@+id/action_save_app_pair"
+ style="@style/GoOverviewActionButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
android:layout_gravity="top|center_horizontal"
- android:orientation="horizontal"
- android:visibility="gone">
-
- <Button
- android:id="@+id/action_save_app_pair"
- style="@style/GoOverviewActionButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:drawableStart="@drawable/ic_save_app_pair_up_down"
- android:text="@string/action_save_app_pair"
- android:theme="@style/ThemeControlHighlightWorkspaceColor" />
-
- </LinearLayout>
+ android:drawableStart="@drawable/ic_save_app_pair_up_down"
+ android:text="@string/action_save_app_pair"
+ android:theme="@style/ThemeControlHighlightWorkspaceColor"
+ android:visibility="gone" />
</com.android.quickstep.views.GoOverviewActionsView>
\ No newline at end of file
diff --git a/quickstep/AndroidManifest-launcher.xml b/quickstep/AndroidManifest-launcher.xml
index c6e2d8c..80d8154 100644
--- a/quickstep/AndroidManifest-launcher.xml
+++ b/quickstep/AndroidManifest-launcher.xml
@@ -48,7 +48,7 @@
android:stateNotNeeded="true"
android:windowSoftInputMode="adjustPan"
android:screenOrientation="unspecified"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:taskAffinity=""
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index bf198b6..4abf6e1 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -80,7 +80,7 @@
android:stateNotNeeded="true"
android:theme="@style/LauncherTheme"
android:screenOrientation="behind"
- android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize"
+ android:configChanges="keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenSize|screenLayout|smallestScreenSize|uiMode"
android:resizeableActivity="true"
android:resumeWhilePausing="true"
android:enableOnBackInvokedCallback="false"
diff --git a/quickstep/res/layout/digital_wellbeing_toast.xml b/quickstep/res/layout/digital_wellbeing_toast.xml
index 42cddbf..9144c7f 100644
--- a/quickstep/res/layout/digital_wellbeing_toast.xml
+++ b/quickstep/res/layout/digital_wellbeing_toast.xml
@@ -19,7 +19,7 @@
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
style="@style/TextTitle"
android:layout_width="match_parent"
- android:layout_height="48dp"
+ android:layout_height="@dimen/digital_wellbeing_toast_height"
android:background="@drawable/bg_wellbeing_toast"
android:forceHasOverlappingRendering="false"
android:gravity="center"
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index 7aaf744..fcd2e54 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -47,22 +47,16 @@
</LinearLayout>
- <LinearLayout
- android:id="@+id/group_action_buttons"
+ <!-- Currently, the only "group action button" is this save app pair button. If more are added,
+ a new LinearLayout may be needed to contain them, but beware of increased memory usage. -->
+ <Button
+ android:id="@+id/action_save_app_pair"
+ style="@style/OverviewActionButton"
android:layout_width="wrap_content"
- android:layout_height="@dimen/overview_actions_height"
+ android:layout_height="wrap_content"
+ android:text="@string/action_save_app_pair"
+ android:theme="@style/ThemeControlHighlightWorkspaceColor"
android:layout_gravity="bottom|center_horizontal"
- android:orientation="horizontal"
- android:visibility="gone">
-
- <Button
- android:id="@+id/action_save_app_pair"
- style="@style/OverviewActionButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="@string/action_save_app_pair"
- android:theme="@style/ThemeControlHighlightWorkspaceColor" />
-
- </LinearLayout>
+ android:visibility="gone" />
</com.android.quickstep.views.OverviewActionsView>
\ No newline at end of file
diff --git a/quickstep/res/layout/split_instructions_view.xml b/quickstep/res/layout/split_instructions_view.xml
index 1115ff2..797ea45 100644
--- a/quickstep/res/layout/split_instructions_view.xml
+++ b/quickstep/res/layout/split_instructions_view.xml
@@ -29,6 +29,7 @@
android:id="@+id/split_instructions_text"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ android:maxWidth="@dimen/split_instructions_view_max_width"
android:textColor="?androidprv:attr/textColorOnAccent"
android:text="@string/toast_split_select_app" />
@@ -36,6 +37,7 @@
android:id="@+id/split_instructions_text_cancel"
android:layout_height="wrap_content"
android:layout_width="wrap_content"
+ android:layout_gravity="center_vertical"
android:textColor="?androidprv:attr/textColorOnAccent"
android:layout_marginStart="@dimen/split_instructions_start_margin_cancel"
android:text="@string/toast_split_select_app_cancel"
diff --git a/quickstep/res/layout/taskbar_divider_popup_menu.xml b/quickstep/res/layout/taskbar_divider_popup_menu.xml
index 7f4f76c..b184191 100644
--- a/quickstep/res/layout/taskbar_divider_popup_menu.xml
+++ b/quickstep/res/layout/taskbar_divider_popup_menu.xml
@@ -16,8 +16,9 @@
-->
<com.android.launcher3.taskbar.TaskbarDividerPopupView
xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="@dimen/taskbar_pinning_popup_menu_width"
+ android:layout_width="wrap_content"
android:layout_height="wrap_content"
+ android:minWidth="@dimen/taskbar_pinning_popup_menu_width"
android:focusable="true"
android:background="@drawable/popup_background"
android:orientation="vertical">
@@ -51,14 +52,13 @@
android:layout_height="wrap_content"
android:id="@+id/taskbar_pinning_switch"
android:background="@null"
- android:clickable="false"
android:gravity="start|center_vertical"
android:textAlignment="viewStart"
android:paddingStart="12dp"
+ android:switchPadding="12dp"
android:layout_weight="1"
android:fontFamily="@*android:string/config_bodyFontFamilyMedium"
android:lines="1"
- android:ellipsize="end"
android:textSize="14sp"
android:textColor="?android:attr/textColorPrimary"
android:text="@string/always_show_taskbar" />
diff --git a/quickstep/res/raw-h480dp/all_set_page_bg.json b/quickstep/res/raw-h480dp/all_set_page_bg.json
new file mode 100644
index 0000000..f2998a0
--- /dev/null
+++ b/quickstep/res/raw-h480dp/all_set_page_bg.json
@@ -0,0 +1 @@
+{"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-w840dp-h480dp/all_set_page_bg.json b/quickstep/res/raw-w840dp-h480dp/all_set_page_bg.json
new file mode 100644
index 0000000..ae1b560
--- /dev/null
+++ b/quickstep/res/raw-w840dp-h480dp/all_set_page_bg.json
@@ -0,0 +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
diff --git a/quickstep/res/values-af/strings.xml b/quickstep/res/values-af/strings.xml
index 0b03e02..73c8129 100644
--- a/quickstep/res/values-af/strings.xml
+++ b/quickstep/res/values-af/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Wys nog # app.}other{Wys nog # apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Wys # rekenaarapp.}other{Wys # rekenaarapps.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Borrel"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oorvloei"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> vanaf <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> en nog <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-am/strings.xml b/quickstep/res/values-am/strings.xml
index c8fd276..f9eed39 100644
--- a/quickstep/res/values-am/strings.xml
+++ b/quickstep/res/values-am/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ተጨማሪ # መተግበሪያ አሳይ።}one{ተጨማሪ # መተግበሪያ አሳይ።}other{ተጨማሪ # መተግበሪያዎች አሳይ።}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# የዴስክቶፕ መተግበሪያ አሳይ።}one{# የዴስክቶፕ መተግበሪያ አሳይ።}other{# የዴስክቶፕ መተግበሪያዎች አሳይ።}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> እና <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"አረፋ"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ትርፍ ፍሰት"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ከ<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> እና <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> ተጨማሪ"</string>
</resources>
diff --git a/quickstep/res/values-ar/strings.xml b/quickstep/res/values-ar/strings.xml
index ca0e1dd..7a0be9b 100644
--- a/quickstep/res/values-ar/strings.xml
+++ b/quickstep/res/values-ar/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{إظهار تطبيق واحد آخر}zero{إظهار # تطبيق آخر}two{إظهار تطبيقَين آخرَين}few{إظهار # تطبيقات أخرى}many{إظهار # تطبيقًا آخر}other{إظهار # تطبيق آخر}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{عرض تطبيق واحد متوافق مع الكمبيوتر المكتبي}zero{عرض # تطبيق متوافق مع الكمبيوتر المكتبي}two{عرض تطبيقَين متوافقين مع الكمبيوتر المكتبي}few{عرض # تطبيقات متوافقة مع الكمبيوتر المكتبي}many{عرض # تطبيقًا متوافقًا مع الكمبيوتر المكتبي}other{عرض # تطبيق متوافق مع الكمبيوتر المكتبي}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"\"<xliff:g id="APP_NAME_1">%1$s</xliff:g>\" و\"<xliff:g id="APP_NAME_2">%2$s</xliff:g>\""</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"فقاعة"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"القائمة الكاملة"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"\"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" من \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"\"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>\" و<xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> غيرها"</string>
</resources>
diff --git a/quickstep/res/values-as/strings.xml b/quickstep/res/values-as/strings.xml
index 7cd7696..d440400 100644
--- a/quickstep/res/values-as/strings.xml
+++ b/quickstep/res/values-as/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{আৰু # টা এপ্ দেখুৱাওক।}one{আৰু # টা এপ্ দেখুৱাওক।}other{আৰু # টা এপ্ দেখুৱাওক।}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# টা ডেস্কটপ এপ্ দেখুৱাওক।}one{# টা ডেস্কটপ এপ্ দেখুৱাওক।}other{# টা ডেস্কটপ এপ্ দেখুৱাওক।}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> আৰু <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"অ’ভাৰফ্ল’"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>ৰ পৰা <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> আৰু <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> টা"</string>
</resources>
diff --git a/quickstep/res/values-az/strings.xml b/quickstep/res/values-az/strings.xml
index f5840ab..9cdcc01 100644
--- a/quickstep/res/values-az/strings.xml
+++ b/quickstep/res/values-az/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Daha # tətbiqi göstərin.}other{Daha # tətbiqi göstərin.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# masaüstü tətbiqini göstərin.}other{# masaüstü tətbiqini göstərin.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> və <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Yumrucuq"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kənara çıxma"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> və daha <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> yumrucuq"</string>
</resources>
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 276a8b9..b6271a9 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju.}one{Prikaži još # aplikaciju.}few{Prikaži još # aplikacije.}other{Prikaži još # aplikacija.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # aplikaciju za računare.}one{Prikaži # aplikaciju za računare.}few{Prikaži # aplikacije za računare.}other{Prikaži # aplikacija za računare.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-be/strings.xml b/quickstep/res/values-be/strings.xml
index 0785e0f..bb6c764 100644
--- a/quickstep/res/values-be/strings.xml
+++ b/quickstep/res/values-be/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Паказаць ячшэ # праграму.}one{Паказаць ячшэ # праграму.}few{Паказаць ячшэ # праграмы.}many{Паказаць ячшэ # праграм.}other{Паказаць ячшэ # праграмы.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Паказаць # праграму для ПК.}one{Паказаць # праграму для ПК.}few{Паказаць # праграмы для ПК.}many{Паказаць # праграм для ПК.}other{Паказаць # праграмы для ПК.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> і <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бурбалкі"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Меню з пашырэннем"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, крыніца: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> і яшчэ <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-bg/strings.xml b/quickstep/res/values-bg/strings.xml
index c26bc6f..d674dbc 100644
--- a/quickstep/res/values-bg/strings.xml
+++ b/quickstep/res/values-bg/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показване на още # приложение.}other{Показване на още # приложения.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показване на # настолно приложение.}other{Показване на # настолни приложения.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Препълване"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> от <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> и още <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-bn/strings.xml b/quickstep/res/values-bn/strings.xml
index f7f666b..3e974f5 100644
--- a/quickstep/res/values-bn/strings.xml
+++ b/quickstep/res/values-bn/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{আরও #টি অ্যাপ দেখুন।}one{আরও #টি অ্যাপ দেখুন।}other{আরও #টি অ্যাপ দেখুন।}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{#টি ডেস্কটপ অ্যাপ দেখুন।}one{#টি ডেস্কটপ অ্যাপ দেখুন।}other{#টি ডেস্কটপ অ্যাপ দেখুন।}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ও <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"বাবল"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ওভারফ্লো"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> থেকে <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> এবং আরও <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>টি"</string>
</resources>
diff --git a/quickstep/res/values-bs/strings.xml b/quickstep/res/values-bs/strings.xml
index 1167145..19268be 100644
--- a/quickstep/res/values-bs/strings.xml
+++ b/quickstep/res/values-bs/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju.}one{Prikaži još # aplikaciju.}few{Prikaži još # aplikacije.}other{Prikaži još # aplikacija.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # aplikaciju za računar.}one{Prikaži # aplikaciju za računar.}few{Prikaži # aplikacije za računar.}other{Prikaži # aplikacija za računar.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Preklopni meni"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ca/strings.xml b/quickstep/res/values-ca/strings.xml
index ba8e3c1..6a6f131 100644
--- a/quickstep/res/values-ca/strings.xml
+++ b/quickstep/res/values-ca/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # aplicació més.}other{Mostra # aplicacions més.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostra # aplicació per a ordinadors.}other{Mostra # aplicacions per a ordinadors.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bombolla"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Desbordament"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> i <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> més"</string>
</resources>
diff --git a/quickstep/res/values-cs/strings.xml b/quickstep/res/values-cs/strings.xml
index 7f1cd94..e134850 100644
--- a/quickstep/res/values-cs/strings.xml
+++ b/quickstep/res/values-cs/strings.xml
@@ -73,7 +73,7 @@
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Přejeďte prstem nahoru z dolního okraje obrazovky"</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Zkuste podržet okno delší dobu, než ho uvolníte"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Přejeďte prstem přímo nahoru a pak udělejte pauzu"</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili jste se používat gesta. Vypnout je můžete v nastavení."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Naučili jste se používat gesta. Vypnout je můžete v Nastavení."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Dokončili jste gesto pro přepínání aplikací"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Přepínání aplikací přejetím prstem"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Přejeďte nahoru z dolního okraje obrazovky, podržte obrazovku a uvolněte."</string>
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobrazit # další aplikaci.}few{Zobrazit # další aplikace.}many{Zobrazit # další aplikace.}other{Zobrazit # dalších aplikací.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Zobrazit # aplikaci pro počítač.}few{Zobrazit # aplikace pro počítač.}many{Zobrazit # aplikace pro počítač.}other{Zobrazit # aplikací pro počítač.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbalovací nabídka"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikace <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> a ještě <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-da/strings.xml b/quickstep/res/values-da/strings.xml
index 1daf365..e9cdbce 100644
--- a/quickstep/res/values-da/strings.xml
+++ b/quickstep/res/values-da/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app mere.}one{Vis # app mere.}other{Vis # apps mere.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Vis # computerprogram.}one{Vis # computerprogram.}other{Vis # computerprogrammer.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overløb"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> mere"</string>
</resources>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index b089976..9e5cb12 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# weitere App anzeigen}other{# weitere Apps anzeigen}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# Desktop-App anzeigen.}other{# Desktop-Apps anzeigen.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> und <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Weitere Optionen"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ aus <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> und <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> weitere"</string>
</resources>
diff --git a/quickstep/res/values-el/strings.xml b/quickstep/res/values-el/strings.xml
index 66ca90e..bbb1282 100644
--- a/quickstep/res/values-el/strings.xml
+++ b/quickstep/res/values-el/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Εμφάνιση # ακόμα εφαρμογής.}other{Εμφάνιση # ακόμα εφαρμογών.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Εμφάνιση # εφαρμογής υπολογιστή.}other{Εμφάνιση # εφαρμογών υπολογιστή.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> και <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Συννεφάκι"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Υπερχείλιση"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> από <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> και <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> ακόμα"</string>
</resources>
diff --git a/quickstep/res/values-en-rAU/strings.xml b/quickstep/res/values-en-rAU/strings.xml
index fe5b479..eedb29e 100644
--- a/quickstep/res/values-en-rAU/strings.xml
+++ b/quickstep/res/values-en-rAU/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> more"</string>
</resources>
diff --git a/quickstep/res/values-en-rCA/strings.xml b/quickstep/res/values-en-rCA/strings.xml
index 3bd2bdd..88cd0dd 100644
--- a/quickstep/res/values-en-rCA/strings.xml
+++ b/quickstep/res/values-en-rCA/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> more"</string>
</resources>
diff --git a/quickstep/res/values-en-rGB/strings.xml b/quickstep/res/values-en-rGB/strings.xml
index fe5b479..eedb29e 100644
--- a/quickstep/res/values-en-rGB/strings.xml
+++ b/quickstep/res/values-en-rGB/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> more"</string>
</resources>
diff --git a/quickstep/res/values-en-rIN/strings.xml b/quickstep/res/values-en-rIN/strings.xml
index fe5b479..eedb29e 100644
--- a/quickstep/res/values-en-rIN/strings.xml
+++ b/quickstep/res/values-en-rIN/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> more"</string>
</resources>
diff --git a/quickstep/res/values-en-rXC/strings.xml b/quickstep/res/values-en-rXC/strings.xml
index 52efe9d..76dab0d 100644
--- a/quickstep/res/values-en-rXC/strings.xml
+++ b/quickstep/res/values-en-rXC/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Show # more app.}other{Show # more apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Show # desktop app.}other{Show # desktop apps.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> and <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> from <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> and <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> more"</string>
</resources>
diff --git a/quickstep/res/values-es-rUS/strings.xml b/quickstep/res/values-es-rUS/strings.xml
index 095b06e..58d540f 100644
--- a/quickstep/res/values-es-rUS/strings.xml
+++ b/quickstep/res/values-es-rUS/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # app más.}other{Mostrar # apps más.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computadoras.}other{Mostrar # apps para computadoras.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ampliada"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> y <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> más"</string>
</resources>
diff --git a/quickstep/res/values-es/strings.xml b/quickstep/res/values-es/strings.xml
index dbc7caa..2a956f0 100644
--- a/quickstep/res/values-es/strings.xml
+++ b/quickstep/res/values-es/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación más.}other{Mostrar # aplicaciones más.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # aplicación para ordenadores.}other{Mostrar # aplicaciones para ordenadores.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> y <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuja"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> y <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> más"</string>
</resources>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index c53f80c..0ecc0c0 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -73,7 +73,7 @@
<string name="overview_gesture_feedback_swipe_too_far_from_edge" msgid="6402349235265407385">"Pühkige kindlasti ekraani alumisest servast üles."</string>
<string name="overview_gesture_feedback_home_detected" msgid="663432226180397138">"Hoidke sõrme aknal pisut kauem, enne kui vabastate"</string>
<string name="overview_gesture_feedback_wrong_swipe_direction" msgid="1191055451018584958">"Pühkige kindlasti otse üles, seejärel peatuge"</string>
- <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Õppisite liigutusi kasutama. Liigutuste väljalülitamiseks avage seaded."</string>
+ <string name="overview_gesture_feedback_complete_with_follow_up" msgid="3544611727467765026">"Õppisite liigutusi kasutama. Liigutuste väljalülitamiseks avage Seaded."</string>
<string name="overview_gesture_feedback_complete_without_follow_up" msgid="2903050864432331629">"Tegite rakenduste vahel vahetamise liigutuse"</string>
<string name="overview_gesture_intro_title" msgid="2902054412868489378">"Pühkige rakenduste vahetamiseks"</string>
<string name="overview_gesture_intro_subtitle" msgid="4968091015637850859">"Rakenduste vahel vahetamiseks pühkige ekraanikuva alaosast üles, hoidke ja seejärel vabastage."</string>
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Kuva veel # rakendus.}other{Kuva veel # rakendust.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Kuva # töölauarakendus.}other{Kuva # töölauarakendust.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Mull"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ületäide"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ja veel <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> mulli"</string>
</resources>
diff --git a/quickstep/res/values-eu/strings.xml b/quickstep/res/values-eu/strings.xml
index ecdacd2..e83ee28 100644
--- a/quickstep/res/values-eu/strings.xml
+++ b/quickstep/res/values-eu/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Erakutsi beste # aplikazio.}other{Erakutsi beste # aplikazio.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Erakutsi ordenagailuetarako # aplikazio.}other{Erakutsi ordenagailuetarako # aplikazio.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> eta <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbuila"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Luzapena"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> eta beste <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-fa/strings.xml b/quickstep/res/values-fa/strings.xml
index 0dad801..b296080 100644
--- a/quickstep/res/values-fa/strings.xml
+++ b/quickstep/res/values-fa/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{نمایش # برنامه دیگر.}one{نمایش # برنامه دیگر.}other{نمایش # برنامه دیگر.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{نمایش # برنامه رایانه.}one{نمایش # برنامه رایانه.}other{نمایش # برنامه رایانه.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> و <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"حبابک"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"سرریز"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> از <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> و <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> حبابک دیگر"</string>
</resources>
diff --git a/quickstep/res/values-fi/strings.xml b/quickstep/res/values-fi/strings.xml
index 8624fe7..5ac124a 100644
--- a/quickstep/res/values-fi/strings.xml
+++ b/quickstep/res/values-fi/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Näytä # muu sovellus.}other{Näytä # muuta sovellusta.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Näytä # työpöytäsovellus.}other{Näytä # työpöytäsovellusta.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ja <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kupla"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ylivuoto"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ja <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> muuta"</string>
</resources>
diff --git a/quickstep/res/values-fr-rCA/strings.xml b/quickstep/res/values-fr-rCA/strings.xml
index 7373800..edfb59e 100644
--- a/quickstep/res/values-fr-rCA/strings.xml
+++ b/quickstep/res/values-fr-rCA/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre application.}one{Afficher # autre application.}other{Afficher # autres applications.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # appli de bureau.}one{Afficher # appli de bureau.}other{Afficher # applis de bureau.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bulle à développer"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> et <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> autres"</string>
</resources>
diff --git a/quickstep/res/values-fr/strings.xml b/quickstep/res/values-fr/strings.xml
index f19a435..60f8944 100644
--- a/quickstep/res/values-fr/strings.xml
+++ b/quickstep/res/values-fr/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afficher # autre appli}one{Afficher # autre appli}other{Afficher # autre applis}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afficher # application de bureau.}one{Afficher # application de bureau.}other{Afficher # applications de bureau.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> et <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bulle"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dépassement"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> et <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> autre(s)"</string>
</resources>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index 0afb288..bf081d4 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar # aplicación máis.}other{Mostrar # aplicacións máis.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # aplicación para ordenadores.}other{Mostrar # aplicacións para ordenadores.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulla"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menú adicional"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> e <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> máis"</string>
</resources>
diff --git a/quickstep/res/values-gu/strings.xml b/quickstep/res/values-gu/strings.xml
index fd5dca6..b20f771 100644
--- a/quickstep/res/values-gu/strings.xml
+++ b/quickstep/res/values-gu/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{વધુ # ઍપ બતાવો.}one{વધુ # ઍપ બતાવો.}other{વધુ # ઍપ બતાવો.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ડેસ્કટૉપ ઍપ બતાવો.}one{# ડેસ્કટૉપ ઍપ બતાવો.}other{# ડેસ્કટૉપ ઍપ બતાવો.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> અને <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"બબલ"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ઓવરફ્લો"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>થી <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> અને વધુ <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 246bdc7..a645186 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# और ऐप्लिकेशन दिखाएं.}one{# और ऐप्लिकेशन दिखाएं.}other{# और ऐप्लिकेशन दिखाएं.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}one{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}other{# डेस्कटॉप ऐप्लिकेशन दिखाएं.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> और <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओवरफ़्लो"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> की <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> वाली सूचना"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> और <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> अन्य"</string>
</resources>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index 0069eda..c96381d 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži još # aplikaciju}one{Prikaži još # aplikaciju}few{Prikaži još # aplikacije}other{Prikaži još # aplikacija}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaži # računalnu aplikaciju.}one{Prikaži # računalnu aplikaciju.}few{Prikaži # računalne aplikacije.}other{Prikaži # računalnih aplikacija.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblačić"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Dodatni izbornik"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> i još <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-hu/strings.xml b/quickstep/res/values-hu/strings.xml
index 162337e..03235aa 100644
--- a/quickstep/res/values-hu/strings.xml
+++ b/quickstep/res/values-hu/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# további alkalmazás megjelenítése.}other{# további alkalmazás megjelenítése.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# asztali alkalmazás megjelenítése.}other{# asztali alkalmazás megjelenítése.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> és <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Buborék"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Túlcsordulás"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>, forrás: <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> és <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> további"</string>
</resources>
diff --git a/quickstep/res/values-hy/strings.xml b/quickstep/res/values-hy/strings.xml
index 8919191..3cb7990 100644
--- a/quickstep/res/values-hy/strings.xml
+++ b/quickstep/res/values-hy/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Ցուցադրել ևս # հավելված։}one{Ցուցադրել ևս # հավելված։}other{Ցուցադրել ևս # հավելված։}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Ցույց տալ # համակարգչային հավելված։}one{Ցույց տալ # համակարգչային հավելված։}other{Ցույց տալ # համակարգչային հավելված։}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> և <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ամպիկ"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Լրացուցիչ ընտրացանկ"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>՝ <xliff:g id="APP_NAME">%2$s</xliff:g> հավելվածից"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ու ևս <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> ամպիկ"</string>
</resources>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index ea62b4d..015b09e 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tampilkan # aplikasi lainnya.}other{Tampilkan # aplikasi lainnya.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Tampilkan # aplikasi desktop.}other{Tampilkan # aplikasi desktop.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tambahan"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> dari <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> dan <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> lainnya"</string>
</resources>
diff --git a/quickstep/res/values-is/strings.xml b/quickstep/res/values-is/strings.xml
index 3e204ce..883fe82 100644
--- a/quickstep/res/values-is/strings.xml
+++ b/quickstep/res/values-is/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Sýna # forrit í viðbót.}one{Sýna # forrit í viðbót.}other{Sýna # forrit í viðbót.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Sýna # skjáborðsforrit.}one{Sýna # skjáborðsforrit.}other{Sýna # skjáborðsforrit.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Blaðra"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Yfirflæði"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> frá <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> í viðbót"</string>
</resources>
diff --git a/quickstep/res/values-it/strings.xml b/quickstep/res/values-it/strings.xml
index f295b07..59b195a 100644
--- a/quickstep/res/values-it/strings.xml
+++ b/quickstep/res/values-it/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostra # altra app.}other{Mostra altre # app.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostra # app desktop.}other{Mostra # app desktop.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Fumetto"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Extra"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> e altri <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-iw/strings.xml b/quickstep/res/values-iw/strings.xml
index 037deec..9f0ed14 100644
--- a/quickstep/res/values-iw/strings.xml
+++ b/quickstep/res/values-iw/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{הצגת אפליקציה אחת (#) נוספת.}one{הצגת # אפליקציות נוספות.}two{הצגת # אפליקציות נוספות.}other{הצגת # אפליקציות נוספות.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{הצגת אפליקציה אחת (#) למחשב.}one{הצגת # אפליקציות למחשב.}two{הצגת # אפליקציות למחשב.}other{הצגת # אפליקציות למחשב.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ו-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"בועה"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"אפשרויות נוספות"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> מתוך <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ועוד <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ja/strings.xml b/quickstep/res/values-ja/strings.xml
index ef335f2..4f1a162 100644
--- a/quickstep/res/values-ja/strings.xml
+++ b/quickstep/res/values-ja/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{他 # 件のアプリを表示できます。}other{他 # 件のアプリを表示できます。}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# 個のデスクトップ アプリが表示されます。}other{# 個のデスクトップ アプリが表示されます。}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> と <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ふきだし"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"オーバーフロー"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>(<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>、他 <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> 件"</string>
</resources>
diff --git a/quickstep/res/values-ka/strings.xml b/quickstep/res/values-ka/strings.xml
index 6da246a..1fb6077 100644
--- a/quickstep/res/values-ka/strings.xml
+++ b/quickstep/res/values-ka/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{#-ით მეტი აპის ჩენება}other{#-ით მეტი აპის ჩვენება.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# დესკტოპის აპის ჩვენება.}other{# დესკტოპის აპის ჩვენება.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> და <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ბუშტი"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"გადავსება"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>: <xliff:g id="APP_NAME">%2$s</xliff:g>-იდან"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> და <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> სხვა"</string>
</resources>
diff --git a/quickstep/res/values-kk/strings.xml b/quickstep/res/values-kk/strings.xml
index 20a1d59..d83e2d3 100644
--- a/quickstep/res/values-kk/strings.xml
+++ b/quickstep/res/values-kk/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Тағы # қолданбаны көрсету.}other{Тағы # қолданбаны көрсету.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерге арналған # қолданбаны көрсету}other{Компьютерге арналған # қолданбаны көрсету}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> және <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Қалқыма терезе"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Қосымша мәзір"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> ұсынатын <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> және тағы <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-km/strings.xml b/quickstep/res/values-km/strings.xml
index 6d5e6f1..5448433 100644
--- a/quickstep/res/values-km/strings.xml
+++ b/quickstep/res/values-km/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{បង្ហាញកម្មវិធី # ទៀត។}other{បង្ហាញកម្មវិធី # ទៀត។}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{បង្ហាញកម្មវិធីកុំព្យូទ័រ #។}other{បង្ហាញកម្មវិធីកុំព្យូទ័រ #។}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> និង <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ផ្ទាំងសារ"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ម៉ឺនុយបន្ថែម"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ពី <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> និង <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> នាក់ទៀត"</string>
</resources>
diff --git a/quickstep/res/values-kn/strings.xml b/quickstep/res/values-kn/strings.xml
index 10ab922..74c7750 100644
--- a/quickstep/res/values-kn/strings.xml
+++ b/quickstep/res/values-kn/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ಇನ್ನೂ # ಆ್ಯಪ್ ಅನ್ನು ತೋರಿಸಿ.}one{ಇನ್ನೂ # ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}other{ಇನ್ನೂ # ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ಡೆಸ್ಕ್ಟಾಪ್ ಆ್ಯಪ್ ತೋರಿಸಿ.}one{# ಡೆಸ್ಕ್ಟಾಪ್ ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}other{# ಡೆಸ್ಕ್ಟಾಪ್ ಆ್ಯಪ್ಗಳನ್ನು ತೋರಿಸಿ.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ಮತ್ತು <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ಬಬಲ್"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ಓವರ್ಫ್ಲೋ"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> ನಿಂದ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ಮತ್ತು ಇನ್ನೂ <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ko/strings.xml b/quickstep/res/values-ko/strings.xml
index 24934f9..1f4275a 100644
--- a/quickstep/res/values-ko/strings.xml
+++ b/quickstep/res/values-ko/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{앱 #개 더 표시}other{앱 #개 더 표시}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{데스크톱 앱 #개를 표시합니다.}other{데스크톱 앱 #개를 표시합니다.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> 및 <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"풍선"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"오버플로"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>의 <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> 외 <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>개"</string>
</resources>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 525a248..f0d2af8 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Дагы # колдонмону көрсөтүү.}other{Дагы # колдонмону көрсөтүү.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# иш такта колдонмосун көрсөтүү.}other{# иш такта колдонмосун көрсөтүү.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> жана <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Көбүкчө"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Кошумча меню"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> колдонмосунан <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> жана дагы <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-lo/strings.xml b/quickstep/res/values-lo/strings.xml
index b5a7ebb..f54c712 100644
--- a/quickstep/res/values-lo/strings.xml
+++ b/quickstep/res/values-lo/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ສະແດງອີກ # ແອັບ.}other{ສະແດງອີກ # ແອັບ.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{ສະແດງແອັບເດັສທັອບ # ລາຍການ.}other{ສະແດງແອັບເດັສທັອບ # ລາຍການ.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ແລະ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ຟອງ"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ລາຍການເພີ່ມເຕີມ"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> ຈາກ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ແລະ ອີກ <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> ລາຍການ"</string>
</resources>
diff --git a/quickstep/res/values-lt/strings.xml b/quickstep/res/values-lt/strings.xml
index 4817e25..554745e 100644
--- a/quickstep/res/values-lt/strings.xml
+++ b/quickstep/res/values-lt/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rodyti dar # programą.}one{Rodyti dar # programą.}few{Rodyti dar # programas.}many{Rodyti dar # programos.}other{Rodyti dar # programų.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Rodyti # darbalaukio programą.}one{Rodyti # darbalaukio programą.}few{Rodyti # darbalaukio programas.}many{Rodyti # darbalaukio programos.}other{Rodyti # darbalaukio programų.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"„<xliff:g id="APP_NAME_1">%1$s</xliff:g>“ ir „<xliff:g id="APP_NAME_2">%2$s</xliff:g>“"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulas"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Perpildymas"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"„<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>“ iš „<xliff:g id="APP_NAME">%2$s</xliff:g>“"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"„<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>“ ir dar <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-lv/strings.xml b/quickstep/res/values-lv/strings.xml
index aa80b7e..a6a0dab 100644
--- a/quickstep/res/values-lv/strings.xml
+++ b/quickstep/res/values-lv/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Rādīt vēl # lietotni}zero{Rādīt vēl # lietotnes}one{Rādīt vēl # lietotni}other{Rādīt vēl # lietotnes}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Rādīt # datora lietotni.}zero{Rādīt # datora lietotnes.}one{Rādīt # datora lietotni.}other{Rādīt # datora lietotnes.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"“<xliff:g id="APP_NAME_1">%1$s</xliff:g>” un “<xliff:g id="APP_NAME_2">%2$s</xliff:g>”"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Burbulis"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Pārpilde"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> no lietotnes <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> un vēl <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-mk/strings.xml b/quickstep/res/values-mk/strings.xml
index 039ee9f..4859055 100644
--- a/quickstep/res/values-mk/strings.xml
+++ b/quickstep/res/values-mk/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Прикажи уште # апликација.}one{Прикажи уште # апликација.}other{Прикажи уште # апликации.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Прикажи # апликација за компјутер.}one{Прикажи # апликација за компјутер.}other{Прикажи # апликации за компјутер.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Балонче"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Проширено балонче"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> од <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> и уште <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ml/strings.xml b/quickstep/res/values-ml/strings.xml
index 8fbc8f7..85b093d 100644
--- a/quickstep/res/values-ml/strings.xml
+++ b/quickstep/res/values-ml/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# ആപ്പ് കൂടി കാണിക്കുക.}other{# ആപ്പുകൾ കൂടി കാണിക്കുക.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ഡെസ്ക്ടോപ്പ് ആപ്പ് കാണിക്കുക.}other{# ഡെസ്ക്ടോപ്പ് ആപ്പുകൾ കാണിക്കുക.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ബബിൾ"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ഓവർഫ്ലോ"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> എന്നതിൽ നിന്നുള്ള <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> എന്നതും മറ്റ് <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> എണ്ണവും"</string>
</resources>
diff --git a/quickstep/res/values-mn/strings.xml b/quickstep/res/values-mn/strings.xml
index d5e4105..7a4c7e9 100644
--- a/quickstep/res/values-mn/strings.xml
+++ b/quickstep/res/values-mn/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Өөр # аппыг харуулна уу.}other{Өөр # аппыг харуулна уу.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Компьютерын # аппыг харуулна уу.}other{Компьютерын # аппыг харуулна уу.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> болон <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Бөмбөлөг"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Урт цэс"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>-с ирсэн <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> болон бусад <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-mr/strings.xml b/quickstep/res/values-mr/strings.xml
index cbce562..7941156 100644
--- a/quickstep/res/values-mr/strings.xml
+++ b/quickstep/res/values-mr/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{आणखी # अॅप दाखवा.}other{आणखी # अॅप्स दाखवा.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटॉप अॅप दाखवा.}other{# डेस्कटॉप अॅप्स दाखवा.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> आणि <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओव्हरफ्लो"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> वरील <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> आणि आणखी <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ms/strings.xml b/quickstep/res/values-ms/strings.xml
index cc1ecdd..c0219e0 100644
--- a/quickstep/res/values-ms/strings.xml
+++ b/quickstep/res/values-ms/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tunjukkan # lagi apl.}other{Tunjukkan # lagi apl.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Tunjukkan # apl desktop.}other{Tunjukkan # apl desktop.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dan <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Gelembung"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Limpahan"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> daripada <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> dan <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> lagi"</string>
</resources>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 0b3a708..7c7ff82 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{နောက်ထပ်အက်ပ် # ခု ပြပါ။}other{နောက်ထပ်အက်ပ် # ခု ပြပါ။}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{ဒက်စတော့ အက်ပ် # ခု ပြပါ။}other{ဒက်စတော့ အက်ပ် # ခု ပြပါ။}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> နှင့် <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ပူဖောင်းကွက်"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"မီနူးအပို"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> မှ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> နှင့် နောက်ထပ် <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> ခု"</string>
</resources>
diff --git a/quickstep/res/values-nb/strings.xml b/quickstep/res/values-nb/strings.xml
index 655ffec..dd3d16e 100644
--- a/quickstep/res/values-nb/strings.xml
+++ b/quickstep/res/values-nb/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Vis # app til.}other{Vis # apper til.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Vis # datamaskinprogram.}other{Vis # datamaskinprogrammer.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> og <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Boble"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflyt"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> fra <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> og <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> andre"</string>
</resources>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 3554aa5..d49fd2d 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{थप # एप देखाउनुहोस्।}other{थप # वटा एप देखाउनुहोस्।}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# डेस्कटप एप देखाउनुहोस्।}other{# वटा डेस्कटप एप देखाउनुहोस्।}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> र <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"बबल"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ओभरफ्लो"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> मा देखाइएका <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> र थप <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-nl/strings.xml b/quickstep/res/values-nl/strings.xml
index c5cebdb..ca44a69 100644
--- a/quickstep/res/values-nl/strings.xml
+++ b/quickstep/res/values-nl/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Nog # app tonen.}other{Nog # apps tonen.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# desktop-app tonen.}other{# desktop-apps tonen.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> en <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbel"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overloop"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> van <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> en nog <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-or/strings.xml b/quickstep/res/values-or/strings.xml
index 765935e..bf0bdc8 100644
--- a/quickstep/res/values-or/strings.xml
+++ b/quickstep/res/values-or/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{ଅଧିକ #ଟି ଆପ ଦେଖାନ୍ତୁ।}other{ଅଧିକ #ଟି ଆପ୍ସ ଦେଖାନ୍ତୁ।}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ଡେସ୍କଟପ ଆପ ଦେଖାନ୍ତୁ।}other{# ଡେସ୍କଟପ ଆପ୍ସ ଦେଖାନ୍ତୁ।}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ଏବଂ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ବବଲ"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ଓଭରଫ୍ଲୋ"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g>ରୁ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ଏବଂ ଅଧିକ <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-pa/strings.xml b/quickstep/res/values-pa/strings.xml
index 769608b..fc60396 100644
--- a/quickstep/res/values-pa/strings.xml
+++ b/quickstep/res/values-pa/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}one{# ਹੋਰ ਐਪ ਦਿਖਾਓ।}other{# ਹੋਰ ਐਪਾਂ ਦਿਖਾਓ।}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ਡੈਸਕਟਾਪ ਐਪ ਦਿਖਾਓ।}one{# ਡੈਸਕਟਾਪ ਐਪ ਦਿਖਾਓ।}other{# ਡੈਸਕਟਾਪ ਐਪਾਂ ਦਿਖਾਓ।}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ਅਤੇ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ਬਬਲ"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ਓਵਰਫ਼ਲੋ"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> ਤੋਂ <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ਅਤੇ <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> ਹੋਰ"</string>
</resources>
diff --git a/quickstep/res/values-pl/strings.xml b/quickstep/res/values-pl/strings.xml
index 752764f..d88e28a 100644
--- a/quickstep/res/values-pl/strings.xml
+++ b/quickstep/res/values-pl/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Pokaż jeszcze # aplikację.}few{Pokaż jeszcze # aplikacje.}many{Pokaż jeszcze # aplikacji.}other{Pokaż jeszcze # aplikacji.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Pokaż # aplikację komputerową.}few{Pokaż # aplikacje komputerowe.}many{Pokaż # aplikacji komputerowych.}other{Pokaż # aplikacji komputerowej.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> i <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Dymek"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozwijany"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikacji <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> i jeszcze <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index a692e69..dd00469 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computador.}other{Mostrar # apps para computador.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Menu adicional"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> da app <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> e mais <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> pessoas"</string>
</resources>
diff --git a/quickstep/res/values-pt/strings.xml b/quickstep/res/values-pt/strings.xml
index dd3c037..4fec4f8 100644
--- a/quickstep/res/values-pt/strings.xml
+++ b/quickstep/res/values-pt/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Mostrar mais # app.}one{Mostrar mais # app.}other{Mostrar mais # apps.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Mostrar # app para computador.}one{Mostrar # app para computador.}other{Mostrar # apps para computador.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> e <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balão"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Balão flutuante"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> do app <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> e mais <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ro/strings.xml b/quickstep/res/values-ro/strings.xml
index 7efeda2..c839602 100644
--- a/quickstep/res/values-ro/strings.xml
+++ b/quickstep/res/values-ro/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Afișează încă # aplicație}few{Afișează încă # aplicații}other{Afișează încă # de aplicații}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Afișează # aplicație pentru computer.}few{Afișează # aplicații pentru computer.}other{Afișează # de aplicații pentru computer.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> și <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Suplimentar"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> de la <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> și încă <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index e8d1ddb..da49ad3 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показать ещё # приложение}one{Показать ещё # приложение}few{Показать ещё # приложения}many{Показать ещё # приложений}other{Показать ещё # приложения}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показать # компьютерное приложение.}one{Показать # компьютерное приложение.}few{Показать # компьютерных приложения.}many{Показать # компьютерных приложений.}other{Показать # компьютерного приложения.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Всплывающая подсказка"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Дополнительное меню"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"\"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" из приложения \"<xliff:g id="APP_NAME">%2$s</xliff:g>\""</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> и ещё <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-si/strings.xml b/quickstep/res/values-si/strings.xml
index 9d1c312..9cbe837 100644
--- a/quickstep/res/values-si/strings.xml
+++ b/quickstep/res/values-si/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{තවත් # යෙදුමක් පෙන්වන්න.}one{තවත් යෙදුම් #ක් පෙන්වන්න.}other{තවත් යෙදුම් #ක් පෙන්වන්න.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ඩෙස්ක්ටොප් යෙදුමක් පෙන්වන්න.}one{ඩෙස්ක්ටොප් යෙදුම් # ක් පෙන්වන්න.}other{ඩෙස්ක්ටොප් යෙදුම් # ක් පෙන්වන්න.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> සහ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"බුබුළු"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"පිටාර යාම"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> සිට <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> හා තව <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>ක්"</string>
</resources>
diff --git a/quickstep/res/values-sk/strings.xml b/quickstep/res/values-sk/strings.xml
index a573b45..3eca787 100644
--- a/quickstep/res/values-sk/strings.xml
+++ b/quickstep/res/values-sk/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Zobraziť # ďalšiu aplikáciu.}few{Zobraziť # ďalšie aplikácie.}many{Show # more apps.}other{Zobraziť # ďalších aplikácií.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Zobraziť # aplikáciu pre počítač.}few{Zobraziť # aplikácie pre počítač.}many{Show # desktop apps.}other{Zobraziť # aplikácií pre počítač.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> a <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bublina"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Rozbaľovacia ponuka"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> z aplikácie <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> a ešte <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-sl/strings.xml b/quickstep/res/values-sl/strings.xml
index 355dc61..52faeb7 100644
--- a/quickstep/res/values-sl/strings.xml
+++ b/quickstep/res/values-sl/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Pokaži še # aplikacijo.}one{Pokaži še # aplikacijo.}two{Pokaži še # aplikaciji.}few{Pokaži še # aplikacije.}other{Pokaži še # aplikacij.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Prikaz # aplikacije za namizni računalnik.}one{Prikaz # aplikacije za namizni računalnik.}two{Prikaz # aplikacij za namizni računalnik.}few{Prikaz # aplikacij za namizni računalnik.}other{Prikaz # aplikacij za namizni računalnik.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> in <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Oblaček"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Oblaček z dodatnimi elementi"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> iz aplikacije <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> in še <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-sq/strings.xml b/quickstep/res/values-sq/strings.xml
index 71eca07..cdb9cf9 100644
--- a/quickstep/res/values-sq/strings.xml
+++ b/quickstep/res/values-sq/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Shfaq # aplikacion tjetër.}other{Shfaq # aplikacione të tjera.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Shfaq # aplikacion për desktop.}other{Shfaq # aplikacione për desktop.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> dhe <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Flluska"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Tejkalimi"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"\"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>\" nga <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"\"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>\" dhe <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> të tjera"</string>
</resources>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 34bcb1c..7456a36 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Прикажи још # апликацију.}one{Прикажи још # апликацију.}few{Прикажи још # апликације.}other{Прикажи још # апликација.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Прикажи # апликацију за рачунаре.}one{Прикажи # апликацију за рачунаре.}few{Прикажи # апликације за рачунаре.}other{Прикажи # апликација за рачунаре.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> и <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Облачић"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Преклопни"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> – <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> и још <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 723cb82..f369dae 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Visa # app till.}other{Visa # appar till.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Visa # datorapp.}other{Visa # datorappar.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> och <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubbla"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Fler alternativ"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> från <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> och <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> till"</string>
</resources>
diff --git a/quickstep/res/values-sw/strings.xml b/quickstep/res/values-sw/strings.xml
index 6a3f624..3d8277b 100644
--- a/quickstep/res/values-sw/strings.xml
+++ b/quickstep/res/values-sw/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Onyesha programu # zaidi.}other{Onyesha programu # zaidi.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Onyesha programu # ya kompyuta ya mezani.}other{Onyesha programu # za kompyuta ya mezani.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> na <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Kiputo"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kiputo cha vipengee vya ziada"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kutoka <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> na vingine <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
index f9528b3..e24d8fe 100644
--- a/quickstep/res/values-sw600dp/dimens.xml
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -45,4 +45,8 @@
<dimen name="allset_page_allset_text_size">38sp</dimen>
<dimen name="allset_page_swipe_up_text_size">15sp</dimen>
+ <!-- Splitscreen -->
+ <!-- Max width of the split instructions view -->
+ <dimen name="split_instructions_view_max_width">300dp</dimen>
+
</resources>
diff --git a/quickstep/res/values-ta/strings.xml b/quickstep/res/values-ta/strings.xml
index 90ff5ea..ed3ebee 100644
--- a/quickstep/res/values-ta/strings.xml
+++ b/quickstep/res/values-ta/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{மேலும் # ஆப்ஸைக் காட்டு.}other{மேலும் # ஆப்ஸைக் காட்டு.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# டெஸ்க்டாப் ஆப்ஸைக் காட்டு.}other{# டெஸ்க்டாப் ஆப்ஸைக் காட்டு.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> மற்றும் <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"குமிழ்"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"கூடுதல் விருப்பங்களைக் காட்டும்"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> வழங்கும் <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> மற்றும் <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-te/strings.xml b/quickstep/res/values-te/strings.xml
index c32f360..a4e1cbf 100644
--- a/quickstep/res/values-te/strings.xml
+++ b/quickstep/res/values-te/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{మరో # యాప్ను చూడండి.}other{మరో # యాప్లను చూడండి.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# డెస్క్టాప్ యాప్ను చూపండి.}other{# డెస్క్టాప్ యాప్లను చూపండి.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>, <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"బబుల్"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"ఓవర్ఫ్లో"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> నుండి <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>, మరో <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-th/strings.xml b/quickstep/res/values-th/strings.xml
index f1fd49b..1bbb137 100644
--- a/quickstep/res/values-th/strings.xml
+++ b/quickstep/res/values-th/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{แสดงเพิ่มเติมอีก # แอป}other{แสดงเพิ่มเติมอีก # แอป}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{แสดงแอปบนเดสก์ท็อป # รายการ}other{แสดงแอปบนเดสก์ท็อป # รายการ}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> และ <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"บับเบิล"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"การดำเนินการเพิ่มเติม"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> จาก <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> และอีก <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> รายการ"</string>
</resources>
diff --git a/quickstep/res/values-tl/strings.xml b/quickstep/res/values-tl/strings.xml
index f0e2311..978a5a3 100644
--- a/quickstep/res/values-tl/strings.xml
+++ b/quickstep/res/values-tl/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Magpakita ng # pang app.}one{Magpakita ng # pang app.}other{Magpakita ng # pang app.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Ipakita ang # desktop app.}one{Ipakita ang # desktop app.}other{Ipakita ang # na desktop app.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> at <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bubble"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Overflow"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> mula sa <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> at <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> pa"</string>
</resources>
diff --git a/quickstep/res/values-tr/strings.xml b/quickstep/res/values-tr/strings.xml
index 5eb84d6..0cc5d7f 100644
--- a/quickstep/res/values-tr/strings.xml
+++ b/quickstep/res/values-tr/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# uygulama daha göster.}other{# uygulama daha göster}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# masaüstü uygulamasını göster.}other{# masaüstü uygulamasını göster.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> ve <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Balon"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Taşma"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> uygulamasından <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> ve <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> tane daha"</string>
</resources>
diff --git a/quickstep/res/values-uk/strings.xml b/quickstep/res/values-uk/strings.xml
index 3be1627..9c706a8 100644
--- a/quickstep/res/values-uk/strings.xml
+++ b/quickstep/res/values-uk/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Показати ще # додаток.}one{Показати ще # додаток.}few{Показати ще # додатки.}many{Показати ще # додатків.}other{Показати ще # додатка.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Показати # комп’ютерну програму.}one{Показати # комп’ютерну програму.}few{Показати # комп’ютерні програми.}many{Показати # комп’ютерних програм.}other{Показати # комп’ютерної програми.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> та <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Повідомлення"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Додаткове повідомлення"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> з додатка <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> і ще <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values-ur/strings.xml b/quickstep/res/values-ur/strings.xml
index 0e951f0..e125248 100644
--- a/quickstep/res/values-ur/strings.xml
+++ b/quickstep/res/values-ur/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# مزید ایپ دکھائیں۔}other{# مزید ایپس دکھائیں۔}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ڈیسک ٹاپ ایپ دکھائیں۔}other{# ڈیسک ٹاپ ایپس دکھائیں۔}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> اور <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"ببل"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"اوورفلو"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> سے <xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> اور <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> مزید"</string>
</resources>
diff --git a/quickstep/res/values-uz/strings.xml b/quickstep/res/values-uz/strings.xml
index 4d57b22..3f4f981 100644
--- a/quickstep/res/values-uz/strings.xml
+++ b/quickstep/res/values-uz/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Yana # ta ilovani chiqarish}other{Yana # ta ilovani chiqarish}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{# ta desktop ilovani chiqarish.}other{# ta desktop ilovani chiqarish.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> va <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Pufak"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Kengaytirish"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> (<xliff:g id="APP_NAME">%2$s</xliff:g>)"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> va yana <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> kishi"</string>
</resources>
diff --git a/quickstep/res/values-vi/strings.xml b/quickstep/res/values-vi/strings.xml
index df8ccdc..9bc526f 100644
--- a/quickstep/res/values-vi/strings.xml
+++ b/quickstep/res/values-vi/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Hiện thêm # ứng dụng.}other{Hiện thêm # ứng dụng.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Hiện # ứng dụng dành cho máy tính.}other{Hiện # ứng dụng dành cho máy tính.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g> và <xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Bong bóng"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Bong bóng bổ sung"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> từ <xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> và <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> bong bóng khác"</string>
</resources>
diff --git a/quickstep/res/values-zh-rCN/strings.xml b/quickstep/res/values-zh-rCN/strings.xml
index e750730..a89227e 100644
--- a/quickstep/res/values-zh-rCN/strings.xml
+++ b/quickstep/res/values-zh-rCN/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{显示另外 # 个应用。}other{显示另外 # 个应用。}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{显示 # 款桌面应用。}other{显示 # 款桌面应用。}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"<xliff:g id="APP_NAME_1">%1$s</xliff:g>和<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"气泡框"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"菜单"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"来自“<xliff:g id="APP_NAME">%2$s</xliff:g>”的<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>以及另外 <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> 个"</string>
</resources>
diff --git a/quickstep/res/values-zh-rHK/strings.xml b/quickstep/res/values-zh-rHK/strings.xml
index 9427b07..b9d8eb7 100644
--- a/quickstep/res/values-zh-rHK/strings.xml
+++ b/quickstep/res/values-zh-rHK/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{顯示另外 # 個應用程式。}other{顯示另外 # 個應用程式。}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{顯示 # 個桌面應用程式。}other{顯示 # 個桌面應用程式。}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"對話氣泡"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"展開式"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="APP_NAME">%2$s</xliff:g> 的「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」通知"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>和其他 <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> 則通知"</string>
</resources>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index 3b06eda..90140cb 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{再多顯示 # 個應用程式。}other{再多顯示 # 個應用程式。}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{顯示 # 個電腦版應用程式。}other{顯示 # 個電腦版應用程式。}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"「<xliff:g id="APP_NAME_1">%1$s</xliff:g>」和「<xliff:g id="APP_NAME_2">%2$s</xliff:g>」"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"泡泡"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"溢位"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"「<xliff:g id="APP_NAME">%2$s</xliff:g>」的「<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g>」通知"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g>和另外 <xliff:g id="BUBBLE_COUNT">%2$d</xliff:g> 則通知"</string>
</resources>
diff --git a/quickstep/res/values-zu/strings.xml b/quickstep/res/values-zu/strings.xml
index cb216fc..73be445 100644
--- a/quickstep/res/values-zu/strings.xml
+++ b/quickstep/res/values-zu/strings.xml
@@ -140,4 +140,8 @@
<string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Bonisa i-app e-# ngaphezulu.}one{Bonisa ama-app angu-# ngaphezulu.}other{Bonisa ama-app angu-# ngaphezulu.}}"</string>
<string name="quick_switch_desktop" msgid="4834587349322698616">"{count,plural, =1{Bonisa i-app engu-# yedeskithophu.}one{Bonisa ama-app angu-# wedeskithophu.}other{Bonisa ama-app angu-# wedeskithophu.}}"</string>
<string name="quick_switch_split_task" msgid="5598194724255333896">"I-<xliff:g id="APP_NAME_1">%1$s</xliff:g> ne-<xliff:g id="APP_NAME_2">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_bubble_fallback_description" msgid="7811684548953452009">"Ibhamuza"</string>
+ <string name="bubble_bar_overflow_description" msgid="8617628132733151708">"Ukugcwala kakhulu"</string>
+ <string name="bubble_bar_bubble_description" msgid="1882466152448446446">"<xliff:g id="NOTIFICATION_TITLE">%1$s</xliff:g> kusuka ku-<xliff:g id="APP_NAME">%2$s</xliff:g>"</string>
+ <string name="bubble_bar_description_multiple_bubbles" msgid="3922207715357143648">"<xliff:g id="BUBBLE_BAR_BUBBLE_DESCRIPTION">%1$s</xliff:g> nokunye okungu-<xliff:g id="BUBBLE_COUNT">%2$d</xliff:g>"</string>
</resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 2021a0b..5c82c99 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -358,12 +358,16 @@
<dimen name="taskbar_running_app_indicator_height">4dp</dimen>
<dimen name="taskbar_running_app_indicator_width">14dp</dimen>
<dimen name="taskbar_running_app_indicator_top_margin">2dp</dimen>
+ <dimen name="taskbar_minimized_app_indicator_height">2dp</dimen>
+ <dimen name="taskbar_minimized_app_indicator_width">12dp</dimen>
+ <dimen name="taskbar_minimized_app_indicator_top_margin">2dp</dimen>
<!-- Transient taskbar -->
<dimen name="transient_taskbar_padding">12dp</dimen>
<dimen name="transient_taskbar_min_width">150dp</dimen>
<dimen name="transient_taskbar_bottom_margin">24dp</dimen>
<dimen name="transient_taskbar_shadow_blur">40dp</dimen>
+ <dimen name="transient_taskbar_stroke_width">1dp</dimen>
<dimen name="transient_taskbar_key_shadow_distance">10dp</dimen>
<dimen name="transient_taskbar_stashed_height">32dp</dimen>
<dimen name="transient_taskbar_all_apps_button_translation_x_offset">8dp</dimen>
@@ -381,6 +385,11 @@
<!-- Taskbar swipe down threshold -->
<dimen name="taskbar_to_nav_threshold">24dp</dimen>
+ <!-- Taskbar variables that help determine when to animate the Taskbar background -->
+ <!-- Velocity defined as dp per s. Negative because the gesture is an upwards motion. -->
+ <dimen name="taskbar_slow_velocity_y_threshold">-288dp</dimen>
+ <integer name="taskbar_background_duration">80</integer>
+
<!-- Taskbar swipe up threshold multipliers -->
<item name="taskbar_nav_threshold_mult" format="float" type="dimen">4.5</item>
<item name="taskbar_app_window_threshold_mult" format="float" type="dimen">10</item>
@@ -484,4 +493,11 @@
<dimen name="keyboard_quick_switch_no_recent_items_icon_size">24dp</dimen>
<dimen name="keyboard_quick_switch_no_recent_items_icon_margin">8dp</dimen>
+ <!-- Digital Wellbeing -->
+ <dimen name="digital_wellbeing_toast_height">48dp</dimen>
+
+ <!-- Splitscreen -->
+ <!-- Max width of the split instructions view -->
+ <dimen name="split_instructions_view_max_width">220dp</dimen>
+
</resources>
diff --git a/quickstep/res/values/strings.xml b/quickstep/res/values/strings.xml
index cf987c3..340d25b 100644
--- a/quickstep/res/values/strings.xml
+++ b/quickstep/res/values/strings.xml
@@ -332,4 +332,14 @@
<!-- Accessibility label for quick switch tiles showing split tasks [CHAR LIMIT=NONE] -->
<string name="quick_switch_split_task"><xliff:g id="app_name_1" example="Chrome">%1$s</xliff:g> and <xliff:g id="app_name_2" example="Gmail">%2$s</xliff:g></string>
+
+ <!-- Strings for bubble bar -->
+ <!-- Fallback name for a bubble if it does have a title [CHAR_LIMIT=none] -->
+ <string name="bubble_bar_bubble_fallback_description">Bubble</string>
+ <!-- content description for the overflow bubble [CHAR_LIMIT=none] -->
+ <string name="bubble_bar_overflow_description">Overflow</string>
+ <!-- Content description for a bubble bar bubble. [CHAR_LIMIT=none] -->
+ <string name="bubble_bar_bubble_description"><xliff:g id="notification_title" example="some title">%1$s</xliff:g> from <xliff:g id="app_name" example="YouTube">%2$s</xliff:g></string>
+ <!-- Content description for bubble bar when it has multiple bubbles. [CHAR_LIMIT=NONE] -->
+ <string name="bubble_bar_description_multiple_bubbles"><xliff:g id="bubble_bar_bubble_description" example="some title from YouTube">%1$s</xliff:g> and <xliff:g id="bubble_count" example="4">%2$d</xliff:g> more</string>
</resources>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 0c499b8..fae281a 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -151,6 +151,7 @@
import com.android.quickstep.util.RectFSpringAnim;
import com.android.quickstep.util.RectFSpringAnim.DefaultSpringConfig;
import com.android.quickstep.util.RectFSpringAnim.TaskbarHotseatSpringConfig;
+import com.android.quickstep.util.ScalingWorkspaceRevealAnim;
import com.android.quickstep.util.StaggeredWorkspaceAnim;
import com.android.quickstep.util.SurfaceTransaction;
import com.android.quickstep.util.SurfaceTransaction.SurfaceProperties;
@@ -174,7 +175,6 @@
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
-import java.util.Map.Entry;
/**
* Manages the opening and closing app transitions from Launcher
@@ -1630,10 +1630,15 @@
anim.play(getUnlockWindowAnimator(appTargets, wallpaperTargets));
} else if (ENABLE_BACK_SWIPE_HOME_ANIMATION.get()
&& !playFallBackAnimation) {
- // Use a fixed velocity to start the animation.
- float velocityPxPerS = DynamicResource.provider(mLauncher)
- .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
- PointF velocity = new PointF(0, -velocityPxPerS);
+ PointF velocity;
+ if (enableScalingRevealHomeAnimation()) {
+ velocity = new PointF();
+ } else {
+ // Use a fixed velocity to start the animation.
+ float velocityPxPerS = DynamicResource.provider(mLauncher)
+ .getDimension(R.dimen.unlock_staggered_velocity_dp_per_s);
+ velocity = new PointF(0, -velocityPxPerS);
+ }
rectFSpringAnim = getClosingWindowAnimators(
anim, appTargets, launcherView, velocity, startRect,
startWindowCornerRadius);
@@ -1642,8 +1647,15 @@
// layout bounds.
skipAllAppsScale = true;
} else if (!fromPredictiveBack) {
- anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
- true /* animateOverviewScrim */, launcherView).getAnimators());
+ if (enableScalingRevealHomeAnimation()) {
+ anim.play(
+ new ScalingWorkspaceRevealAnim(
+ mLauncher, rectFSpringAnim,
+ rectFSpringAnim.getTargetRect()).getAnimators());
+ } else {
+ anim.play(new StaggeredWorkspaceAnim(mLauncher, velocity.y,
+ true /* animateOverviewScrim */, launcherView).getAnimators());
+ }
if (!areAllTargetsTranslucent(appTargets)) {
anim.play(ObjectAnimator.ofFloat(mLauncher.getDepthController().stateDepth,
diff --git a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
index 23cb8e9..943c08c 100644
--- a/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
+++ b/quickstep/src/com/android/launcher3/WidgetPickerActivity.java
@@ -194,6 +194,11 @@
return false;
}
+ View dragView = widgetCell.getDragAndDropView();
+ if (dragView == null) {
+ return false;
+ }
+
ClipData clipData = new ClipData(
new ClipDescription(
/* label= */ "", // not displayed anywhere; so, set to empty.
@@ -209,9 +214,9 @@
.putExtra(EXTRA_IS_PENDING_WIDGET_DRAG, true));
// DRAG_FLAG_GLOBAL permits dragging data beyond app window.
- return view.startDragAndDrop(
+ return dragView.startDragAndDrop(
clipData,
- new View.DragShadowBuilder(view),
+ new View.DragShadowBuilder(dragView),
/* myLocalState= */ null,
View.DRAG_FLAG_GLOBAL
);
diff --git a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
index 3ef8e54..0000c0d 100644
--- a/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
+++ b/quickstep/src/com/android/launcher3/desktop/DesktopRecentsTransitionController.kt
@@ -30,6 +30,7 @@
import com.android.quickstep.SystemUiProxy
import com.android.quickstep.TaskViewUtils
import com.android.quickstep.views.DesktopTaskView
+import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
import java.util.function.Consumer
/** Manage recents related operations with desktop tasks */
@@ -57,8 +58,8 @@
}
/** Launch desktop tasks from recents view */
- fun moveToDesktop(taskId: Int) {
- systemUiProxy.moveToDesktop(taskId)
+ fun moveToDesktop(taskId: Int, transitionSource: DesktopModeTransitionSource) {
+ systemUiProxy.moveToDesktop(taskId, transitionSource)
}
private class RemoteDesktopLaunchTransitionRunner(
diff --git a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
index 39f2c00..64bb05e 100644
--- a/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
+++ b/quickstep/src/com/android/launcher3/model/WidgetsPredictionUpdateTask.java
@@ -19,6 +19,7 @@
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
import android.app.prediction.AppTarget;
+import android.content.ComponentName;
import android.content.Context;
import android.text.TextUtils;
@@ -29,7 +30,6 @@
import com.android.launcher3.model.QuickstepModelDelegate.PredictorState;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.ComponentKey;
-import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.widget.PendingAddWidgetInfo;
import com.android.launcher3.widget.picker.WidgetRecommendationCategoryProvider;
@@ -64,36 +64,24 @@
widget -> new ComponentKey(widget.providerName, widget.user)).collect(
Collectors.toSet());
Predicate<WidgetItem> notOnWorkspace = w -> !widgetsInWorkspace.contains(w);
- Map<PackageUserKey, List<WidgetItem>> allWidgets =
- dataModel.widgetsModel.getAllWidgetsWithoutShortcuts();
+ Map<ComponentKey, WidgetItem> allWidgets =
+ dataModel.widgetsModel.getAllWidgetComponentsWithoutShortcuts();
List<WidgetItem> servicePredictedItems = new ArrayList<>();
- List<WidgetItem> localFilteredWidgets = new ArrayList<>();
for (AppTarget app : mTargets) {
- PackageUserKey packageUserKey = new PackageUserKey(app.getPackageName(), app.getUser());
- List<WidgetItem> widgets = allWidgets.get(packageUserKey);
- if (widgets == null || widgets.isEmpty()) {
+ ComponentKey componentKey = new ComponentKey(
+ new ComponentName(app.getPackageName(), app.getClassName()), app.getUser());
+ WidgetItem widget = allWidgets.get(componentKey);
+ if (widget == null) {
continue;
}
String className = app.getClassName();
if (!TextUtils.isEmpty(className)) {
- WidgetItem item = widgets.stream()
- .filter(w -> className.equals(w.componentName.getClassName()))
- .filter(notOnWorkspace)
- .findFirst()
- .orElse(null);
- if (item != null) {
- servicePredictedItems.add(item);
- continue;
+ if (notOnWorkspace.test(widget)) {
+ servicePredictedItems.add(widget);
}
}
- // No widget was added by the service, try local filtering
- widgets.stream().filter(notOnWorkspace).findFirst()
- .ifPresent(localFilteredWidgets::add);
- }
- if (servicePredictedItems.isEmpty()) {
- servicePredictedItems.addAll(localFilteredWidgets);
}
List<ItemInfo> items;
diff --git a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
deleted file mode 100644
index 3649c4e..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsController.kt
+++ /dev/null
@@ -1,148 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.taskbar
-
-import android.app.ActivityManager.RunningTaskInfo
-import android.app.WindowConfiguration
-import android.util.Log
-import android.util.SparseArray
-import androidx.annotation.VisibleForTesting
-import androidx.core.util.valueIterator
-import com.android.launcher3.model.data.AppInfo
-import com.android.launcher3.model.data.ItemInfo
-import com.android.launcher3.model.data.WorkspaceItemInfo
-import com.android.launcher3.statehandlers.DesktopVisibilityController
-import com.android.quickstep.RecentsModel
-import kotlin.collections.filterNotNull
-
-/**
- * Shows running apps when in Desktop Mode.
- *
- * Users can enter and exit Desktop Mode at run-time, meaning this class falls back to the default
- * recent-apps behaviour when outside of Desktop Mode.
- *
- * This class should only be used if
- * [com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps] is enabled.
- */
-class DesktopTaskbarRunningAppsController(
- private val recentsModel: RecentsModel,
- // Pass a provider here instead of the actual DesktopVisibilityController instance since that
- // instance might not be available when this constructor is called.
- private val desktopVisibilityControllerProvider: () -> DesktopVisibilityController?,
-) : TaskbarRecentAppsController() {
-
- private var apps: Array<AppInfo>? = null
- private var allRunningDesktopAppInfos: List<AppInfo>? = null
-
- private val desktopVisibilityController: DesktopVisibilityController?
- get() = desktopVisibilityControllerProvider()
-
- private val isInDesktopMode: Boolean
- get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false
-
- override fun onDestroy() {
- super.onDestroy()
- apps = null
- }
-
- @VisibleForTesting
- public override fun setApps(apps: Array<AppInfo>?) {
- this.apps = apps
- }
-
- override fun isEnabled() = true
-
- @VisibleForTesting
- public override fun updateHotseatItemInfos(hotseatItems: Array<ItemInfo?>): Array<ItemInfo?> {
- if (!isInDesktopMode) {
- Log.d(TAG, "updateHotseatItemInfos: not in Desktop Mode")
- return hotseatItems
- }
- val newHotseatItemInfos =
- hotseatItems
- .filterNotNull()
- // Ignore predicted apps - we show running apps instead
- .filter { itemInfo -> !itemInfo.isPredictedItem }
- .toMutableList()
- val runningDesktopAppInfos =
- allRunningDesktopAppInfos?.let {
- getRunningDesktopAppInfosExceptHotseatApps(it, newHotseatItemInfos.toList())
- }
- if (runningDesktopAppInfos != null) {
- newHotseatItemInfos.addAll(runningDesktopAppInfos)
- }
- return newHotseatItemInfos.toTypedArray()
- }
-
- override fun getRunningApps(): Set<String> {
- if (!isInDesktopMode) {
- return emptySet()
- }
- return allRunningDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet()
- }
-
- @VisibleForTesting
- public override fun updateRunningApps() {
- if (!isInDesktopMode) {
- Log.d(TAG, "updateRunningApps: not in Desktop Mode")
- mControllers.taskbarViewController.commitRunningAppsToUI()
- return
- }
- allRunningDesktopAppInfos = getRunningDesktopAppInfos()
- mControllers.taskbarViewController.commitRunningAppsToUI()
- }
-
- private fun getRunningDesktopAppInfosExceptHotseatApps(
- allRunningDesktopAppInfos: List<AppInfo>,
- hotseatItems: List<ItemInfo>
- ): List<ItemInfo> {
- val hotseatPackages = hotseatItems.map { it.targetPackage }
- return allRunningDesktopAppInfos
- .filter { appInfo -> !hotseatPackages.contains(appInfo.targetPackage) }
- .map { WorkspaceItemInfo(it) }
- }
-
- private fun getRunningDesktopAppInfos(): List<AppInfo> {
- return getAppInfosFromRunningTasks(
- recentsModel.runningTasks
- .filter { taskInfo: RunningTaskInfo ->
- taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
- }
- .toList()
- )
- }
-
- // TODO(b/335398876) fetch app icons from Tasks instead of AppInfos
- private fun getAppInfosFromRunningTasks(tasks: List<RunningTaskInfo>): List<AppInfo> {
- // Early return if apps is empty, since we then have no AppInfo to compare to
- if (apps == null) {
- return emptyList()
- }
- val packageNames = tasks.map { it.realActivity?.packageName }.distinct().filterNotNull()
- return packageNames
- .map { packageName -> apps?.find { app -> packageName == app.targetPackage } }
- .filterNotNull()
- }
-
- private fun <E> SparseArray<E>.toList(): List<E> {
- return valueIterator().asSequence().toList()
- }
-
- companion object {
- private const val TAG = "TabletDesktopTaskbarRunningAppsController"
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
index b213203..358d703 100644
--- a/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/KeyboardQuickSwitchController.java
@@ -148,7 +148,7 @@
});
}
- private void processLoadedTasks(ArrayList<GroupTask> tasks) {
+ private void processLoadedTasks(List<GroupTask> tasks) {
// Only store MAX_TASK tasks, from most to least recent
Collections.reverse(tasks);
mTasks = tasks.stream()
@@ -157,7 +157,7 @@
mNumHiddenTasks = Math.max(0, tasks.size() - MAX_TASKS);
}
- private void processLoadedTasksOnDesktop(ArrayList<GroupTask> tasks) {
+ private void processLoadedTasksOnDesktop(List<GroupTask> tasks) {
// Find the single desktop task that contains a grouping of desktop tasks
DesktopTask desktopTask = findDesktopTask(tasks);
@@ -173,7 +173,7 @@
}
@Nullable
- private DesktopTask findDesktopTask(ArrayList<GroupTask> tasks) {
+ private DesktopTask findDesktopTask(List<GroupTask> tasks) {
return (DesktopTask) tasks.stream()
.filter(t -> t instanceof DesktopTask)
.findFirst()
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 8d4c34d..252f2a8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -118,7 +118,7 @@
mControllers = controllers;
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
Resources resources = mActivity.getResources();
- if (mActivity.isPhoneGestureNavMode()) {
+ if (mActivity.isPhoneGestureNavMode() || mActivity.isTinyTaskbar()) {
mTaskbarSize = resources.getDimensionPixelSize(R.dimen.taskbar_phone_size);
mStashedHandleWidth =
resources.getDimensionPixelSize(R.dimen.taskbar_stashed_small_screen);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 1571ac0..05c2f08 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -41,8 +41,7 @@
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
-import static com.android.window.flags.Flags.enableDesktopWindowingMode;
-import static com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps;
+import static com.android.wm.shell.Flags.enableTinyTaskbar;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
@@ -303,7 +302,9 @@
new VoiceInteractionWindowController(this),
new TaskbarTranslationController(this),
new TaskbarSpringOnStashController(this),
- createTaskbarRecentAppsController(),
+ new TaskbarRecentAppsController(
+ RecentsModel.INSTANCE.get(this),
+ LauncherActivityInterface.INSTANCE::getDesktopVisibilityController),
TaskbarEduTooltipController.newInstance(this),
new KeyboardQuickSwitchController(),
new TaskbarPinningController(this, () ->
@@ -313,16 +314,6 @@
mLauncherPrefs = LauncherPrefs.get(this);
}
- private TaskbarRecentAppsController createTaskbarRecentAppsController() {
- // TODO(b/335401172): unify DesktopMode checks in Launcher
- if (enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps()) {
- return new DesktopTaskbarRunningAppsController(
- RecentsModel.INSTANCE.get(this),
- LauncherActivityInterface.INSTANCE::getDesktopVisibilityController);
- }
- return TaskbarRecentAppsController.DEFAULT;
- }
-
/** Updates {@link DeviceProfile} instances for any Taskbar windows. */
public void updateDeviceProfile(DeviceProfile launcherDp) {
applyDeviceProfile(launcherDp);
@@ -416,7 +407,9 @@
* single window for taskbar and navbar.
*/
public boolean isPhoneMode() {
- return ENABLE_TASKBAR_NAVBAR_UNIFICATION && mDeviceProfile.isPhone;
+ return ENABLE_TASKBAR_NAVBAR_UNIFICATION
+ && mDeviceProfile.isPhone
+ && !mDeviceProfile.isTaskbarPresent;
}
/**
@@ -433,6 +426,11 @@
return isPhoneMode() && !isThreeButtonNav();
}
+ /** Returns {@code true} iff a tiny version of taskbar is shown on phone. */
+ public boolean isTinyTaskbar() {
+ return enableTinyTaskbar() && mDeviceProfile.isPhone && mDeviceProfile.isTaskbarPresent;
+ }
+
/**
* Returns if software keyboard is docked or input toolbar is placed at the taskbar area
*/
@@ -981,7 +979,7 @@
public int getDefaultTaskbarWindowSize() {
Resources resources = getResources();
- if (ENABLE_TASKBAR_NAVBAR_UNIFICATION && mDeviceProfile.isPhone) {
+ if (isPhoneMode()) {
return isThreeButtonNav() ?
resources.getDimensionPixelSize(R.dimen.taskbar_phone_size) :
resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
@@ -1398,6 +1396,13 @@
}
/**
+ * Plays the taskbar background alpha animation if one is not currently playing.
+ */
+ public void playTaskbarBackgroundAlphaAnimation() {
+ mControllers.taskbarStashController.playTaskbarBackgroundAlphaAnimation();
+ }
+
+ /**
* Called to start the taskbar translation spring to its settled translation (0).
*/
public void startTranslationSpring() {
@@ -1597,4 +1602,9 @@
boolean canToggleHomeAllApps() {
return mControllers.uiController.canToggleHomeAllApps();
}
+
+ @VisibleForTesting
+ public TaskbarControllers getControllers() {
+ return mControllers;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index e290c3f..7144a38 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -37,8 +37,6 @@
class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
private val isInSetup: Boolean = !context.isUserSetupComplete
- private val DARK_THEME_SHADOW_ALPHA = 51f
- private val LIGHT_THEME_SHADOW_ALPHA = 25f
private val maxTransientTaskbarHeight =
context.transientTaskbarDeviceProfile.taskbarHeight.toFloat()
@@ -54,6 +52,7 @@
var isAnimatingPinning = false
val paint = Paint()
+ private val strokePaint = Paint()
val lastDrawnTransientRect = RectF()
var backgroundHeight = context.deviceProfile.taskbarHeight.toFloat()
var translationYForSwipe = 0f
@@ -62,6 +61,7 @@
private val transientBackgroundBounds = context.transientTaskbarBounds
private val shadowAlpha: Float
+ private val strokeAlpha: Int
private var shadowBlur = 0f
private var keyShadowDistance = 0f
private var bottomMargin = 0
@@ -86,10 +86,18 @@
paint.color = context.getColor(R.color.taskbar_background)
paint.flags = Paint.ANTI_ALIAS_FLAG
paint.style = Paint.Style.FILL
-
- shadowAlpha =
- if (Utilities.isDarkTheme(context)) DARK_THEME_SHADOW_ALPHA
- else LIGHT_THEME_SHADOW_ALPHA
+ strokePaint.color = context.getColor(R.color.taskbar_stroke)
+ strokePaint.flags = Paint.ANTI_ALIAS_FLAG
+ strokePaint.style = Paint.Style.STROKE
+ strokePaint.strokeWidth =
+ context.resources.getDimension(R.dimen.transient_taskbar_stroke_width)
+ if (Utilities.isDarkTheme(context)) {
+ strokeAlpha = DARK_THEME_STROKE_ALPHA
+ shadowAlpha = DARK_THEME_SHADOW_ALPHA
+ } else {
+ strokeAlpha = LIGHT_THEME_STROKE_ALPHA
+ shadowAlpha = LIGHT_THEME_SHADOW_ALPHA
+ }
setCornerRoundness(DEFAULT_ROUNDNESS)
}
@@ -97,8 +105,11 @@
fun updateStashedHandleWidth(context: TaskbarActivityContext, res: Resources) {
stashedHandleWidth =
res.getDimensionPixelSize(
- if (context.isPhoneMode) R.dimen.taskbar_stashed_small_screen
- else R.dimen.taskbar_stashed_handle_width
+ if (context.isPhoneMode || context.isTinyTaskbar) {
+ R.dimen.taskbar_stashed_small_screen
+ } else {
+ R.dimen.taskbar_stashed_handle_width
+ }
)
}
@@ -233,6 +244,7 @@
keyShadowDistance,
setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
)
+ strokePaint.alpha = (paint.alpha * strokeAlpha) / 255
lastDrawnTransientRect.set(
transientBackgroundBounds.left + halfWidthDelta,
@@ -244,6 +256,7 @@
lastDrawnTransientRect.inset(horizontalInset, 0f)
canvas.drawRoundRect(lastDrawnTransientRect, radius, radius, paint)
+ canvas.drawRoundRect(lastDrawnTransientRect, radius, radius, strokePaint)
}
/**
@@ -256,5 +269,9 @@
companion object {
const val DEFAULT_ROUNDNESS = 1f
+ private const val DARK_THEME_STROKE_ALPHA = 51
+ private const val LIGHT_THEME_STROKE_ALPHA = 41
+ private const val DARK_THEME_SHADOW_ALPHA = 51f
+ private const val LIGHT_THEME_SHADOW_ALPHA = 25f
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index f9ddc3d..58c5e83 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -180,8 +180,9 @@
taskbarUnfoldAnimationController, taskbarKeyguardController,
stashedHandleViewController, taskbarStashController,
taskbarAutohideSuspendController, taskbarPopupController, taskbarInsetsController,
- voiceInteractionWindowController, taskbarTranslationController,
- taskbarEduTooltipController, keyboardQuickSwitchController, taskbarPinningController
+ voiceInteractionWindowController, taskbarRecentAppsController,
+ taskbarTranslationController, taskbarEduTooltipController,
+ keyboardQuickSwitchController, taskbarPinningController,
};
mBackgroundRendererControllers = new BackgroundRendererController[] {
taskbarDragLayerController, taskbarScrimViewController,
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index 12f1e63..a635537 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -69,8 +69,6 @@
private lateinit var dividerView: View
- private val menuWidth =
- resources.getDimensionPixelSize(R.dimen.taskbar_pinning_popup_menu_width)
private val popupCornerRadius = Themes.getDialogCornerRadius(context)
private val arrowWidth = resources.getDimension(R.dimen.popup_arrow_width)
private val arrowHeight = resources.getDimension(R.dimen.popup_arrow_height)
@@ -98,16 +96,21 @@
popupContainer.getDescendantRectRelativeToSelf(dividerView, outPos)
}
- @SuppressLint("UseSwitchCompatOrMaterialCode")
+ @SuppressLint("UseSwitchCompatOrMaterialCode", "ClickableViewAccessibility")
override fun onFinishInflate() {
super.onFinishInflate()
val taskbarSwitchOption = requireViewById<LinearLayout>(R.id.taskbar_switch_option)
val alwaysShowTaskbarSwitch = requireViewById<Switch>(R.id.taskbar_pinning_switch)
val taskbarVisibilityIcon = requireViewById<View>(R.id.taskbar_pinning_visibility_icon)
+
alwaysShowTaskbarSwitch.isChecked = alwaysShowTaskbarOn
+ alwaysShowTaskbarSwitch.setOnTouchListener { view, event ->
+ (view.parent as View).onTouchEvent(event)
+ }
+ alwaysShowTaskbarSwitch.setOnClickListener { view -> (view.parent as View).performClick() }
+
if (ActivityContext.lookupContext<TaskbarActivityContext>(context).isGestureNav) {
taskbarSwitchOption.setOnClickListener {
- alwaysShowTaskbarSwitch.isClickable = true
alwaysShowTaskbarSwitch.isChecked = !alwaysShowTaskbarOn
onClickAlwaysShowTaskbarSwitchOption()
}
@@ -125,7 +128,7 @@
/** Orient object as usual and then center object horizontally. */
override fun orientAboutObject() {
super.orientAboutObject()
- x = mTempRect.centerX() - menuWidth / 2f
+ x = mTempRect.centerX() - measuredWidth / 2f
}
override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 84874a9..f703463 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -18,6 +18,7 @@
import static android.view.KeyEvent.ACTION_UP;
import static android.view.KeyEvent.KEYCODE_BACK;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import android.content.Context;
@@ -41,6 +42,7 @@
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.views.BaseDragLayer;
@@ -104,7 +106,10 @@
mTaskbarBackgroundAlpha = new MultiPropertyFactory<>(this, BG_ALPHA, INDEX_COUNT,
(a, b) -> a * b, 1f);
mTaskbarBackgroundAlpha.get(INDEX_ALL_OTHER_STATES).setValue(0);
- mTaskbarBackgroundAlpha.get(INDEX_STASH_ANIM).setValue(1);
+ mTaskbarBackgroundAlpha.get(INDEX_STASH_ANIM).setValue(
+ enableScalingRevealHomeAnimation() && DisplayController.isTransientTaskbar(context)
+ ? 0
+ : 1);
}
public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index d43055d..5cbd5c9 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -81,7 +81,11 @@
protected val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
open val shouldShowSearchEdu = false
private val isTooltipEnabled: Boolean
- get() = !Utilities.isRunningInTestHarness() && !activityContext.isPhoneMode
+ get() {
+ return !Utilities.isRunningInTestHarness() &&
+ !activityContext.isPhoneMode &&
+ !activityContext.isTinyTaskbar
+ }
private val isOpen: Boolean
get() = tooltip?.isOpen ?: false
val isBeforeTooltipFeaturesStep: Boolean
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 4a8ed87..0b60e45 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -51,6 +51,7 @@
import com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION
import com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
+import com.android.launcher3.testing.shared.ResourceUtils
import com.android.launcher3.util.DisplayController
import java.io.PrintWriter
import kotlin.jvm.optionals.getOrNull
@@ -231,8 +232,25 @@
val contentHeight = controllers.taskbarStashController.contentHeightToReportToApps
val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
val res = context.resources
- if (provider.type == navigationBars() || provider.type == mandatorySystemGestures()) {
+ if (provider.type == navigationBars()) {
provider.insetsSize = getInsetsForGravityWithCutout(contentHeight, gravity, endRotation)
+ } else if (provider.type == mandatorySystemGestures()) {
+ if (context.isThreeButtonNav) {
+ provider.insetsSize = getInsetsForGravityWithCutout(contentHeight, gravity,
+ endRotation)
+ } else {
+ val gestureHeight =
+ ResourceUtils.getNavbarSize(
+ ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE,
+ context.resources)
+ val isPinnedTaskbar = context.deviceProfile.isTaskbarPresent
+ && !context.deviceProfile.isTransientTaskbar
+ val mandatoryGestureHeight =
+ if (isPinnedTaskbar) contentHeight
+ else gestureHeight
+ provider.insetsSize = getInsetsForGravityWithCutout(mandatoryGestureHeight, gravity,
+ endRotation)
+ }
} else if (provider.type == tappableElement()) {
provider.insetsSize = getInsetsForGravity(tappableHeight, gravity)
} else if (provider.type == systemGestures() && provider.index == INDEX_LEFT) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
index eac4eaa..911140a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarKeyguardController.java
@@ -5,9 +5,6 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK;
@@ -16,6 +13,7 @@
import android.app.KeyguardManager;
import com.android.launcher3.AbstractFloatingView;
+import com.android.quickstep.util.SystemUiFlagUtils;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -26,19 +24,6 @@
*/
public class TaskbarKeyguardController implements TaskbarControllers.LoggableTaskbarController {
- private static final long KEYGUARD_SYSUI_FLAGS = SYSUI_STATE_BOUNCER_SHOWING
- | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING | SYSUI_STATE_DEVICE_DOZING
- | SYSUI_STATE_OVERVIEW_DISABLED | SYSUI_STATE_HOME_DISABLED
- | SYSUI_STATE_BACK_DISABLED | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
- | SYSUI_STATE_WAKEFULNESS_MASK;
-
- // If any of these SysUi flags (via QuickstepContract) is set, the device to be considered
- // locked.
- public static final long MASK_ANY_SYSUI_LOCKED = SYSUI_STATE_BOUNCER_SHOWING
- | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
- | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED
- | SYSUI_STATE_DEVICE_DREAMING;
-
private final TaskbarActivityContext mContext;
private long mKeyguardSysuiFlags;
private boolean mBouncerShowing;
@@ -55,7 +40,7 @@
}
public void updateStateForSysuiFlags(@SystemUiStateFlags long systemUiStateFlags) {
- long interestingKeyguardFlags = systemUiStateFlags & KEYGUARD_SYSUI_FLAGS;
+ long interestingKeyguardFlags = systemUiStateFlags & SystemUiFlagUtils.KEYGUARD_SYSUI_FLAGS;
if (interestingKeyguardFlags == mKeyguardSysuiFlags) {
// No change in keyguard relevant flags
return;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index ead1a8a..cb9f24a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -16,7 +16,6 @@
package com.android.launcher3.taskbar;
import static com.android.app.animation.Interpolators.EMPHASIZED;
-import static com.android.launcher3.taskbar.TaskbarKeyguardController.MASK_ANY_SYSUI_LOCKED;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_OVERVIEW;
import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE;
@@ -51,6 +50,7 @@
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.quickstep.RecentsAnimationCallbacks;
import com.android.quickstep.RecentsAnimationController;
+import com.android.quickstep.util.SystemUiFlagUtils;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.animation.ViewRootSync;
import com.android.systemui.shared.recents.model.ThumbnailData;
@@ -343,8 +343,7 @@
prevIsAwake && hasAnyFlag(FLAGS_LAUNCHER_ACTIVE));
}
- boolean isDeviceLocked = hasAnyFlag(systemUiStateFlags, MASK_ANY_SYSUI_LOCKED);
- updateStateForFlag(FLAG_DEVICE_LOCKED, isDeviceLocked);
+ updateStateForFlag(FLAG_DEVICE_LOCKED, SystemUiFlagUtils.isLocked(systemUiStateFlags));
// Taskbar is hidden whenever the device is dreaming. The dreaming state includes the
// interactive dreams, AoD, screen off. Since the SYSUI_STATE_DEVICE_DREAMING only kicks in
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index e8dc177..2a58db2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -519,7 +519,7 @@
}
}
- private static boolean isTaskbarEnabled(DeviceProfile deviceProfile) {
+ private boolean isTaskbarEnabled(DeviceProfile deviceProfile) {
return ENABLE_TASKBAR_NAVBAR_UNIFICATION || deviceProfile.isTaskbarPresent;
}
@@ -611,7 +611,8 @@
}
}
- private void addTaskbarRootViewToWindow() {
+ @VisibleForTesting
+ void addTaskbarRootViewToWindow() {
if (enableTaskbarNoRecreate() && !mAddedWindow && mTaskbarActivityContext != null) {
mWindowManager.addView(mTaskbarRootLayout,
mTaskbarActivityContext.getWindowLayoutParams());
@@ -619,7 +620,8 @@
}
}
- private void removeTaskbarRootViewFromWindow() {
+ @VisibleForTesting
+ void removeTaskbarRootViewFromWindow() {
if (enableTaskbarNoRecreate() && mAddedWindow) {
mWindowManager.removeViewImmediate(mTaskbarRootLayout);
mAddedWindow = false;
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
index 9f24d38..2b0e169 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarModelCallbacks.java
@@ -68,7 +68,7 @@
// Used to defer any UI updates during the SUW unstash animation.
private boolean mDeferUpdatesForSUW;
private Runnable mDeferredUpdates;
- private DesktopVisibilityController.DesktopVisibilityListener mDesktopVisibilityListener =
+ private final DesktopVisibilityController.DesktopVisibilityListener mDesktopVisibilityListener =
visible -> updateRunningApps();
public TaskbarModelCallbacks(
@@ -79,7 +79,7 @@
public void init(TaskbarControllers controllers) {
mControllers = controllers;
- if (mControllers.taskbarRecentAppsController.isEnabled()) {
+ if (mControllers.taskbarRecentAppsController.getCanShowRunningApps()) {
RecentsModel.INSTANCE.get(mContext).registerRunningTasksListener(this);
if (shouldShowRunningAppsInDesktopMode()) {
@@ -235,20 +235,23 @@
hotseatItemInfos = mControllers.taskbarRecentAppsController
.updateHotseatItemInfos(hotseatItemInfos);
Set<String> runningPackages = mControllers.taskbarRecentAppsController.getRunningApps();
+ Set<String> minimizedPackages = mControllers.taskbarRecentAppsController.getMinimizedApps();
if (mDeferUpdatesForSUW) {
ItemInfo[] finalHotseatItemInfos = hotseatItemInfos;
mDeferredUpdates = () ->
- commitHotseatItemUpdates(finalHotseatItemInfos, runningPackages);
+ commitHotseatItemUpdates(finalHotseatItemInfos, runningPackages,
+ minimizedPackages);
} else {
- commitHotseatItemUpdates(hotseatItemInfos, runningPackages);
+ commitHotseatItemUpdates(hotseatItemInfos, runningPackages, minimizedPackages);
}
}
- private void commitHotseatItemUpdates(
- ItemInfo[] hotseatItemInfos, Set<String> runningPackages) {
+ private void commitHotseatItemUpdates(ItemInfo[] hotseatItemInfos, Set<String> runningPackages,
+ Set<String> minimizedPackages) {
mContainer.updateHotseatItems(hotseatItemInfos);
- mControllers.taskbarViewController.updateIconViewsRunningStates(runningPackages);
+ mControllers.taskbarViewController.updateIconViewsRunningStates(runningPackages,
+ minimizedPackages);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
deleted file mode 100644
index a29c74b..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.java
+++ /dev/null
@@ -1,72 +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.taskbar;
-
-import static java.util.Collections.emptySet;
-
-import androidx.annotation.CallSuper;
-import androidx.annotation.NonNull;
-
-import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.ItemInfo;
-
-import java.util.Set;
-
-/**
- * Base class for providing recent apps functionality
- */
-public class TaskbarRecentAppsController {
-
- public static final TaskbarRecentAppsController DEFAULT = new TaskbarRecentAppsController();
-
- // Initialized in init.
- protected TaskbarControllers mControllers;
-
- @CallSuper
- protected void init(TaskbarControllers taskbarControllers) {
- mControllers = taskbarControllers;
- }
-
- @CallSuper
- protected void onDestroy() {
- mControllers = null;
- }
-
- /** Stores the current {@link AppInfo} instances, no-op except in desktop environment. */
- protected void setApps(AppInfo[] apps) {
- }
-
- /**
- * Indicates whether recent apps functionality is enabled, should return false except in
- * desktop environment.
- */
- protected boolean isEnabled() {
- return false;
- }
-
- /** Called to update hotseatItems, no-op except in desktop environment. */
- protected ItemInfo[] updateHotseatItemInfos(@NonNull ItemInfo[] hotseatItems) {
- return hotseatItems;
- }
-
- /** Called to update the list of currently running apps, no-op except in desktop environment. */
- protected void updateRunningApps() {}
-
- /** Returns the currently running apps, or an empty Set if outside of Desktop environment. */
- public Set<String> getRunningApps() {
- return emptySet();
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
new file mode 100644
index 0000000..0946caf
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarRecentAppsController.kt
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.launcher3.taskbar
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.app.WindowConfiguration
+import androidx.annotation.VisibleForTesting
+import com.android.launcher3.Flags.enableRecentsInTaskbar
+import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.statehandlers.DesktopVisibilityController
+import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
+import com.android.quickstep.RecentsModel
+import com.android.window.flags.Flags.enableDesktopWindowingMode
+import com.android.window.flags.Flags.enableDesktopWindowingTaskbarRunningApps
+import java.io.PrintWriter
+
+/**
+ * Provides recent apps functionality, when the Taskbar Recent Apps section is enabled. Behavior:
+ * - When in Fullscreen mode: show the N most recent Tasks
+ * - When in Desktop Mode: show the currently running (open) Tasks
+ */
+class TaskbarRecentAppsController(
+ private val recentsModel: RecentsModel,
+ // Pass a provider here instead of the actual DesktopVisibilityController instance since that
+ // instance might not be available when this constructor is called.
+ private val desktopVisibilityControllerProvider: () -> DesktopVisibilityController?,
+) : LoggableTaskbarController {
+
+ // TODO(b/335401172): unify DesktopMode checks in Launcher.
+ val canShowRunningApps =
+ enableDesktopWindowingMode() && enableDesktopWindowingTaskbarRunningApps()
+
+ // TODO(b/343532825): Add a setting to disable Recents even when the flag is on.
+ @VisibleForTesting
+ var isEnabled = enableRecentsInTaskbar() || canShowRunningApps
+
+ // Initialized in init.
+ private lateinit var controllers: TaskbarControllers
+
+ private var apps: Array<AppInfo>? = null
+ private var allRunningDesktopAppInfos: List<AppInfo>? = null
+ private var allMinimizedDesktopAppInfos: List<AppInfo>? = null
+
+ private val desktopVisibilityController: DesktopVisibilityController?
+ get() = desktopVisibilityControllerProvider()
+
+ private val isInDesktopMode: Boolean
+ get() = desktopVisibilityController?.areDesktopTasksVisible() ?: false
+
+ val runningApps: Set<String>
+ get() {
+ if (!isEnabled || !isInDesktopMode) {
+ return emptySet()
+ }
+ return allRunningDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet() ?: emptySet()
+ }
+
+ val minimizedApps: Set<String>
+ get() {
+ if (!isInDesktopMode) {
+ return emptySet()
+ }
+ return allMinimizedDesktopAppInfos?.mapNotNull { it.targetPackage }?.toSet()
+ ?: emptySet()
+ }
+
+ fun init(taskbarControllers: TaskbarControllers) {
+ controllers = taskbarControllers
+ }
+
+ fun onDestroy() {
+ apps = null
+ }
+
+ /** Stores the current [AppInfo] instances, no-op except in desktop environment. */
+ fun setApps(apps: Array<AppInfo>?) {
+ this.apps = apps
+ }
+
+ /** Called to update hotseatItems, in order to de-dupe them from Recent/Running tasks later. */
+ // TODO(next CL): add new section of Tasks instead of changing Hotseat items
+ fun updateHotseatItemInfos(hotseatItems: Array<ItemInfo?>): Array<ItemInfo?> {
+ if (!isEnabled || !isInDesktopMode) {
+ return hotseatItems
+ }
+ val newHotseatItemInfos =
+ hotseatItems
+ .filterNotNull()
+ // Ignore predicted apps - we show running apps instead
+ .filter { itemInfo -> !itemInfo.isPredictedItem }
+ .toMutableList()
+ val runningDesktopAppInfos =
+ allRunningDesktopAppInfos?.let {
+ getRunningDesktopAppInfosExceptHotseatApps(it, newHotseatItemInfos.toList())
+ }
+ if (runningDesktopAppInfos != null) {
+ newHotseatItemInfos.addAll(runningDesktopAppInfos)
+ }
+ return newHotseatItemInfos.toTypedArray()
+ }
+
+ private fun getRunningDesktopAppInfosExceptHotseatApps(
+ allRunningDesktopAppInfos: List<AppInfo>,
+ hotseatItems: List<ItemInfo>
+ ): List<ItemInfo> {
+ val hotseatPackages = hotseatItems.map { it.targetPackage }
+ return allRunningDesktopAppInfos
+ .filter { appInfo -> !hotseatPackages.contains(appInfo.targetPackage) }
+ .map { WorkspaceItemInfo(it) }
+ }
+
+ private fun getDesktopRunningTasks(): List<RunningTaskInfo> =
+ recentsModel.runningTasks.filter { taskInfo: RunningTaskInfo ->
+ taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM
+ }
+
+ // TODO(b/335398876) fetch app icons from Tasks instead of AppInfos
+ private fun getAppInfosFromRunningTasks(tasks: List<RunningTaskInfo>): List<AppInfo> {
+ // Early return if apps is empty, since we then have no AppInfo to compare to
+ if (apps == null) {
+ return emptyList()
+ }
+ val packageNames = tasks.map { it.realActivity?.packageName }.distinct().filterNotNull()
+ return packageNames
+ .map { packageName -> apps?.find { app -> packageName == app.targetPackage } }
+ .filterNotNull()
+ }
+
+ /** Called to update the list of currently running apps, no-op except in desktop environment. */
+ fun updateRunningApps() {
+ if (!isEnabled || !isInDesktopMode) {
+ return controllers.taskbarViewController.commitRunningAppsToUI()
+ }
+ val runningTasks = getDesktopRunningTasks()
+ val runningAppInfo = getAppInfosFromRunningTasks(runningTasks)
+ allRunningDesktopAppInfos = runningAppInfo
+ updateMinimizedApps(runningTasks, runningAppInfo)
+ controllers.taskbarViewController.commitRunningAppsToUI()
+ }
+
+ private fun updateMinimizedApps(
+ runningTasks: List<RunningTaskInfo>,
+ runningAppInfo: List<AppInfo>,
+ ) {
+ val allRunningAppTasks =
+ runningAppInfo
+ .mapNotNull { appInfo -> appInfo.targetPackage?.let { appInfo to it } }
+ .associate { (appInfo, targetPackage) ->
+ appInfo to
+ runningTasks
+ .filter { it.realActivity?.packageName == targetPackage }
+ .map { it.taskId }
+ }
+ val minimizedTaskIds = runningTasks.associate { it.taskId to !it.isVisible }
+ allMinimizedDesktopAppInfos =
+ allRunningAppTasks
+ .filterValues { taskIds -> taskIds.all { minimizedTaskIds[it] ?: false } }
+ .keys
+ .toList()
+ }
+
+ override fun dumpLogs(prefix: String, pw: PrintWriter) {
+ pw.println("$prefix TaskbarRecentAppsController:")
+ pw.println("$prefix\tisEnabled=$isEnabled")
+ pw.println("$prefix\tcanShowRunningApps=$canShowRunningApps")
+ // TODO(next CL): add more logs
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
index 92d9b23..48d2bc2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarScrimViewController.java
@@ -103,14 +103,20 @@
}
private float getScrimAlpha() {
+ final boolean isPersistentTaskBarVisible =
+ mTaskbarVisible && !DisplayController.isTransientTaskbar(mScrimView.getContext());
final boolean manageMenuExpanded =
(mSysUiStateFlags & SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0;
- return manageMenuExpanded
- // When manage menu shows there's the first scrim and second scrim so figure out
- // what the total transparency would be.
- ? (BUBBLE_EXPANDED_SCRIM_ALPHA + (BUBBLE_EXPANDED_SCRIM_ALPHA
- * (1 - BUBBLE_EXPANDED_SCRIM_ALPHA)))
- : shouldShowScrim() ? BUBBLE_EXPANDED_SCRIM_ALPHA : 0;
+ if (isPersistentTaskBarVisible && manageMenuExpanded) {
+ // When manage menu shows for persistent task bar there's the first scrim and second
+ // scrim so figure out what the total transparency would be.
+ return BUBBLE_EXPANDED_SCRIM_ALPHA
+ + (BUBBLE_EXPANDED_SCRIM_ALPHA * (1 - BUBBLE_EXPANDED_SCRIM_ALPHA));
+ } else if (shouldShowScrim()) {
+ return BUBBLE_EXPANDED_SCRIM_ALPHA;
+ } else {
+ return 0;
+ }
}
private void showScrim(boolean showScrim, float alpha, boolean skipAnim) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index 74d2d60..7ff887c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -22,10 +22,10 @@
import static com.android.app.animation.Interpolators.INSTANT;
import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.internal.jank.InteractionJankMonitor.Configuration;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TRANSIENT_TASKBAR_SHOW;
-import static com.android.launcher3.taskbar.TaskbarKeyguardController.MASK_ANY_SYSUI_LOCKED;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.FlagDebugUtils.appendFlag;
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
@@ -35,11 +35,11 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
import android.app.RemoteAction;
import android.graphics.drawable.Icon;
import android.os.SystemClock;
@@ -66,6 +66,7 @@
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.util.SystemUiFlagUtils;
import java.io.PrintWriter;
import java.lang.annotation.Retention;
@@ -100,7 +101,10 @@
// If we're in an app and any of these flags are enabled, taskbar should be stashed.
private static final int FLAGS_STASHED_IN_APP = FLAG_STASHED_IN_APP_SYSUI
| FLAG_STASHED_IN_APP_SETUP | FLAG_STASHED_IN_TASKBAR_ALL_APPS
- | FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IN_APP_AUTO;
+ | FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IN_APP_AUTO | FLAG_STASHED_IME;
+
+ // If we're in overview and any of these flags are enabled, taskbar should be stashed.
+ private static final int FLAGS_STASHED_IN_OVERVIEW = FLAG_STASHED_IME;
// If any of these flags are enabled, inset apps by our stashed height instead of our unstashed
// height. This way the reported insets are consistent even during transitions out of the app.
@@ -111,7 +115,7 @@
// If any of these flags are enabled, the taskbar must be stashed.
private static final int FLAGS_FORCE_STASHED = FLAG_STASHED_SYSUI | FLAG_STASHED_DEVICE_LOCKED
- | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN | FLAG_STASHED_IME;
+ | FLAG_STASHED_IN_TASKBAR_ALL_APPS | FLAG_STASHED_SMALL_SCREEN;
/**
* How long to stash/unstash when manually invoked via long press.
@@ -239,13 +243,22 @@
private final Alarm mTimeoutAlarm = new Alarm();
private boolean mEnableBlockingTimeoutDuringTests = false;
+ private Animator mTaskbarBackgroundAlphaAnimator;
+ private long mTaskbarBackgroundDuration;
+ private boolean mIsGoingHome;
+
// Evaluate whether the handle should be stashed
private final LongPredicate mIsStashedPredicate = flags -> {
boolean inApp = hasAnyFlag(flags, FLAGS_IN_APP);
boolean stashedInApp = hasAnyFlag(flags, FLAGS_STASHED_IN_APP);
boolean stashedLauncherState = hasAnyFlag(flags, FLAG_IN_STASHED_LAUNCHER_STATE);
+ boolean inOverview = hasAnyFlag(flags, FLAG_IN_OVERVIEW);
+ boolean stashedInOverview = hasAnyFlag(flags, FLAGS_STASHED_IN_OVERVIEW);
boolean forceStashed = hasAnyFlag(flags, FLAGS_FORCE_STASHED);
- return (inApp && stashedInApp) || (!inApp && stashedLauncherState) || forceStashed;
+ return (inApp && stashedInApp)
+ || (!inApp && stashedLauncherState)
+ || (inOverview && stashedInOverview)
+ || forceStashed;
};
private final StatePropertyHolder mStatePropertyHolder = new StatePropertyHolder(
mIsStashedPredicate);
@@ -258,6 +271,8 @@
mSystemUiProxy = SystemUiProxy.INSTANCE.get(activity);
mAccessibilityManager = mActivity.getSystemService(AccessibilityManager.class);
+ mTaskbarBackgroundDuration =
+ activity.getResources().getInteger(R.integer.taskbar_background_duration);
if (mActivity.isPhoneMode()) {
mUnstashedHeight = mActivity.getResources().getDimensionPixelSize(
R.dimen.taskbar_phone_size);
@@ -752,9 +767,16 @@
backgroundAndHandleAlphaStartDelay,
backgroundAndHandleAlphaDuration, LINEAR);
- play(as, mTaskbarBackgroundAlphaForStash.animateToValue(backgroundAlphaTarget),
- backgroundAndHandleAlphaStartDelay,
- backgroundAndHandleAlphaDuration, LINEAR);
+ if (enableScalingRevealHomeAnimation() && !isStashed) {
+ play(as, getTaskbarBackgroundAnimatorWhenNotGoingHome(duration),
+ 0, 0, LINEAR);
+ as.addListener(AnimatorListeners.forEndCallback(
+ () -> mTaskbarBackgroundAlphaForStash.setValue(backgroundAlphaTarget)));
+ } else {
+ play(as, mTaskbarBackgroundAlphaForStash.animateToValue(backgroundAlphaTarget),
+ backgroundAndHandleAlphaStartDelay,
+ backgroundAndHandleAlphaDuration, LINEAR);
+ }
// The rest of the animations might be "skipped" in TRANSITION_HANDLE_FADE transitions.
AnimatorSet skippable = as;
@@ -797,6 +819,62 @@
.setDuration(isStashed ? duration / 2 : duration));
}
+ private Animator getTaskbarBackgroundAnimatorWhenNotGoingHome(long duration) {
+ ValueAnimator a = ValueAnimator.ofFloat(0, 1);
+ a.setDuration(duration);
+ a.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ // This value is arbitrary.
+ private static final float ANIMATED_FRACTION_THRESHOLD = 0.25f;
+ private boolean mTaskbarBgAlphaAnimationStarted = false;
+ @Override
+ public void onAnimationUpdate(ValueAnimator valueAnimator) {
+ if (mIsGoingHome) {
+ mTaskbarBgAlphaAnimationStarted = true;
+ }
+ if (mTaskbarBgAlphaAnimationStarted) {
+ return;
+ }
+
+ if (valueAnimator.getAnimatedFraction() >= ANIMATED_FRACTION_THRESHOLD) {
+ if (!mIsGoingHome) {
+ playTaskbarBackgroundAlphaAnimation();
+ setUserIsGoingHome(false);
+ mTaskbarBgAlphaAnimationStarted = true;
+ }
+ }
+ }
+ });
+ return a;
+ }
+
+ /**
+ * Sets whether the user is going home based on the current gesture.
+ */
+ public void setUserIsGoingHome(boolean isGoingHome) {
+ mIsGoingHome = isGoingHome;
+ }
+
+ /**
+ * Plays the taskbar background alpha animation if one is not currently playing.
+ */
+ public void playTaskbarBackgroundAlphaAnimation() {
+ if (mTaskbarBackgroundAlphaAnimator != null
+ && mTaskbarBackgroundAlphaAnimator.isRunning()) {
+ return;
+ }
+ mTaskbarBackgroundAlphaAnimator = mTaskbarBackgroundAlphaForStash
+ .animateToValue(1f)
+ .setDuration(mTaskbarBackgroundDuration);
+ mTaskbarBackgroundAlphaAnimator.setInterpolator(LINEAR);
+ mTaskbarBackgroundAlphaAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mTaskbarBackgroundAlphaAnimator = null;
+ }
+ });
+ mTaskbarBackgroundAlphaAnimator.start();
+ }
+
private static void play(AnimatorSet as, @Nullable Animator a, long startDelay, long duration,
Interpolator interpolator) {
if (a == null) {
@@ -942,9 +1020,8 @@
&& DisplayController.isTransientTaskbar(mActivity);
updateStateForFlag(FLAG_STASHED_SYSUI,
hasAnyFlag(systemUiStateFlags, SYSUI_STATE_SCREEN_PINNING) || stashForBubbles);
- boolean isLocked = hasAnyFlag(systemUiStateFlags, MASK_ANY_SYSUI_LOCKED)
- && !hasAnyFlag(systemUiStateFlags, SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY);
- updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED, isLocked);
+ updateStateForFlag(FLAG_STASHED_DEVICE_LOCKED,
+ SystemUiFlagUtils.isLocked(systemUiStateFlags));
mIsImeShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SHOWING);
mIsImeSwitcherShowing = hasAnyFlag(systemUiStateFlags, SYSUI_STATE_IME_SWITCHER_SHOWING);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
index 2b68b52..593285f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java
@@ -411,4 +411,11 @@
public void setSkipNextRecentsAnimEnd() {
// Overridden
}
+
+ /**
+ * Sets whether the user is going home based on the current gesture.
+ */
+ public void setUserIsGoingHome(boolean isGoingHome) {
+ mControllers.taskbarStashController.setUserIsGoingHome(isGoingHome);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index e4ccc58..570221c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -25,7 +25,6 @@
import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.quickstep.RecentsAnimationDeviceState.QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON;
import android.content.Context;
import android.content.res.Resources;
@@ -33,7 +32,6 @@
import android.graphics.Rect;
import android.os.Bundle;
import android.util.AttributeSet;
-import android.util.Log;
import android.view.DisplayCutout;
import android.view.InputDevice;
import android.view.LayoutInflater;
@@ -68,7 +66,6 @@
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.views.IconButtonView;
import com.android.quickstep.DeviceConfigWrapper;
-import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.quickstep.util.AssistStateManager;
import java.util.function.Predicate;
@@ -78,8 +75,6 @@
*/
public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconParent, Insettable,
DeviceProfile.OnDeviceProfileChangeListener {
- private static final String TAG = "TaskbarView";
-
private static final Rect sTmpRect = new Rect();
private final int[] mTempOutLocation = new int[2];
@@ -89,10 +84,8 @@
private final int mItemPadding;
private final int mFolderLeaveBehindColor;
private final boolean mIsRtl;
- private final boolean mIsTransientTaskbar;
private final TaskbarActivityContext mActivityContext;
- private final RecentsAnimationDeviceState mDeviceState;
// Initialized in init.
private TaskbarViewCallbacks mControllerCallbacks;
@@ -107,8 +100,6 @@
private Runnable mAllAppsTouchRunnable;
private long mAllAppsButtonTouchDelayMs;
private boolean mAllAppsTouchTriggered;
- private MotionEvent mCurrentDownEvent;
- private float mTouchSlopSquared;
// Only non-null when device supports having an All Apps button.
private @Nullable IconButtonView mTaskbarDivider;
@@ -138,7 +129,7 @@
mActivityContext = ActivityContext.lookupContext(context);
mIconLayoutBounds = mActivityContext.getTransientTaskbarBounds();
Resources resources = getResources();
- mIsTransientTaskbar = DisplayController.isTransientTaskbar(mActivityContext)
+ boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivityContext)
&& !mActivityContext.isPhoneMode();
mIsRtl = Utilities.isRtl(resources);
mTransientTaskbarMinWidth = resources.getDimension(R.dimen.transient_taskbar_min_width);
@@ -172,7 +163,7 @@
mAllAppsButton = (IconButtonView) LayoutInflater.from(context)
.inflate(R.layout.taskbar_all_apps_button, this, false);
mAllAppsButton.setIconDrawable(resources.getDrawable(
- getAllAppsButton(mIsTransientTaskbar)));
+ getAllAppsButton(isTransientTaskbar)));
mAllAppsButton.setPadding(mItemPadding, mItemPadding, mItemPadding, mItemPadding);
mAllAppsButton.setForegroundTint(
mActivityContext.getColor(R.color.all_apps_button_color));
@@ -191,10 +182,6 @@
// Default long press (touch) delay = 400ms
mAllAppsButtonTouchDelayMs = ViewConfiguration.getLongPressTimeout();
- // Default touch slop
- mDeviceState = new RecentsAnimationDeviceState(mContext);
- mTouchSlopSquared = mDeviceState.getSquaredTouchSlop(
- QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON, 1);
}
@DrawableRes
@@ -299,12 +286,6 @@
&& assistStateManager.getLPNHDurationMillis().isPresent()) {
mAllAppsButtonTouchDelayMs = assistStateManager.getLPNHDurationMillis().get();
}
- if (DeviceConfigWrapper.get().getCustomLpaaThresholds()
- && assistStateManager.getLPNHCustomSlopMultiplier().isPresent()) {
- mTouchSlopSquared = mDeviceState.getSquaredTouchSlop(
- QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON,
- assistStateManager.getLPNHCustomSlopMultiplier().get());
- }
}
if (mTaskbarDivider != null && !mActivityContext.isThreeButtonNav()) {
mTaskbarDivider.setOnLongClickListener(
@@ -727,27 +708,10 @@
private boolean onAllAppsButtonTouch(View view, MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
- if (mCurrentDownEvent != null) {
- mCurrentDownEvent.recycle();
- }
- mCurrentDownEvent = MotionEvent.obtain(ev);
mAllAppsTouchTriggered = false;
MAIN_EXECUTOR.getHandler().postDelayed(
mAllAppsTouchRunnable, mAllAppsButtonTouchDelayMs);
break;
- case MotionEvent.ACTION_MOVE:
- if (!MAIN_EXECUTOR.getHandler().hasCallbacks(mAllAppsTouchRunnable)
- || mIsTransientTaskbar) {
- break;
- }
- float dx = ev.getX() - mCurrentDownEvent.getX();
- float dy = ev.getY() - mCurrentDownEvent.getY();
- double distanceSquared = (dx * dx) + (dy * dy);
- if (distanceSquared > mTouchSlopSquared) {
- Log.d(TAG, "Touch slop out");
- cancelAllAppsButtonTouch();
- }
- break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
cancelAllAppsButtonTouch();
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 93814b7..55745b5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -347,6 +347,11 @@
float allAppIconTranslateRange = mapRange(scale, transientTaskbarAllAppsOffset,
persistentTaskbarAllAppsOffset);
+ // no x translation required when all apps button is the only icon in taskbar.
+ if (iconViews.length <= 1) {
+ allAppIconTranslateRange = 0f;
+ }
+
if (mIsRtl) {
allAppIconTranslateRange *= -1;
}
@@ -377,7 +382,7 @@
-finalMarginScale * (iconIndex - halfIconCount));
}
- if (iconView.equals(mTaskbarView.getAllAppsButtonView()) && iconViews.length > 1) {
+ if (iconView.equals(mTaskbarView.getAllAppsButtonView())) {
((IconButtonView) iconView).setTranslationXForTaskbarAllAppsIcon(
allAppIconTranslateRange);
}
@@ -510,14 +515,30 @@
}
/** Updates which icons are marked as running given the Set of currently running packages. */
- public void updateIconViewsRunningStates(Set<String> runningPackages) {
+ public void updateIconViewsRunningStates(Set<String> runningPackages,
+ Set<String> minimizedPackages) {
for (View iconView : getIconViews()) {
if (iconView instanceof BubbleTextView btv) {
- btv.updateRunningState(runningPackages.contains(btv.getTargetPackageName()));
+ btv.updateRunningState(
+ getRunningAppState(btv.getTargetPackageName(), runningPackages,
+ minimizedPackages));
}
}
}
+ private BubbleTextView.RunningAppState getRunningAppState(
+ String packageName,
+ Set<String> runningPackages,
+ Set<String> minimizedPackages) {
+ if (minimizedPackages.contains(packageName)) {
+ return BubbleTextView.RunningAppState.MINIMIZED;
+ }
+ if (runningPackages.contains(packageName)) {
+ return BubbleTextView.RunningAppState.RUNNING;
+ }
+ return BubbleTextView.RunningAppState.NOT_RUNNING;
+ }
+
/**
* Defers any updates to the UI for the setup wizard animation.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index 8e05686..90ac872 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -17,6 +17,8 @@
import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.launcher3.Flags.enablePredictiveBackGesture;
+import static com.android.launcher3.touch.AllAppsSwipeController.ALL_APPS_FADE_MANUAL;
+import static com.android.launcher3.touch.AllAppsSwipeController.SCRIM_FADE_MANUAL;
import android.animation.Animator;
import android.content.Context;
@@ -32,6 +34,7 @@
import androidx.annotation.Nullable;
+import com.android.app.animation.Interpolators;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
@@ -40,6 +43,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsViewController.TaskbarAllAppsCallbacks;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
+import com.android.launcher3.util.Themes;
import com.android.launcher3.views.AbstractSlideInView;
/** Wrapper for taskbar all apps with slide-in behavior. */
@@ -113,8 +117,25 @@
@Override
protected void onOpenCloseAnimationPending(PendingAnimation animation) {
- mAllAppsCallbacks.onAllAppsAnimationPending(
- animation, mToTranslationShift == TRANSLATION_SHIFT_OPENED);
+ final boolean isOpening = mToTranslationShift == TRANSLATION_SHIFT_OPENED;
+
+ if (mActivityContext.getDeviceProfile().isPhone) {
+ final Interpolator allAppsFadeInterpolator =
+ isOpening ? ALL_APPS_FADE_MANUAL : Interpolators.reverse(ALL_APPS_FADE_MANUAL);
+ animation.setViewAlpha(mAppsView, 1 - mToTranslationShift, allAppsFadeInterpolator);
+ }
+
+ mAllAppsCallbacks.onAllAppsAnimationPending(animation, isOpening);
+ }
+
+ @Override
+ protected Interpolator getScrimInterpolator() {
+ if (mActivityContext.getDeviceProfile().isTablet) {
+ return super.getScrimInterpolator();
+ }
+ return mToTranslationShift == TRANSLATION_SHIFT_OPENED
+ ? SCRIM_FADE_MANUAL
+ : Interpolators.reverse(SCRIM_FADE_MANUAL);
}
/** The apps container inside this view. */
@@ -154,6 +175,9 @@
protected void onFinishInflate() {
super.onFinishInflate();
mAppsView = findViewById(R.id.apps_view);
+ if (mActivityContext.getDeviceProfile().isPhone) {
+ mAppsView.setAlpha(0);
+ }
mContent = mAppsView;
// Setup header protection for search bar, if enabled.
@@ -214,7 +238,9 @@
@Override
protected int getScrimColor(Context context) {
- return context.getColor(R.color.widgets_picker_scrim);
+ return mActivityContext.getDeviceProfile().isPhone
+ ? Themes.getAttrColor(context, R.attr.allAppsScrimColor)
+ : context.getColor(R.color.widgets_picker_scrim);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
index a59e81b..bc13c89 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarBackground.kt
@@ -19,7 +19,9 @@
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.ColorFilter
+import android.graphics.Matrix
import android.graphics.Paint
+import android.graphics.Path
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
import com.android.app.animation.Interpolators
@@ -28,28 +30,28 @@
import com.android.launcher3.Utilities.mapToRange
import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
import com.android.launcher3.popup.RoundedArrowDrawable
+import kotlin.math.max
+import kotlin.math.min
/** Drawable for the background of the bubble bar. */
class BubbleBarBackground(context: Context, private var backgroundHeight: Float) : Drawable() {
- private val DARK_THEME_SHADOW_ALPHA = 51f
- private val LIGHT_THEME_SHADOW_ALPHA = 25f
-
- private val paint: Paint = Paint()
- private val pointerWidth: Float
- private val pointerHeight: Float
- private val pointerTipRadius: Float
- private val pointerVisibleHeight: Float
+ private val fillPaint: Paint = Paint()
+ private val strokePaint: Paint = Paint()
+ private val arrowWidth: Float
+ private val arrowHeight: Float
+ private val arrowTipRadius: Float
+ private val arrowVisibleHeight: Float
private val shadowAlpha: Float
private var shadowBlur = 0f
private var keyShadowDistance = 0f
+ private var arrowHeightFraction = 1f
var arrowPositionX: Float = 0f
private set
private var showingArrow: Boolean = false
- private var arrowDrawable: RoundedArrowDrawable
var width: Float = 0f
@@ -70,34 +72,31 @@
}
init {
- paint.color = context.getColor(R.color.taskbar_background)
- paint.flags = Paint.ANTI_ALIAS_FLAG
- paint.style = Paint.Style.FILL
-
val res = context.resources
+ // configure fill paint
+ fillPaint.color = context.getColor(R.color.taskbar_background)
+ fillPaint.flags = Paint.ANTI_ALIAS_FLAG
+ fillPaint.style = Paint.Style.FILL
+ // configure stroke paint
+ strokePaint.color = context.getColor(R.color.taskbar_stroke)
+ strokePaint.flags = Paint.ANTI_ALIAS_FLAG
+ strokePaint.style = Paint.Style.STROKE
+ strokePaint.strokeWidth = res.getDimension(R.dimen.transient_taskbar_stroke_width)
+ // apply theme alpha attributes
+ if (Utilities.isDarkTheme(context)) {
+ strokePaint.alpha = DARK_THEME_STROKE_ALPHA
+ shadowAlpha = DARK_THEME_SHADOW_ALPHA
+ } else {
+ strokePaint.alpha = LIGHT_THEME_STROKE_ALPHA
+ shadowAlpha = LIGHT_THEME_SHADOW_ALPHA
+ }
+
shadowBlur = res.getDimension(R.dimen.transient_taskbar_shadow_blur)
keyShadowDistance = res.getDimension(R.dimen.transient_taskbar_key_shadow_distance)
- pointerWidth = res.getDimension(R.dimen.bubblebar_pointer_width)
- pointerHeight = res.getDimension(R.dimen.bubblebar_pointer_height)
- pointerVisibleHeight = res.getDimension(R.dimen.bubblebar_pointer_visible_size)
- pointerTipRadius = res.getDimension(R.dimen.bubblebar_pointer_radius)
-
- shadowAlpha =
- if (Utilities.isDarkTheme(context)) {
- DARK_THEME_SHADOW_ALPHA
- } else {
- LIGHT_THEME_SHADOW_ALPHA
- }
-
- arrowDrawable =
- RoundedArrowDrawable.createVerticalRoundedArrow(
- pointerWidth,
- pointerHeight,
- pointerTipRadius,
- /* isPointingUp= */ true,
- context.getColor(R.color.taskbar_background)
- )
- arrowDrawable.setBounds(0, 0, pointerWidth.toInt(), pointerHeight.toInt())
+ arrowWidth = res.getDimension(R.dimen.bubblebar_pointer_width)
+ arrowHeight = res.getDimension(R.dimen.bubblebar_pointer_height)
+ arrowVisibleHeight = res.getDimension(R.dimen.bubblebar_pointer_visible_size)
+ arrowTipRadius = res.getDimension(R.dimen.bubblebar_pointer_radius)
}
fun showArrow(show: Boolean) {
@@ -115,40 +114,53 @@
// TODO (b/277359345): Should animate the alpha similar to taskbar (see TaskbarDragLayer)
// Draw shadows.
val newShadowAlpha =
- mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, shadowAlpha, Interpolators.LINEAR)
- paint.setShadowLayer(
+ mapToRange(fillPaint.alpha.toFloat(), 0f, 255f, 0f, shadowAlpha, Interpolators.LINEAR)
+ fillPaint.setShadowLayer(
shadowBlur,
0f,
keyShadowDistance,
setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
)
- arrowDrawable.setShadowLayer(
- shadowBlur,
- 0f,
- keyShadowDistance,
- setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
- )
-
- // Draw background.
+ // Create background path
+ val backgroundPath = Path()
val radius = backgroundHeight / 2f
val left = bounds.left + (if (anchorLeft) 0f else bounds.width().toFloat() - width)
val right = bounds.left + (if (anchorLeft) width else bounds.width().toFloat())
- val top = bounds.top + pointerVisibleHeight
+ val top = bounds.top + arrowVisibleHeight
val bottom = bounds.top + bounds.height().toFloat()
- canvas.drawRoundRect(left, top, right, bottom, radius, radius, paint)
+ backgroundPath.addRoundRect(left, top, right, bottom, radius, radius, Path.Direction.CW)
+ addArrowPathIfNeeded(backgroundPath)
- if (showingArrow) {
- // Draw arrow.
- val transX = bounds.left + arrowPositionX - pointerWidth / 2f
- canvas.translate(transX, 0f)
- arrowDrawable.draw(canvas)
- }
+ // Draw background.
+ canvas.drawPath(backgroundPath, fillPaint)
+ canvas.drawPath(backgroundPath, strokePaint)
canvas.restore()
}
+ private fun addArrowPathIfNeeded(sourcePath: Path) {
+ if (!showingArrow || arrowHeightFraction <= 0) return
+ val arrowPath = Path()
+ RoundedArrowDrawable.addDownPointingRoundedTriangleToPath(
+ arrowWidth,
+ arrowHeight,
+ arrowTipRadius,
+ arrowPath
+ )
+ // flip it horizontally
+ val pathTransform = Matrix()
+ pathTransform.setRotate(180f, arrowWidth * 0.5f, arrowHeight * 0.5f)
+ arrowPath.transform(pathTransform)
+ // shift to arrow position
+ val arrowStart = bounds.left + arrowPositionX - (arrowWidth / 2f)
+ val arrowTop = (1 - arrowHeightFraction) * arrowVisibleHeight
+ arrowPath.offset(arrowStart, arrowTop)
+ // union with rectangle
+ sourcePath.op(arrowPath, Path.Op.UNION)
+ }
+
override fun getOpacity(): Int {
- return when (paint.alpha) {
+ return when (fillPaint.alpha) {
255 -> PixelFormat.OPAQUE
0 -> PixelFormat.TRANSPARENT
else -> PixelFormat.TRANSLUCENT
@@ -156,24 +168,40 @@
}
override fun setAlpha(alpha: Int) {
- paint.alpha = alpha
- arrowDrawable.alpha = alpha
+ fillPaint.alpha = alpha
invalidateSelf()
}
override fun getAlpha(): Int {
- return paint.alpha
+ return fillPaint.alpha
}
override fun setColorFilter(colorFilter: ColorFilter?) {
- paint.colorFilter = colorFilter
- }
-
- fun setArrowAlpha(alpha: Int) {
- arrowDrawable.alpha = alpha
+ fillPaint.colorFilter = colorFilter
}
fun setHeight(newHeight: Float) {
backgroundHeight = newHeight
}
+
+ /**
+ * Set fraction of the arrow height that should be displayed. Allowed values range are [0..1].
+ * If value passed is out of range it will be converted to the closest value in tha allowed
+ * range.
+ */
+ fun setArrowHeightFraction(arrowHeightFraction: Float) {
+ var newHeightFraction = arrowHeightFraction
+ if (newHeightFraction !in 0f..1f) {
+ newHeightFraction = min(max(newHeightFraction, 0f), 1f)
+ }
+ this.arrowHeightFraction = newHeightFraction
+ invalidateSelf()
+ }
+
+ companion object {
+ private const val DARK_THEME_STROKE_ALPHA = 51
+ private const val LIGHT_THEME_STROKE_ALPHA = 41
+ private const val DARK_THEME_SHADOW_ALPHA = 51f
+ private const val LIGHT_THEME_SHADOW_ALPHA = 25f
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
index 23e52e6..2efecfb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java
@@ -98,6 +98,8 @@
// During fade in animation we shift the bubble bar 1/60th of the screen width
private static final float FADE_IN_ANIM_POSITION_SHIFT = 1 / 60f;
+ private static final int SCALE_IN_ANIMATION_DURATION_MS = 250;
+
/**
* Custom property to set alpha value for the bar view while a bubble is being dragged.
* Skips applying alpha to the dragged bubble.
@@ -157,6 +159,10 @@
// collapsed state and 1 to the fully expanded state.
private final ValueAnimator mWidthAnimator = ValueAnimator.ofFloat(0, 1);
+ /** An animator used for scaling in a new bubble to the bubble bar while expanded. */
+ @Nullable
+ private ValueAnimator mNewBubbleScaleInAnimator = null;
+
@Nullable
private Animator mBubbleBarLocationAnimator = null;
@@ -212,7 +218,7 @@
mWidthAnimator.setDuration(WIDTH_ANIMATION_DURATION_MS);
mWidthAnimator.addUpdateListener(animation -> {
- updateChildrenRenderNodeProperties(mBubbleBarLocation);
+ updateBubblesLayoutProperties(mBubbleBarLocation);
invalidate();
});
mWidthAnimator.addListener(new Animator.AnimatorListener() {
@@ -298,7 +304,7 @@
if (!mDragging) {
// Position the views when not dragging
- updateChildrenRenderNodeProperties(mBubbleBarLocation);
+ updateBubblesLayoutProperties(mBubbleBarLocation);
}
}
@@ -444,7 +450,7 @@
mBubbleBarLocationAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
- updateChildrenRenderNodeProperties(bubbleBarLocation);
+ updateBubblesLayoutProperties(bubbleBarLocation);
mBubbleBarBackground.setAnchorLeft(bubbleBarLocation.isOnLeft(isLayoutRtl()));
// Animate it in
@@ -613,6 +619,45 @@
mIsAnimatingNewBubble = false;
}
+ /** Add a new bubble to the bubble bar. */
+ public void addBubble(View bubble, FrameLayout.LayoutParams lp) {
+ if (isExpanded()) {
+ // if we're expanded scale the new bubble in
+ bubble.setScaleX(0f);
+ bubble.setScaleY(0f);
+ addView(bubble, 0, lp);
+ createNewBubbleScaleInAnimator(bubble);
+ mNewBubbleScaleInAnimator.start();
+ } else {
+ addView(bubble, 0, lp);
+ }
+ }
+
+ private void createNewBubbleScaleInAnimator(View bubble) {
+ mNewBubbleScaleInAnimator = ValueAnimator.ofFloat(0, 1);
+ mNewBubbleScaleInAnimator.setDuration(SCALE_IN_ANIMATION_DURATION_MS);
+ mNewBubbleScaleInAnimator.addUpdateListener(animation -> {
+ float animatedFraction = animation.getAnimatedFraction();
+ bubble.setScaleX(animatedFraction);
+ bubble.setScaleY(animatedFraction);
+ updateBubblesLayoutProperties(mBubbleBarLocation);
+ invalidate();
+ });
+ mNewBubbleScaleInAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationCancel(Animator animation) {
+ bubble.setScaleX(1);
+ bubble.setScaleY(1);
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ updateWidth();
+ mNewBubbleScaleInAnimator = null;
+ }
+ });
+ }
+
// TODO: (b/280605790) animate it
@Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
@@ -623,6 +668,8 @@
}
super.addView(child, index, params);
updateWidth();
+ updateBubbleAccessibilityStates();
+ updateContentDescription();
}
// TODO: (b/283309949) animate it
@@ -634,6 +681,8 @@
mBubbleBarBackground.showArrow(false);
}
updateWidth();
+ updateBubbleAccessibilityStates();
+ updateContentDescription();
}
private void updateWidth() {
@@ -659,7 +708,7 @@
* Updates the z order, positions, and badge visibility of the bubble views in the bar based
* on the expanded state.
*/
- private void updateChildrenRenderNodeProperties(BubbleBarLocation bubbleBarLocation) {
+ private void updateBubblesLayoutProperties(BubbleBarLocation bubbleBarLocation) {
final float widthState = (float) mWidthAnimator.getAnimatedValue();
final float currentWidth = getWidth();
final float expandedWidth = expandedWidth();
@@ -715,6 +764,8 @@
} else if (i == MAX_VISIBLE_BUBBLES_COLLAPSED - 1
&& bubbleCount == MAX_VISIBLE_BUBBLES_COLLAPSED) {
bv.setAlpha(0);
+ } else {
+ bv.setAlpha(1);
}
}
}
@@ -742,21 +793,67 @@
}
}
mBubbleBarBackground.setArrowPosition(arrowPosition);
- mBubbleBarBackground.setArrowAlpha((int) (255 * widthState));
+ mBubbleBarBackground.setArrowHeightFraction(widthState);
mBubbleBarBackground.setWidth(interpolatedWidth);
}
- private float getExpandedBubbleTranslationX(int bubbleIndex, int bubbleCount,
- boolean onLeft) {
+ private float getExpandedBubbleTranslationX(int bubbleIndex, int bubbleCount, boolean onLeft) {
if (bubbleIndex < 0 || bubbleIndex >= bubbleCount) {
return 0;
}
- if (onLeft) {
- // If bar is on the left, bubbles are ordered right to left
- return (bubbleCount - bubbleIndex - 1) * (mIconSize + mExpandedBarIconsSpacing);
+ final float iconAndSpacing = mIconSize + mExpandedBarIconsSpacing;
+ if (mNewBubbleScaleInAnimator != null && mNewBubbleScaleInAnimator.isRunning()) {
+ return getExpandedBubbleTranslationXDuringScaleAnimation(
+ bubbleIndex, bubbleCount, onLeft);
+ } else if (onLeft) {
+ return (bubbleCount - bubbleIndex - 1) * iconAndSpacing;
} else {
- // Bubbles ordered left to right, don't move the first bubble
- return bubbleIndex * (mIconSize + mExpandedBarIconsSpacing);
+ return bubbleIndex * iconAndSpacing;
+ }
+ }
+
+ /**
+ * Returns the translation X for the bubble at index {@code bubbleIndex} when the bubble bar is
+ * expanded <b>and</b> a new bubble is animating in.
+ *
+ * <p>This method assumes that the animation is running so callers are expected to verify that
+ * before calling it.
+ */
+ private float getExpandedBubbleTranslationXDuringScaleAnimation(
+ int bubbleIndex, int bubbleCount, boolean onLeft) {
+ // when the new bubble scale animation is running, a new bubble is animating in while the
+ // bubble bar is expanded, so we have at least 2 bubbles in the bubble bar - the expanded
+ // one, and the new one animating in.
+
+ if (mNewBubbleScaleInAnimator == null) {
+ // callers of this method are expected to verify that the animation is running, but the
+ // compiler doesn't know that.
+ return 0;
+ }
+ final float iconAndSpacing = mIconSize + mExpandedBarIconsSpacing;
+ final float newBubbleScale = mNewBubbleScaleInAnimator.getAnimatedFraction();
+ // the new bubble is scaling in from the center, so we need to adjust its translation so
+ // that the distance to the adjacent bubble scales at the same rate.
+ final float pivotAdjustment = -(1 - newBubbleScale) * mIconSize / 2f;
+
+ if (onLeft) {
+ if (bubbleIndex == 0) {
+ // this is the animating bubble. use scaled spacing between it and the bubble to
+ // its left
+ return (bubbleCount - 1) * mIconSize
+ + (bubbleCount - 2) * mExpandedBarIconsSpacing
+ + newBubbleScale * mExpandedBarIconsSpacing
+ + pivotAdjustment;
+ }
+ // when the bubble bar is on the left, only the translation of the right-most bubble
+ // is affected by the scale animation.
+ return (bubbleCount - bubbleIndex - 1) * iconAndSpacing;
+ } else if (bubbleIndex == 0) {
+ // the bubble bar is on the right, and this is the animating bubble. it only needs
+ // to be adjusted for the scaling pivot.
+ return pivotAdjustment;
+ } else {
+ return iconAndSpacing * (bubbleIndex - 1 + newBubbleScale);
}
}
@@ -798,7 +895,8 @@
addViewInLayout(child, i, child.getLayoutParams());
}
}
- updateChildrenRenderNodeProperties(mBubbleBarLocation);
+ updateBubblesLayoutProperties(mBubbleBarLocation);
+ updateContentDescription();
}
}
@@ -876,15 +974,9 @@
private float arrowPositionForSelectedWhenExpanded(BubbleBarLocation bubbleBarLocation) {
final int index = indexOfChild(mSelectedBubbleView);
- final int bubblePosition;
- if (bubbleBarLocation.isOnLeft(isLayoutRtl())) {
- // Bubble positions are reversed. First bubble is on the right.
- bubblePosition = getChildCount() - index - 1;
- } else {
- bubblePosition = index;
- }
- return getPaddingStart() + bubblePosition * (mIconSize + mExpandedBarIconsSpacing)
- + mIconSize / 2f;
+ final float selectedBubbleTranslationX = getExpandedBubbleTranslationX(
+ index, getChildCount(), bubbleBarLocation.isOnLeft(isLayoutRtl()));
+ return getPaddingStart() + selectedBubbleTranslationX + mIconSize / 2f;
}
private float arrowPositionForSelectedWhenCollapsed(BubbleBarLocation bubbleBarLocation) {
@@ -895,7 +987,8 @@
// bubbles than the current bubble and overflow.
bubblePosition = index == 0 && getChildCount() > MAX_VISIBLE_BUBBLES_COLLAPSED ? 1 : 0;
} else {
- bubblePosition = index;
+ bubblePosition = index >= MAX_VISIBLE_BUBBLES_COLLAPSED
+ ? MAX_VISIBLE_BUBBLES_COLLAPSED - 1 : index;
}
return getPaddingStart() + bubblePosition * (mIconOverlapAmount) + mIconSize / 2f;
}
@@ -927,6 +1020,7 @@
} else {
mWidthAnimator.reverse();
}
+ updateBubbleAccessibilityStates();
}
}
@@ -946,8 +1040,19 @@
final int childCount = getChildCount();
final int horizontalPadding = getPaddingStart() + getPaddingEnd();
// spaces amount is less than child count by 1, or 0 if no child views
- int spacesCount = Math.max(childCount - 1, 0);
- return childCount * mIconSize + spacesCount * mExpandedBarIconsSpacing + horizontalPadding;
+ final float totalSpace;
+ final float totalIconSize;
+ if (mNewBubbleScaleInAnimator != null && mNewBubbleScaleInAnimator.isRunning()) {
+ // when this animation is running, a new bubble is animating in while the bubble bar is
+ // expanded, so we have at least 2 bubbles in the bubble bar.
+ final float newBubbleScale = mNewBubbleScaleInAnimator.getAnimatedFraction();
+ totalSpace = (childCount - 2 + newBubbleScale) * mExpandedBarIconsSpacing;
+ totalIconSize = (childCount - 1 + newBubbleScale) * mIconSize;
+ } else {
+ totalSpace = Math.max(childCount - 1, 0) * mExpandedBarIconsSpacing;
+ totalIconSize = childCount * mIconSize;
+ }
+ return totalIconSize + totalSpace + horizontalPadding;
}
private float collapsedWidth() {
@@ -998,6 +1103,47 @@
return mIsAnimatingNewBubble;
}
+ private boolean hasOverview() {
+ // Overview is always the last bubble
+ View lastChild = getChildAt(getChildCount() - 1);
+ if (lastChild instanceof BubbleView bubbleView) {
+ return bubbleView.getBubble() instanceof BubbleBarOverflow;
+ }
+ return false;
+ }
+
+ private void updateBubbleAccessibilityStates() {
+ final int childA11y;
+ if (mIsBarExpanded) {
+ // Bar is expanded, focus on the bubbles
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ childA11y = View.IMPORTANT_FOR_ACCESSIBILITY_YES;
+ } else {
+ // Bar is collapsed, only focus on the bar
+ setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ childA11y = View.IMPORTANT_FOR_ACCESSIBILITY_NO;
+ }
+ for (int i = 0; i < getChildCount(); i++) {
+ getChildAt(i).setImportantForAccessibility(childA11y);
+ // Only allowing focusing on bubbles when bar is expanded. Otherwise, in talkback mode,
+ // bubbles can be navigates to in collapsed mode.
+ getChildAt(i).setFocusable(mIsBarExpanded);
+ }
+ }
+
+ private void updateContentDescription() {
+ View firstChild = getChildAt(0);
+ CharSequence contentDesc = firstChild != null ? firstChild.getContentDescription() : "";
+
+ // Don't count overflow if it exists
+ int bubbleCount = getChildCount() - (hasOverview() ? 1 : 0);
+ if (bubbleCount > 1) {
+ contentDesc = getResources().getString(R.string.bubble_bar_description_multiple_bubbles,
+ contentDesc, bubbleCount - 1);
+ }
+ setContentDescription(contentDesc);
+ }
+
/** 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 f614dc6..0bfd1d7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java
@@ -98,7 +98,6 @@
mBarView = barView;
mSystemUiProxy = SystemUiProxy.INSTANCE.get(mActivity);
mBubbleBarAlpha = new MultiValueAlpha(mBarView, 1 /* num alpha channels */);
- mBubbleBarAlpha.setUpdateVisibility(true);
mIconSize = activity.getResources().getDimensionPixelSize(
R.dimen.bubblebar_icon_size);
}
@@ -403,12 +402,24 @@
*/
public void addBubble(BubbleBarItem b, boolean isExpanding, boolean suppressAnimation) {
if (b != null) {
- mBarView.addView(b.getView(), 0,
- new FrameLayout.LayoutParams(mIconSize, mIconSize, Gravity.LEFT));
+ mBarView.addBubble(
+ b.getView(), new FrameLayout.LayoutParams(mIconSize, mIconSize, Gravity.LEFT));
b.getView().setOnClickListener(mBubbleClickListener);
mBubbleDragController.setupBubbleView(b.getView());
+ if (b instanceof BubbleBarOverflow) {
+ return;
+ }
+
if (suppressAnimation || !(b instanceof BubbleBarBubble bubble)) {
+ // the bubble bar and handle are initialized as part of the first bubble animation.
+ // if the animation is suppressed, immediately stash or show the bubble bar to
+ // ensure they've been initialized.
+ if (mTaskbarStashController.isInApp()) {
+ mBubbleStashController.stashBubbleBarImmediate();
+ } else {
+ mBubbleStashController.showBubbleBarImmediate();
+ }
return;
}
animateBubbleNotification(bubble, isExpanding);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
index 0e6fa3c..a6096e2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
@@ -169,7 +169,8 @@
private void setupMagnetizedObject(@NonNull View magnetizedView) {
mMagnetizedObject = new MagnetizedObject<>(mActivity.getApplicationContext(),
- magnetizedView, DynamicAnimation.TRANSLATION_X, DynamicAnimation.TRANSLATION_Y) {
+ magnetizedView, BubbleDragController.DRAG_TRANSLATION_X,
+ DynamicAnimation.TRANSLATION_Y) {
@Override
public float getWidth(@NonNull View underlyingObject) {
return underlyingObject.getWidth() * underlyingObject.getScaleX();
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
index 287e906..7aed2d2 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragAnimator.java
@@ -60,7 +60,6 @@
private final float mBubbleFocusedScale;
private final float mBubbleCapturedScale;
private final float mDismissCapturedScale;
- private final FloatPropertyCompat<View> mTranslationXProperty;
/**
* Should be initialised for each dragged view
@@ -82,28 +81,9 @@
if (view instanceof BubbleBarView) {
mBubbleFocusedScale = SCALE_BUBBLE_BAR_FOCUSED;
mBubbleCapturedScale = mDismissCapturedScale;
- mTranslationXProperty = DynamicAnimation.TRANSLATION_X;
} else {
mBubbleFocusedScale = SCALE_BUBBLE_FOCUSED;
mBubbleCapturedScale = SCALE_BUBBLE_CAPTURED;
- // Wrap BubbleView.DRAG_TRANSLATION_X as it can't be cast to FloatPropertyCompat<View>
- mTranslationXProperty = new FloatPropertyCompat<>(
- BubbleView.DRAG_TRANSLATION_X.getName()) {
- @Override
- public float getValue(View object) {
- if (object instanceof BubbleView bubbleView) {
- return BubbleView.DRAG_TRANSLATION_X.get(bubbleView);
- }
- return 0;
- }
-
- @Override
- public void setValue(View object, float value) {
- if (object instanceof BubbleView bubbleView) {
- BubbleView.DRAG_TRANSLATION_X.setValue(bubbleView, value);
- }
- }
- };
}
}
@@ -140,7 +120,7 @@
mBubbleAnimator
.spring(DynamicAnimation.SCALE_X, 1f)
.spring(DynamicAnimation.SCALE_Y, 1f)
- .spring(mTranslationXProperty, restingPosition.x, velocity.x,
+ .spring(BubbleDragController.DRAG_TRANSLATION_X, restingPosition.x, velocity.x,
mTranslationConfig)
.spring(DynamicAnimation.TRANSLATION_Y, restingPosition.y, velocity.y,
mTranslationConfig)
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index 2ebc3e8..efc747c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -24,6 +24,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.dynamicanimation.animation.FloatPropertyCompat;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.wm.shell.common.bubbles.BaseBubblePinController.LocationChangeListener;
@@ -38,6 +39,37 @@
* Restores initial position of dragged view if released outside of the dismiss target.
*/
public class BubbleDragController {
+
+ /**
+ * Property to update dragged bubble x-translation value.
+ * <p>
+ * When applied to {@link BubbleView}, will use set the translation through
+ * {@link BubbleView#getDragTranslationX()} and {@link BubbleView#setDragTranslationX(float)}
+ * methods.
+ * <p>
+ * When applied to {@link BubbleBarView}, will use {@link View#getTranslationX()} and
+ * {@link View#setTranslationX(float)}.
+ */
+ public static final FloatPropertyCompat<View> DRAG_TRANSLATION_X = new FloatPropertyCompat<>(
+ "dragTranslationX") {
+ @Override
+ public float getValue(View view) {
+ if (view instanceof BubbleView bubbleView) {
+ return bubbleView.getDragTranslationX();
+ }
+ return view.getTranslationX();
+ }
+
+ @Override
+ public void setValue(View view, float value) {
+ if (view instanceof BubbleView bubbleView) {
+ bubbleView.setDragTranslationX(value);
+ } else {
+ view.setTranslationX(value);
+ }
+ }
+ };
+
private final TaskbarActivityContext mActivity;
private BubbleBarController mBubbleBarController;
private BubbleBarViewController mBubbleBarViewController;
@@ -62,8 +94,10 @@
mBubblePinController = bubbleControllers.bubblePinController;
mBubbleDismissController.setListener(
stuck -> {
- mBubbleBarPinController.setDropTargetHidden(stuck);
- mBubblePinController.setDropTargetHidden(stuck);
+ if (stuck) {
+ mBubbleBarPinController.onStuckToDismissTarget();
+ mBubblePinController.onStuckToDismissTarget();
+ }
});
}
@@ -119,6 +153,7 @@
@Override
protected void onDragDismiss() {
mBubblePinController.onDragEnd();
+ mBubbleBarViewController.onBubbleDragEnd();
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
index 5d01b9b..74ddf90 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java
@@ -418,6 +418,7 @@
/** Stashes the bubble bar immediately without animation. */
public void stashBubbleBarImmediate() {
mHandleViewController.setTranslationYForSwipe(0);
+ mBubbleStashedHandleAlpha.setValue(1);
mIconAlphaForStash.setValue(0);
mIconTranslationYForStash.updateValue(getStashTranslation());
mIconScaleForStash.updateValue(STASHED_BAR_SCALE);
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
index 61a6bce..2f92fbb 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleView.java
@@ -21,14 +21,13 @@
import android.graphics.Canvas;
import android.graphics.Outline;
import android.graphics.Rect;
+import android.text.TextUtils;
import android.util.AttributeSet;
-import android.util.FloatProperty;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.widget.ImageView;
-import androidx.annotation.NonNull;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.launcher3.R;
@@ -49,25 +48,6 @@
public static final int DEFAULT_PATH_SIZE = 100;
/**
- * Property to update drag translation value.
- *
- * @see BubbleView#getDragTranslationX()
- * @see BubbleView#setDragTranslationX(float)
- */
- public static final FloatProperty<BubbleView> DRAG_TRANSLATION_X = new FloatProperty<>(
- "dragTranslationX") {
- @Override
- public void setValue(@NonNull BubbleView bubbleView, float value) {
- bubbleView.setDragTranslationX(value);
- }
-
- @Override
- public Float get(BubbleView bubbleView) {
- return bubbleView.getDragTranslationX();
- }
- };
-
- /**
* Flags that suppress the visibility of the 'new' dot or the app badge, for one reason or
* another. If any of these flags are set, the dot will not be shown.
* If {@link SuppressionFlag#BEHIND_STACK} then the app badge will not be shown.
@@ -208,6 +188,16 @@
mAppIcon.setImageBitmap(bubble.getBadge());
mDotColor = bubble.getDotColor();
mDotRenderer = new DotRenderer(mBubbleSize, bubble.getDotPath(), DEFAULT_PATH_SIZE);
+ String contentDesc = bubble.getInfo().getTitle();
+ if (TextUtils.isEmpty(contentDesc)) {
+ contentDesc = getResources().getString(R.string.bubble_bar_bubble_fallback_description);
+ }
+ String appName = bubble.getInfo().getAppName();
+ if (!TextUtils.isEmpty(appName)) {
+ contentDesc = getResources().getString(R.string.bubble_bar_bubble_description,
+ contentDesc, appName);
+ }
+ setContentDescription(contentDesc);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
index adbec65..7eb34a5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayController.java
@@ -133,16 +133,19 @@
* <p>
* This method should be called after an exit animation finishes, if applicable.
*/
- @SuppressLint("WrongConstant")
void maybeCloseWindow() {
- if (mOverlayContext != null && (AbstractFloatingView.hasOpenView(mOverlayContext, TYPE_ALL)
- || mOverlayContext.getDragController().isSystemDragInProgress())) {
- return;
- }
+ if (!canCloseWindow()) return;
mProxyView.close(false);
onDestroy();
}
+ @SuppressLint("WrongConstant")
+ private boolean canCloseWindow() {
+ if (mOverlayContext == null) return true;
+ if (AbstractFloatingView.hasOpenView(mOverlayContext, TYPE_ALL)) return false;
+ return !mOverlayContext.getDragController().isSystemDragInProgress();
+ }
+
/** Destroys the controller and any overlay window if present. */
public void onDestroy() {
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
@@ -212,10 +215,17 @@
@Override
protected void handleClose(boolean animate) {
- if (mIsOpen) {
- mTaskbarContext.getDragLayer().removeView(this);
- Optional.ofNullable(mOverlayContext).ifPresent(c -> closeAllOpenViews(c, animate));
- }
+ if (!mIsOpen) return;
+ mTaskbarContext.getDragLayer().removeView(this);
+ Optional.ofNullable(mOverlayContext).ifPresent(c -> {
+ if (canCloseWindow()) {
+ onDestroy(); // Window is already ready to be destroyed.
+ } else {
+ // Close window's AFVs before destroying it. Its drag layer will attempt to
+ // close the proxy view again once its children are removed.
+ closeAllOpenViews(c, animate);
+ }
+ });
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index c33e4cc..e3a2bab 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -542,18 +542,16 @@
if (mDesktopVisibilityController != null) {
mDesktopVisibilityController.unregisterSystemUiListener();
}
- mDesktopVisibilityController = null;
if (mSplitSelectStateController != null) {
- removeBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler());
mSplitSelectStateController.onDestroy();
}
- mSplitSelectStateController = null;
super.onDestroy();
mHotseatPredictionController.destroy();
mSplitWithKeyboardShortcutController.onDestroy();
if (mViewCapture != null) mViewCapture.close();
+ removeBackAnimationCallback(mSplitSelectStateController.getSplitBackHandler());
}
@Override
@@ -758,6 +756,9 @@
@Override
public boolean isSplitSelectionActive() {
+ if (mSplitSelectStateController == null) {
+ return false;
+ }
return mSplitSelectStateController.isSplitSelectActive();
}
@@ -1275,7 +1276,7 @@
if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
getDragLayer().recreateControllers();
if (mActionsView != null) {
- mActionsView.updateVerticalMargin(info.navigationMode);
+ mActionsView.updateVerticalMargin(info.getNavigationMode());
}
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
index 146ff3d..0469636 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
+++ b/quickstep/src/com/android/launcher3/uioverrides/SystemApiWrapper.kt
@@ -17,24 +17,32 @@
import android.app.ActivityOptions
import android.app.PendingIntent
+import android.app.role.RoleManager
import android.content.Context
+import android.content.IIntentReceiver
+import android.content.IIntentSender
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.LauncherActivityInfo
import android.content.pm.LauncherApps
import android.content.pm.ShortcutInfo
+import android.os.Bundle
import android.os.Flags.allowPrivateProfile
+import android.os.IBinder
import android.os.UserHandle
import android.os.UserManager
import android.util.ArrayMap
+import android.widget.Toast
import android.window.RemoteTransition
import com.android.launcher3.Flags.enablePrivateSpace
import com.android.launcher3.Flags.enablePrivateSpaceInstallShortcut
import com.android.launcher3.Flags.privateSpaceAppInstallerButton
import com.android.launcher3.Flags.privateSpaceSysAppsSeparation
+import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.proxy.ProxyActivityStarter
import com.android.launcher3.util.ApiWrapper
+import com.android.launcher3.util.Executors
import com.android.launcher3.util.StartActivityParams
import com.android.launcher3.util.UserIconInfo
import com.android.quickstep.util.FadeOutRemoteTransition
@@ -115,8 +123,7 @@
intentSender =
mContext
.getSystemService(LauncherApps::class.java)
- ?.privateSpaceSettingsIntent
- ?: return null
+ ?.privateSpaceSettingsIntent ?: return null
options =
ActivityOptions.makeBasic()
.setPendingIntentBackgroundActivityStartMode(
@@ -130,4 +137,50 @@
override fun isNonResizeableActivity(lai: LauncherActivityInfo) =
lai.activityInfo.resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE
+
+ /**
+ * Starts an Activity which can be used to set this Launcher as the HOME app, via a consent
+ * screen. In case the consent screen cannot be shown, or the user does not set current Launcher
+ * as HOME app, a toast asking the user to do the latter is shown.
+ */
+ override fun assignDefaultHomeRole(context: Context) {
+ val roleManager = context.getSystemService(RoleManager::class.java)
+ if (
+ (roleManager!!.isRoleAvailable(RoleManager.ROLE_HOME) &&
+ !roleManager.isRoleHeld(RoleManager.ROLE_HOME))
+ ) {
+ val roleRequestIntent = roleManager.createRequestRoleIntent(RoleManager.ROLE_HOME)
+ val pendingIntent =
+ PendingIntent(
+ object : IIntentSender.Stub() {
+ override fun send(
+ code: Int,
+ intent: Intent,
+ resolvedType: String?,
+ allowlistToken: IBinder?,
+ finishedReceiver: IIntentReceiver?,
+ requiredPermission: String?,
+ options: Bundle?
+ ) {
+ if (code != -1) {
+ Executors.MAIN_EXECUTOR.execute {
+ Toast.makeText(
+ context,
+ context.getString(
+ R.string.set_default_home_app,
+ context.getString(R.string.derived_app_name)
+ ),
+ Toast.LENGTH_LONG
+ )
+ .show()
+ }
+ }
+ }
+ }
+ )
+ val params = StartActivityParams(pendingIntent, 0)
+ params.intent = roleRequestIntent
+ context.startActivity(ProxyActivityStarter.getLaunchIntent(context, params))
+ }
+ }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index 2625919..fa80dc2 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -102,6 +102,11 @@
}
@Override
+ public int getTitle() {
+ return R.string.all_apps_label;
+ }
+
+ @Override
public float getVerticalProgress(Launcher launcher) {
return 0f;
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 7173298..6822f1b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -182,6 +182,11 @@
return launcher.getString(R.string.accessibility_recent_apps);
}
+ @Override
+ public int getTitle() {
+ return R.string.accessibility_recent_apps;
+ }
+
public static float getDefaultSwipeHeight(Launcher launcher) {
return LayoutUtils.getDefaultSwipeHeight(launcher, launcher.getDeviceProfile());
}
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 463222d..1acafab 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -32,6 +32,7 @@
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
import static com.android.launcher3.Flags.enableAdditionalHomeAnimations;
import static com.android.launcher3.Flags.enableGridOnlyOverview;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.PagedView.INVALID_PAGE;
import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_BACKGROUND;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
@@ -1193,6 +1194,10 @@
setDividerShown(true);
break;
}
+ if (mContainerInterface.getTaskbarController() != null) {
+ // Resets this value as the gesture is now complete.
+ mContainerInterface.getTaskbarController().setUserIsGoingHome(false);
+ }
ActiveGestureLog.INSTANCE.addLog(
new ActiveGestureLog.CompoundString("onSettledOnEndTarget ")
.append(endTarget.name()),
@@ -1341,6 +1346,13 @@
mGestureState.setEndTarget(endTarget, false /* isAtomic */);
mAnimationFactory.setEndTarget(endTarget);
+ if (enableScalingRevealHomeAnimation()
+ && mIsTransientTaskbar
+ && mContainerInterface.getTaskbarController() != null) {
+ mContainerInterface.getTaskbarController()
+ .setUserIsGoingHome(endTarget == GestureState.GestureEndTarget.HOME);
+ }
+
float endShift = endTarget == ALL_APPS ? mDragLengthFactor
: endTarget.isLauncher ? 1 : 0;
final float startShift;
@@ -1614,7 +1626,8 @@
mSwipePipToHomeAnimator.getComponentName(),
mSwipePipToHomeAnimator.getDestinationBounds(),
mSwipePipToHomeAnimator.getContentOverlay(),
- mSwipePipToHomeAnimator.getAppBounds());
+ mSwipePipToHomeAnimator.getAppBounds(),
+ mSwipePipToHomeAnimator.getSourceRectHint());
windowAnim = mSwipePipToHomeAnimators;
} else {
diff --git a/quickstep/src/com/android/quickstep/BaseContainerInterface.java b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
index 9955183..b1d511c 100644
--- a/quickstep/src/com/android/quickstep/BaseContainerInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseContainerInterface.java
@@ -41,7 +41,6 @@
import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.taskbar.TaskbarUIController;
-import com.android.launcher3.touch.PagedOrientationHandler;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.views.ScrimView;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
@@ -207,10 +206,10 @@
}
public final void calculateTaskSize(Context context, DeviceProfile dp, Rect outRect,
- PagedOrientationHandler orientedState) {
+ RecentsPagedOrientationHandler orientationHandler) {
if (dp.isTablet) {
if (Flags.enableGridOnlyOverview()) {
- calculateGridTaskSize(context, dp, outRect, orientedState);
+ calculateGridTaskSize(context, dp, outRect, orientationHandler);
} else {
calculateFocusTaskSize(context, dp, outRect);
}
@@ -218,15 +217,19 @@
Resources res = context.getResources();
float maxScale = res.getFloat(R.dimen.overview_max_scale);
int taskMargin = dp.overviewTaskMarginPx;
+ // In fake orientation, OverviewActions is hidden and we only leave a margin there.
+ int overviewActionsClaimedSpace = orientationHandler.isLayoutNaturalToLauncher()
+ ? dp.getOverviewActionsClaimedSpace() : dp.overviewActionsTopMarginPx;
calculateTaskSizeInternal(
context,
dp,
dp.overviewTaskThumbnailTopMarginPx,
- dp.getOverviewActionsClaimedSpace(),
+ overviewActionsClaimedSpace,
res.getDimensionPixelSize(R.dimen.overview_minimum_next_prev_size) + taskMargin,
maxScale,
Gravity.CENTER,
- outRect);
+ outRect,
+ orientationHandler);
}
}
@@ -234,7 +237,7 @@
* Calculates the taskView size for carousel during app to overview animation on tablets.
*/
public final void calculateCarouselTaskSize(Context context, DeviceProfile dp, Rect outRect,
- PagedOrientationHandler orientedState) {
+ RecentsPagedOrientationHandler orientationHandler) {
if (dp.isTablet && dp.isGestureMode) {
Resources res = context.getResources();
float minScale = res.getFloat(R.dimen.overview_carousel_min_scale);
@@ -243,7 +246,7 @@
calculateTaskSizeInternal(context, dp, gridRect, minScale, Gravity.CENTER | Gravity.TOP,
outRect);
} else {
- calculateTaskSize(context, dp, outRect, orientedState);
+ calculateTaskSize(context, dp, outRect, orientationHandler);
}
}
@@ -257,16 +260,39 @@
private void calculateTaskSizeInternal(Context context, DeviceProfile dp, int claimedSpaceAbove,
int claimedSpaceBelow, int minimumHorizontalPadding, float maxScale, int gravity,
- Rect outRect) {
- Rect insets = dp.getInsets();
-
+ Rect outRect, RecentsPagedOrientationHandler orientationHandler) {
Rect potentialTaskRect = new Rect(0, 0, dp.widthPx, dp.heightPx);
- potentialTaskRect.inset(insets.left, insets.top, insets.right, insets.bottom);
- potentialTaskRect.inset(
+
+ Rect insets;
+ if (orientationHandler.isLayoutNaturalToLauncher()) {
+ insets = dp.getInsets();
+ } else {
+ Rect portraitInsets = dp.getInsets();
+ DisplayController displayController = DisplayController.INSTANCE.get(context);
+ Rect deviceRotationInsets = displayController.getInfo().getCurrentBounds().get(
+ orientationHandler.getRotation()).insets;
+ // 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
+ // either orientations.
+ outRect.set(
+ Math.max(outRect.left, portraitInsets.left),
+ Math.max(outRect.top, portraitInsets.top),
+ Math.max(outRect.right, portraitInsets.right),
+ Math.max(outRect.bottom, portraitInsets.bottom)
+ );
+ insets = outRect;
+ }
+ potentialTaskRect.inset(insets);
+
+ outRect.set(
minimumHorizontalPadding,
claimedSpaceAbove,
minimumHorizontalPadding,
claimedSpaceBelow);
+ // Rotate the paddings to portrait perspective,
+ orientationHandler.rotateInsets(outRect, outRect);
+ potentialTaskRect.inset(outRect);
calculateTaskSizeInternal(context, dp, potentialTaskRect, maxScale, gravity, outRect);
}
@@ -326,7 +352,7 @@
* Calculates the overview grid non-focused task size for the provided device configuration.
*/
public final void calculateGridTaskSize(Context context, DeviceProfile dp, Rect outRect,
- PagedOrientationHandler orientedState) {
+ RecentsPagedOrientationHandler orientationHandler) {
Resources res = context.getResources();
Rect potentialTaskRect = new Rect();
if (Flags.enableGridOnlyOverview()) {
@@ -344,7 +370,7 @@
int outHeight = Math.round(scale * taskDimension.y);
int gravity = Gravity.TOP;
- gravity |= orientedState.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
+ gravity |= orientationHandler.getRecentsRtlSetting(res) ? Gravity.RIGHT : Gravity.LEFT;
Gravity.apply(gravity, outWidth, outHeight, potentialTaskRect, outRect);
}
@@ -352,8 +378,8 @@
* Calculates the modal taskView size for the provided device configuration
*/
public final void calculateModalTaskSize(Context context, DeviceProfile dp, Rect outRect,
- PagedOrientationHandler orientedState) {
- calculateTaskSize(context, dp, outRect, orientedState);
+ RecentsPagedOrientationHandler orientationHandler) {
+ calculateTaskSize(context, dp, outRect, orientationHandler);
boolean isGridOnlyOverview = dp.isTablet && Flags.enableGridOnlyOverview();
int claimedSpaceBelow = isGridOnlyOverview
? dp.overviewActionsTopMarginPx + dp.overviewActionsHeight + dp.stashedTaskbarHeight
@@ -372,6 +398,7 @@
minimumHorizontalPadding,
1f /*maxScale*/,
Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM,
- outRect);
+ outRect,
+ orientationHandler);
}
}
diff --git a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
index 50a06fc..9c188f3 100644
--- a/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
+++ b/quickstep/src/com/android/quickstep/DesktopSystemShortcut.kt
@@ -24,6 +24,7 @@
import com.android.quickstep.views.RecentsView
import com.android.quickstep.views.RecentsViewContainer
import com.android.quickstep.views.TaskView.TaskContainer
+import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
import com.android.wm.shell.shared.DesktopModeStatus
/** A menu item, "Desktop", that allows the user to bring the current app into Desktop Windowing. */
@@ -43,7 +44,10 @@
override fun onClick(view: View) {
dismissTaskMenuView()
val recentsView = mTarget.getOverviewPanel<RecentsView<*, *>>()
- recentsView.moveTaskToDesktop(taskContainer) {
+ recentsView.moveTaskToDesktop(
+ taskContainer,
+ DesktopModeTransitionSource.APP_FROM_OVERVIEW
+ ) {
mTarget.statsLogManager
.logger()
.withItemInfo(taskContainer.itemInfo)
diff --git a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
index 811b9fd..08c2e1c 100644
--- a/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/LauncherActivityInterface.java
@@ -308,7 +308,8 @@
return;
}
LauncherOverlayManager om = launcher.getOverlayManager();
- if (!launcher.isStarted() || launcher.isForceInvisible()) {
+ if (!SystemUiProxy.INSTANCE.get(launcher).getHomeVisibilityState().isHomeVisible()
+ || launcher.isForceInvisible()) {
om.hideOverlay(false /* animate */);
} else {
om.hideOverlay(150);
diff --git a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
index 080e03a..3c66590 100644
--- a/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
+++ b/quickstep/src/com/android/quickstep/LauncherSwipeHandlerV2.java
@@ -173,14 +173,10 @@
}
@Override
- public void playAtomicAnimation(float velocity) {
- if (enableScalingRevealHomeAnimation()) {
- if (mContainer != null) {
- new ScalingWorkspaceRevealAnim(
- mContainer, mSiblingAnimation, getWindowTargetRect()).start();
- }
- } else {
- super.playAtomicAnimation(velocity);
+ protected void playScalingRevealAnimation() {
+ if (mContainer != null) {
+ new ScalingWorkspaceRevealAnim(mContainer, mSiblingAnimation,
+ getWindowTargetRect()).start();
}
}
@@ -370,9 +366,25 @@
@Override
public void playAtomicAnimation(float velocity) {
- new StaggeredWorkspaceAnim(mContainer, velocity, true /* animateOverviewScrim */,
- getViewIgnoredInWorkspaceRevealAnimation())
- .start();
+ if (enableScalingRevealHomeAnimation()) {
+ playScalingRevealAnimation();
+ } else {
+ new StaggeredWorkspaceAnim(mContainer, velocity, true /* animateOverviewScrim */,
+ getViewIgnoredInWorkspaceRevealAnimation())
+ .start();
+ }
+ }
+
+ /**
+ * Extracted in a different method so subclasses that have a custom window animation with a
+ * target (icons, widgets) can pass the optional parameters.
+ */
+ protected void playScalingRevealAnimation() {
+ if (mContainer != null) {
+ new ScalingWorkspaceRevealAnim(
+ mContainer, null /* siblingAnimation */,
+ null /* windowTargetRect */).start();
+ }
}
}
}
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
index 3091e3d..26a7c2f 100644
--- a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -28,9 +28,11 @@
import android.graphics.PointF;
import android.os.SystemClock;
import android.os.Trace;
+import android.util.Log;
import android.view.View;
import androidx.annotation.BinderThread;
+import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
@@ -58,6 +60,7 @@
* Helper class to handle various atomic commands for switching between Overview.
*/
public class OverviewCommandHelper {
+ private static final String TAG = "OverviewCommandHelper";
public static final int TYPE_SHOW = 1;
public static final int TYPE_KEYBOARD_INPUT = 2;
@@ -105,10 +108,19 @@
* Called when the command finishes execution.
*/
private void scheduleNextTask(CommandInfo command) {
- if (!mPendingCommands.isEmpty() && mPendingCommands.get(0) == command) {
- mPendingCommands.remove(0);
- executeNext();
+ if (mPendingCommands.isEmpty()) {
+ Log.d(TAG, "no pending commands to schedule");
+ return;
}
+ if (mPendingCommands.get(0) != command) {
+ Log.d(TAG, "next task not scheduled."
+ + " mPendingCommands[0] type is " + mPendingCommands.get(0)
+ + " - command type is: " + command);
+ return;
+ }
+ Log.d(TAG, "scheduleNextTask called: " + command);
+ mPendingCommands.remove(0);
+ executeNext();
}
/**
@@ -119,10 +131,14 @@
@UiThread
private void executeNext() {
if (mPendingCommands.isEmpty()) {
+ Log.d(TAG, "executeNext - mPendingCommands is empty");
return;
}
CommandInfo cmd = mPendingCommands.get(0);
- if (executeCommand(cmd)) {
+
+ boolean result = executeCommand(cmd);
+ Log.d(TAG, "executeNext cmd type: " + cmd + ", result: " + result);
+ if (result) {
scheduleNextTask(cmd);
}
}
@@ -144,14 +160,18 @@
@BinderThread
public void addCommand(int type) {
if (mPendingCommands.size() >= MAX_QUEUE_SIZE) {
+ Log.d(TAG, "the pending command queue is full (" + mPendingCommands.size() + "). "
+ + "command not added: " + type);
return;
}
+ Log.d(TAG, "adding command type: " + type);
CommandInfo cmd = new CommandInfo(type);
MAIN_EXECUTOR.execute(() -> addCommand(cmd));
}
@UiThread
public void clearPendingCommands() {
+ Log.d(TAG, "clearing pending commands - size: " + mPendingCommands.size());
mPendingCommands.clear();
}
@@ -182,9 +202,11 @@
if (callbackList != null) {
callbackList.add(() -> {
+ Log.d(TAG, "launching task callback: " + cmd);
scheduleNextTask(cmd);
mWaitForToggleCommandComplete = false;
});
+ Log.d(TAG, "launching task - waiting for callback: " + cmd);
return false;
} else {
recents.startHome();
@@ -200,12 +222,17 @@
private <T extends StatefulActivity<?> & RecentsViewContainer> boolean executeCommand(
CommandInfo cmd) {
if (mWaitForToggleCommandComplete && cmd.type == TYPE_TOGGLE) {
+ Log.d(TAG, "executeCommand: " + cmd
+ + " - waiting for toggle command complete");
return true;
}
BaseActivityInterface<?, T> activityInterface =
mOverviewComponentObserver.getActivityInterface();
RecentsView visibleRecentsView = activityInterface.getVisibleRecentsView();
RecentsView createdRecentsView;
+
+ Log.d(TAG, "executeCommand: " + cmd
+ + " - visibleRecentsView: " + visibleRecentsView);
if (visibleRecentsView == null) {
T activity = activityInterface.getCreatedContainer();
createdRecentsView = activity == null ? null : activity.getOverviewPanel();
@@ -292,14 +319,17 @@
updateRecentsViewFocus(cmd);
logShowOverviewFrom(cmd.type);
}
+
@Override
public void onAnimationEnd(Animator animation) {
+ Log.d(TAG, "switching to Overview state - onAnimationEnd: " + cmd);
super.onAnimationEnd(animation);
onRecentsViewFocusUpdated(cmd);
scheduleNextTask(cmd);
}
};
if (activityInterface.switchToRecentsIfVisible(animatorListener)) {
+ Log.d(TAG, "switching to Overview state - waiting: " + cmd);
// If successfully switched, wait until animation finishes
return false;
}
@@ -366,10 +396,12 @@
cmd.mActiveCallbacks.addListener(recentAnimListener);
}
Trace.beginAsyncSection(TRANSITION_NAME, 0);
+ Log.d(TAG, "switching via recents animation - onGestureStarted: " + cmd);
return false;
}
private void onTransitionComplete(CommandInfo cmd, AbsSwipeUpHandler handler) {
+ Log.d(TAG, "switching via recents animation - onTransitionComplete: " + cmd);
cmd.removeListener(handler);
Trace.endAsyncSection(TRANSITION_NAME, 0);
onRecentsViewFocusUpdated(cmd);
@@ -478,5 +510,15 @@
mActiveCallbacks.removeListener(listener);
}
}
+
+ @NonNull
+ @Override
+ public String toString() {
+ return "CommandInfo("
+ + "type=" + type + ", "
+ + "createTime=" + createTime + ", "
+ + "mActiveCallbacks=" + mActiveCallbacks
+ + ")";
+ }
}
}
diff --git a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
index dfbae65..b4b8c5b 100644
--- a/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
+++ b/quickstep/src/com/android/quickstep/QuickstepTestInformationHandler.java
@@ -198,6 +198,12 @@
.unstashBubbleBarIfStashed();
});
return response;
+ case TestProtocol.REQUEST_INJECT_FAKE_TRACKPAD:
+ runOnTISBinder(tisBinder -> tisBinder.injectFakeTrackpadForTesting());
+ return response;
+ case TestProtocol.REQUEST_EJECT_FAKE_TRACKPAD:
+ runOnTISBinder(tisBinder -> tisBinder.ejectFakeTrackpadForTesting());
+ return response;
}
return super.call(method, arg, extras);
diff --git a/quickstep/src/com/android/quickstep/RecentTasksList.java b/quickstep/src/com/android/quickstep/RecentTasksList.java
index 711882c..b08a46f 100644
--- a/quickstep/src/com/android/quickstep/RecentTasksList.java
+++ b/quickstep/src/com/android/quickstep/RecentTasksList.java
@@ -31,6 +31,7 @@
import android.os.RemoteException;
import android.util.SparseBooleanArray;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.util.LooperExecutor;
@@ -44,6 +45,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.List;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -73,7 +75,7 @@
private ArrayList<ActivityManager.RunningTaskInfo> mRunningTasks;
public RecentTasksList(LooperExecutor mainThreadExecutor, KeyguardManager keyguardManager,
- SystemUiProxy sysUiProxy) {
+ SystemUiProxy sysUiProxy, TopTaskTracker topTaskTracker) {
mMainThreadExecutor = mainThreadExecutor;
mKeyguardManager = keyguardManager;
mChangeId = 1;
@@ -104,6 +106,13 @@
RecentTasksList.this.onRunningTaskChanged(taskInfo);
});
}
+
+ @Override
+ public void onTaskMovedToFront(ActivityManager.RunningTaskInfo taskInfo) {
+ mMainThreadExecutor.execute(() -> {
+ topTaskTracker.onTaskMovedToFront(taskInfo);
+ });
+ }
});
// We may receive onRunningTaskAppeared events later for tasks which have already been
// included in the list returned by mSysUiProxy.getRunningTasks(), or may receive
@@ -133,11 +142,11 @@
* Asynchronously fetches the list of recent tasks, reusing cached list if available.
*
* @param loadKeysOnly Whether to load other associated task data, or just the key
- * @param callback The callback to receive the list of recent tasks
+ * @param callback The callback to receive the list of recent tasks
* @return The change id of the current task list
*/
public synchronized int getTasks(boolean loadKeysOnly,
- Consumer<ArrayList<GroupTask>> callback, Predicate<GroupTask> filter) {
+ @Nullable Consumer<List<GroupTask>> callback, Predicate<GroupTask> filter) {
final int requestLoadId = mChangeId;
if (mResultsUi.isValidForRequest(requestLoadId, loadKeysOnly)) {
// The list is up to date, send the callback on the next frame,
@@ -198,7 +207,7 @@
mChangeId++;
}
- /**
+ /**
* Registers a listener for running tasks
*/
public void registerRunningTasksListener(RecentsModel.RunningTasksListener listener) {
diff --git a/quickstep/src/com/android/quickstep/RecentsActivity.java b/quickstep/src/com/android/quickstep/RecentsActivity.java
index 97a0b3f..3df62da 100644
--- a/quickstep/src/com/android/quickstep/RecentsActivity.java
+++ b/quickstep/src/com/android/quickstep/RecentsActivity.java
@@ -371,6 +371,9 @@
getSystemUiController().updateUiState(SystemUiController.UI_STATE_BASE_WINDOW,
Themes.getAttrBoolean(this, R.attr.isWorkspaceDarkText));
ACTIVITY_TRACKER.handleCreate(this);
+
+ // Set screen title for Talkback
+ setTitle(R.string.accessibility_recent_apps);
}
@Override
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 34b50ca..7adce74 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -45,6 +45,7 @@
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED;
import android.app.ActivityTaskManager;
import android.content.Context;
@@ -91,7 +92,7 @@
static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
// TODO: Move to quickstep contract
- public static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 3f;
+ private static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 3f;
private static final float QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL = 1.414f;
private final Context mContext;
@@ -386,7 +387,7 @@
boolean canStartWithNavHidden = (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0
|| (mSystemUiStateFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) != 0
|| mRotationTouchHelper.isTaskListFrozen();
- return canStartWithNavHidden && canStartTrackpadGesture();
+ return canStartWithNavHidden && canStartAnyGesture();
}
/**
@@ -395,14 +396,24 @@
* mode.
*/
public boolean canStartTrackpadGesture() {
- return (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0
- && (mSystemUiStateFlags & SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING) == 0
- && (mSystemUiStateFlags & SYSUI_STATE_QUICK_SETTINGS_EXPANDED) == 0
- && (mSystemUiStateFlags & SYSUI_STATE_MAGNIFICATION_OVERLAP) == 0
- && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
- || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0)
- && (mSystemUiStateFlags & SYSUI_STATE_DEVICE_DREAMING) == 0
- && (mSystemUiStateFlags & SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION) == 0;
+ boolean trackpadGesturesEnabled =
+ (mSystemUiStateFlags & SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED) == 0;
+ return trackpadGesturesEnabled && canStartAnyGesture();
+ }
+
+ /**
+ * Common logic to determine if either trackpad or finger gesture can be started
+ */
+ private boolean canStartAnyGesture() {
+ boolean homeOrOverviewEnabled = (mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0
+ || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0;
+ long gestureDisablingStates = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+ | SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
+ | SYSUI_STATE_QUICK_SETTINGS_EXPANDED
+ | SYSUI_STATE_MAGNIFICATION_OVERLAP
+ | SYSUI_STATE_DEVICE_DREAMING
+ | SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
+ return (gestureDisablingStates & mSystemUiStateFlags) == 0 && homeOrOverviewEnabled;
}
/**
@@ -610,16 +621,6 @@
return touchSlop * touchSlop;
}
- /**
- * Returns the squared touch slop using the given base slop multiplier {@code slopMultiplier}
- * and custom slop multiplier {@code customSlopMultiplier}.
- */
- public float getSquaredTouchSlop(float slopMultiplier, float customSlopMultiplier) {
- float systemTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- float touchSlop = customSlopMultiplier * slopMultiplier * systemTouchSlop;
- return touchSlop * touchSlop;
- }
-
public String getSystemUiStateString() {
return QuickStepContract.getSystemUiStateString(mSystemUiStateFlags);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 89351aa..6eefe4a 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -33,6 +33,7 @@
import android.os.Process;
import android.os.UserHandle;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.icons.IconProvider;
@@ -40,6 +41,7 @@
import com.android.launcher3.util.Executors.SimpleThreadFactory;
import com.android.launcher3.util.MainThreadInitializedObject;
import com.android.launcher3.util.SafeCloseable;
+import com.android.quickstep.recents.data.RecentTasksDataSource;
import com.android.quickstep.util.GroupTask;
import com.android.quickstep.util.TaskVisualsChangeListener;
import com.android.systemui.shared.recents.model.Task;
@@ -60,8 +62,8 @@
* Singleton class to load and manage recents model.
*/
@TargetApi(Build.VERSION_CODES.O)
-public class RecentsModel implements IconChangeListener, TaskStackChangeListener,
- TaskVisualsChangeListener, SafeCloseable {
+public class RecentsModel implements RecentTasksDataSource, IconChangeListener,
+ TaskStackChangeListener, TaskVisualsChangeListener, SafeCloseable {
// We do not need any synchronization for this variable as its only written on UI thread.
public static final MainThreadInitializedObject<RecentsModel> INSTANCE =
@@ -88,7 +90,8 @@
this(context,
new RecentTasksList(MAIN_EXECUTOR,
context.getSystemService(KeyguardManager.class),
- SystemUiProxy.INSTANCE.get(context)),
+ SystemUiProxy.INSTANCE.get(context),
+ TopTaskTracker.INSTANCE.get(context)),
new TaskIconCache(context, RECENTS_MODEL_EXECUTOR, iconProvider),
new TaskThumbnailCache(context, RECENTS_MODEL_EXECUTOR),
iconProvider,
@@ -141,7 +144,8 @@
* always called on the UI thread.
* @return the request id associated with this call.
*/
- public int getTasks(Consumer<ArrayList<GroupTask>> callback) {
+ @Override
+ public int getTasks(@Nullable Consumer<List<GroupTask>> callback) {
return mTaskList.getTasks(false /* loadKeysOnly */, callback,
RecentsFilterState.DEFAULT_FILTER);
}
@@ -155,7 +159,7 @@
* callback.
* @return the request id associated with this call.
*/
- public int getTasks(Consumer<ArrayList<GroupTask>> callback, Predicate<GroupTask> filter) {
+ public int getTasks(@Nullable Consumer<List<GroupTask>> callback, Predicate<GroupTask> filter) {
return mTaskList.getTasks(false /* loadKeysOnly */, callback, filter);
}
diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
index 3380291..6f1ab7d 100644
--- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java
+++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java
@@ -157,7 +157,7 @@
// Register for navigation mode changes
mDisplayController.addChangeListener(this);
DisplayController.Info info = mDisplayController.getInfo();
- onDisplayInfoChangedInternal(info, CHANGE_ALL, info.navigationMode.hasGestures);
+ onDisplayInfoChangedInternal(info, CHANGE_ALL, info.getNavigationMode().hasGestures);
runOnDestroy(() -> mDisplayController.removeChangeListener(this));
mOrientationListener = new OrientationEventListener(mContext) {
@@ -291,7 +291,7 @@
}
if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
- NavigationMode newMode = info.navigationMode;
+ NavigationMode newMode = info.getNavigationMode();
mOrientationTouchTransformer.setNavigationMode(newMode, mDisplayController.getInfo(),
mContext.getResources());
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 0ac3ec7..433baa9 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -85,6 +85,7 @@
import com.android.wm.shell.bubbles.IBubbles;
import com.android.wm.shell.bubbles.IBubblesListener;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
+import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.common.pip.IPip;
import com.android.wm.shell.common.pip.IPipAnimationListener;
import com.android.wm.shell.common.split.SplitScreenConstants.PersistentSnapPosition;
@@ -683,11 +684,11 @@
* should be responsible for cleaning up the overlay.
*/
public void stopSwipePipToHome(int taskId, ComponentName componentName, Rect destinationBounds,
- SurfaceControl overlay, Rect appBounds) {
+ SurfaceControl overlay, Rect appBounds, Rect sourceRectHint) {
if (mPip != null) {
try {
mPip.stopSwipePipToHome(taskId, componentName, destinationBounds, overlay,
- appBounds);
+ appBounds, sourceRectHint);
} catch (RemoteException e) {
Log.w(TAG, "Failed call stopSwipePipToHome");
}
@@ -1494,10 +1495,10 @@
}
/** Call shell to move a task with given `taskId` to desktop */
- public void moveToDesktop(int taskId) {
+ public void moveToDesktop(int taskId, DesktopModeTransitionSource transitionSource) {
if (mDesktopMode != null) {
try {
- mDesktopMode.moveToDesktop(taskId);
+ mDesktopMode.moveToDesktop(taskId, transitionSource);
} catch (RemoteException e) {
Log.w(TAG, "Failed call moveToDesktop", e);
}
diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
index 2348f28..28fa81a 100644
--- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java
+++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java
@@ -26,6 +26,8 @@
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_INITIALIZED;
import static com.android.quickstep.GestureState.STATE_RECENTS_ANIMATION_STARTED;
import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.START_RECENTS_ANIMATION;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -44,9 +46,11 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.util.ActiveGestureLog;
+import com.android.quickstep.util.SystemUiFlagUtils;
import com.android.quickstep.views.RecentsView;
import com.android.systemui.shared.recents.model.ThumbnailData;
import com.android.systemui.shared.system.ActivityManagerWrapper;
+import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
@@ -373,20 +377,54 @@
return mCallbacks;
}
- public void endLiveTile() {
- if (mLastGestureState == null) {
- return;
- }
- BaseContainerInterface containerInterface = mLastGestureState.getContainerInterface();
- if (containerInterface.isInLiveTileMode()
- && containerInterface.getCreatedContainer() != null) {
- RecentsView recentsView = containerInterface.getCreatedContainer().getOverviewPanel();
- if (recentsView != null) {
- recentsView.switchToScreenshot(null,
- () -> recentsView.finishRecentsAnimation(true /* toRecents */,
- false /* shouldPip */, null));
+ public void onSystemUiFlagsChanged(@QuickStepContract.SystemUiStateFlags long lastSysUIFlags,
+ @QuickStepContract.SystemUiStateFlags long newSysUIFlags) {
+ long isShadeExpandedFlagMask =
+ SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
+ boolean wasExpanded = hasAnyFlag(lastSysUIFlags, isShadeExpandedFlagMask);
+ boolean isExpanded = hasAnyFlag(newSysUIFlags, isShadeExpandedFlagMask);
+ if (wasExpanded != isExpanded && isExpanded) {
+ // End live tile when expanding the notification panel for the first time from
+ // overview.
+ if (endLiveTile()) {
+ return;
}
}
+
+ boolean wasLocked = SystemUiFlagUtils.isLocked(lastSysUIFlags);
+ boolean isLocked = SystemUiFlagUtils.isLocked(newSysUIFlags);
+ if (wasLocked != isLocked && isLocked) {
+ // Finish the running recents animation when locking the device.
+ finishRunningRecentsAnimation(
+ mController != null && mController.getFinishTargetIsLauncher());
+ }
+ }
+
+ private boolean hasAnyFlag(long flags, long flagMask) {
+ return (flags & flagMask) != 0;
+ }
+
+ /**
+ * Switches the {@link RecentsView} to screenshot if in live tile mode.
+ *
+ * @return true iff the {@link RecentsView} was in live tile mode and was switched to screenshot
+ */
+ public boolean endLiveTile() {
+ if (mLastGestureState == null) {
+ return false;
+ }
+ BaseContainerInterface containerInterface = mLastGestureState.getContainerInterface();
+ if (!containerInterface.isInLiveTileMode()
+ || containerInterface.getCreatedContainer() == null) {
+ return false;
+ }
+ RecentsView recentsView = containerInterface.getCreatedContainer().getOverviewPanel();
+ if (recentsView == null) {
+ return false;
+ }
+ recentsView.switchToScreenshot(null, () -> recentsView.finishRecentsAnimation(
+ true /* toRecents */, false /* shouldPip */, null));
+ return true;
}
public void setLiveTileCleanUpHandler(Runnable cleanUpHandler) {
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 4b5c826..fd141c3 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -21,6 +21,7 @@
import static android.view.Surface.ROTATION_0;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_FREE_FORM_TAP;
+import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.window.flags.Flags.enableDesktopWindowingMode;
import android.app.ActivityOptions;
@@ -107,10 +108,14 @@
public List<SystemShortcut> getShortcuts(RecentsViewContainer container,
TaskContainer taskContainer) {
TaskView taskView = taskContainer.getTaskView();
+ int actionId = taskContainer.getStagePosition() == STAGE_POSITION_BOTTOM_OR_RIGHT
+ ? R.id.action_app_info_bottom_right
+ : R.id.action_app_info_top_left;
+
AppInfo.SplitAccessibilityInfo accessibilityInfo =
new AppInfo.SplitAccessibilityInfo(taskView.containsMultipleTasks(),
TaskUtils.getTitle(taskView.getContext(), taskContainer.getTask()),
- taskContainer.getA11yNodeId()
+ actionId
);
return Collections.singletonList(new AppInfo(container, taskContainer.getItemInfo(),
taskView, accessibilityInfo));
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
index 7ebb767..38e927f 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailCache.java
@@ -21,11 +21,13 @@
import android.content.Context;
import android.content.res.Resources;
+import androidx.annotation.NonNull;
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.R;
import com.android.launcher3.util.CancellableTask;
import com.android.launcher3.util.Preconditions;
+import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource;
import com.android.quickstep.util.TaskKeyByLastActiveTimeCache;
import com.android.quickstep.util.TaskKeyCache;
import com.android.quickstep.util.TaskKeyLruCache;
@@ -38,7 +40,7 @@
import java.util.concurrent.Executor;
import java.util.function.Consumer;
-public class TaskThumbnailCache {
+public class TaskThumbnailCache implements TaskThumbnailDataSource {
private final Executor mBgExecutor;
private final TaskKeyCache<ThumbnailData> mCache;
@@ -148,8 +150,9 @@
* @param callback The callback to receive the task after its data has been populated.
* @return A cancelable handle to the request
*/
+ @Override
public CancellableTask<ThumbnailData> updateThumbnailInBackground(
- Task task, Consumer<ThumbnailData> callback) {
+ Task task, @NonNull Consumer<ThumbnailData> callback) {
Preconditions.assertUIThread();
boolean lowResolution = !mHighResLoadingState.isEnabled();
diff --git a/quickstep/src/com/android/quickstep/TopTaskTracker.java b/quickstep/src/com/android/quickstep/TopTaskTracker.java
index 3a6b804..6ed05c8 100644
--- a/quickstep/src/com/android/quickstep/TopTaskTracker.java
+++ b/quickstep/src/com/android/quickstep/TopTaskTracker.java
@@ -28,6 +28,7 @@
import android.annotation.UserIdInt;
import android.app.ActivityManager.RunningTaskInfo;
import android.content.Context;
+import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -47,6 +48,7 @@
import com.android.systemui.shared.system.TaskStackChangeListeners;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
+import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -61,6 +63,10 @@
public class TopTaskTracker extends ISplitScreenListener.Stub
implements TaskStackChangeListener, SafeCloseable {
+ private static final String TAG = "TopTaskTracker";
+
+ private static final boolean DEBUG = true;
+
public static MainThreadInitializedObject<TopTaskTracker> INSTANCE =
new MainThreadInitializedObject<>(TopTaskTracker::new);
@@ -92,10 +98,19 @@
@Override
public void onTaskRemoved(int taskId) {
mOrderedTaskList.removeIf(rto -> rto.taskId == taskId);
+ if (DEBUG) {
+ Log.i(TAG, "onTaskRemoved: taskId=" + taskId);
+ }
}
@Override
public void onTaskMovedToFront(RunningTaskInfo taskInfo) {
+ if (!mOrderedTaskList.isEmpty()
+ && mOrderedTaskList.getFirst().taskId != taskInfo.taskId
+ && DEBUG) {
+ Log.i(TAG, "onTaskMovedToFront: (moved taskInfo to front) taskId=" + taskInfo.taskId
+ + ", baseIntent=" + taskInfo.baseIntent);
+ }
mOrderedTaskList.removeIf(rto -> rto.taskId == taskInfo.taskId);
mOrderedTaskList.addFirst(taskInfo);
@@ -106,6 +121,11 @@
final RunningTaskInfo topTaskOnHomeDisplay = mOrderedTaskList.stream()
.filter(rto -> rto.displayId == DEFAULT_DISPLAY).findFirst().orElse(null);
if (topTaskOnHomeDisplay != null) {
+ if (DEBUG) {
+ Log.i(TAG, "onTaskMovedToFront: (removing top task on home display) taskId="
+ + topTaskOnHomeDisplay.taskId
+ + ", baseIntent=" + topTaskOnHomeDisplay.baseIntent);
+ }
mOrderedTaskList.removeIf(rto -> rto.taskId == topTaskOnHomeDisplay.taskId);
mOrderedTaskList.addFirst(topTaskOnHomeDisplay);
}
@@ -119,6 +139,10 @@
if (info.taskId != taskInfo.taskId
&& info.taskId != mMainStagePosition.taskId
&& info.taskId != mSideStagePosition.taskId) {
+ if (DEBUG) {
+ Log.i(TAG, "onTaskMovedToFront: (removing task list overflow) taskId="
+ + taskInfo.taskId + ", baseIntent=" + taskInfo.baseIntent);
+ }
itr.remove();
return;
}
@@ -128,6 +152,9 @@
@Override
public void onStagePositionChanged(@StageType int stage, @StagePosition int position) {
+ if (DEBUG) {
+ Log.i(TAG, "onStagePositionChanged: stage=" + stage + ", position=" + position);
+ }
if (stage == SplitConfigurationOptions.STAGE_TYPE_MAIN) {
mMainStagePosition.stagePosition = position;
} else {
@@ -137,6 +164,10 @@
@Override
public void onTaskStageChanged(int taskId, @StageType int stage, boolean visible) {
+ if (DEBUG) {
+ Log.i(TAG, "onTaskStageChanged: taskId=" + taskId
+ + ", stage=" + stage + ", visible=" + visible);
+ }
// If a task is not visible anymore or has been moved to undefined, stop tracking it.
if (!visible || stage == SplitConfigurationOptions.STAGE_TYPE_UNDEFINED) {
if (mMainStagePosition.taskId == taskId) {
@@ -156,17 +187,24 @@
@Override
public void onActivityPinned(String packageName, int userId, int taskId, int stackId) {
+ if (DEBUG) {
+ Log.i(TAG, "onActivityPinned: packageName=" + packageName
+ + ", userId=" + userId + ", stackId=" + stackId);
+ }
mPinnedTaskId = taskId;
}
@Override
public void onActivityUnpinned() {
+ if (DEBUG) {
+ Log.i(TAG, "onActivityUnpinned");
+ }
mPinnedTaskId = INVALID_TASK_ID;
}
/**
* @return index 0 will be task in left/top position, index 1 in right/bottom position.
- * Will return empty array if device is not in staged split
+ * Will return empty array if device is not in staged split
*/
public int[] getRunningSplitTaskIds() {
if (mMainStagePosition.taskId == INVALID_TASK_ID
@@ -212,6 +250,21 @@
return new CachedTaskInfo(tasks);
}
+ public void dump(String prefix, PrintWriter writer) {
+ writer.println(prefix + "TopTaskTracker:");
+
+ writer.println(prefix + "\tmOrderedTaskList=[");
+ for (RunningTaskInfo taskInfo : mOrderedTaskList) {
+ writer.println(prefix + "\t\t(taskId=" + taskInfo.taskId
+ + "; baseIntent=" + taskInfo.baseIntent
+ + "; isRunning=" + taskInfo.isRunning + ")");
+ }
+ writer.println(prefix + "\t]");
+ writer.println(prefix + "\tmMainStagePosition=" + mMainStagePosition);
+ writer.println(prefix + "\tmSideStagePosition=" + mSideStagePosition);
+ writer.println(prefix + "\tmPinnedTaskId=" + mPinnedTaskId);
+ }
+
/**
* Class to provide information about a task which can be safely cached and do not change
* during the lifecycle of the task.
@@ -242,7 +295,7 @@
* If the given task holds an activity that is excluded from recents, and there
* is another running task that is not excluded from recents, returns that underlying task.
*/
- public @Nullable CachedTaskInfo otherVisibleTaskThisIsExcludedOver() {
+ public @Nullable CachedTaskInfo getVisibleNonExcludedTask() {
if (mTopTask == null
|| (mTopTask.baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0) {
// Not an excluded task.
@@ -250,7 +303,9 @@
}
List<RunningTaskInfo> visibleNonExcludedTasks = mAllCachedTasks.stream()
.filter(t -> t.isVisible
- && (t.baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0)
+ && (t.baseIntent.getFlags() & FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0
+ && t.getActivityType() != ACTIVITY_TYPE_HOME
+ && t.getActivityType() != ACTIVITY_TYPE_RECENTS)
.toList();
return visibleNonExcludedTasks.isEmpty() ? null
: new CachedTaskInfo(visibleNonExcludedTasks);
@@ -284,7 +339,7 @@
*/
public Task[] getPlaceholderTasks() {
return mTopTask == null ? new Task[0]
- : new Task[] {Task.from(new TaskKey(mTopTask), mTopTask, false)};
+ : new Task[]{Task.from(new TaskKey(mTopTask), mTopTask, false)};
}
/**
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index 4599f18..bfdc3df 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -47,8 +47,6 @@
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNFOLD_ANIMATION_FORWARDER;
import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_UNLOCK_ANIMATION_CONTROLLER;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.wm.shell.Flags.enableBubblesLongPressNavHandle;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BACK_ANIMATION;
import static com.android.wm.shell.sysui.ShellSharedConstants.KEY_EXTRA_SHELL_BUBBLES;
@@ -68,11 +66,13 @@
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Region;
+import android.hardware.input.InputManager;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Looper;
import android.os.SystemClock;
import android.os.Trace;
+import android.util.ArraySet;
import android.util.Log;
import android.view.Choreographer;
import android.view.InputDevice;
@@ -83,6 +83,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.UiThread;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.ConstantItem;
@@ -146,6 +147,7 @@
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -396,6 +398,25 @@
return tis.mTaskbarManager;
}
+ @VisibleForTesting
+ public void injectFakeTrackpadForTesting() {
+ TouchInteractionService tis = mTis.get();
+ if (tis == null) return;
+ tis.mTrackpadsConnected.add(1000);
+ tis.initInputMonitor("tapl testing");
+ }
+
+ @VisibleForTesting
+ public void ejectFakeTrackpadForTesting() {
+ TouchInteractionService tis = mTis.get();
+ if (tis == null) return;
+ tis.mTrackpadsConnected.clear();
+ // This method destroys the current input monitor if set up, and only init a new one
+ // in 3-button mode if {@code mTrackpadsConnected} is not empty. So in other words,
+ // it will destroy the input monitor.
+ tis.initInputMonitor("tapl testing");
+ }
+
/**
* Sets whether a predictive back-to-home animation is in progress in the device state
*/
@@ -453,6 +474,50 @@
}
}
+ private final InputManager.InputDeviceListener mInputDeviceListener =
+ new InputManager.InputDeviceListener() {
+ @Override
+ public void onInputDeviceAdded(int deviceId) {
+ if (isTrackpadDevice(deviceId)) {
+ boolean wasEmpty = mTrackpadsConnected.isEmpty();
+ mTrackpadsConnected.add(deviceId);
+ if (wasEmpty) {
+ update();
+ }
+ }
+ }
+
+ @Override
+ public void onInputDeviceChanged(int deviceId) {
+ }
+
+ @Override
+ public void onInputDeviceRemoved(int deviceId) {
+ mTrackpadsConnected.remove(deviceId);
+ if (mTrackpadsConnected.isEmpty()) {
+ update();
+ }
+ }
+
+ private void update() {
+ if (mInputMonitorCompat != null && !mTrackpadsConnected.isEmpty()) {
+ // Don't destroy and reinitialize input monitor due to trackpad
+ // connecting when it's already set up.
+ return;
+ }
+ initInputMonitor("onTrackpadConnected()");
+ }
+
+ private boolean isTrackpadDevice(int deviceId) {
+ InputDevice inputDevice = mInputManager.getInputDevice(deviceId);
+ if (inputDevice == null) {
+ return false;
+ }
+ return inputDevice.getSources() == (InputDevice.SOURCE_MOUSE
+ | InputDevice.SOURCE_TOUCHPAD);
+ }
+ };
+
private static boolean sConnected = false;
private static boolean sIsInitialized = false;
private RotationTouchHelper mRotationTouchHelper;
@@ -503,6 +568,8 @@
private TaskbarManager mTaskbarManager;
private Function<GestureState, AnimatedFloat> mSwipeUpProxyProvider = i -> null;
private AllAppsActionManager mAllAppsActionManager;
+ private InputManager mInputManager;
+ private final Set<Integer> mTrackpadsConnected = new ArraySet<>();
@Override
public void onCreate() {
@@ -512,10 +579,19 @@
mMainChoreographer = Choreographer.getInstance();
mAM = ActivityManagerWrapper.getInstance();
mDeviceState = new RecentsAnimationDeviceState(this, true);
+ mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
mAllAppsActionManager = new AllAppsActionManager(
this, UI_HELPER_EXECUTOR, this::createAllAppsPendingIntent);
+ mInputManager = getSystemService(InputManager.class);
+ if (ENABLE_TRACKPAD_GESTURE.get()) {
+ mInputManager.registerInputDeviceListener(mInputDeviceListener,
+ UI_HELPER_EXECUTOR.getHandler());
+ int [] inputDevices = mInputManager.getInputDeviceIds();
+ for (int inputDeviceId : inputDevices) {
+ mInputDeviceListener.onInputDeviceAdded(inputDeviceId);
+ }
+ }
mTaskbarManager = new TaskbarManager(this, mAllAppsActionManager, mNavCallbacks);
- mRotationTouchHelper = mDeviceState.getRotationTouchHelper();
mInputConsumer = InputConsumerController.getRecentsAnimationInputConsumer();
// Call runOnUserUnlocked() before any other callbacks to ensure everything is initialized.
@@ -542,7 +618,8 @@
private void initInputMonitor(String reason) {
disposeEventHandlers("Initializing input monitor due to: " + reason);
- if (mDeviceState.isButtonNavMode() && !ENABLE_TRACKPAD_GESTURE.get()) {
+ if (mDeviceState.isButtonNavMode() && (!ENABLE_TRACKPAD_GESTURE.get()
+ || mTrackpadsConnected.isEmpty())) {
return;
}
@@ -643,16 +720,7 @@
SystemUiProxy.INSTANCE.get(this).setLastSystemUiStateFlags(systemUiStateFlags);
mOverviewComponentObserver.onSystemUiStateChanged();
mTaskbarManager.onSystemUiFlagsChanged(systemUiStateFlags);
-
- long isShadeExpandedFlag =
- SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED | SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
- boolean wasExpanded = (lastSysUIFlags & isShadeExpandedFlag) != 0;
- boolean isExpanded = (systemUiStateFlags & isShadeExpandedFlag) != 0;
- if (wasExpanded != isExpanded && isExpanded) {
- // End live tile when expanding the notification panel for the first time from
- // overview.
- mTaskAnimationManager.endLiveTile();
- }
+ mTaskAnimationManager.onSystemUiFlagsChanged(lastSysUIFlags, systemUiStateFlags);
}
}
@@ -678,6 +746,9 @@
mAllAppsActionManager.onDestroy();
+ mInputManager.unregisterInputDeviceListener(mInputDeviceListener);
+ mTrackpadsConnected.clear();
+
mTaskbarManager.destroy();
sConnected = false;
@@ -1174,7 +1245,7 @@
// running activity as the task behind the overlay.
TopTaskTracker.CachedTaskInfo otherVisibleTask = runningTask == null
? null
- : runningTask.otherVisibleTaskThisIsExcludedOver();
+ : runningTask.getVisibleNonExcludedTask();
if (otherVisibleTask != null) {
ActiveGestureLog.INSTANCE.addLog(new CompoundString("Changing active task to ")
.append(otherVisibleTask.getPackageName())
@@ -1467,6 +1538,7 @@
pw.println("\tmConsumer=" + mConsumer.getName());
ActiveGestureLog.INSTANCE.dump("", pw);
RecentsModel.INSTANCE.get(this).dump("", pw);
+ TopTaskTracker.INSTANCE.get(this).dump("", pw);
if (mTaskAnimationManager != null) {
mTaskAnimationManager.dump("", pw);
}
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 096ed2c..485d6c4 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -54,6 +54,7 @@
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
public class FallbackRecentsView extends RecentsView<RecentsActivity, RecentsState>
implements StateListener<RecentsState> {
@@ -179,7 +180,7 @@
}
@Override
- protected void applyLoadPlan(ArrayList<GroupTask> taskGroups) {
+ protected void applyLoadPlan(List<GroupTask> taskGroups) {
// When quick-switching on 3p-launcher, we add a "stub" tile corresponding to Launcher
// as well. This tile is never shown as we have setCurrentTaskHidden, but allows use to
// track the index of the next task appropriately, as if we are switching on any other app.
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
index 9a25c32..95295b0 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/TaskbarUnstashInputConsumer.java
@@ -21,6 +21,7 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.launcher3.Flags.enableCursorHoverStates;
+import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.MotionEventsUtils.isTrackpadMotionEvent;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_TOUCHING;
@@ -32,6 +33,7 @@
import android.os.Looper;
import android.view.InputDevice;
import android.view.MotionEvent;
+import android.view.VelocityTracker;
import android.view.ViewConfiguration;
import androidx.annotation.Nullable;
@@ -55,6 +57,9 @@
public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
private static final int HOVER_TASKBAR_UNSTASH_TIMEOUT = 500;
+
+ private static final int NUM_MOTION_MOVE_THRESHOLD = 3;
+
private static final Handler sUnstashHandler = new Handler(Looper.getMainLooper());
private final TaskbarActivityContext mTaskbarActivityContext;
@@ -83,6 +88,11 @@
private final @Nullable TransitionCallback mTransitionCallback;
private final GestureState mGestureState;
+ private VelocityTracker mVelocityTracker;
+ private boolean mCanPlayTaskbarBgAlphaAnimation = true;
+ private int mMotionMoveCount = 0;
+ // Velocity defined as dp per s
+ private float mTaskbarSlowVelocityYThreshold;
public TaskbarUnstashInputConsumer(Context context, InputConsumer delegate,
InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext,
@@ -101,6 +111,8 @@
mIsTaskbarAllAppsOpen = mTaskbarActivityContext.isTaskbarAllAppsOpen();
mIsTransientTaskbar = DisplayController.isTransientTaskbar(context);
+ mTaskbarSlowVelocityYThreshold =
+ res.getDimensionPixelSize(R.dimen.taskbar_slow_velocity_y_threshold);
mBottomScreenEdge = res.getDimensionPixelSize(
R.dimen.taskbar_stashed_screen_edge_hover_deadzone_height);
@@ -125,6 +137,9 @@
@Override
public void onMotionEvent(MotionEvent ev) {
+ if (enableScalingRevealHomeAnimation() && mIsTransientTaskbar) {
+ checkVelocityForTaskbarBackground(ev);
+ }
if (mState != STATE_ACTIVE) {
boolean isStashedTaskbarHovered = isMouseEvent(ev)
&& isStashedTaskbarHovered((int) ev.getX(), (int) ev.getY());
@@ -254,6 +269,31 @@
}
}
+ private void checkVelocityForTaskbarBackground(MotionEvent ev) {
+ int actionMasked = ev.getActionMasked();
+ if (actionMasked == MotionEvent.ACTION_DOWN && mVelocityTracker != null) {
+ mVelocityTracker.clear();
+ }
+ if (mVelocityTracker == null) {
+ mVelocityTracker = VelocityTracker.obtain();
+ }
+ mVelocityTracker.addMovement(ev);
+
+ mVelocityTracker.computeCurrentVelocity(1000);
+ if (ev.getAction() == ACTION_MOVE) {
+ mMotionMoveCount++;
+ }
+
+ float velocityYPxPerS = mVelocityTracker.getYVelocity();
+ if (mCanPlayTaskbarBgAlphaAnimation
+ && mMotionMoveCount >= NUM_MOTION_MOVE_THRESHOLD // Arbitrary value
+ && velocityYPxPerS != 0 // Ignore these
+ && velocityYPxPerS >= mTaskbarSlowVelocityYThreshold) {
+ mTaskbarActivityContext.playTaskbarBackgroundAlphaAnimation();
+ mCanPlayTaskbarBgAlphaAnimation = false;
+ }
+ }
+
private void cleanupAfterMotionEvent() {
mTaskbarActivityContext.setAutohideSuspendFlag(
FLAG_AUTOHIDE_SUSPEND_TOUCHING, false);
@@ -264,6 +304,13 @@
mIsInBubbleBarArea = false;
mIsVerticalGestureOverBubbleBar = false;
mIsPassedBubbleBarSlop = false;
+
+ if (mVelocityTracker != null) {
+ mVelocityTracker.recycle();
+ }
+ mVelocityTracker = null;
+ mCanPlayTaskbarBgAlphaAnimation = true;
+ mMotionMoveCount = 0;
}
private boolean isInBubbleBarArea(float x) {
diff --git a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
index f8d695c..5ac04da 100644
--- a/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
+++ b/quickstep/src/com/android/quickstep/logging/SettingsChangeLogger.java
@@ -148,7 +148,7 @@
@Override
public void onDisplayInfoChanged(Context context, Info info, int flags) {
if ((flags & CHANGE_NAVIGATION_MODE) != 0) {
- mNavMode = info.navigationMode;
+ mNavMode = info.getNavigationMode();
mStatsLogManager.logger().log(mNavMode.launcherEvent);
}
}
diff --git a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
index 8f8cc6e..ec04cb7 100644
--- a/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/LandscapePagedViewHandler.kt
@@ -121,6 +121,10 @@
override fun getEnd(rect: RectF): Float = rect.bottom
+ override fun rotateInsets(insets: Rect, outInsets: Rect) {
+ outInsets.set(insets.bottom, insets.left, insets.top, insets.right)
+ }
+
override fun getClearAllSidePadding(view: View, isRtl: Boolean): Int =
if (isRtl) view.paddingBottom / 2 else -view.paddingTop / 2
diff --git a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
index f6284d5..758a737 100644
--- a/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
+++ b/quickstep/src/com/android/quickstep/orientation/PortraitPagedViewHandler.java
@@ -130,6 +130,11 @@
}
@Override
+ public void rotateInsets(@NonNull Rect insets, @NonNull Rect outInsets) {
+ outInsets.set(insets);
+ }
+
+ @Override
public int getClearAllSidePadding(View view, boolean isRtl) {
return (isRtl ? view.getPaddingRight() : - view.getPaddingLeft()) / 2;
}
diff --git a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
index 5bc1be8..df4b030 100644
--- a/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/RecentsPagedOrientationHandler.kt
@@ -70,6 +70,9 @@
fun getEnd(rect: RectF): Float
+ /** Rotate the provided insets to portrait perspective. */
+ fun rotateInsets(insets: Rect, outInsets: Rect)
+
fun getClearAllSidePadding(view: View, isRtl: Boolean): Int
fun getSecondaryDimension(view: View): Int
diff --git a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
index 46e4b0c..333359f 100644
--- a/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
+++ b/quickstep/src/com/android/quickstep/orientation/SeascapePagedViewHandler.kt
@@ -44,6 +44,10 @@
import com.android.quickstep.views.IconAppChipView
class SeascapePagedViewHandler : LandscapePagedViewHandler() {
+ override fun rotateInsets(insets: Rect, outInsets: Rect) {
+ outInsets.set(insets.top, insets.right, insets.bottom, insets.left)
+ }
+
override val secondaryTranslationDirectionFactor: Int = -1
override fun getSplitTranslationDirectionFactor(
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksDataSource.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksDataSource.kt
new file mode 100644
index 0000000..6719099
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksDataSource.kt
@@ -0,0 +1,24 @@
+/*
+ * 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 com.android.quickstep.util.GroupTask
+import java.util.function.Consumer
+
+interface RecentTasksDataSource {
+ fun getTasks(callback: Consumer<List<GroupTask>>?): Int
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
new file mode 100644
index 0000000..c1eef0b
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/RecentTasksRepository.kt
@@ -0,0 +1,37 @@
+/*
+ * 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 com.android.systemui.shared.recents.model.Task
+import kotlinx.coroutines.flow.Flow
+
+interface RecentTasksRepository {
+ /** Gets all the recent tasks, refreshing from data sources if [forceRefresh] is true. */
+ fun getAllTaskData(forceRefresh: Boolean = false): Flow<List<Task>>
+
+ /**
+ * Gets the data associated with a task that has id [taskId]. Flow will settle on null if the
+ * task was not found.
+ */
+ fun getTaskDataById(taskId: Int): Flow<Task?>
+
+ /**
+ * Sets the tasks that are visible, indicating that properties relating to visuals need to be
+ * populated e.g. icons/thumbnails etc.
+ */
+ fun setVisibleTasks(visibleTaskIdList: List<Int>)
+}
diff --git a/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
new file mode 100644
index 0000000..b21a1b4
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/recents/data/TasksRepository.kt
@@ -0,0 +1,114 @@
+/*
+ * 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 com.android.quickstep.TaskIconCache
+import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource
+import com.android.quickstep.util.GroupTask
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import kotlin.coroutines.resume
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.suspendCancellableCoroutine
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class TasksRepository(
+ private val recentsModel: RecentTasksDataSource,
+ private val taskThumbnailDataSource: TaskThumbnailDataSource,
+ private val taskIconCache: TaskIconCache,
+) : RecentTasksRepository {
+ private val groupedTaskData = MutableStateFlow(emptyList<GroupTask>())
+ private val _taskData =
+ groupedTaskData.map { groupTaskList -> groupTaskList.flatMap { it.tasks } }
+ private val visibleTaskIds = MutableStateFlow(emptySet<Int>())
+
+ private val taskData: Flow<List<Task>> =
+ combine(_taskData, getThumbnailQueryResults()) { tasks, results ->
+ tasks.forEach { task ->
+ // Add retrieved thumbnails + remove unnecessary thumbnails
+ task.thumbnail = results[task.key.id]
+ }
+ tasks
+ }
+
+ override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> {
+ if (forceRefresh) {
+ recentsModel.getTasks { groupedTaskData.value = it }
+ }
+ return taskData
+ }
+
+ override fun getTaskDataById(taskId: Int): Flow<Task?> =
+ taskData.map { taskList -> taskList.firstOrNull { it.key.id == taskId } }
+
+ override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
+ this.visibleTaskIds.value = visibleTaskIdList.toSet()
+ }
+
+ /** Flow wrapper for [TaskThumbnailDataSource.updateThumbnailInBackground] api */
+ private fun getThumbnailDataRequest(task: Task): ThumbnailDataRequest =
+ flow {
+ emit(task.key.id to task.thumbnail)
+ val thumbnailDataResult: ThumbnailData? =
+ suspendCancellableCoroutine { continuation ->
+ val cancellableTask =
+ taskThumbnailDataSource.updateThumbnailInBackground(task) {
+ continuation.resume(it)
+ }
+ continuation.invokeOnCancellation { cancellableTask?.cancel() }
+ }
+ emit(task.key.id to thumbnailDataResult)
+ }
+ .distinctUntilChanged()
+
+ /**
+ * This is a Flow that makes a query for thumbnail data to the [taskThumbnailDataSource] for
+ * each visible task. It then collects the responses and returns them in a Map as soon as they
+ * are available.
+ */
+ private fun getThumbnailQueryResults(): Flow<Map<Int, ThumbnailData?>> {
+ val visibleTasks =
+ combine(_taskData, visibleTaskIds) { tasks, visibleIds ->
+ tasks.filter { it.key.id in visibleIds }
+ }
+ val visibleThumbnailDataRequests: Flow<List<ThumbnailDataRequest>> =
+ visibleTasks.map {
+ it.map { visibleTask ->
+ val taskCopy = Task(visibleTask).apply { thumbnail = visibleTask.thumbnail }
+ getThumbnailDataRequest(taskCopy)
+ }
+ }
+ return visibleThumbnailDataRequests.flatMapLatest {
+ thumbnailRequestFlows: List<ThumbnailDataRequest> ->
+ if (thumbnailRequestFlows.isEmpty()) {
+ flowOf(emptyMap())
+ } else {
+ combine(thumbnailRequestFlows) { it.toMap() }
+ }
+ }
+ }
+}
+
+typealias ThumbnailDataRequest = Flow<Pair<Int, ThumbnailData?>>
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
index 0843ae3..40f9b28 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailUiState.kt
@@ -16,11 +16,19 @@
package com.android.quickstep.task.thumbnail
-import com.android.systemui.shared.recents.model.Task
+import android.graphics.Bitmap
+import android.graphics.Rect
+import androidx.annotation.ColorInt
sealed class TaskThumbnailUiState {
data object Uninitialized : TaskThumbnailUiState()
data object LiveTile : TaskThumbnailUiState()
+ data class BackgroundOnly(@ColorInt val backgroundColor: Int) : TaskThumbnailUiState()
+ data class Snapshot(
+ val bitmap: Bitmap,
+ val drawnRect: Rect,
+ @ColorInt val backgroundColor: Int
+ ) : TaskThumbnailUiState()
}
-data class TaskThumbnail(val task: Task, val isRunning: Boolean)
+data class TaskThumbnail(val taskId: Int, val isRunning: Boolean)
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
index 8762976..2836c89 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailView.kt
@@ -19,15 +19,20 @@
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 androidx.annotation.ColorInt
import com.android.launcher3.Utilities
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.util.TaskCornerRadius
import com.android.quickstep.views.RecentsView
@@ -42,17 +47,26 @@
// to [TaskView], and also shared between [TaskView] and [TaskThumbnailView]
// This is using a lazy for now because the dependencies cannot be obtained without DI.
val viewModel by lazy {
- TaskThumbnailViewModel(
+ val recentsView =
RecentsViewContainer.containerFromContext<RecentsViewContainer>(context)
.getOverviewPanel<RecentsView<*, *>>()
- .mRecentsViewData,
- (parent as TaskView).taskViewData
+ TaskThumbnailViewModel(
+ recentsView.mRecentsViewData,
+ (parent as TaskView).taskViewData,
+ recentsView.mTasksRepository,
)
}
private var uiState: TaskThumbnailUiState = Uninitialized
private var inheritedScale: Float = 1f
+ private val backgroundPaint = Paint(Paint.ANTI_ALIAS_FLAG)
+ private val _measuredBounds = Rect()
+ private val measuredBounds: Rect
+ get() {
+ _measuredBounds.set(0, 0, measuredWidth, measuredHeight)
+ return _measuredBounds
+ }
private var cornerRadius: Float = TaskCornerRadius.get(context)
private var fullscreenCornerRadius: Float = QuickStepContract.getWindowCornerRadius(context)
@@ -85,24 +99,25 @@
outlineProvider =
object : ViewOutlineProvider() {
override fun getOutline(view: View, outline: Outline) {
- outline.setRoundRect(
- 0,
- 0,
- view.measuredWidth,
- view.measuredHeight,
- getCurrentCornerRadius()
- )
+ outline.setRoundRect(measuredBounds, getCurrentCornerRadius())
}
}
}
override fun onDraw(canvas: Canvas) {
- when (uiState) {
- is Uninitialized -> {}
+ 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)
}
}
+ private fun drawBackgroundOnly(canvas: Canvas, @ColorInt backgroundColor: Int) {
+ backgroundPaint.color = backgroundColor
+ canvas.drawRect(measuredBounds, backgroundPaint)
+ }
+
override fun onConfigurationChanged(newConfig: Configuration?) {
super.onConfigurationChanged(newConfig)
@@ -112,7 +127,12 @@
}
private fun drawTransparentUiState(canvas: Canvas) {
- canvas.drawRect(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat(), CLEAR_PAINT)
+ canvas.drawRect(measuredBounds, CLEAR_PAINT)
+ }
+
+ private fun drawSnapshotState(canvas: Canvas, snapshot: Snapshot) {
+ drawBackgroundOnly(canvas, snapshot.backgroundColor)
+ canvas.drawBitmap(snapshot.bitmap, snapshot.drawnRect, measuredBounds, null)
}
private fun getCurrentCornerRadius() =
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
index 71bc865..4511ea7 100644
--- a/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModel.kt
@@ -16,32 +16,76 @@
package com.android.quickstep.task.thumbnail
+import android.annotation.ColorInt
+import android.graphics.Rect
+import androidx.core.graphics.ColorUtils
+import com.android.quickstep.recents.data.RecentTasksRepository
import com.android.quickstep.recents.viewmodel.RecentsViewData
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.task.viewmodel.TaskViewData
+import com.android.systemui.shared.recents.model.Task
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
-class TaskThumbnailViewModel(recentsViewData: RecentsViewData, taskViewData: TaskViewData) {
- private val task = MutableStateFlow<TaskThumbnail?>(null)
+@OptIn(ExperimentalCoroutinesApi::class)
+class TaskThumbnailViewModel(
+ recentsViewData: RecentsViewData,
+ taskViewData: TaskViewData,
+ private val tasksRepository: RecentTasksRepository,
+) {
+ private val task = MutableStateFlow<Flow<Task?>>(flowOf(null))
+ private var boundTaskIsRunning = false
val recentsFullscreenProgress = recentsViewData.fullscreenProgress
val inheritedScale =
combine(recentsViewData.scale, taskViewData.scale) { recentsScale, taskScale ->
recentsScale * taskScale
}
- val uiState =
- task.map { taskVal ->
- when {
- taskVal == null -> Uninitialized
- taskVal.isRunning -> LiveTile
- else -> Uninitialized
+ val uiState: Flow<TaskThumbnailUiState> =
+ task
+ .flatMapLatest { taskFlow ->
+ taskFlow.map { taskVal ->
+ when {
+ taskVal == null -> Uninitialized
+ boundTaskIsRunning -> LiveTile
+ isBackgroundOnly(taskVal) ->
+ BackgroundOnly(taskVal.colorBackground.removeAlpha())
+ isSnapshotState(taskVal) -> {
+ val bitmap = taskVal.thumbnail?.thumbnail!!
+ Snapshot(
+ bitmap,
+ Rect(0, 0, bitmap.width, bitmap.height),
+ taskVal.colorBackground.removeAlpha()
+ )
+ }
+ else -> Uninitialized
+ }
+ }
}
- }
+ .distinctUntilChanged()
- fun bind(task: TaskThumbnail) {
- this.task.value = task
+ fun bind(taskThumbnail: TaskThumbnail) {
+ boundTaskIsRunning = taskThumbnail.isRunning
+ task.value = tasksRepository.getTaskDataById(taskThumbnail.taskId)
}
+
+ private fun isBackgroundOnly(task: Task): Boolean = task.isLocked || task.thumbnail == null
+
+ private fun isSnapshotState(task: Task): Boolean {
+ val thumbnailPresent = task.thumbnail?.thumbnail != null
+ val taskLocked = task.isLocked
+
+ return thumbnailPresent && !taskLocked
+ }
+
+ @ColorInt private fun Int.removeAlpha(): Int = ColorUtils.setAlphaComponent(this, 0xff)
}
diff --git a/quickstep/src/com/android/quickstep/task/thumbnail/data/TaskThumbnailDataSource.kt b/quickstep/src/com/android/quickstep/task/thumbnail/data/TaskThumbnailDataSource.kt
new file mode 100644
index 0000000..55598f0
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/task/thumbnail/data/TaskThumbnailDataSource.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.task.thumbnail.data
+
+import com.android.launcher3.util.CancellableTask
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import java.util.function.Consumer
+
+interface TaskThumbnailDataSource {
+ fun updateThumbnailInBackground(
+ task: Task,
+ callback: Consumer<ThumbnailData>
+ ): CancellableTask<ThumbnailData>?
+}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index e4e2eb2..6f9cbfd 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -27,6 +27,8 @@
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_50_50;
+import static com.android.wm.shell.common.split.SplitScreenConstants.SNAP_TO_NONE;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.common.split.SplitScreenConstants.isPersistentSnapPosition;
@@ -186,6 +188,10 @@
}
@PersistentSnapPosition int snapPosition = gtv.getSnapPosition();
+ if (snapPosition == SNAP_TO_NONE) {
+ // Free snap mode is enabled, just save it as 50/50 split.
+ snapPosition = SNAP_TO_50_50;
+ }
if (!isPersistentSnapPosition(snapPosition)) {
// If we received an illegal snap position, log an error and do not create the app pair
Log.wtf(TAG, "Tried to save an app pair with illegal snapPosition "
diff --git a/quickstep/src/com/android/quickstep/util/DesktopTask.java b/quickstep/src/com/android/quickstep/util/DesktopTask.java
index 07f2d68..8d99069 100644
--- a/quickstep/src/com/android/quickstep/util/DesktopTask.java
+++ b/quickstep/src/com/android/quickstep/util/DesktopTask.java
@@ -21,7 +21,7 @@
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
-import java.util.ArrayList;
+import java.util.List;
/**
* A {@link Task} container that can contain N number of tasks that are part of the desktop in
@@ -30,9 +30,9 @@
public class DesktopTask extends GroupTask {
@NonNull
- public final ArrayList<Task> tasks;
+ public final List<Task> tasks;
- public DesktopTask(@NonNull ArrayList<Task> tasks) {
+ public DesktopTask(@NonNull List<Task> tasks) {
super(tasks.get(0), null, null, TaskView.Type.DESKTOP);
this.tasks = tasks;
}
@@ -53,6 +53,12 @@
}
@Override
+ @NonNull
+ public List<Task> getTasks() {
+ return tasks;
+ }
+
+ @Override
public DesktopTask copy() {
return new DesktopTask(tasks);
}
diff --git a/quickstep/src/com/android/quickstep/util/GroupTask.java b/quickstep/src/com/android/quickstep/util/GroupTask.java
index 7dd6afc..945ffe3 100644
--- a/quickstep/src/com/android/quickstep/util/GroupTask.java
+++ b/quickstep/src/com/android/quickstep/util/GroupTask.java
@@ -23,6 +23,10 @@
import com.android.quickstep.views.TaskView;
import com.android.systemui.shared.recents.model.Task;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
/**
* A {@link Task} container that can contain one or two tasks, depending on if the two tasks
* are represented as an app-pair in the recents task list.
@@ -62,6 +66,17 @@
}
/**
+ * Returns a List of all the Tasks in this GroupTask
+ */
+ public List<Task> getTasks() {
+ if (task2 == null) {
+ return Collections.singletonList(task1);
+ } else {
+ return Arrays.asList(task1, task2);
+ }
+ }
+
+ /**
* Create a copy of this instance
*/
public GroupTask copy() {
diff --git a/quickstep/src/com/android/quickstep/util/NavBarPosition.java b/quickstep/src/com/android/quickstep/util/NavBarPosition.java
deleted file mode 100644
index 9418512..0000000
--- a/quickstep/src/com/android/quickstep/util/NavBarPosition.java
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep.util;
-
-import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
-
-import android.view.Surface;
-
-import com.android.launcher3.util.DisplayController.Info;
-import com.android.launcher3.util.NavigationMode;
-
-/**
- * Utility class to check nav bar position.
- */
-public class NavBarPosition {
-
- private final boolean mIsTablet;
- private final NavigationMode mMode;
- private final int mDisplayRotation;
-
- public NavBarPosition(NavigationMode mode, Info info) {
- mIsTablet = info.isTablet(info.realBounds);
- mMode = mode;
- mDisplayRotation = info.rotation;
- }
-
- public boolean isRightEdge() {
- return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_90 && !mIsTablet;
- }
-
- public boolean isLeftEdge() {
- return mMode != NO_BUTTON && mDisplayRotation == Surface.ROTATION_270 && !mIsTablet;
- }
-
- public float getRotation() {
- return isLeftEdge() ? 90 : (isRightEdge() ? -90 : 0);
- }
-}
diff --git a/quickstep/src/com/android/quickstep/util/NavBarPosition.kt b/quickstep/src/com/android/quickstep/util/NavBarPosition.kt
new file mode 100644
index 0000000..43cf540
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/NavBarPosition.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util
+
+import android.view.Surface
+import com.android.launcher3.util.DisplayController.Info
+import com.android.launcher3.util.NavigationMode
+import com.android.launcher3.util.NavigationMode.NO_BUTTON
+
+/** Utility class to check nav bar position. */
+data class NavBarPosition(
+ val isTablet: Boolean,
+ val displayRotation: Int,
+ val mode: NavigationMode
+) {
+ constructor(
+ mode: NavigationMode,
+ info: Info
+ ) : this(info.isTablet(info.realBounds), info.rotation, mode)
+
+ val isRightEdge: Boolean
+ get() = mode != NO_BUTTON && displayRotation == Surface.ROTATION_90 && !isTablet
+ val isLeftEdge: Boolean
+ get() = mode != NO_BUTTON && displayRotation == Surface.ROTATION_270 && !isTablet
+
+ val rotation: Float
+ get() = if (isLeftEdge) 90f else if (isRightEdge) -90f else 0f
+}
diff --git a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
index 769ccc0..00b4011 100644
--- a/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
+++ b/quickstep/src/com/android/quickstep/util/RectFSpringAnim.java
@@ -157,6 +157,10 @@
mCurrentY = getTrackedYFromRect(mStartRect);
}
+ public RectF getTargetRect() {
+ return mTargetRect;
+ }
+
private float getTrackedYFromRect(RectF rect) {
switch (mTracking) {
case TRACKING_TOP:
diff --git a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
index 4513fa2..f547a7fb 100644
--- a/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
+++ b/quickstep/src/com/android/quickstep/util/ScalingWorkspaceRevealAnim.kt
@@ -16,6 +16,7 @@
package com.android.quickstep.util
+import android.animation.AnimatorSet
import android.graphics.Matrix
import android.graphics.Path
import android.graphics.RectF
@@ -187,7 +188,11 @@
)
}
+ fun getAnimators(): AnimatorSet {
+ return animation.buildAnim()
+ }
+
fun start() {
- animation.buildAnim().start()
+ getAnimators().start()
}
}
diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
index 99f10a7..2d606f3 100644
--- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
+++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java
@@ -154,8 +154,23 @@
}
if (sourceRectHint.isEmpty()) {
- mSourceRectHint.setEmpty();
- mSourceHintRectInsets = null;
+ // Crop a Rect matches the aspect ratio and pivots at the center point.
+ // To make the animation path simplified.
+ final float aspectRatio = destinationBounds.width()
+ / (float) destinationBounds.height();
+ if ((appBounds.width() / (float) appBounds.height()) > aspectRatio) {
+ // use the full height.
+ mSourceRectHint.set(0, 0,
+ (int) (appBounds.height() * aspectRatio), appBounds.height());
+ mSourceRectHint.offset(
+ (appBounds.width() - mSourceRectHint.width()) / 2, 0);
+ } else {
+ // use the full width.
+ mSourceRectHint.set(0, 0,
+ appBounds.width(), (int) (appBounds.width() / aspectRatio));
+ mSourceRectHint.offset(
+ 0, (appBounds.height() - mSourceRectHint.height()) / 2);
+ }
// Create a new overlay layer. We do not call detach on this instance, it's propagated
// to other classes like PipTaskOrganizer / RecentsAnimationController to complete
@@ -168,11 +183,11 @@
Log.d(TAG, getContentOverlay() + " is created: " + reasonForCreateOverlay);
} else {
mSourceRectHint.set(sourceRectHint);
- mSourceHintRectInsets = new Rect(sourceRectHint.left - appBounds.left,
- sourceRectHint.top - appBounds.top,
- appBounds.right - sourceRectHint.right,
- appBounds.bottom - sourceRectHint.bottom);
}
+ mSourceHintRectInsets = new Rect(mSourceRectHint.left - appBounds.left,
+ mSourceRectHint.top - appBounds.top,
+ appBounds.right - mSourceRectHint.right,
+ appBounds.bottom - mSourceRectHint.bottom);
addAnimatorListener(new AnimationSuccessListener() {
@Override
@@ -217,27 +232,7 @@
if (mPipContentOverlay != null) {
mPipContentOverlay.onAnimationUpdate(tx, mCurrentBounds, progress);
}
- final PictureInPictureSurfaceTransaction op;
- if (mSourceHintRectInsets == null) {
- // no source rect hint been set, directly scale the window down
- op = onAnimationScale(progress, tx, mCurrentBounds);
- } else {
- // scale and crop according to the source rect hint
- op = onAnimationScaleAndCrop(progress, tx, mCurrentBounds);
- }
- return op;
- }
-
- /** scale the window directly with no source rect hint being set */
- private PictureInPictureSurfaceTransaction onAnimationScale(
- float progress, SurfaceControl.Transaction tx, Rect bounds) {
- if (mFromRotation == Surface.ROTATION_90 || mFromRotation == Surface.ROTATION_270) {
- final RotatedPosition rotatedPosition = getRotatedPosition(progress);
- return mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds,
- rotatedPosition.degree, rotatedPosition.positionX, rotatedPosition.positionY);
- } else {
- return mSurfaceTransactionHelper.scale(tx, mLeash, mAppBounds, bounds);
- }
+ return onAnimationScaleAndCrop(progress, tx, mCurrentBounds);
}
/** scale and crop the window with source rect hint */
@@ -272,6 +267,10 @@
return mAppBounds;
}
+ public Rect getSourceRectHint() {
+ return mSourceRectHint;
+ }
+
@Nullable
public SurfaceControl getContentOverlay() {
return mPipContentOverlay == null ? null : mPipContentOverlay.getLeash();
diff --git a/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt b/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt
new file mode 100644
index 0000000..5f4388c
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/util/SystemUiFlagUtils.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.quickstep.util
+
+import com.android.systemui.shared.system.QuickStepContract
+import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags
+
+/** Util class for holding and checking [SystemUiStateFlags] masks. */
+object SystemUiFlagUtils {
+ const val KEYGUARD_SYSUI_FLAGS =
+ (QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING or
+ QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING or
+ QuickStepContract.SYSUI_STATE_DEVICE_DOZING or
+ QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED or
+ QuickStepContract.SYSUI_STATE_HOME_DISABLED or
+ QuickStepContract.SYSUI_STATE_BACK_DISABLED or
+ QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED or
+ QuickStepContract.SYSUI_STATE_WAKEFULNESS_MASK)
+
+ // If any of these SysUi flags (via QuickstepContract) is set, the device to be considered
+ // locked.
+ private const val MASK_ANY_SYSUI_LOCKED =
+ (QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING or
+ QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING or
+ QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING_OCCLUDED or
+ QuickStepContract.SYSUI_STATE_DEVICE_DREAMING)
+
+ /**
+ * Returns true iff the given [SystemUiStateFlags] imply that the device is considered locked.
+ */
+ @JvmStatic
+ fun isLocked(@SystemUiStateFlags flags: Long): Boolean {
+ return hasAnyFlag(flags, MASK_ANY_SYSUI_LOCKED) &&
+ !hasAnyFlag(flags, QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_GOING_AWAY)
+ }
+
+ private fun hasAnyFlag(@SystemUiStateFlags flags: Long, flagMask: Long): Boolean {
+ return (flags and flagMask) != 0L
+ }
+}
diff --git a/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java b/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
index c63a58e..671b2ea 100644
--- a/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
+++ b/quickstep/src/com/android/quickstep/util/TriggerSwipeUpTouchTracker.java
@@ -99,6 +99,7 @@
if (mDisableHorizontalSwipe
&& Math.abs(displacementX) > Math.abs(displacementY)) {
// Horizontal gesture is not allowed in this region
+ mOnSwipeUp.onSwipeUpCancelled();
endTouchTracking();
break;
}
@@ -111,6 +112,7 @@
}
case ACTION_CANCEL:
+ mOnSwipeUp.onSwipeUpCancelled();
endTouchTracking();
break;
diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
index a8ebe51..4a5b9e4 100644
--- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
+++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java
@@ -23,6 +23,7 @@
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
+import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherApps;
import android.content.pm.LauncherApps.AppUsageLimit;
@@ -38,6 +39,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewOutlineProvider;
+import android.view.accessibility.AccessibilityNodeInfo;
import android.widget.FrameLayout;
import android.widget.TextView;
@@ -49,6 +51,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
import com.android.launcher3.util.SplitConfigurationOptions.SplitBounds;
+import com.android.quickstep.TaskUtils;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
import com.android.systemui.shared.recents.model.Task;
@@ -68,13 +71,15 @@
private static final int SPLIT_GRID_BANNER_LARGE = 1;
/** Used for grid task view, only showing icon */
private static final int SPLIT_GRID_BANNER_SMALL = 2;
+
@IntDef(value = {
SPLIT_BANNER_FULLSCREEN,
SPLIT_GRID_BANNER_LARGE,
SPLIT_GRID_BANNER_SMALL,
})
@Retention(RetentionPolicy.SOURCE)
- @interface SPLIT_BANNER_CONFIG{}
+ @interface SplitBannerConfig {
+ }
static final Intent OPEN_APP_USAGE_SETTINGS_TEMPLATE = new Intent(ACTION_APP_USAGE_SETTINGS);
static final int MINUTE_MS = 60000;
@@ -85,10 +90,11 @@
private final TaskView mTaskView;
private final LauncherApps mLauncherApps;
+ private final int mBannerHeight;
+
private Task mTask;
private boolean mHasLimit;
- private long mAppUsageLimitTimeMs;
private long mAppRemainingTimeMs;
@Nullable
private View mBanner;
@@ -96,26 +102,27 @@
private float mBannerOffsetPercentage;
@Nullable
private SplitBounds mSplitBounds;
- private int mSplitBannerConfig = SPLIT_BANNER_FULLSCREEN;
private float mSplitOffsetTranslationY;
private float mSplitOffsetTranslationX;
+ private boolean mIsDestroyed = false;
+
public DigitalWellBeingToast(RecentsViewContainer container, TaskView taskView) {
mContainer = container;
mTaskView = taskView;
mLauncherApps = container.asContext().getSystemService(LauncherApps.class);
+ mBannerHeight = container.asContext().getResources().getDimensionPixelSize(
+ R.dimen.digital_wellbeing_toast_height);
}
private void setNoLimit() {
mHasLimit = false;
mTaskView.setContentDescription(mTask.titleDescription);
replaceBanner(null);
- mAppUsageLimitTimeMs = -1;
mAppRemainingTimeMs = -1;
}
private void setLimit(long appUsageLimitTimeMs, long appRemainingTimeMs) {
- mAppUsageLimitTimeMs = appUsageLimitTimeMs;
mAppRemainingTimeMs = appRemainingTimeMs;
mHasLimit = true;
TextView toast = mContainer.getViewCache().getView(R.layout.digital_wellbeing_toast,
@@ -138,89 +145,95 @@
}
public void initialize(Task task) {
- mAppUsageLimitTimeMs = mAppRemainingTimeMs = -1;
+ if (mIsDestroyed) {
+ throw new IllegalStateException("Cannot re-initialize a destroyed toast");
+ }
mTask = task;
ORDERED_BG_EXECUTOR.execute(() -> {
- AppUsageLimit usageLimit = null;
- try {
- usageLimit = mLauncherApps.getAppUsageLimit(
- mTask.getTopComponent().getPackageName(),
- UserHandle.of(mTask.key.userId));
- } catch (Exception e) {
- Log.e(TAG, "Error initializing digital well being toast", e);
- }
- final long appUsageLimitTimeMs =
- usageLimit != null ? usageLimit.getTotalUsageLimit() : -1;
- final long appRemainingTimeMs =
- usageLimit != null ? usageLimit.getUsageRemaining() : -1;
+ AppUsageLimit usageLimit = null;
+ try {
+ usageLimit = mLauncherApps.getAppUsageLimit(
+ mTask.getTopComponent().getPackageName(),
+ UserHandle.of(mTask.key.userId));
+ } catch (Exception e) {
+ Log.e(TAG, "Error initializing digital well being toast", e);
+ }
+ final long appUsageLimitTimeMs =
+ usageLimit != null ? usageLimit.getTotalUsageLimit() : -1;
+ final long appRemainingTimeMs =
+ usageLimit != null ? usageLimit.getUsageRemaining() : -1;
- mTaskView.post(() -> {
- if (appUsageLimitTimeMs < 0 || appRemainingTimeMs < 0) {
- setNoLimit();
- } else {
- setLimit(appUsageLimitTimeMs, appRemainingTimeMs);
- }
- });
-
+ mTaskView.post(() -> {
+ if (mIsDestroyed) {
+ return;
}
- );
+ if (appUsageLimitTimeMs < 0 || appRemainingTimeMs < 0) {
+ setNoLimit();
+ } else {
+ setLimit(appUsageLimitTimeMs, appRemainingTimeMs);
+ }
+ });
+ });
}
- public void setSplitConfiguration(SplitBounds splitBounds) {
+ /**
+ * Mark the DWB toast as destroyed and remove banner from TaskView.
+ */
+ public void destroy() {
+ mIsDestroyed = true;
+ mTaskView.post(() -> replaceBanner(null));
+ }
+
+ public void setSplitBounds(@Nullable SplitBounds splitBounds) {
mSplitBounds = splitBounds;
+ }
+
+ private @SplitBannerConfig int getSplitBannerConfig() {
if (mSplitBounds == null
|| !mContainer.getDeviceProfile().isTablet
|| mTaskView.isFocusedTask()) {
- mSplitBannerConfig = SPLIT_BANNER_FULLSCREEN;
- return;
+ return SPLIT_BANNER_FULLSCREEN;
}
// For portrait grid only height of task changes, not width. So we keep the text the same
if (!mContainer.getDeviceProfile().isLeftRightSplit) {
- mSplitBannerConfig = SPLIT_GRID_BANNER_LARGE;
- return;
+ return SPLIT_GRID_BANNER_LARGE;
}
// For landscape grid, for 30% width we only show icon, otherwise show icon and time
if (mTask.key.id == mSplitBounds.leftTopTaskId) {
- mSplitBannerConfig = mSplitBounds.leftTaskPercent < THRESHOLD_LEFT_ICON_ONLY ?
- SPLIT_GRID_BANNER_SMALL : SPLIT_GRID_BANNER_LARGE;
+ return mSplitBounds.leftTaskPercent < THRESHOLD_LEFT_ICON_ONLY
+ ? SPLIT_GRID_BANNER_SMALL : SPLIT_GRID_BANNER_LARGE;
} else {
- mSplitBannerConfig = mSplitBounds.leftTaskPercent > THRESHOLD_RIGHT_ICON_ONLY ?
- SPLIT_GRID_BANNER_SMALL : SPLIT_GRID_BANNER_LARGE;
+ return mSplitBounds.leftTaskPercent > THRESHOLD_RIGHT_ICON_ONLY
+ ? SPLIT_GRID_BANNER_SMALL : SPLIT_GRID_BANNER_LARGE;
}
}
private String getReadableDuration(
Duration duration,
- FormatWidth formatWidthHourAndMinute,
- @StringRes int durationLessThanOneMinuteStringId,
- boolean forceFormatWidth) {
+ @StringRes int durationLessThanOneMinuteStringId) {
int hours = Math.toIntExact(duration.toHours());
int minutes = Math.toIntExact(duration.minusHours(hours).toMinutes());
- // Apply formatWidthHourAndMinute if both the hour part and the minute part are non-zero.
+ // Apply FormatWidth.WIDE if both the hour part and the minute part are non-zero.
if (hours > 0 && minutes > 0) {
- return MeasureFormat.getInstance(Locale.getDefault(), formatWidthHourAndMinute)
+ return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.NARROW)
.formatMeasures(
new Measure(hours, MeasureUnit.HOUR),
new Measure(minutes, MeasureUnit.MINUTE));
}
- // Apply formatWidthHourOrMinute if only the hour part is non-zero (unless forced).
+ // Apply FormatWidth.WIDE if only the hour part is non-zero (unless forced).
if (hours > 0) {
- return MeasureFormat.getInstance(
- Locale.getDefault(),
- forceFormatWidth ? formatWidthHourAndMinute : FormatWidth.WIDE)
- .formatMeasures(new Measure(hours, MeasureUnit.HOUR));
+ return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.WIDE).formatMeasures(
+ new Measure(hours, MeasureUnit.HOUR));
}
- // Apply formatWidthHourOrMinute if only the minute part is non-zero (unless forced).
+ // Apply FormatWidth.WIDE if only the minute part is non-zero (unless forced).
if (minutes > 0) {
- return MeasureFormat.getInstance(
- Locale.getDefault()
- , forceFormatWidth ? formatWidthHourAndMinute : FormatWidth.WIDE)
- .formatMeasures(new Measure(minutes, MeasureUnit.MINUTE));
+ return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.WIDE).formatMeasures(
+ new Measure(minutes, MeasureUnit.MINUTE));
}
// Use a specific string for usage less than one minute but non-zero.
@@ -229,13 +242,12 @@
}
// Otherwise, return 0-minute string.
- return MeasureFormat.getInstance(
- Locale.getDefault(), forceFormatWidth ? formatWidthHourAndMinute : FormatWidth.WIDE)
- .formatMeasures(new Measure(0, MeasureUnit.MINUTE));
+ return MeasureFormat.getInstance(Locale.getDefault(), FormatWidth.WIDE).formatMeasures(
+ new Measure(0, MeasureUnit.MINUTE));
}
/**
- * Returns text to show for the banner depending on {@link #mSplitBannerConfig}
+ * Returns text to show for the banner depending on {@link #getSplitBannerConfig()}
* If {@param forContentDesc} is {@code true}, this will always return the full
* string corresponding to {@link #SPLIT_BANNER_FULLSCREEN}
*/
@@ -245,16 +257,16 @@
(remainingTime + MINUTE_MS - 1) / MINUTE_MS * MINUTE_MS :
remainingTime);
String readableDuration = getReadableDuration(duration,
- FormatWidth.NARROW,
- R.string.shorter_duration_less_than_one_minute,
- false /* forceFormatWidth */);
- if (forContentDesc || mSplitBannerConfig == SPLIT_BANNER_FULLSCREEN) {
+ R.string.shorter_duration_less_than_one_minute
+ /* forceFormatWidth */);
+ @SplitBannerConfig int splitBannerConfig = getSplitBannerConfig();
+ if (forContentDesc || splitBannerConfig == SPLIT_BANNER_FULLSCREEN) {
return mContainer.asContext().getString(
R.string.time_left_for_app,
readableDuration);
}
- if (mSplitBannerConfig == SPLIT_GRID_BANNER_SMALL) {
+ if (splitBannerConfig == SPLIT_GRID_BANNER_SMALL) {
// show no text
return "";
} else { // SPLIT_GRID_BANNER_LARGE
@@ -309,7 +321,7 @@
private void setBanner(@Nullable View view) {
mBanner = view;
- if (view != null && mTaskView.getRecentsView() != null) {
+ if (mBanner != null && mTaskView.getRecentsView() != null) {
setupAndAddBanner();
setBannerOutline();
}
@@ -351,10 +363,12 @@
}
void updateBannerOffset(float offsetPercentage) {
- if (mBanner != null && mBannerOffsetPercentage != offsetPercentage) {
+ if (mBannerOffsetPercentage != offsetPercentage) {
mBannerOffsetPercentage = offsetPercentage;
- updateTranslationY();
- mBanner.invalidateOutline();
+ if (mBanner != null) {
+ updateTranslationY();
+ mBanner.invalidateOutline();
+ }
}
}
@@ -364,7 +378,7 @@
}
mBanner.setTranslationY(
- (mBannerOffsetPercentage * mBanner.getHeight()) + mSplitOffsetTranslationY);
+ (mBannerOffsetPercentage * mBannerHeight) + mSplitOffsetTranslationY);
}
private void updateTranslationX() {
@@ -395,4 +409,36 @@
mBanner.setVisibility(visibility);
}
+
+ private int getAccessibilityActionId() {
+ return (mSplitBounds != null
+ && mSplitBounds.rightBottomTaskId == mTask.key.id)
+ ? R.id.action_digital_wellbeing_bottom_right
+ : R.id.action_digital_wellbeing_top_left;
+ }
+
+ @Nullable
+ public AccessibilityNodeInfo.AccessibilityAction getDWBAccessibilityAction() {
+ if (!hasLimit()) {
+ return null;
+ }
+
+ Context context = mContainer.asContext();
+ String label =
+ (mTaskView.containsMultipleTasks())
+ ? context.getString(
+ R.string.split_app_usage_settings,
+ TaskUtils.getTitle(context, mTask)
+ ) : context.getString(R.string.accessibility_app_usage_settings);
+ return new AccessibilityNodeInfo.AccessibilityAction(getAccessibilityActionId(), label);
+ }
+
+ public boolean handleAccessibilityAction(int action) {
+ if (getAccessibilityActionId() == action) {
+ openAppUsageSettings(mTaskView);
+ return true;
+ } else {
+ return false;
+ }
+ }
}
diff --git a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
index 0e451b5..acbb2ec 100644
--- a/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
+++ b/quickstep/src/com/android/quickstep/views/FloatingTaskView.java
@@ -187,7 +187,13 @@
viewBounds, false /* ignoreTransform */, null /* recycle */,
mStartingPosition);
}
-
+ // In some cases originalView is off-screen so we don't get a valid starting position
+ // ex. on rotation
+ // TODO(b/345556328) We shouldn't be animating if starting position of view isn't ready
+ if (mStartingPosition.isEmpty()) {
+ // Set to non empty for now so calculations in #update() don't break
+ mStartingPosition.set(0, 0, 1, 1);
+ }
final BaseDragLayer.LayoutParams lp = new BaseDragLayer.LayoutParams(
Math.round(mStartingPosition.width()),
Math.round(mStartingPosition.height()));
diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
index efbfa09..d6a3376 100644
--- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.kt
@@ -162,6 +162,7 @@
PreviewPositionHelper.STAGE_POSITION_BOTTOM_OR_RIGHT
)
}
+ taskContainers.forEach { it.digitalWellBeingToast?.setSplitBounds(splitBoundsConfig) }
setOrientationState(orientedState)
}
@@ -240,6 +241,10 @@
fun updateSplitBoundsConfig(splitBounds: SplitConfigurationOptions.SplitBounds?) {
splitBoundsConfig = splitBounds
+ taskContainers.forEach {
+ it.digitalWellBeingToast?.setSplitBounds(splitBoundsConfig)
+ it.digitalWellBeingToast?.initialize(it.task)
+ }
invalidate()
}
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index 83a2ceb..d9468c7 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -20,6 +20,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
@@ -49,6 +50,7 @@
*/
public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayout
implements OnClickListener, Insettable {
+ public static final String TAG = "OverviewActionsView";
private final Rect mInsets = new Rect();
@IntDef(flag = true, value = {
@@ -110,9 +112,11 @@
/** Container for the action buttons below a focused, non-split Overview tile. */
protected LinearLayout mActionButtons;
- /** Container for the action buttons below a focused, split Overview tile. */
- protected LinearLayout mGroupActionButtons;
private Button mSplitButton;
+ /**
+ * The "save app pair" button. Currently this is the only button that is not contained in
+ * mActionButtons, since it is the sole button that appears for a grouped task.
+ */
private Button mSaveAppPairButton;
@ActionsHiddenFlags
@@ -150,15 +154,16 @@
super.onFinishInflate();
// Initialize 2 view containers: one for single tasks, one for grouped tasks.
// These will take up the same space on the screen and alternate visibility as needed.
+ // Currently, the only grouped task action is "save app pairs".
mActionButtons = findViewById(R.id.action_buttons);
- mGroupActionButtons = findViewById(R.id.group_action_buttons);
- // Initialize a list to hold alphas for mActionButtons and mGroupActionButtons.
+ mSaveAppPairButton = findViewById(R.id.action_save_app_pair);
+ // Initialize a list to hold alphas for mActionButtons and any group action buttons.
mMultiValueAlphas[ACTIONS_ALPHAS] = new MultiValueAlpha(mActionButtons, NUM_ALPHAS);
mMultiValueAlphas[GROUP_ACTIONS_ALPHAS] =
- new MultiValueAlpha(mGroupActionButtons, NUM_ALPHAS);
+ new MultiValueAlpha(mSaveAppPairButton, NUM_ALPHAS);
Arrays.stream(mMultiValueAlphas).forEach(a -> a.setUpdateVisibility(true));
- // To control alpha simultaneously on mActionButtons and mGroupActionButtons, we set up an
- // AnimatedFloat for each alpha property.
+ // To control alpha simultaneously on mActionButtons and any group action buttons, we set up
+ // an AnimatedFloat for each alpha property.
for (int i = 0; i < NUM_ALPHAS; i++) {
final int index = i;
mAlphaProperties[index] = new AnimatedFloat(() -> {
@@ -175,7 +180,6 @@
screenshotButton.setOnClickListener(this);
mSplitButton = findViewById(R.id.action_split);
mSplitButton.setOnClickListener(this);
- mSaveAppPairButton = findViewById(R.id.action_save_app_pair);
mSaveAppPairButton.setOnClickListener(this);
}
@@ -252,6 +256,8 @@
* pair.
*/
public void updateForGroupedTask(boolean isGroupedTask, boolean canSaveAppPair) {
+ Log.d(TAG, "updateForGroupedTask() called with: isGroupedTask = [" + isGroupedTask
+ + "], canSaveAppPair = [" + canSaveAppPair + "]");
mIsGroupedTask = isGroupedTask;
mCanSaveAppPair = canSaveAppPair;
updateActionButtonsVisibility();
@@ -271,6 +277,8 @@
assert mDp != null;
boolean showSingleTaskActions = !mIsGroupedTask;
boolean showGroupActions = mIsGroupedTask && mDp.isTablet && mCanSaveAppPair;
+ Log.d(TAG, "updateActionButtonsVisibility() called: showSingleTaskActions = ["
+ + showSingleTaskActions + "], showGroupActions = [" + showGroupActions + "]");
getActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showSingleTaskActions ? 1 : 0);
getGroupActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showGroupActions ? 1 : 0);
}
@@ -336,7 +344,7 @@
*/
public boolean areActionsButtonsVisible() {
return mActionButtons.getVisibility() == View.VISIBLE
- || mGroupActionButtons.getVisibility() == View.VISIBLE;
+ || mSaveAppPairButton.getVisibility() == View.VISIBLE;
}
/**
@@ -350,11 +358,11 @@
/** Updates vertical margins for different navigation mode or configuration changes. */
public void updateVerticalMargin(NavigationMode mode) {
updateActionBarPosition(mActionButtons);
- updateActionBarPosition(mGroupActionButtons);
+ updateActionBarPosition(mSaveAppPairButton);
}
/** Positions actions buttons according to device settings and insets. */
- private void updateActionBarPosition(LinearLayout actionBar) {
+ private void updateActionBarPosition(View actionBar) {
if (mDp == null) {
return;
}
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 275734d..9096b75 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -188,6 +188,7 @@
import com.android.quickstep.TopTaskTracker;
import com.android.quickstep.ViewUtils;
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
+import com.android.quickstep.recents.data.TasksRepository;
import com.android.quickstep.recents.viewmodel.RecentsViewData;
import com.android.quickstep.util.ActiveGestureErrorDetector;
import com.android.quickstep.util.ActiveGestureLog;
@@ -216,6 +217,7 @@
import com.android.systemui.shared.system.PackageManagerWrapper;
import com.android.systemui.shared.system.TaskStackChangeListener;
import com.android.systemui.shared.system.TaskStackChangeListeners;
+import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource;
import com.android.wm.shell.common.pip.IPipAnimationListener;
import com.android.wm.shell.shared.DesktopModeStatus;
@@ -305,6 +307,7 @@
public static final float SCROLL_VIBRATION_PRIMITIVE_SCALE = 0.6f;
public static final VibrationEffect SCROLL_VIBRATION_FALLBACK =
VibrationConstants.EFFECT_TEXTURE_TICK;
+ public static final int UNBOUND_TASK_VIEW_ID = -1;
/**
* Can be used to tint the color of the RecentsView to simulate a scrim that can views
@@ -456,6 +459,7 @@
private static final float FOREGROUND_SCRIM_TINT = 0.32f;
public final RecentsViewData mRecentsViewData = new RecentsViewData();
+ public final TasksRepository mTasksRepository;
protected final RecentsOrientedState mOrientationState;
protected final BaseContainerInterface<STATE_TYPE, CONTAINER_TYPE> mSizeStrategy;
@@ -800,6 +804,12 @@
.getDimensionPixelSize(R.dimen.recents_fast_fling_velocity);
mModel = RecentsModel.INSTANCE.get(context);
mIdp = InvariantDeviceProfile.INSTANCE.get(context);
+ if (enableRefactorTaskThumbnail()) {
+ mTasksRepository = new TasksRepository(
+ mModel, mModel.getThumbnailCache(), mModel.getIconCache());
+ } else {
+ mTasksRepository = null;
+ }
mClearAllButton = (ClearAllButton) LayoutInflater.from(context)
.inflate(R.layout.overview_clear_all_button, this, false);
@@ -1165,7 +1175,6 @@
} else {
mTaskViewPool.recycle(taskView);
}
- taskView.setTaskViewId(-1);
mActionsView.updateHiddenFlags(HIDDEN_NO_TASKS, getTaskViewCount() == 0);
}
}
@@ -1716,7 +1725,7 @@
return super.isPageScrollsInitialized() && mLoadPlanEverApplied;
}
- protected void applyLoadPlan(ArrayList<GroupTask> taskGroups) {
+ protected void applyLoadPlan(List<GroupTask> taskGroups) {
if (mPendingAnimation != null) {
mPendingAnimation.addEndListener(success -> applyLoadPlan(taskGroups));
return;
@@ -2362,6 +2371,8 @@
upper = Math.min(centerPageIndex + 2, numChildren - 1);
}
+ List<Integer> visibleTaskIds = new ArrayList<>();
+
// Update the task data for the in/visible children
for (int i = 0; i < getTaskViewCount(); i++) {
TaskView taskView = requireTaskViewAt(i);
@@ -2381,6 +2392,10 @@
List<Task> tasksToUpdate = containers.stream()
.map(TaskContainer::getTask)
.collect(Collectors.toCollection(ArrayList::new));
+ if (enableRefactorTaskThumbnail()) {
+ visibleTaskIds.addAll(
+ tasksToUpdate.stream().map((task) -> task.key.id).toList());
+ }
if (mTmpRunningTasks != null) {
for (Task t : mTmpRunningTasks) {
// Skip loading if this is the task that we are animating into
@@ -2416,6 +2431,9 @@
}
}
}
+ if (enableRefactorTaskThumbnail()) {
+ mTasksRepository.setVisibleTasks(visibleTaskIds);
+ }
}
/**
@@ -2602,6 +2620,9 @@
if (!mModel.isTaskListValid(mTaskListChangeId)) {
mTaskListChangeId = mModel.getTasks(this::applyLoadPlan, RecentsFilterState
.getFilter(mFilterState.getPackageNameToFilter()));
+ if (enableRefactorTaskThumbnail()) {
+ mTasksRepository.getAllTaskData(/* forceRefresh = */ true);
+ }
}
}
@@ -2646,6 +2667,20 @@
// Let system take care of the rotation
return;
}
+
+ if (mRunningTaskShowScreenshot) {
+ animateRotation(newRotation);
+ } else {
+ // Animate the rotation and stops running task
+ switchToScreenshot(() -> {
+ animateRotation(newRotation);
+ finishRecentsAnimation(true /* toRecents */, false /* shouldPip */,
+ null /* onFinishComplete */);
+ });
+ }
+ }
+
+ private void animateRotation(int newRotation) {
AnimatorSet pa = setRecentsChangedOrientation(true);
pa.addListener(AnimatorListeners.forSuccessCallback(() -> {
setLayoutRotation(newRotation, mOrientationState.getDisplayRotation());
@@ -2655,17 +2690,9 @@
pa.start();
}
- public AnimatorSet setRecentsChangedOrientation(boolean fadeInChildren) {
- getRunningTaskIndex();
- int runningIndex = getCurrentPage();
+ public AnimatorSet setRecentsChangedOrientation(boolean fadeOut) {
AnimatorSet as = new AnimatorSet();
- for (int i = 0; i < getTaskViewCount(); i++) {
- View taskView = requireTaskViewAt(i);
- if (runningIndex == i && taskView.getAlpha() != 0) {
- continue;
- }
- as.play(ObjectAnimator.ofFloat(taskView, View.ALPHA, fadeInChildren ? 0 : 1));
- }
+ as.play(ObjectAnimator.ofFloat(this, View.ALPHA, fadeOut ? 0 : 1));
return as;
}
@@ -2935,7 +2962,6 @@
int taskCount = getTaskViewCount();
for (int i = 0; i < taskCount; i++) {
TaskView taskView = requireTaskViewAt(i);
- taskView.setIconScaleAnimStartProgress(0f);
taskView.animateIconScaleAndDimIntoView();
}
}
@@ -3768,7 +3794,7 @@
anim.setFloat(taskView, taskView.getSecondaryDismissTranslationProperty(),
secondaryTranslation, clampToProgress(LINEAR, animationStartProgress,
dismissTranslationInterpolationEnd));
- anim.setFloat(taskView, TaskView.FOCUS_TRANSITION, 0f,
+ anim.setFloat(taskView, TaskView.SCALE_AND_DIM_OUT, 0f,
clampToProgress(LINEAR, 0f, ANIMATION_DISMISS_PROGRESS_MIDPOINT));
} else {
float primaryTranslation =
@@ -5912,7 +5938,7 @@
return;
}
- taskView.setShouldShowScreenshot(true);
+ setRunningTaskViewShowScreenshot(true);
for (TaskContainer container : taskView.getTaskContainers()) {
if (container == null) {
continue;
@@ -6284,20 +6310,22 @@
* Moves the provided task into desktop mode, and invoke {@code successCallback} if succeeded.
*/
public void moveTaskToDesktop(TaskContainer taskContainer,
+ DesktopModeTransitionSource transitionSource,
Runnable successCallback) {
if (!DesktopModeStatus.canEnterDesktopMode(mContext)) {
return;
}
switchToScreenshot(() -> finishRecentsAnimation(/* toRecents= */true, /* shouldPip= */false,
- () -> moveTaskToDesktopInternal(taskContainer, successCallback)));
+ () -> moveTaskToDesktopInternal(taskContainer, successCallback, transitionSource)));
}
private void moveTaskToDesktopInternal(TaskContainer taskContainer,
- Runnable successCallback) {
+ Runnable successCallback, DesktopModeTransitionSource transitionSource) {
if (mDesktopRecentsTransitionController == null) {
return;
}
- mDesktopRecentsTransitionController.moveToDesktop(taskContainer.getTask().key.id);
+ mDesktopRecentsTransitionController.moveToDesktop(taskContainer.getTask().key.id,
+ transitionSource);
successCallback.run();
}
diff --git a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
index a56d51e..3d994e8 100644
--- a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
@@ -18,13 +18,16 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SPLIT_SELECTION_EXIT_CANCEL_BUTTON;
+import static com.android.settingslib.widget.theme.R.dimen.settingslib_preferred_minimum_touch_target;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.content.Context;
+import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.FloatProperty;
+import android.view.TouchDelegate;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -41,9 +44,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StateManager;
-import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.states.StateAnimationConfig;
-
import com.android.quickstep.util.SplitSelectStateController;
/**
@@ -133,6 +134,28 @@
cancelTextView.setVisibility(VISIBLE);
cancelTextView.setOnClickListener((v) -> exitSplitSelection());
instructionTextView.setText(R.string.toast_contextual_split_select_app);
+
+ // After layout, expand touch target of cancel button to meet minimum a11y measurements.
+ post(() -> {
+ int minTouchSize = getResources()
+ .getDimensionPixelSize(settingslib_preferred_minimum_touch_target);
+ Rect r = new Rect();
+ cancelTextView.getHitRect(r);
+
+ if (r.width() < minTouchSize) {
+ // add 1 to ensure ceiling on int division
+ int expandAmount = (minTouchSize + 1 - r.width()) / 2;
+ r.left -= expandAmount;
+ r.right += expandAmount;
+ }
+ if (r.height() < minTouchSize) {
+ int expandAmount = (minTouchSize + 1 - r.height()) / 2;
+ r.top -= expandAmount;
+ r.bottom += expandAmount;
+ }
+
+ setTouchDelegate(new TouchDelegate(r, cancelTextView));
+ });
}
// Set accessibility title, will be announced by a11y tools.
diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
index 59ffc39..eda58c5 100644
--- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java
@@ -112,11 +112,7 @@
@Override
protected void handleClose(boolean animate) {
- if (animate || enableOverviewIconMenu()) {
- animateClose();
- } else {
- closeComplete();
- }
+ animateClose();
}
@Override
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.kt b/quickstep/src/com/android/quickstep/views/TaskView.kt
index 05b9d40..5e79743 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.kt
+++ b/quickstep/src/com/android/quickstep/views/TaskView.kt
@@ -38,6 +38,7 @@
import android.view.ViewGroup
import android.view.ViewStub
import android.view.accessibility.AccessibilityNodeInfo
+import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction
import android.widget.FrameLayout
import android.widget.Toast
import androidx.annotation.IntDef
@@ -51,7 +52,6 @@
import com.android.launcher3.Flags.enableRefactorTaskThumbnail
import com.android.launcher3.Flags.privateSpaceRestrictAccessibilityDrag
import com.android.launcher3.LauncherSettings
-import com.android.launcher3.LauncherState
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.config.FeatureFlags.ENABLE_KEYBOARD_QUICK_SWITCH
@@ -64,10 +64,11 @@
import com.android.launcher3.testing.shared.TestProtocol
import com.android.launcher3.util.CancellableTask
import com.android.launcher3.util.Executors
+import com.android.launcher3.util.MultiPropertyFactory
+import com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE
import com.android.launcher3.util.RunnableList
import com.android.launcher3.util.SafeCloseable
import com.android.launcher3.util.SplitConfigurationOptions
-import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT
import com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED
import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption
import com.android.launcher3.util.SplitConfigurationOptions.StagePosition
@@ -93,6 +94,7 @@
import com.android.quickstep.util.RecentsOrientedState
import com.android.quickstep.util.TaskCornerRadius
import com.android.quickstep.util.TaskRemovedDuringLaunchListener
+import com.android.quickstep.views.RecentsView.UNBOUND_TASK_VIEW_ID
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.recents.model.ThumbnailData
import com.android.systemui.shared.system.ActivityManagerWrapper
@@ -132,19 +134,26 @@
val taskIds: IntArray
/** Returns a copy of integer array containing taskIds of all tasks in the TaskView. */
get() = taskContainers.map { it.task.key.id }.toIntArray()
+
val thumbnailViews: Array<TaskThumbnailViewDeprecated>
get() = taskContainers.map { it.thumbnailViewDeprecated }.toTypedArray()
+
val isGridTask: Boolean
/** Returns whether the task is part of overview grid and not being focused. */
get() = container.deviceProfile.isTablet && !isFocusedTask
+
val isRunningTask: Boolean
get() = this === recentsView?.runningTaskView
+
val isFocusedTask: Boolean
get() = this === recentsView?.focusedTaskView
+
val taskCornerRadius: Float
get() = currentFullscreenParams.cornerRadius
+
val recentsView: RecentsView<*, *>?
get() = parent as? RecentsView<*, *>
+
val pagedOrientationHandler: RecentsPagedOrientationHandler
get() = orientedState.orientationHandler
@@ -152,10 +161,12 @@
val firstTask: Task
/** Returns the first task bound to this TaskView. */
get() = taskContainers[0].task
+
@get:Deprecated("Use [taskContainers] instead.")
val firstThumbnailViewDeprecated: TaskThumbnailViewDeprecated
/** Returns the first thumbnailView of the TaskView. */
get() = taskContainers[0].thumbnailViewDeprecated
+
@get:Deprecated("Use [taskContainers] instead.")
val firstItemInfo: ItemInfo
get() = taskContainers[0].itemInfo
@@ -172,6 +183,7 @@
* not change according to a temporary state.
*/
get() = Utilities.mapRange(gridProgress, nonGridScale, 1f)
+
protected val persistentTranslationX: Float
/**
* Returns addition of translationX that is persistent (e.g. fullscreen and grid), and does
@@ -181,42 +193,50 @@
(getNonGridTrans(nonGridTranslationX) +
getGridTrans(this.gridTranslationX) +
getNonGridTrans(nonGridPivotTranslationX))
+
protected val persistentTranslationY: Float
/**
* Returns addition of translationY that is persistent (e.g. fullscreen and grid), and does
* not change according to a temporary state (e.g. task offset).
*/
get() = boxTranslationY + getGridTrans(gridTranslationY)
+
protected val primarySplitTranslationProperty: FloatProperty<TaskView>
get() =
pagedOrientationHandler.getPrimaryValue(
SPLIT_SELECT_TRANSLATION_X,
SPLIT_SELECT_TRANSLATION_Y
)
+
protected val secondarySplitTranslationProperty: FloatProperty<TaskView>
get() =
pagedOrientationHandler.getSecondaryValue(
SPLIT_SELECT_TRANSLATION_X,
SPLIT_SELECT_TRANSLATION_Y
)
+
protected val primaryDismissTranslationProperty: FloatProperty<TaskView>
get() =
pagedOrientationHandler.getPrimaryValue(DISMISS_TRANSLATION_X, DISMISS_TRANSLATION_Y)
+
protected val secondaryDismissTranslationProperty: FloatProperty<TaskView>
get() =
pagedOrientationHandler.getSecondaryValue(DISMISS_TRANSLATION_X, DISMISS_TRANSLATION_Y)
+
protected val primaryTaskOffsetTranslationProperty: FloatProperty<TaskView>
get() =
pagedOrientationHandler.getPrimaryValue(
TASK_OFFSET_TRANSLATION_X,
TASK_OFFSET_TRANSLATION_Y
)
+
protected val secondaryTaskOffsetTranslationProperty: FloatProperty<TaskView>
get() =
pagedOrientationHandler.getSecondaryValue(
TASK_OFFSET_TRANSLATION_X,
TASK_OFFSET_TRANSLATION_Y
)
+
protected val taskResistanceTranslationProperty: FloatProperty<TaskView>
get() =
pagedOrientationHandler.getSecondaryValue(
@@ -233,9 +253,10 @@
/** Returns a list of all TaskContainers in the TaskView. */
lateinit var taskContainers: List<TaskContainer>
protected set
+
lateinit var orientedState: RecentsOrientedState
- var taskViewId = -1
+ var taskViewId = UNBOUND_TASK_VIEW_ID
var isEndQuickSwitchCuj = false
// Various animation progress variables.
@@ -245,12 +266,14 @@
field = Utilities.boundToRange(value, 0f, 1f)
onFullscreenProgressChanged(field)
}
+
// gridProgress 0 = carousel; 1 = 2 row grid.
protected var gridProgress = 0f
set(value) {
field = value
onGridProgressChanged()
}
+
/**
* The modalness of this view is how it should be displayed when it is shown on its own in the
* modal state of overview. 0 being in context with other tasks, 1 being shown on its own.
@@ -263,74 +286,88 @@
field = value
onModalnessUpdated(field)
}
+
protected var taskThumbnailSplashAlpha = 0f
set(value) {
field = value
applyThumbnailSplashAlpha()
}
+
protected var nonGridScale = 1f
set(value) {
field = value
applyScale()
}
+
private var dismissScale = 1f
set(value) {
field = value
applyScale()
}
+
private var dismissTranslationX = 0f
set(value) {
field = value
applyTranslationX()
}
+
private var dismissTranslationY = 0f
set(value) {
field = value
applyTranslationY()
}
+
private var taskOffsetTranslationX = 0f
set(value) {
field = value
applyTranslationX()
}
+
private var taskOffsetTranslationY = 0f
set(value) {
field = value
applyTranslationY()
}
+
private var taskResistanceTranslationX = 0f
set(value) {
field = value
applyTranslationX()
}
+
private var taskResistanceTranslationY = 0f
set(value) {
field = value
applyTranslationY()
}
+
// The following translation variables should only be used in the same orientation as Launcher.
private var boxTranslationY = 0f
set(value) {
field = value
applyTranslationY()
}
+
// The following grid translations scales with mGridProgress.
protected var gridTranslationX = 0f
set(value) {
field = value
applyTranslationX()
}
+
var gridTranslationY = 0f
protected set(value) {
field = value
applyTranslationY()
}
+
// The following grid translation is used to animate closing the gap between grid and clear all.
private var gridEndTranslationX = 0f
set(value) {
field = value
applyTranslationX()
}
+
// Applied as a complement to gridTranslation, for adjusting the carousel overview and quick
// switch.
protected var nonGridTranslationX = 0f
@@ -338,29 +375,35 @@
field = value
applyTranslationX()
}
+
protected var nonGridPivotTranslationX = 0f
set(value) {
field = value
applyTranslationX()
}
+
// Used when in SplitScreenSelectState
private var splitSelectTranslationY = 0f
set(value) {
field = value
applyTranslationY()
}
+
private var splitSelectTranslationX = 0f
set(value) {
field = value
applyTranslationX()
}
+
protected var stableAlpha = 1f
set(value) {
field = value
alpha = stableAlpha
}
+
protected var shouldShowScreenshot = false
get() = !isRunningTask || field
+
/** Enable or disable showing border on hover and focus change */
@VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)
var borderEnabled = false
@@ -374,8 +417,36 @@
hoverBorderAnimator?.setBorderVisibility(visible = field && isHovered, animated = true)
focusBorderAnimator?.setBorderVisibility(visible = field && isFocused, animated = true)
}
- protected var iconScaleAnimStartProgress = 0f
+
private var focusTransitionProgress = 1f
+ set(value) {
+ field = value
+ onFocusTransitionProgressUpdated(field)
+ }
+
+ private val focusTransitionPropertyFactory =
+ MultiPropertyFactory(
+ this,
+ FOCUS_TRANSITION,
+ FOCUS_TRANSITION_INDEX_COUNT,
+ { x: Float, y: Float -> x * y },
+ 1f
+ )
+ private val focusTransitionFullscreen =
+ 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.
+ */
+ private var focusTransitionScaleAndDimOut = focusTransitionScaleAndDim.value
+ set(value) {
+ field = value
+ focusTransitionScaleAndDim.value =
+ FOCUS_TRANSITION_FAST_OUT_INTERPOLATOR.getInterpolation(field)
+ }
private var iconAndDimAnimator: ObjectAnimator? = null
// The current background requests to load the task thumbnail and icon
@@ -502,7 +573,6 @@
resetPersistentViewTransforms()
// Clear any references to the thumbnail (it will be re-read either from the cache or the
// system on next bind)
- // TODO(b/334825222): Implement thumbnail/snapshot for the new [TaskThumbnailView].
if (enableRefactorTaskThumbnail()) {
notifyIsRunningTaskUpdated()
} else {
@@ -511,6 +581,8 @@
setOverlayEnabled(false)
onTaskListVisibilityChanged(false)
borderEnabled = false
+ taskViewId = UNBOUND_TASK_VIEW_ID
+ taskContainers.forEach { it.destroy() }
}
// TODO: Clip-out the icon region from the thumbnail, since they are overlapping.
@@ -520,11 +592,12 @@
super.onInitializeAccessibilityNodeInfo(info)
with(info) {
addAction(
- AccessibilityNodeInfo.AccessibilityAction(
- R.string.accessibility_close,
+ AccessibilityAction(
+ R.id.action_close,
context.getText(R.string.accessibility_close)
)
)
+
taskContainers.forEach {
TraceHelper.allowIpcs("TV.a11yInfo") {
TaskOverlayFactory.getEnabledShortcuts(this@TaskView, it).forEach { shortcut ->
@@ -532,15 +605,12 @@
}
}
}
- // TODO(b/341672022): handle multiple digitalWellBeingToast accessibility actions
- if (taskContainers[0].digitalWellBeingToast?.hasLimit() == true) {
- addAction(
- AccessibilityNodeInfo.AccessibilityAction(
- R.string.accessibility_app_usage_settings,
- context.getText(R.string.accessibility_app_usage_settings)
- )
- )
+
+ // Add DWB accessibility action at the end of the list
+ taskContainers.forEach {
+ it.digitalWellBeingToast?.getDWBAccessibilityAction()?.let(::addAction)
}
+
recentsView?.let {
collectionItemInfo =
AccessibilityNodeInfo.CollectionItemInfo.obtain(
@@ -555,16 +625,17 @@
}
override fun performAccessibilityAction(action: Int, arguments: Bundle?): Boolean {
- if (action == R.string.accessibility_close) {
+ // TODO(b/343708271): Add support for multiple tasks per action.
+ if (action == R.id.action_close) {
recentsView?.dismissTask(this, true /*animateTaskView*/, true /*removeTask*/)
return true
}
- if (action == R.string.accessibility_app_usage_settings) {
- // TODO(b/341672022): handle multiple digitalWellBeingToast accessibility actions
- taskContainers[0].digitalWellBeingToast?.openAppUsageSettings(this)
- return true
- }
+
taskContainers.forEach {
+ if (it.digitalWellBeingToast?.handleAccessibilityAction(action) == true) {
+ return true
+ }
+
TaskOverlayFactory.getEnabledShortcuts(this, it).forEach { shortcut ->
if (shortcut.hasHandlerForAction(action)) {
shortcut.onClick(this)
@@ -572,6 +643,7 @@
}
}
}
+
return super.performAccessibilityAction(action, arguments)
}
@@ -753,7 +825,10 @@
taskContainers.forEach {
val thumbnailBounds = Rect()
if (relativeToDragLayer) {
- container.dragLayer.getDescendantRectRelativeToSelf(it.snapshotView, bounds)
+ container.dragLayer.getDescendantRectRelativeToSelf(
+ it.snapshotView,
+ thumbnailBounds
+ )
} else {
thumbnailBounds.set(it.snapshotView)
}
@@ -780,22 +855,19 @@
val recentsModel = RecentsModel.INSTANCE.get(context)
// These calls are no-ops if the data is already loaded, try and load the high
// resolution thumbnail if the state permits
- if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL)) {
- if (!enableRefactorTaskThumbnail()) {
- // TODO(b/334825222) add thumbnail state
- taskContainers.forEach {
- if (visible) {
- recentsModel.thumbnailCache
- .updateThumbnailInBackground(it.task) { thumbnailData ->
- it.thumbnailViewDeprecated.setThumbnail(it.task, thumbnailData)
- }
- ?.also { request -> pendingThumbnailLoadRequests.add(request) }
- } else {
- it.thumbnailViewDeprecated.setThumbnail(null, null)
- // Reset the task thumbnail reference as well (it will be fetched from the
- // cache or reloaded next time we need it)
- it.task.thumbnail = null
- }
+ if (needsUpdate(changes, FLAG_UPDATE_THUMBNAIL) && !enableRefactorTaskThumbnail()) {
+ taskContainers.forEach {
+ if (visible) {
+ recentsModel.thumbnailCache
+ .updateThumbnailInBackground(it.task) { thumbnailData ->
+ it.thumbnailViewDeprecated.setThumbnail(it.task, thumbnailData)
+ }
+ ?.also { request -> pendingThumbnailLoadRequests.add(request) }
+ } else {
+ it.thumbnailViewDeprecated.setThumbnail(null, null)
+ // Reset the task thumbnail reference as well (it will be fetched from the
+ // cache or reloaded next time we need it)
+ it.task.thumbnail = null
}
}
}
@@ -803,12 +875,12 @@
taskContainers.forEach {
if (visible) {
recentsModel.iconCache
- .updateIconInBackground(it.task) { thumbnailData ->
- setIcon(it.iconView, thumbnailData.icon)
+ .updateIconInBackground(it.task) { task ->
+ setIcon(it.iconView, task.icon)
if (enableOverviewIconMenu()) {
- setText(it.iconView, thumbnailData.title)
+ setText(it.iconView, task.title)
}
- it.digitalWellBeingToast?.initialize(thumbnailData)
+ it.digitalWellBeingToast?.initialize(task)
}
?.also { request -> pendingIconLoadRequests.add(request) }
} else {
@@ -861,7 +933,7 @@
open fun refreshThumbnails(thumbnailDatas: HashMap<Int, ThumbnailData?>?) {
if (enableRefactorTaskThumbnail()) {
- // TODO(b/334825222) add thumbnail logic
+ // TODO(b/342560598) add thumbnail logic
return
}
@@ -1268,43 +1340,23 @@
}
}
- protected open fun setIconsAndBannersFullscreenProgress(progress: Float) {
- // Animate icons and DWB banners in/out, except in QuickSwitch state, when tiles are
- // oversized and banner would look disproportionately large.
- if (recentsView?.stateManager?.state == LauncherState.BACKGROUND_APP) {
- return
- }
- setIconsAndBannersTransitionProgress(progress, invert = true)
- }
-
/**
* Called to animate a smooth transition when going directly from an app into Overview (and vice
* versa). Icons fade in, and DWB banners slide in with a "shift up" animation.
*/
- protected open fun setIconsAndBannersTransitionProgress(progress: Float, invert: Boolean) {
- focusTransitionProgress = if (invert) 1 - progress else progress
- getIconContentScale(invert).let { iconContentScale ->
- taskContainers.forEach {
- it.iconView.setContentAlpha(iconContentScale)
- it.digitalWellBeingToast?.updateBannerOffset(1f - iconContentScale)
- }
+ private fun onFocusTransitionProgressUpdated(focusTransitionProgress: Float) {
+ taskContainers.forEach {
+ it.iconView.setContentAlpha(focusTransitionProgress)
+ it.digitalWellBeingToast?.updateBannerOffset(1f - focusTransitionProgress)
}
}
- private fun getIconContentScale(invert: Boolean): Float {
- val iconScalePercentage = SCALE_ICON_DURATION.toFloat() / DIM_ANIM_DURATION
- val lowerClamp = if (invert) 1f - iconScalePercentage else 0f
- val upperClamp = if (invert) 1f else iconScalePercentage
- return Interpolators.clampToProgress(Interpolators.FAST_OUT_SLOW_IN, lowerClamp, upperClamp)
- .getInterpolation(focusTransitionProgress)
- }
-
fun animateIconScaleAndDimIntoView() {
iconAndDimAnimator?.cancel()
iconAndDimAnimator =
- ObjectAnimator.ofFloat(this, FOCUS_TRANSITION, 1f).apply {
- setCurrentFraction(iconScaleAnimStartProgress)
- setDuration(DIM_ANIM_DURATION).interpolator = Interpolators.LINEAR
+ ObjectAnimator.ofFloat(focusTransitionScaleAndDim, MULTI_PROPERTY_VALUE, 0f, 1f).apply {
+ duration = SCALE_ICON_DURATION
+ interpolator = Interpolators.LINEAR
addListener(
object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
@@ -1318,7 +1370,7 @@
fun setIconScaleAndDim(iconScale: Float) {
iconAndDimAnimator?.cancel()
- setIconsAndBannersTransitionProgress(iconScale, invert = false)
+ focusTransitionScaleAndDim.value = iconScale
}
/** Set a color tint on the snapshot and supporting views. */
@@ -1421,7 +1473,8 @@
it.iconView.setVisibility(if (fullscreenProgress < 1) VISIBLE else INVISIBLE)
it.overlay.setFullscreenProgress(fullscreenProgress)
}
- setIconsAndBannersFullscreenProgress(fullscreenProgress)
+ focusTransitionFullscreen.value =
+ FOCUS_TRANSITION_FAST_OUT_INTERPOLATOR.getInterpolation(1 - fullscreenProgress)
updateSnapshotRadius()
}
@@ -1556,11 +1609,6 @@
) {
val overlay: TaskOverlay<*> = taskOverlayFactory.createOverlay(this)
- @IdRes
- val a11yNodeId: Int =
- if (stagePosition == STAGE_POSITION_BOTTOM_OR_RIGHT) R.id.split_bottomRight_appInfo
- else R.id.split_topLeft_appInfo
-
val snapshotView: View
get() = thumbnailView ?: thumbnailViewDeprecated
@@ -1588,10 +1636,17 @@
val taskView: TaskView
get() = this@TaskView
+ fun destroy() {
+ digitalWellBeingToast?.destroy()
+ thumbnailView?.let { taskView.removeView(it) }
+ }
+
// 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() {
- thumbnailView?.viewModel?.bind(TaskThumbnail(task, isRunningTask))
+ // TODO(b/343364498): Existing view has shouldShowScreenshot as an override as well but
+ // this should be decided inside TaskThumbnailViewModel.
+ thumbnailView?.viewModel?.bind(TaskThumbnail(task.key.id, isRunningTask))
}
}
@@ -1603,21 +1658,43 @@
const val FLAG_UPDATE_ALL =
(FLAG_UPDATE_ICON or FLAG_UPDATE_THUMBNAIL or FLAG_UPDATE_CORNER_RADIUS)
+ const val FOCUS_TRANSITION_INDEX_FULLSCREEN = 0
+ const val FOCUS_TRANSITION_INDEX_SCALE_AND_DIM = 1
+ const val FOCUS_TRANSITION_INDEX_COUNT = 2
+
/** The maximum amount that a task view can be scrimmed, dimmed or tinted. */
const val MAX_PAGE_SCRIM_ALPHA = 0.4f
const val SCALE_ICON_DURATION: Long = 120
private const val DIM_ANIM_DURATION: Long = 700
+ private const val FOCUS_TRANSITION_THRESHOLD =
+ SCALE_ICON_DURATION.toFloat() / DIM_ANIM_DURATION
+ val FOCUS_TRANSITION_FAST_OUT_INTERPOLATOR =
+ Interpolators.clampToProgress(
+ Interpolators.FAST_OUT_SLOW_IN,
+ 1f - FOCUS_TRANSITION_THRESHOLD,
+ 1f
+ )!!
private val SYSTEM_GESTURE_EXCLUSION_RECT = listOf(Rect())
- @JvmField
- val FOCUS_TRANSITION: FloatProperty<TaskView> =
+ private val FOCUS_TRANSITION: FloatProperty<TaskView> =
object : FloatProperty<TaskView>("focusTransition") {
override fun setValue(taskView: TaskView, v: Float) {
- taskView.setIconsAndBannersTransitionProgress(v, false /* invert */)
+ taskView.focusTransitionProgress = v
}
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) {
@@ -1626,6 +1703,7 @@
override fun get(taskView: TaskView) = taskView.splitSelectTranslationX
}
+
private val SPLIT_SELECT_TRANSLATION_Y: FloatProperty<TaskView> =
object : FloatProperty<TaskView>("splitSelectTranslationY") {
override fun setValue(taskView: TaskView, v: Float) {
@@ -1634,6 +1712,7 @@
override fun get(taskView: TaskView) = taskView.splitSelectTranslationY
}
+
private val DISMISS_TRANSLATION_X: FloatProperty<TaskView> =
object : FloatProperty<TaskView>("dismissTranslationX") {
override fun setValue(taskView: TaskView, v: Float) {
@@ -1642,6 +1721,7 @@
override fun get(taskView: TaskView) = taskView.dismissTranslationX
}
+
private val DISMISS_TRANSLATION_Y: FloatProperty<TaskView> =
object : FloatProperty<TaskView>("dismissTranslationY") {
override fun setValue(taskView: TaskView, v: Float) {
@@ -1650,6 +1730,7 @@
override fun get(taskView: TaskView) = taskView.dismissTranslationY
}
+
private val TASK_OFFSET_TRANSLATION_X: FloatProperty<TaskView> =
object : FloatProperty<TaskView>("taskOffsetTranslationX") {
override fun setValue(taskView: TaskView, v: Float) {
@@ -1658,6 +1739,7 @@
override fun get(taskView: TaskView) = taskView.taskOffsetTranslationX
}
+
private val TASK_OFFSET_TRANSLATION_Y: FloatProperty<TaskView> =
object : FloatProperty<TaskView>("taskOffsetTranslationY") {
override fun setValue(taskView: TaskView, v: Float) {
@@ -1666,6 +1748,7 @@
override fun get(taskView: TaskView) = taskView.taskOffsetTranslationY
}
+
private val TASK_RESISTANCE_TRANSLATION_X: FloatProperty<TaskView> =
object : FloatProperty<TaskView>("taskResistanceTranslationX") {
override fun setValue(taskView: TaskView, v: Float) {
@@ -1674,6 +1757,7 @@
override fun get(taskView: TaskView) = taskView.taskResistanceTranslationX
}
+
private val TASK_RESISTANCE_TRANSLATION_Y: FloatProperty<TaskView> =
object : FloatProperty<TaskView>("taskResistanceTranslationY") {
override fun setValue(taskView: TaskView, v: Float) {
@@ -1682,6 +1766,7 @@
override fun get(taskView: TaskView) = taskView.taskResistanceTranslationY
}
+
@JvmField
val GRID_END_TRANSLATION_X: FloatProperty<TaskView> =
object : FloatProperty<TaskView>("gridEndTranslationX") {
@@ -1691,6 +1776,7 @@
override fun get(taskView: TaskView) = taskView.gridEndTranslationX
}
+
@JvmField
val DISMISS_SCALE: FloatProperty<TaskView> =
object : FloatProperty<TaskView>("dismissScale") {
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarUnitTestRule.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarUnitTestRule.kt
new file mode 100644
index 0000000..a999e7f
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarUnitTestRule.kt
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar
+
+import android.app.Instrumentation
+import android.app.PendingIntent
+import android.content.IIntentSender
+import android.content.Intent
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.rule.ServiceTestRule
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks
+import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
+import com.android.launcher3.util.LauncherMultivalentJUnit.Companion.isRunningInRobolectric
+import com.android.quickstep.AllAppsActionManager
+import com.android.quickstep.TouchInteractionService
+import com.android.quickstep.TouchInteractionService.TISBinder
+import org.junit.Assume.assumeTrue
+import org.junit.rules.MethodRule
+import org.junit.runners.model.FrameworkMethod
+import org.junit.runners.model.Statement
+
+/**
+ * Manages the Taskbar lifecycle for unit tests.
+ *
+ * See [InjectController] for grabbing controller(s) under test with minimal boilerplate.
+ *
+ * The rule interacts with [TaskbarManager] on the main thread. A good rule of thumb for tests is
+ * that code that is executed on the main thread in production should also happen on that thread
+ * when tested.
+ *
+ * `@UiThreadTest` is a simple way to run an entire test body on the main thread. But if a test
+ * executes code that appends message(s) to the main thread's `MessageQueue`, the annotation will
+ * prevent those messages from being processed until after the test body finishes.
+ *
+ * To test pending messages, instead use something like [Instrumentation.runOnMainSync] to perform
+ * only sections of the test body on the main thread synchronously:
+ * ```
+ * @Test
+ * fun example() {
+ * instrumentation.runOnMainSync { doWorkThatPostsMessage() }
+ * // Second lambda will not execute until message is processed.
+ * instrumentation.runOnMainSync { verifyMessageResults() }
+ * }
+ * ```
+ */
+class TaskbarUnitTestRule : MethodRule {
+ private val instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val serviceTestRule = ServiceTestRule()
+
+ private lateinit var taskbarManager: TaskbarManager
+ private lateinit var target: Any
+
+ val activityContext: TaskbarActivityContext
+ get() {
+ return taskbarManager.currentActivityContext
+ ?: throw RuntimeException("Failed to obtain TaskbarActivityContext.")
+ }
+
+ override fun apply(base: Statement, method: FrameworkMethod, target: Any): Statement {
+ return object : Statement() {
+ override fun evaluate() {
+ this@TaskbarUnitTestRule.target = target
+
+ val context = instrumentation.targetContext
+ instrumentation.runOnMainSync {
+ assumeTrue(
+ LauncherAppState.getIDP(context).getDeviceProfile(context).isTaskbarPresent
+ )
+ }
+
+ // Check for existing Taskbar instance from Launcher process.
+ val launcherTaskbarManager: TaskbarManager? =
+ if (!isRunningInRobolectric) {
+ try {
+ val tisBinder =
+ serviceTestRule.bindService(
+ Intent(context, TouchInteractionService::class.java)
+ ) as? TISBinder
+ tisBinder?.taskbarManager
+ } catch (_: Exception) {
+ null
+ }
+ } else {
+ null
+ }
+
+ instrumentation.runOnMainSync {
+ taskbarManager =
+ TaskbarManager(
+ context,
+ AllAppsActionManager(context, UI_HELPER_EXECUTOR) {
+ PendingIntent(IIntentSender.Default())
+ },
+ object : TaskbarNavButtonCallbacks {},
+ )
+ }
+
+ try {
+ // Replace Launcher Taskbar window with test instance.
+ instrumentation.runOnMainSync {
+ launcherTaskbarManager?.removeTaskbarRootViewFromWindow()
+ taskbarManager.onUserUnlocked() // Required to complete initialization.
+ }
+
+ injectControllers()
+ base.evaluate()
+ } finally {
+ // Revert Taskbar window.
+ instrumentation.runOnMainSync {
+ taskbarManager.destroy()
+ launcherTaskbarManager?.addTaskbarRootViewToWindow()
+ }
+ }
+ }
+ }
+ }
+
+ /** Simulates Taskbar recreation lifecycle. */
+ fun recreateTaskbar() {
+ taskbarManager.recreateTaskbar()
+ injectControllers()
+ }
+
+ private fun injectControllers() {
+ val controllers = activityContext.controllers
+ val controllerFieldsByType = controllers.javaClass.fields.associateBy { it.type }
+ target.javaClass.fields
+ .filter { it.isAnnotationPresent(InjectController::class.java) }
+ .forEach {
+ it.set(
+ target,
+ controllerFieldsByType[it.type]?.get(controllers)
+ ?: throw NoSuchElementException("Failed to find controller for ${it.type}"),
+ )
+ }
+ }
+
+ /**
+ * Annotates test controller fields to inject the corresponding controllers from the current
+ * [TaskbarControllers] instance.
+ *
+ * Controllers are injected during test setup and upon calling [recreateTaskbar].
+ *
+ * Multiple controllers can be injected if needed.
+ */
+ @Retention(AnnotationRetention.RUNTIME)
+ @Target(AnnotationTarget.FIELD)
+ annotation class InjectController
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
index 49e54fb..cc579ab 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/bubbles/animation/BubbleBarViewAnimatorTest.kt
@@ -392,7 +392,8 @@
overflowView.setOverflow(BubbleBarOverflow(overflowView), bitmap)
bubbleBarView.addView(overflowView)
- val bubbleInfo = BubbleInfo("key", 0, null, null, 0, context.packageName, null, false)
+ val bubbleInfo =
+ BubbleInfo("key", 0, null, null, 0, context.packageName, null, null, false)
bubbleView =
inflater.inflate(R.layout.bubblebar_item_view, bubbleBarView, false) as BubbleView
bubble =
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayControllerTest.kt
new file mode 100644
index 0000000..eebd8f9
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/overlay/TaskbarOverlayControllerTest.kt
@@ -0,0 +1,252 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.taskbar.overlay
+
+import android.app.ActivityManager.RunningTaskInfo
+import android.view.MotionEvent
+import androidx.test.annotation.UiThreadTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
+import com.android.launcher3.AbstractFloatingView
+import com.android.launcher3.AbstractFloatingView.TYPE_OPTIONS_POPUP
+import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS
+import com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY
+import com.android.launcher3.AbstractFloatingView.hasOpenView
+import com.android.launcher3.taskbar.TaskbarActivityContext
+import com.android.launcher3.taskbar.TaskbarUnitTestRule
+import com.android.launcher3.taskbar.TaskbarUnitTestRule.InjectController
+import com.android.launcher3.util.LauncherMultivalentJUnit
+import com.android.launcher3.util.LauncherMultivalentJUnit.EmulatedDevices
+import com.android.launcher3.views.BaseDragLayer
+import com.android.systemui.shared.system.TaskStackChangeListeners
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(LauncherMultivalentJUnit::class)
+@EmulatedDevices(["pixelFoldable2023"])
+class TaskbarOverlayControllerTest {
+
+ @get:Rule val taskbarUnitTestRule = TaskbarUnitTestRule()
+ @InjectController lateinit var overlayController: TaskbarOverlayController
+
+ private val taskbarContext: TaskbarActivityContext
+ get() = taskbarUnitTestRule.activityContext
+
+ @Test
+ @UiThreadTest
+ fun testRequestWindow_twice_reusesWindow() {
+ val context1 = overlayController.requestWindow()
+ val context2 = overlayController.requestWindow()
+ assertThat(context1).isSameInstanceAs(context2)
+ }
+
+ @Test
+ @UiThreadTest
+ fun testRequestWindow_afterHidingExistingWindow_createsNewWindow() {
+ val context1 = overlayController.requestWindow()
+ overlayController.hideWindow()
+
+ val context2 = overlayController.requestWindow()
+ assertThat(context1).isNotSameInstanceAs(context2)
+ }
+
+ @Test
+ @UiThreadTest
+ fun testRequestWindow_afterHidingOverlay_createsNewWindow() {
+ val context1 = overlayController.requestWindow()
+ TestOverlayView.show(context1)
+ overlayController.hideWindow()
+
+ val context2 = overlayController.requestWindow()
+ assertThat(context1).isNotSameInstanceAs(context2)
+ }
+
+ @Test
+ @UiThreadTest
+ fun testRequestWindow_addsProxyView() {
+ TestOverlayView.show(overlayController.requestWindow())
+ assertThat(hasOpenView(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)).isTrue()
+ }
+
+ @Test
+ @UiThreadTest
+ fun testRequestWindow_closeProxyView_closesOverlay() {
+ val overlay = TestOverlayView.show(overlayController.requestWindow())
+ AbstractFloatingView.closeOpenContainer(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)
+ assertThat(overlay.isOpen).isFalse()
+ }
+
+ @Test
+ fun testRequestWindow_attachesDragLayer() {
+ lateinit var dragLayer: BaseDragLayer<*>
+ getInstrumentation().runOnMainSync {
+ dragLayer = overlayController.requestWindow().dragLayer
+ }
+
+ // Allow drag layer to attach before checking.
+ getInstrumentation().runOnMainSync { assertThat(dragLayer.isAttachedToWindow).isTrue() }
+ }
+
+ @Test
+ @UiThreadTest
+ fun testHideWindow_closesOverlay() {
+ val overlay = TestOverlayView.show(overlayController.requestWindow())
+ overlayController.hideWindow()
+ assertThat(overlay.isOpen).isFalse()
+ }
+
+ @Test
+ fun testHideWindow_detachesDragLayer() {
+ lateinit var dragLayer: BaseDragLayer<*>
+ getInstrumentation().runOnMainSync {
+ dragLayer = overlayController.requestWindow().dragLayer
+ }
+
+ // Wait for drag layer to be attached to window before hiding.
+ getInstrumentation().runOnMainSync {
+ overlayController.hideWindow()
+ assertThat(dragLayer.isAttachedToWindow).isFalse()
+ }
+ }
+
+ @Test
+ @UiThreadTest
+ fun testTwoOverlays_closeOne_windowStaysOpen() {
+ val context = overlayController.requestWindow()
+ val overlay1 = TestOverlayView.show(context)
+ val overlay2 = TestOverlayView.show(context)
+
+ overlay1.close(false)
+ assertThat(overlay2.isOpen).isTrue()
+ assertThat(hasOpenView(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)).isTrue()
+ }
+
+ @Test
+ @UiThreadTest
+ fun testTwoOverlays_closeAll_closesWindow() {
+ val context = overlayController.requestWindow()
+ val overlay1 = TestOverlayView.show(context)
+ val overlay2 = TestOverlayView.show(context)
+
+ overlay1.close(false)
+ overlay2.close(false)
+ assertThat(hasOpenView(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)).isFalse()
+ }
+
+ @Test
+ @UiThreadTest
+ fun testRecreateTaskbar_closesWindow() {
+ TestOverlayView.show(overlayController.requestWindow())
+ taskbarUnitTestRule.recreateTaskbar()
+ assertThat(hasOpenView(taskbarContext, TYPE_TASKBAR_OVERLAY_PROXY)).isFalse()
+ }
+
+ @Test
+ fun testTaskMovedToFront_closesOverlay() {
+ lateinit var overlay: TestOverlayView
+ getInstrumentation().runOnMainSync {
+ overlay = TestOverlayView.show(overlayController.requestWindow())
+ }
+
+ TaskStackChangeListeners.getInstance().listenerImpl.onTaskMovedToFront(RunningTaskInfo())
+ // Make sure TaskStackChangeListeners' Handler posts the callback before checking state.
+ getInstrumentation().runOnMainSync { assertThat(overlay.isOpen).isFalse() }
+ }
+
+ @Test
+ fun testTaskStackChanged_allAppsClosed_overlayStaysOpen() {
+ lateinit var overlay: TestOverlayView
+ getInstrumentation().runOnMainSync {
+ overlay = TestOverlayView.show(overlayController.requestWindow())
+ taskbarContext.controllers.sharedState?.allAppsVisible = false
+ }
+
+ TaskStackChangeListeners.getInstance().listenerImpl.onTaskStackChanged()
+ getInstrumentation().runOnMainSync { assertThat(overlay.isOpen).isTrue() }
+ }
+
+ @Test
+ fun testTaskStackChanged_allAppsOpen_closesOverlay() {
+ lateinit var overlay: TestOverlayView
+ getInstrumentation().runOnMainSync {
+ overlay = TestOverlayView.show(overlayController.requestWindow())
+ taskbarContext.controllers.sharedState?.allAppsVisible = true
+ }
+
+ TaskStackChangeListeners.getInstance().listenerImpl.onTaskStackChanged()
+ getInstrumentation().runOnMainSync { assertThat(overlay.isOpen).isFalse() }
+ }
+
+ @Test
+ @UiThreadTest
+ fun testUpdateLauncherDeviceProfile_overlayNotRebindSafe_closesOverlay() {
+ val overlayContext = overlayController.requestWindow()
+ val overlay = TestOverlayView.show(overlayContext).apply { type = TYPE_OPTIONS_POPUP }
+
+ overlayController.updateLauncherDeviceProfile(
+ overlayController.launcherDeviceProfile
+ .toBuilder(overlayContext)
+ .setGestureMode(false)
+ .build()
+ )
+
+ assertThat(overlay.isOpen).isFalse()
+ }
+
+ @Test
+ @UiThreadTest
+ fun testUpdateLauncherDeviceProfile_overlayRebindSafe_overlayStaysOpen() {
+ val overlayContext = overlayController.requestWindow()
+ val overlay = TestOverlayView.show(overlayContext).apply { type = TYPE_TASKBAR_ALL_APPS }
+
+ overlayController.updateLauncherDeviceProfile(
+ overlayController.launcherDeviceProfile
+ .toBuilder(overlayContext)
+ .setGestureMode(false)
+ .build()
+ )
+
+ assertThat(overlay.isOpen).isTrue()
+ }
+
+ private class TestOverlayView
+ private constructor(
+ private val overlayContext: TaskbarOverlayContext,
+ ) : AbstractFloatingView(overlayContext, null) {
+
+ var type = TYPE_OPTIONS_POPUP
+
+ private fun show() {
+ mIsOpen = true
+ overlayContext.dragLayer.addView(this)
+ }
+
+ override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean = false
+
+ override fun handleClose(animate: Boolean) = overlayContext.dragLayer.removeView(this)
+
+ override fun isOfType(type: Int): Boolean = (type and this.type) != 0
+
+ companion object {
+ /** Adds a generic View to the Overlay window for testing. */
+ fun show(context: TaskbarOverlayContext): TestOverlayView {
+ return TestOverlayView(context).apply { show() }
+ }
+ }
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentTasksDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentTasksDataSource.kt
new file mode 100644
index 0000000..eaeb513
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeRecentTasksDataSource.kt
@@ -0,0 +1,33 @@
+/*
+ * 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 com.android.quickstep.util.GroupTask
+import java.util.function.Consumer
+
+class FakeRecentTasksDataSource : RecentTasksDataSource {
+ var taskList: List<GroupTask> = listOf()
+
+ override fun getTasks(callback: Consumer<List<GroupTask>>?): Int {
+ callback?.accept(taskList)
+ return 0
+ }
+
+ fun seedTasks(tasks: List<GroupTask>) {
+ taskList = tasks
+ }
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
new file mode 100644
index 0000000..b66b735
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTaskThumbnailDataSource.kt
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.quickstep.recents.data
+
+import android.graphics.Bitmap
+import com.android.launcher3.util.CancellableTask
+import com.android.quickstep.task.thumbnail.data.TaskThumbnailDataSource
+import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import java.util.function.Consumer
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+class FakeTaskThumbnailDataSource : TaskThumbnailDataSource {
+
+ val taskIdToBitmap: Map<Int, Bitmap> = (0..10).associateWith { mock() }
+ val taskIdToUpdatingTask: MutableMap<Int, () -> Unit> = mutableMapOf()
+ var shouldLoadSynchronously: Boolean = true
+
+ /** Retrieves and sets a thumbnail on [task] from [taskIdToBitmap]. */
+ override fun updateThumbnailInBackground(
+ task: Task,
+ callback: Consumer<ThumbnailData>
+ ): CancellableTask<ThumbnailData>? {
+ val thumbnailData = mock<ThumbnailData>()
+ whenever(thumbnailData.thumbnail).thenReturn(taskIdToBitmap[task.key.id])
+ val wrappedCallback = {
+ task.thumbnail = thumbnailData
+ callback.accept(thumbnailData)
+ }
+ if (shouldLoadSynchronously) {
+ wrappedCallback()
+ } else {
+ taskIdToUpdatingTask[task.key.id] = wrappedCallback
+ }
+ return null
+ }
+}
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
new file mode 100644
index 0000000..e160627
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/FakeTasksRepository.kt
@@ -0,0 +1,47 @@
+/*
+ * 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 com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.map
+
+class FakeTasksRepository : RecentTasksRepository {
+ private var thumbnailDataMap: Map<Int, ThumbnailData> = emptyMap()
+ private var tasks: MutableStateFlow<List<Task>> = MutableStateFlow(emptyList())
+ private var visibleTasks: MutableStateFlow<List<Int>> = MutableStateFlow(emptyList())
+
+ override fun getAllTaskData(forceRefresh: Boolean): Flow<List<Task>> = tasks
+
+ override fun getTaskDataById(taskId: Int): Flow<Task?> =
+ getAllTaskData().map { taskList -> taskList.firstOrNull { it.key.id == taskId } }
+
+ override fun setVisibleTasks(visibleTaskIdList: List<Int>) {
+ visibleTasks.value = visibleTaskIdList
+ tasks.value = tasks.value.map { it.apply { thumbnail = thumbnailDataMap[it.key.id] } }
+ }
+
+ fun seedTasks(tasks: List<Task>) {
+ this.tasks.value = tasks
+ }
+
+ fun seedThumbnailData(thumbnailDataMap: Map<Int, ThumbnailData>) {
+ this.thumbnailDataMap = thumbnailDataMap
+ }
+}
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
new file mode 100644
index 0000000..c28a85a
--- /dev/null
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/recents/data/TasksRepositoryTest.kt
@@ -0,0 +1,150 @@
+/*
+ * 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.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
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.flow.drop
+import kotlinx.coroutines.flow.first
+import kotlinx.coroutines.flow.toList
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Test
+import org.mockito.kotlin.mock
+
+@OptIn(ExperimentalCoroutinesApi::class)
+class TasksRepositoryTest {
+ private val tasks = (0..5).map(::createTaskWithId)
+ private val defaultTaskList =
+ listOf(
+ GroupTask(tasks[0]),
+ GroupTask(tasks[1], tasks[2], null),
+ DesktopTask(tasks.subList(3, 6))
+ )
+ private val recentsModel = FakeRecentTasksDataSource()
+ private val taskThumbnailDataSource = FakeTaskThumbnailDataSource()
+ private val taskIconCache = mock<TaskIconCache>()
+
+ private val systemUnderTest =
+ TasksRepository(recentsModel, taskThumbnailDataSource, taskIconCache)
+
+ @Test
+ fun getAllTaskDataReturnsFlattenedListOfTasks() = runTest {
+ recentsModel.seedTasks(defaultTaskList)
+
+ assertThat(systemUnderTest.getAllTaskData(forceRefresh = true).first()).isEqualTo(tasks)
+ }
+
+ @Test
+ fun getTaskDataByIdReturnsSpecificTask() = runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ assertThat(systemUnderTest.getTaskDataById(2).first()).isEqualTo(tasks[2])
+ }
+
+ @Test
+ fun setVisibleTasksPopulatesThumbnails() = runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap1 = taskThumbnailDataSource.taskIdToBitmap[1]
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ // .drop(1) to ignore initial null content before from thumbnail was loaded.
+ assertThat(systemUnderTest.getTaskDataById(1).drop(1).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap1)
+ assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap2)
+ }
+
+ @Test
+ fun changingVisibleTasksContainsAlreadyPopulatedThumbnails() = runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ 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)
+
+ // Prevent new loading of Bitmaps
+ taskThumbnailDataSource.shouldLoadSynchronously = false
+ systemUnderTest.setVisibleTasks(listOf(2, 3))
+
+ assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail!!.thumbnail)
+ .isEqualTo(bitmap2)
+ }
+
+ @Test
+ fun retrievedThumbnailsAreDiscardedWhenTaskBecomesInvisible() = runTest {
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+
+ 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)
+
+ // Prevent new loading of Bitmaps
+ taskThumbnailDataSource.shouldLoadSynchronously = false
+ systemUnderTest.setVisibleTasks(listOf(0, 1))
+
+ assertThat(systemUnderTest.getTaskDataById(2).first()!!.thumbnail).isNull()
+ }
+
+ @Test
+ fun retrievedThumbnailsCauseEmissionOnTaskDataFlow() = runTest {
+ // Setup fakes
+ recentsModel.seedTasks(defaultTaskList)
+ val bitmap2 = taskThumbnailDataSource.taskIdToBitmap[2]
+ taskThumbnailDataSource.shouldLoadSynchronously = false
+
+ // Setup TasksRepository
+ systemUnderTest.getAllTaskData(forceRefresh = true)
+ systemUnderTest.setVisibleTasks(listOf(1, 2))
+
+ // Assert there is no bitmap in first emission
+ val taskFlow = systemUnderTest.getTaskDataById(2)
+ val taskFlowValuesList = mutableListOf<Task?>()
+ backgroundScope.launch(UnconfinedTestDispatcher(testScheduler)) {
+ taskFlow.toList(taskFlowValuesList)
+ }
+ assertThat(taskFlowValuesList[0]!!.thumbnail).isNull()
+
+ // Simulate bitmap loading after first emission
+ taskThumbnailDataSource.taskIdToUpdatingTask.getValue(2).invoke()
+
+ // Check for second emission
+ assertThat(taskFlowValuesList[1]!!.thumbnail!!.thumbnail).isEqualTo(bitmap2)
+ }
+
+ private fun createTaskWithId(taskId: Int) =
+ Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000))
+}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
index efd7bec..3b8754c 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/task/thumbnail/TaskThumbnailViewModelTest.kt
@@ -16,33 +16,51 @@
package com.android.quickstep.task.thumbnail
+import android.content.ComponentName
+import android.content.Intent
+import android.graphics.Bitmap
+import android.graphics.Color
+import android.graphics.Rect
import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.quickstep.recents.data.FakeTasksRepository
import com.android.quickstep.recents.viewmodel.RecentsViewData
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.BackgroundOnly
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Snapshot
+import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
import com.android.quickstep.task.viewmodel.TaskViewData
import com.android.systemui.shared.recents.model.Task
+import com.android.systemui.shared.recents.model.ThumbnailData
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.test.runTest
import org.junit.Test
import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
@RunWith(AndroidJUnit4::class)
class TaskThumbnailViewModelTest {
private val recentsViewData = RecentsViewData()
private val taskViewData = TaskViewData()
- private val systemUnderTest = TaskThumbnailViewModel(recentsViewData, taskViewData)
+ private val tasksRepository = FakeTasksRepository()
+ private val systemUnderTest =
+ TaskThumbnailViewModel(recentsViewData, taskViewData, tasksRepository)
+
+ private val tasks = (0..5).map(::createTaskWithId)
@Test
fun initialStateIsUninitialized() = runTest {
- assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.Uninitialized)
+ assertThat(systemUnderTest.uiState.first()).isEqualTo(Uninitialized)
}
@Test
fun bindRunningTask_thenStateIs_LiveTile() = runTest {
- val taskThumbnail = TaskThumbnail(Task(), isRunning = true)
+ tasksRepository.seedTasks(tasks)
+ val taskThumbnail = TaskThumbnail(taskId = 1, isRunning = true)
systemUnderTest.bind(taskThumbnail)
- assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.LiveTile)
+ assertThat(systemUnderTest.uiState.first()).isEqualTo(LiveTile)
}
@Test
@@ -65,15 +83,96 @@
}
@Test
- fun bindRunningTaskThenStoppedTask_thenStateIs_Uninitialized() = runTest {
- // TODO(b/334825222): Change the expectation here when snapshot state is implemented
- val task = Task()
- val runningTask = TaskThumbnail(task, isRunning = true)
- val stoppedTask = TaskThumbnail(task, isRunning = false)
- systemUnderTest.bind(runningTask)
- assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.LiveTile)
+ fun bindRunningTaskThenStoppedTaskWithoutThumbnail_thenStateChangesToBackgroundOnly() =
+ runTest {
+ tasksRepository.seedTasks(tasks)
+ val runningTask = TaskThumbnail(taskId = 1, isRunning = true)
+ val stoppedTask = TaskThumbnail(taskId = 2, isRunning = false)
+ systemUnderTest.bind(runningTask)
+ assertThat(systemUnderTest.uiState.first()).isEqualTo(LiveTile)
+
+ systemUnderTest.bind(stoppedTask)
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(BackgroundOnly(backgroundColor = Color.rgb(2, 2, 2)))
+ }
+
+ @Test
+ fun bindStoppedTaskWithoutThumbnail_thenStateIs_BackgroundOnly_withAlphaRemoved() = runTest {
+ tasksRepository.seedTasks(tasks)
+ val stoppedTask = TaskThumbnail(taskId = 2, isRunning = false)
systemUnderTest.bind(stoppedTask)
- assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.Uninitialized)
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(BackgroundOnly(backgroundColor = Color.rgb(2, 2, 2)))
+ }
+
+ @Test
+ fun bindLockedTaskWithThumbnail_thenStateIs_BackgroundOnly() = runTest {
+ tasksRepository.seedThumbnailData(mapOf(2 to createThumbnailData()))
+ tasks[2].isLocked = true
+ tasksRepository.seedTasks(tasks)
+ val recentTask = TaskThumbnail(taskId = 2, isRunning = false)
+
+ systemUnderTest.bind(recentTask)
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(BackgroundOnly(backgroundColor = Color.rgb(2, 2, 2)))
+ }
+
+ @Test
+ fun bindStoppedTaskWithThumbnail_thenStateIs_Snapshot_withAlphaRemoved() = runTest {
+ val expectedThumbnailData = createThumbnailData()
+ tasksRepository.seedThumbnailData(mapOf(2 to expectedThumbnailData))
+ tasksRepository.seedTasks(tasks)
+ tasksRepository.setVisibleTasks(listOf(2))
+ val recentTask = TaskThumbnail(taskId = 2, isRunning = false)
+
+ systemUnderTest.bind(recentTask)
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(
+ Snapshot(
+ backgroundColor = Color.rgb(2, 2, 2),
+ bitmap = expectedThumbnailData.thumbnail!!,
+ drawnRect = Rect(0, 0, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT)
+ )
+ )
+ }
+
+ @Test
+ fun bindNonVisibleStoppedTask_whenMadeVisible_thenStateIsSnapshot() = runTest {
+ val expectedThumbnailData = createThumbnailData()
+ tasksRepository.seedThumbnailData(mapOf(2 to expectedThumbnailData))
+ tasksRepository.seedTasks(tasks)
+ val recentTask = TaskThumbnail(taskId = 2, isRunning = false)
+
+ systemUnderTest.bind(recentTask)
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(BackgroundOnly(backgroundColor = Color.rgb(2, 2, 2)))
+ tasksRepository.setVisibleTasks(listOf(2))
+ assertThat(systemUnderTest.uiState.first())
+ .isEqualTo(
+ Snapshot(
+ backgroundColor = Color.rgb(2, 2, 2),
+ bitmap = expectedThumbnailData.thumbnail!!,
+ drawnRect = Rect(0, 0, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT)
+ )
+ )
+ }
+
+ private fun createTaskWithId(taskId: Int) =
+ Task(Task.TaskKey(taskId, 0, Intent(), ComponentName("", ""), 0, 2000)).apply {
+ colorBackground = Color.argb(taskId, taskId, taskId, taskId)
+ }
+
+ private fun createThumbnailData(): ThumbnailData {
+ val bitmap = mock<Bitmap>()
+ whenever(bitmap.width).thenReturn(THUMBNAIL_WIDTH)
+ whenever(bitmap.height).thenReturn(THUMBNAIL_HEIGHT)
+
+ return ThumbnailData(thumbnail = bitmap)
+ }
+
+ companion object {
+ const val THUMBNAIL_WIDTH = 100
+ const val THUMBNAIL_HEIGHT = 200
}
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
index 0de5f19..aa08ca4 100644
--- a/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/util/SplitSelectStateControllerTest.kt
@@ -31,7 +31,6 @@
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.statehandlers.DepthController
import com.android.launcher3.statemanager.StateManager
-import com.android.launcher3.statemanager.StatefulActivity
import com.android.launcher3.util.ComponentKey
import com.android.launcher3.util.SplitConfigurationOptions
import com.android.quickstep.RecentsModel
@@ -121,7 +120,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(nonMatchingComponent),
false /* findExactPairMatch */,
@@ -174,7 +173,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent),
false /* findExactPairMatch */,
@@ -215,7 +214,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(nonPrimaryUserComponent),
false /* findExactPairMatch */,
@@ -271,7 +270,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(nonPrimaryUserComponent),
false /* findExactPairMatch */,
@@ -324,7 +323,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent),
false /* findExactPairMatch */,
@@ -378,7 +377,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(nonMatchingComponent, matchingComponent),
false /* findExactPairMatch */,
@@ -431,7 +430,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent, matchingComponent),
false /* findExactPairMatch */,
@@ -497,7 +496,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent, matchingComponent),
false /* findExactPairMatch */,
@@ -549,7 +548,7 @@
// Capture callback from recentsModel#getTasks()
val consumer =
- argumentCaptor<Consumer<ArrayList<GroupTask>>> {
+ argumentCaptor<Consumer<List<GroupTask>>> {
splitSelectStateController.findLastActiveTasksAndRunCallback(
listOf(matchingComponent2, matchingComponent),
true /* findExactPairMatch */,
diff --git a/quickstep/tests/multivalentTestsForDeviceless b/quickstep/tests/multivalentTestsForDeviceless
deleted file mode 120000
index fa0fabf..0000000
--- a/quickstep/tests/multivalentTestsForDeviceless
+++ /dev/null
@@ -1 +0,0 @@
-./multivalentTests
\ No newline at end of file
diff --git a/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java b/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
index 8702f70..7b57c81 100644
--- a/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
+++ b/quickstep/tests/src/com/android/launcher3/model/WidgetsPredicationUpdateTaskTest.java
@@ -184,7 +184,7 @@
}
@Test
- public void widgetsRecommendationRan_shouldReturnPackageWidgetsWhenEmpty() {
+ public void widgetsRecommendationRan_shouldReturnEmptyWidgetsWhenEmpty() {
runOnExecutorSync(MODEL_EXECUTOR, () -> {
// Not installed widget
@@ -204,19 +204,12 @@
newWidgetsPredicationTask(List.of(widget5, widget3, widget4, widget1)));
runOnExecutorSync(MAIN_EXECUTOR, () -> { });
- // THEN only 2 widgets are returned because the launcher only filters out
- // non-exist widgets.
+ // Only widgets suggested by prediction system are returned.
List<PendingAddWidgetInfo> recommendedWidgets = mCallback.mRecommendedWidgets.items
.stream()
.map(itemInfo -> (PendingAddWidgetInfo) itemInfo)
.collect(Collectors.toList());
- assertThat(recommendedWidgets).hasSize(2);
- recommendedWidgets.forEach(pendingAddWidgetInfo ->
- assertThat(pendingAddWidgetInfo.recommendationCategory).isNotNull()
- );
- // Another widget from the same package
- assertWidgetInfo(recommendedWidgets.get(0).info, mApp4Provider2);
- assertWidgetInfo(recommendedWidgets.get(1).info, mApp1Provider1);
+ assertThat(recommendedWidgets).hasSize(0);
});
}
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
similarity index 70%
rename from quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
rename to quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
index 4fafde8..104263a 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/DesktopTaskbarRunningAppsControllerTest.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
@@ -37,7 +37,7 @@
import org.mockito.kotlin.whenever
@RunWith(AndroidTestingRunner::class)
-class DesktopTaskbarRunningAppsControllerTest : TaskbarBaseTestCase() {
+class TaskbarRecentAppsControllerTest : TaskbarBaseTestCase() {
@get:Rule val mockitoRule = MockitoJUnit.rule()
@@ -46,19 +46,18 @@
private var nextTaskId: Int = 500
- private lateinit var taskbarRunningAppsController: DesktopTaskbarRunningAppsController
+ private lateinit var recentAppsController: TaskbarRecentAppsController
private lateinit var userHandle: UserHandle
@Before
fun setUp() {
super.setup()
userHandle = Process.myUserHandle()
- taskbarRunningAppsController =
- DesktopTaskbarRunningAppsController(mockRecentsModel) {
- mockDesktopVisibilityController
- }
- taskbarRunningAppsController.init(taskbarControllers)
- taskbarRunningAppsController.setApps(
+ recentAppsController =
+ TaskbarRecentAppsController(mockRecentsModel) { mockDesktopVisibilityController }
+ recentAppsController.init(taskbarControllers)
+ recentAppsController.isEnabled = true
+ recentAppsController.setApps(
ALL_APP_PACKAGES.map { createTestAppInfo(packageName = it) }.toTypedArray()
)
}
@@ -69,7 +68,7 @@
val hotseatItems =
createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
- assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
+ assertThat(recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
.isEqualTo(hotseatItems.toTypedArray())
}
@@ -81,12 +80,13 @@
val runningTasks =
createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
- taskbarRunningAppsController.updateRunningApps()
+ recentAppsController.updateRunningApps()
val newHotseatItems =
- taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+ recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
- assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(hotseatPackages)
+ assertThat(newHotseatItems.map { it?.targetPackage })
+ .containsExactlyElementsIn(hotseatPackages)
}
@Test
@@ -95,7 +95,7 @@
val hotseatItems =
createHotseatItemsFromPackageNames(listOf(HOTSEAT_PACKAGE_1, HOTSEAT_PACKAGE_2))
- assertThat(taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
+ assertThat(recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray()))
.isEqualTo(hotseatItems.toTypedArray())
}
@@ -107,10 +107,10 @@
val runningTasks =
createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
- taskbarRunningAppsController.updateRunningApps()
+ recentAppsController.updateRunningApps()
val newHotseatItems =
- taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+ recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
val expectedPackages =
listOf(
@@ -119,7 +119,8 @@
RUNNING_APP_PACKAGE_1,
RUNNING_APP_PACKAGE_2,
)
- assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(expectedPackages)
+ assertThat(newHotseatItems.map { it?.targetPackage })
+ .containsExactlyElementsIn(expectedPackages)
}
@Test
@@ -132,10 +133,10 @@
listOf(HOTSEAT_PACKAGE_1, RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
)
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
- taskbarRunningAppsController.updateRunningApps()
+ recentAppsController.updateRunningApps()
val newHotseatItems =
- taskbarRunningAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
+ recentAppsController.updateHotseatItemInfos(hotseatItems.toTypedArray())
val expectedPackages =
listOf(
@@ -144,7 +145,8 @@
RUNNING_APP_PACKAGE_1,
RUNNING_APP_PACKAGE_2,
)
- assertThat(newHotseatItems.map { it?.targetPackage }).isEqualTo(expectedPackages)
+ assertThat(newHotseatItems.map { it?.targetPackage })
+ .containsExactlyElementsIn(expectedPackages)
}
@Test
@@ -153,9 +155,10 @@
val runningTasks =
createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
- taskbarRunningAppsController.updateRunningApps()
+ recentAppsController.updateRunningApps()
- assertThat(taskbarRunningAppsController.runningApps).isEqualTo(emptySet<String>())
+ assertThat(recentAppsController.runningApps).isEmpty()
+ assertThat(recentAppsController.minimizedApps).isEmpty()
}
@Test
@@ -164,10 +167,30 @@
val runningTasks =
createDesktopTasksFromPackageNames(listOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
- taskbarRunningAppsController.updateRunningApps()
+ recentAppsController.updateRunningApps()
- assertThat(taskbarRunningAppsController.runningApps)
- .isEqualTo(setOf(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2))
+ assertThat(recentAppsController.runningApps)
+ .containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2)
+ assertThat(recentAppsController.minimizedApps).isEmpty()
+ }
+
+ @Test
+ fun getMinimizedApps_inDesktopMode_returnsAllAppsRunningAndInvisibleAppsMinimized() {
+ setInDesktopMode(true)
+ val runningTasks =
+ ArrayList(
+ listOf(
+ createDesktopTaskInfo(RUNNING_APP_PACKAGE_1) { isVisible = true },
+ createDesktopTaskInfo(RUNNING_APP_PACKAGE_2) { isVisible = true },
+ createDesktopTaskInfo(RUNNING_APP_PACKAGE_3) { isVisible = false },
+ )
+ )
+ whenever(mockRecentsModel.runningTasks).thenReturn(runningTasks)
+ recentAppsController.updateRunningApps()
+
+ assertThat(recentAppsController.runningApps)
+ .containsExactly(RUNNING_APP_PACKAGE_1, RUNNING_APP_PACKAGE_2, RUNNING_APP_PACKAGE_3)
+ assertThat(recentAppsController.minimizedApps).containsExactly(RUNNING_APP_PACKAGE_3)
}
private fun createHotseatItemsFromPackageNames(packageNames: List<String>): List<ItemInfo> {
@@ -180,11 +203,15 @@
return ArrayList(packageNames.map { createDesktopTaskInfo(packageName = it) })
}
- private fun createDesktopTaskInfo(packageName: String): RunningTaskInfo {
+ private fun createDesktopTaskInfo(
+ packageName: String,
+ init: RunningTaskInfo.() -> Unit = { isVisible = true },
+ ): RunningTaskInfo {
return RunningTaskInfo().apply {
taskId = nextTaskId++
configuration.windowConfiguration.windowingMode = WINDOWING_MODE_FREEFORM
realActivity = ComponentName(packageName, "TestActivity")
+ init()
}
}
diff --git a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
index 36f2ccf..50b5df1 100644
--- a/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/DesktopSystemShortcutTest.kt
@@ -38,6 +38,7 @@
import com.android.systemui.shared.recents.model.Task
import com.android.systemui.shared.recents.model.Task.TaskKey
import com.android.window.flags.Flags
+import com.android.wm.shell.common.desktopmode.DesktopModeTransitionSource
import com.android.wm.shell.shared.DesktopModeStatus
import com.google.common.truth.Truth.assertThat
import org.junit.After
@@ -152,8 +153,8 @@
whenever(launcher.statsLogManager).thenReturn(statsLogManager)
whenever(statsLogManager.logger()).thenReturn(statsLogger)
whenever(statsLogger.withItemInfo(any())).thenReturn(statsLogger)
- whenever(recentsView.moveTaskToDesktop(any(), any())).thenAnswer {
- val successCallback = it.getArgument<Runnable>(1)
+ whenever(recentsView.moveTaskToDesktop(any(), any(), any())).thenAnswer {
+ val successCallback = it.getArgument<Runnable>(2)
successCallback.run()
}
doReturn(workspaceItemInfo).whenever(taskContainer).itemInfo
@@ -169,7 +170,12 @@
val allTypesExceptRebindSafe =
AbstractFloatingView.TYPE_ALL and AbstractFloatingView.TYPE_REBIND_SAFE.inv()
verify(abstractFloatingViewHelper).closeOpenViews(launcher, true, allTypesExceptRebindSafe)
- verify(recentsView).moveTaskToDesktop(eq(taskContainer), any())
+ verify(recentsView)
+ .moveTaskToDesktop(
+ eq(taskContainer),
+ eq(DesktopModeTransitionSource.APP_FROM_OVERVIEW),
+ any()
+ )
verify(statsLogger).withItemInfo(workspaceItemInfo)
verify(statsLogger).log(LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_DESKTOP_TAP)
}
diff --git a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
index 094fd4c..4459ed6 100644
--- a/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
+++ b/quickstep/tests/src/com/android/quickstep/NavigationModeSwitchRule.java
@@ -162,8 +162,8 @@
final Context targetContext = getInstrumentation().getTargetContext();
final DisplayController.DisplayInfoChangeListener listener =
(context, info, flags) -> {
- if (LauncherInstrumentation.getNavigationModel(info.navigationMode.resValue)
- == expectedMode) {
+ if (LauncherInstrumentation.getNavigationModel(
+ info.getNavigationMode().resValue) == expectedMode) {
latch.countDown();
}
};
diff --git a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
index ed5526f..03244eb 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
+++ b/quickstep/tests/src/com/android/quickstep/RecentTasksListTest.java
@@ -48,6 +48,8 @@
@Mock
private SystemUiProxy mockSystemUiProxy;
+ @Mock
+ private TopTaskTracker mTopTaskTracker;
// Class under test
private RecentTasksList mRecentTasksList;
@@ -58,7 +60,7 @@
LooperExecutor mockMainThreadExecutor = mock(LooperExecutor.class);
KeyguardManager mockKeyguardManager = mock(KeyguardManager.class);
mRecentTasksList = new RecentTasksList(mockMainThreadExecutor, mockKeyguardManager,
- mockSystemUiProxy);
+ mockSystemUiProxy, mTopTaskTracker);
}
@Test
diff --git a/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt b/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
index 2916952..80fbce7 100644
--- a/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
+++ b/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt
@@ -9,8 +9,19 @@
import com.android.launcher3.util.DisplayController.CHANGE_ROTATION
import com.android.launcher3.util.DisplayController.Info
import com.android.launcher3.util.NavigationMode
-import com.android.launcher3.util.window.WindowManagerProxy
import com.android.quickstep.util.GestureExclusionManager
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DREAMING
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_MAGNIFICATION_OVERLAP
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED
+import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@@ -18,6 +29,7 @@
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.doReturn
import org.mockito.kotlin.verifyZeroInteractions
import org.mockito.kotlin.whenever
@@ -27,7 +39,6 @@
class RecentsAnimationDeviceStateTest {
@Mock private lateinit var exclusionManager: GestureExclusionManager
- @Mock private lateinit var windowManagerProxy: WindowManagerProxy
@Mock private lateinit var info: Info
private val context = ApplicationProvider.getApplicationContext() as Context
@@ -79,7 +90,7 @@
@Test
fun onDisplayInfoChanged_noButton_registerExclusionListener() {
- whenever(windowManagerProxy.getNavigationMode(context)).thenReturn(NavigationMode.NO_BUTTON)
+ doReturn(NavigationMode.NO_BUTTON).whenever(info).getNavigationMode()
underTest.onDisplayInfoChanged(context, info, CHANGE_ROTATION or CHANGE_NAVIGATION_MODE)
@@ -107,4 +118,88 @@
verifyZeroInteractions(exclusionManager)
}
+
+ @Test
+ fun trackpadGesturesNotAllowedForSelectedStates() {
+ val disablingStates = GESTURE_DISABLING_SYSUI_STATES +
+ SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED
+
+ allSysUiStates().forEach { state ->
+ val canStartGesture = !disablingStates.contains(state)
+ underTest.setSystemUiFlags(state)
+ assertThat(underTest.canStartTrackpadGesture()).isEqualTo(canStartGesture)
+ }
+ }
+
+ @Test
+ fun trackpadGesturesNotAllowedIfHomeAndOverviewIsDisabled() {
+ val stateToExpectedResult = mapOf(
+ SYSUI_STATE_HOME_DISABLED to true,
+ SYSUI_STATE_OVERVIEW_DISABLED to true,
+ DEFAULT_STATE
+ .enable(SYSUI_STATE_OVERVIEW_DISABLED)
+ .enable(SYSUI_STATE_HOME_DISABLED) to false
+ )
+
+ stateToExpectedResult.forEach { (state, allowed) ->
+ underTest.setSystemUiFlags(state)
+ assertThat(underTest.canStartTrackpadGesture()).isEqualTo(allowed)
+ }
+ }
+
+ @Test
+ fun systemGesturesNotAllowedForSelectedStates() {
+ val disablingStates = GESTURE_DISABLING_SYSUI_STATES + SYSUI_STATE_NAV_BAR_HIDDEN
+
+ allSysUiStates().forEach { state ->
+ val canStartGesture = !disablingStates.contains(state)
+ underTest.setSystemUiFlags(state)
+ assertThat(underTest.canStartSystemGesture()).isEqualTo(canStartGesture)
+ }
+ }
+
+ @Test
+ fun systemGesturesNotAllowedWhenGestureStateDisabledAndNavBarVisible() {
+ val stateToExpectedResult = mapOf(
+ DEFAULT_STATE
+ .enable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
+ .disable(SYSUI_STATE_NAV_BAR_HIDDEN) to true,
+ DEFAULT_STATE
+ .enable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
+ .enable(SYSUI_STATE_NAV_BAR_HIDDEN) to true,
+ DEFAULT_STATE
+ .disable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
+ .disable(SYSUI_STATE_NAV_BAR_HIDDEN) to true,
+ DEFAULT_STATE
+ .disable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY)
+ .enable(SYSUI_STATE_NAV_BAR_HIDDEN) to false,
+ )
+
+ stateToExpectedResult.forEach {(state, gestureAllowed) ->
+ underTest.setSystemUiFlags(state)
+ assertThat(underTest.canStartSystemGesture()).isEqualTo(gestureAllowed)
+ }
+ }
+
+ private fun allSysUiStates(): List<Long> {
+ // SYSUI_STATES_* are binary flags
+ return (0..SYSUI_STATES_COUNT).map { 1L shl it }
+ }
+
+ companion object {
+ private val GESTURE_DISABLING_SYSUI_STATES = listOf(
+ SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
+ SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING,
+ SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
+ SYSUI_STATE_MAGNIFICATION_OVERLAP,
+ SYSUI_STATE_DEVICE_DREAMING,
+ SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION,
+ )
+ private const val SYSUI_STATES_COUNT = 33
+ private const val DEFAULT_STATE = 0L
+ }
+
+ private fun Long.enable(state: Long) = this or state
+
+ private fun Long.disable(state: Long) = this and state.inv()
}
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index fa10b61..b7fd8be 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -88,6 +88,8 @@
}
private void createAndLaunchASplitPair() {
+ clearAllRecentTasks();
+
startTestActivity(2);
startTestActivity(3);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
index 8290508..23a29f7 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplPrivateSpaceTest.java
@@ -35,7 +35,6 @@
import com.android.launcher3.util.rule.ScreenRecordRule;
import org.junit.After;
-import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -50,6 +49,7 @@
private static final String PRIVATE_PROFILE_NAME = "LauncherPrivateProfile";
private static final String INSTALLED_APP_NAME = "Aardwolf";
+ private static final int MAX_STATE_TOGGLE_TRIES = 2;
private static final String TAG = "TaplPrivateSpaceTest";
@Override
@@ -167,14 +167,15 @@
@Test
@ScreenRecordRule.ScreenRecord // b/334946529
- @Ignore("b/339179262")
public void testPrivateSpaceLockingBehaviour() throws IOException {
// Scroll to the bottom of All Apps
executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
HomeAllApps homeAllApps = mLauncher.getAllApps();
// Disable Private Space
- togglePrivateSpace(PrivateProfileManager.STATE_DISABLED, homeAllApps);
+ togglePrivateSpaceWithRetry(PrivateProfileManager.STATE_DISABLED, homeAllApps);
+ // Scroll to the bottom of All Apps
+ executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
homeAllApps.freeze();
try {
@@ -186,7 +187,9 @@
}
// Enable Private Space
- togglePrivateSpace(PrivateProfileManager.STATE_ENABLED, homeAllApps);
+ togglePrivateSpaceWithRetry(PrivateProfileManager.STATE_ENABLED, homeAllApps);
+ // Scroll to the bottom of All Apps
+ executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
homeAllApps.freeze();
try {
@@ -219,6 +222,25 @@
waitForLauncherUIUpdate();
}
+ private void togglePrivateSpaceWithRetry(int state, HomeAllApps homeAllApps) {
+ int togglePsCount = 0;
+ boolean shouldRetry;
+ do {
+ togglePsCount ++;
+ try {
+ togglePrivateSpace(state, homeAllApps);
+ // No need to retry if the toggle was successful.
+ shouldRetry = false;
+ } catch (AssertionError error) {
+ if (togglePsCount < MAX_STATE_TOGGLE_TRIES) {
+ shouldRetry = true;
+ } else {
+ throw error;
+ }
+ }
+ } while (shouldRetry);
+ }
+
private void waitForPrivateSpaceSetup() {
waitForLauncherCondition("Private Profile not setup",
launcher -> launcher.getAppsView().hasPrivateProfile(),
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
index bfd7bdb..8adf793 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsSplitscreen.java
@@ -33,9 +33,7 @@
import com.android.launcher3.tapl.Overview;
import com.android.launcher3.tapl.Taskbar;
import com.android.launcher3.tapl.TaskbarAppIcon;
-import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.util.rule.TestStabilityRule;
-import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
import com.android.wm.shell.Flags;
import org.junit.After;
@@ -74,14 +72,6 @@
}
@Test
- @PortraitLandscape
- public void testSplitFromOverview() {
- createAndLaunchASplitPair();
- }
-
- @Test
- @PortraitLandscape
- @TaskbarModeSwitch
@TestStabilityRule.Stability(flavors = PLATFORM_POSTSUBMIT | LOCAL) // b/295225524
public void testSplitAppFromHomeWithItself() throws Exception {
// Currently only tablets have Taskbar in Overview, so test is only active on tablets
@@ -129,8 +119,6 @@
overview.getCurrentTask()
.tapMenu()
.hasMenuItem("Save app pair"));
- } else {
- overview.getOverviewGroupActions().assertHasAction("Save app pair");
}
}
@@ -154,11 +142,7 @@
// Currently only tablets have Taskbar in Overview, so test is only active on tablets
assumeTrue(mLauncher.isTablet());
- if (!mLauncher.getRecentTasks().isEmpty()) {
- // Clear all recent tasks
- mLauncher.goHome().switchToOverview().dismissAllTasks();
- }
-
+ clearAllRecentTasks();
startAppFast(getAppPackageName());
Overview overview = mLauncher.goHome().switchToOverview();
@@ -175,6 +159,8 @@
}
private void createAndLaunchASplitPair() {
+ clearAllRecentTasks();
+
startTestActivity(2);
startTestActivity(3);
diff --git a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
index e4f8b6c..2c23f86 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplTestsTrackpad.java
@@ -37,6 +37,7 @@
import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
import org.junit.After;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -47,8 +48,14 @@
private static final String READ_DEVICE_CONFIG_PERMISSION =
"android.permission.READ_DEVICE_CONFIG";
+ @Before
+ public void setup() {
+ mLauncher.injectFakeTrackpad();
+ }
+
@After
public void tearDown() {
+ mLauncher.ejectFakeTrackpad();
mLauncher.setTrackpadGestureType(TrackpadGestureType.NONE);
}
@@ -110,8 +117,8 @@
}
@Test
- @NavigationModeSwitch
@PortraitLandscape
+ @NavigationModeSwitch
public void testQuickSwitchFromHome() throws Exception {
assumeTrue(mLauncher.isTablet());
diff --git a/quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java b/quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java
deleted file mode 100644
index 208920a..0000000
--- a/quickstep/tests/src/com/android/quickstep/TaplViewInflationDuringSwipeUp.java
+++ /dev/null
@@ -1,288 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.quickstep;
-
-import static androidx.test.InstrumentationRegistry.getContext;
-import static androidx.test.InstrumentationRegistry.getInstrumentation;
-
-import static com.android.launcher3.WorkspaceLayoutManager.FIRST_SCREEN_ID;
-import static com.android.launcher3.testcomponent.TestCommandReceiver.EXTRA_VALUE;
-import static com.android.launcher3.testcomponent.TestCommandReceiver.SET_LIST_VIEW_SERVICE_BINDER;
-import static com.android.launcher3.util.WidgetUtils.createWidgetInfo;
-import static com.android.quickstep.NavigationModeSwitchRule.Mode.ZERO_BUTTON;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertTrue;
-import static org.mockito.Mockito.doAnswer;
-import static org.mockito.Mockito.spy;
-
-import android.appwidget.AppWidgetManager;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.util.Log;
-import android.util.SparseArray;
-import android.view.View;
-import android.view.ViewConfiguration;
-import android.widget.RemoteViews;
-
-import androidx.test.ext.junit.runners.AndroidJUnit4;
-import androidx.test.filters.LargeTest;
-import androidx.test.filters.Suppress;
-import androidx.test.uiautomator.By;
-import androidx.test.uiautomator.UiDevice;
-import androidx.test.uiautomator.Until;
-
-import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherModel;
-import com.android.launcher3.celllayout.FavoriteItemsTransaction;
-import com.android.launcher3.model.data.LauncherAppWidgetInfo;
-import com.android.launcher3.tapl.LaunchedAppState;
-import com.android.launcher3.testcomponent.ListViewService;
-import com.android.launcher3.testcomponent.ListViewService.SimpleViewsFactory;
-import com.android.launcher3.testcomponent.TestCommandReceiver;
-import com.android.launcher3.ui.TestViewHelpers;
-import com.android.launcher3.util.Executors;
-import com.android.launcher3.widget.LauncherAppWidgetProviderInfo;
-import com.android.quickstep.NavigationModeSwitchRule.NavigationModeSwitch;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.mockito.invocation.InvocationOnMock;
-import org.mockito.stubbing.Answer;
-
-import java.lang.reflect.Field;
-import java.util.concurrent.atomic.AtomicInteger;
-import java.util.function.IntConsumer;
-
-/**
- * Test to verify view inflation does not happen during swipe up.
- * To verify view inflation, we setup a stub ViewConfiguration and check if any call to that class
- * does from a View.init method or not.
- *
- * Alternative approaches considered:
- * Overriding LayoutInflater: This does not cover views initialized
- * directly (ex: new LinearLayout)
- * Using ExtendedMockito: Mocking static methods from platform classes (loaded in zygote) makes
- * the main thread extremely slow and untestable
- */
-@LargeTest
-@RunWith(AndroidJUnit4.class)
-public class TaplViewInflationDuringSwipeUp extends AbstractQuickStepTest {
-
- private SparseArray<ViewConfiguration> mConfigMap;
- private InitTracker mInitTracker;
- private LauncherModel mModel;
-
- @Before
- public void setUp() throws Exception {
- // Workaround for b/142351228, when there are no activities, the system may not destroy the
- // activity correctly for activities under instrumentation, which can leave two concurrent
- // activities, which changes the order in which the activities are cleaned up (overlapping
- // stop and start) leading to all sort of issues. To workaround this, ensure that the test
- // is started only after starting another app.
- startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
-
- super.setUp();
-
- mModel = LauncherAppState.getInstance(mTargetContext).getModel();
- Executors.MODEL_EXECUTOR.submit(mModel.getModelDbController()::createEmptyDB).get();
-
- // Get static configuration map
- Field field = ViewConfiguration.class.getDeclaredField("sConfigurations");
- field.setAccessible(true);
- mConfigMap = (SparseArray<ViewConfiguration>) field.get(null);
-
- mInitTracker = new InitTracker();
- }
-
- @Test
- @NavigationModeSwitch(mode = ZERO_BUTTON)
- @Suppress // until b/190618549 is fixed
- public void testSwipeUpFromApp() throws Exception {
- try {
- // Go to overview once so that all views are initialized and cached
- startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
- mLauncher.getLaunchedAppState().switchToOverview().dismissAllTasks();
-
- // Track view creations
- mInitTracker.startTracking();
-
- startTestActivity(2);
- mLauncher.getLaunchedAppState().switchToOverview();
-
- assertEquals("Views inflated during swipe up", 0, mInitTracker.viewInitCount);
- } finally {
- mConfigMap.clear();
- }
- }
-
- @Test
- @NavigationModeSwitch(mode = ZERO_BUTTON)
- @Suppress // until b/190729479 is fixed
- public void testSwipeUpFromApp_widget_update() {
- String stubText = "Some random stub text";
-
- executeSwipeUpTestWithWidget(
- widgetId -> { },
- widgetId -> AppWidgetManager.getInstance(getContext())
- .updateAppWidget(widgetId, createMainWidgetViews(stubText)),
- stubText);
- }
-
- @Test
- @NavigationModeSwitch(mode = ZERO_BUTTON)
- @Suppress // until b/190729479 is fixed
- public void testSwipeUp_with_list_widgets() {
- SimpleViewsFactory viewFactory = new SimpleViewsFactory();
- viewFactory.viewCount = 1;
- Bundle args = new Bundle();
- args.putBinder(EXTRA_VALUE, viewFactory.toBinder());
- TestCommandReceiver.callCommand(SET_LIST_VIEW_SERVICE_BINDER, null, args);
-
- try {
- executeSwipeUpTestWithWidget(
- widgetId -> {
- // Initialize widget
- RemoteViews views = createMainWidgetViews("List widget title");
- views.setRemoteAdapter(android.R.id.list,
- new Intent(getContext(), ListViewService.class));
- AppWidgetManager.getInstance(getContext()).updateAppWidget(widgetId, views);
- verifyWidget(viewFactory.getLabel(0));
- },
- widgetId -> {
- // Update widget
- viewFactory.viewCount = 2;
- AppWidgetManager.getInstance(getContext())
- .notifyAppWidgetViewDataChanged(widgetId, android.R.id.list);
- },
- viewFactory.getLabel(1)
- );
- } finally {
- TestCommandReceiver.callCommand(SET_LIST_VIEW_SERVICE_BINDER, null, new Bundle());
- }
- }
-
- private void executeSwipeUpTestWithWidget(IntConsumer widgetIdCreationCallback,
- IntConsumer updateBeforeSwipeUp, String finalWidgetText) {
- try {
- LauncherAppWidgetProviderInfo info = TestViewHelpers.findWidgetProvider(false);
-
- // Make sure the widget is big enough to show a list of items
- info.minSpanX = 2;
- info.minSpanY = 2;
- info.spanX = 2;
- info.spanY = 2;
- AtomicInteger widgetId = new AtomicInteger();
-
- commitTransactionAndLoadHome(new FavoriteItemsTransaction(mTargetContext)
- .addItem(() -> {
- LauncherAppWidgetInfo item = createWidgetInfo(info, mTargetContext, true);
- item.screenId = FIRST_SCREEN_ID;
- widgetId.set(item.appWidgetId);
- return item;
- }));
-
- assertTrue("Widget is not present",
- mLauncher.goHome().tryGetWidget(info.label, DEFAULT_UI_TIMEOUT) != null);
-
- // Verify widget id
- widgetIdCreationCallback.accept(widgetId.get());
-
- // Go to overview once so that all views are initialized and cached
- startAppFast(resolveSystemApp(Intent.CATEGORY_APP_CALCULATOR));
- mLauncher.getLaunchedAppState().switchToOverview().dismissAllTasks();
-
- // Track view creations
- mInitTracker.startTracking();
-
- startTestActivity(2);
- LaunchedAppState launchedAppState = mLauncher.getLaunchedAppState();
-
- // Update widget
- updateBeforeSwipeUp.accept(widgetId.get());
-
- launchedAppState.switchToOverview();
- assertEquals("Views inflated during swipe up", 0, mInitTracker.viewInitCount);
-
- // Widget is updated when going home
- mInitTracker.disableLog();
- mLauncher.goHome();
- verifyWidget(finalWidgetText);
- assertNotEquals(1, mInitTracker.viewInitCount);
- } finally {
- mConfigMap.clear();
- }
- }
-
- private void verifyWidget(String text) {
- assertNotNull("Widget not updated",
- UiDevice.getInstance(getInstrumentation())
- .wait(Until.findObject(By.text(text)), DEFAULT_UI_TIMEOUT));
- }
-
- private RemoteViews createMainWidgetViews(String title) {
- Context c = getContext();
- int layoutId = c.getResources().getIdentifier(
- "test_layout_widget_list", "layout", c.getPackageName());
- RemoteViews views = new RemoteViews(c.getPackageName(), layoutId);
- views.setTextViewText(android.R.id.text1, title);
- return views;
- }
-
- private class InitTracker implements Answer {
-
- public int viewInitCount = 0;
-
- public boolean log = true;
-
- @Override
- public Object answer(InvocationOnMock invocation) throws Throwable {
- Exception ex = new Exception();
-
- boolean found = false;
- for (StackTraceElement ste : ex.getStackTrace()) {
- if ("<init>".equals(ste.getMethodName())
- && View.class.getName().equals(ste.getClassName())) {
- found = true;
- break;
- }
- }
- if (found) {
- viewInitCount++;
- if (log) {
- Log.d("InitTracker", "New view inflated", ex);
- }
-
- }
- return invocation.callRealMethod();
- }
-
- public void disableLog() {
- log = false;
- }
-
- public void startTracking() {
- ViewConfiguration vc = ViewConfiguration.get(mTargetContext);
- ViewConfiguration spyVC = spy(vc);
- mConfigMap.put(mConfigMap.keyAt(mConfigMap.indexOfValue(vc)), spyVC);
- doAnswer(this).when(spyVC).getScaledTouchSlop();
- }
- }
-}
diff --git a/res/color-night-v31/taskbar_stroke.xml b/res/color-night-v31/taskbar_stroke.xml
new file mode 100644
index 0000000..db7a510
--- /dev/null
+++ b/res/color-night-v31/taskbar_stroke.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#9AA0A6" />
+</selector>
\ No newline at end of file
diff --git a/res/color/taskbar_stroke.xml b/res/color/taskbar_stroke.xml
new file mode 100644
index 0000000..b691082
--- /dev/null
+++ b/res/color/taskbar_stroke.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="#BDC1C6" />
+</selector>
\ No newline at end of file
diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml
index cefe394..9c0f129 100644
--- a/res/layout/private_space_header.xml
+++ b/res/layout/private_space_header.xml
@@ -37,7 +37,7 @@
android:gravity="center_vertical"
android:layout_alignParentEnd="true"
android:animateLayoutChanges="false">
- <ImageButton
+ <com.android.launcher3.allapps.PrivateSpaceSettingsButton
android:id="@+id/ps_settings_button"
android:layout_width="@dimen/ps_header_image_height"
android:layout_height="@dimen/ps_header_image_height"
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index b936ad0..ba50721 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Tuis"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Stoor apppaar"</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">"Hierdie apppaar word nie op hierdie toestel gesteun nie"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deïnstalleer"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Appinligting"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installeer privaat"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Deïnstalleer app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installeer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Moenie voorstel nie"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Vasspeldvoorspelling"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Privaat Ruimte-oorgang"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Installeer"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installeer apps in privaat ruimte"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Oorvloei"</string>
</resources>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 19d4604..10d68aa 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"መነሻ"</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>
<string name="save_app_pair" msgid="5647523853662686243">"የመተግበሪያ ጥምረትን ያስቀምጡ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ይህ የመተግበሪያ ጥምረት በዚህ መሣሪያ ላይ አይደገፍም"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"አራግፍ"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"የመተግበሪያ መረጃ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"በግል ይጫኑ"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"መተግበሪያን አራግፍ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ጫን"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"መተግበሪያውን አይጠቁሙ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"የፒን ግምት"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ትርፍ ፍሰት"</string>
</resources>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 500fe61..6ba2ce6 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"الشاشة الرئيسية"</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>
<string name="save_app_pair" msgid="5647523853662686243">"حفظ استخدام التطبيقين معًا"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"لا يمكن استخدام هذين التطبيقَين في الوقت نفسه على هذا الجهاز"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"إلغاء التثبيت"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"معلومات عن التطبيق"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"تثبيت في مساحة خاصّة"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"إلغاء تثبيت التطبيق"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"تثبيت"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"عدم اقتراح التطبيق"</string>
<string name="pin_prediction" msgid="4196423321649756498">"تثبيت التطبيق المتوقّع"</string>
@@ -183,7 +185,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"فلتر"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"تعذَّر <xliff:g id="WHAT">%1$s</xliff:g>."</string>
<string name="private_space_label" msgid="2359721649407947001">"مساحة خاصة"</string>
- <string name="private_space_secondary_label" msgid="9203933341714508907">"النقر للإعداد أو الفتح"</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_unlock_button_content_description" msgid="9181551784092204234">"المساحة الخاصة غير مُقفلة."</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"القائمة الكاملة"</string>
</resources>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index cb490b5..ce86039 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"গৃহ স্ক্ৰীন"</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>
<string name="save_app_pair" msgid="5647523853662686243">"এপৰ পেয়াৰ ছেভ কৰক"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"এই ডিভাইচটোত এই এপ্ পেয়াৰ কৰাৰ সুবিধাটো সমৰ্থিত নহয়"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"আনইনষ্টল কৰক"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"এপ্ সম্পৰ্কীয় তথ্য"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"গোপনে ইনষ্টল কৰক"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"এপ্ আনইনষ্টল কৰক"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ইনষ্টল কৰক"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"পৰামৰ্শ নিদিব"</string>
<string name="pin_prediction" msgid="4196423321649756498">"পূৰ্বানুমান কৰা এপ্টো পিন কৰক"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"অ’ভাৰফ্ল’"</string>
</resources>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index c6cc267..9ad053a 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Əsas səhifə"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Tətbiq cütünü saxlayın"</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">"Bu tətbiq cütü bu cihazda dəstəklənmir"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Sistemdən sil"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Tətbiq haqqında"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Məxfi quraşdırın"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Tətbiqi sistemdən silin"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Quraşdırın"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Tətbiq təklif olunmasın"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Proqnozlaşdırılan tətbiqi bərkidin"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Şəxsi məkana keçid"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Quraşdırın"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Tətbiqləri şəxsi sahədə quraşdırın"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Kənara çıxma"</string>
</resources>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index 830de4e..408a425 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Početni ekran"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Sačuvaj par aplikacija"</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">"Ovaj par aplikacija nije podržan na ovom uređaju"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Podaci o aplikaciji"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj na privatni"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Deinstalirajte aplikaciju"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Prenos privatnog prostora"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instalirajte"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instaliraj aplikacije u privatan prostor"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Preklopno"</string>
</resources>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 1a3a870..c7ed9d9 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Галоўны экран"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Захаваць спалучэнне праграм"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Дадзенае спалучэнне праграм не падтрымліваецца на гэтай прыладзе"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Дэінсталяваць"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Звесткі аб праграме"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Усталяваць прыватна"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Выдаліць праграму"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Усталяваць"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не прапаноўваць праграму"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Замацаваць прапанаваную праграму"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Дадатковае меню"</string>
</resources>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 5030e7c..ce62054 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Начален екран"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Запазване на двойката приложения"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Тази двойка приложения не се поддържа на устройството"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталиране"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Информация за прилож."</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Инстал. в частно простр."</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Деинсталиране на приложението"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталиране"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Без предлагане на приложение"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Фиксиране на предвиждането"</string>
@@ -182,15 +184,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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Препълване"</string>
</resources>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index 34edae0..a9f4585 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"হোম"</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>
<string name="save_app_pair" msgid="5647523853662686243">"অ্যাপ পেয়ার সেভ করুন"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"এই ডিভাইসে এই অ্যাপ পেয়ারটি কাজ করে না"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"আনইনস্টল করুন"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"অ্যাপের তথ্য"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"প্রাইভেট প্রোফাইলে ইনস্টল করুন"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"অ্যাপ আনইনস্টল করুন"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ইনস্টল করুন"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"অ্যাপ সাজেস্ট করবেন না"</string>
<string name="pin_prediction" msgid="4196423321649756498">"আপনার প্রয়োজন হতে পারে এমন অ্যাপ পিন করুন"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ওভারফ্লো"</string>
</resources>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 1ad9a5c..325d65d 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Početni ekran"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Sačuvaj par aplikacija"</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">"Par aplikacija nije podržan na uređaju"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Inform. o aplikaciji"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj u Privatno"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Deinstalirajte aplikaciju"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Zakači predviđanje"</string>
@@ -190,7 +192,6 @@
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privatno, zaključano."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Zaključaj"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"Prelazak u privatan prostor"</string>
- <string name="ps_add_button_label" msgid="8127988716897128773">"Instaliraj"</string>
+ <string name="ps_add_button_label" msgid="8127988716897128773">"Instalirajte"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instaliranje aplikacija u privatni prostor"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Preklopni meni"</string>
</resources>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 33f75b5..50ded7b 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Inici"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Desa la parella d\'aplicacions"</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">"Aquesta parella d\'aplicacions no s\'admet en aquest dispositiu"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstal·la"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Informació de l\'aplicació"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instal·la en privat"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstal·la l\'aplicació"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instal·la"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No suggereixis l\'aplicació"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixa la predicció"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Canvia a Espai privat"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instal·la"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instal·la les aplicacions a Espai privat"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menú addicional"</string>
</resources>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 6ac1d57..c570ef1 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Domů"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Uložit dvojici aplikací"</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">"Tento pár aplikací není na tomto zařízení podporován"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinstalovat"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"O aplikaci"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalovat soukromě"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Odinstalovat aplikaci"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Nainstalovat"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nenavrhovat aplikaci"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Připnout předpověď"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Převádění soukromého prostoru"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instalovat"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalovat aplikace do soukromého prostoru"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Rozbalovací nabídka"</string>
</resources>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index bf09aeb..e6f741f 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Startskærm"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Gem appsammenknytning"</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">"Denne appsammenknytning understøttes ikke på enheden"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Afinstaller"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Appinfo"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer (privat)"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Afinstaller appen"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Foreslå ikke en app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fastgør forslaget"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Ændringer af tilstanden for det private område"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Installer"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer apps i privat område"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overløb"</string>
</resources>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index 834100b..7f89246 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Startbildschirm"</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>
<string name="save_app_pair" msgid="5647523853662686243">"App-Paar speichern"</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">"Dieses App-Paar wird auf diesem Gerät nicht unterstützt"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstallieren"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App-Info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Vertraul. installieren"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"App deinstallieren"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installieren"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"App nicht vorschlagen"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Vorgeschlagene App fixieren"</string>
@@ -184,7 +186,7 @@
<string name="remote_action_failed" msgid="1383965239183576790">"Fehler: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Vertrauliches Profil"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Zum Einrichten oder Öffnen tippen"</string>
- <string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
+ <string name="ps_container_title" msgid="4391796149519594205">"Vertraulich"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Einstellungen für vertrauliches Profil"</string>
<string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Privat, entsperrt."</string>
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Privat, gesperrt."</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Sperrzustand des vertraulichen Profils wird gerade geändert"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Installieren"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Apps im vertraulichen Profil installieren"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Weitere Optionen"</string>
</resources>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index f0496b5..8ace970 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Αρχική οθόνη"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Αποθήκευση ζεύγους εφαρμογών"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Αυτό το ζεύγος εφαρμογών δεν υποστηρίζεται σε αυτή τη συσκευή"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Απεγκατάσταση"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Πληροφ. εφαρμογής"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Εγκατ. στο απόρρητο"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Απεγκατάσταση εφαρμογής"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Εγκατάσταση"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Να μην προτείνεται"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Καρφίτσωμα πρόβλεψης"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Υπερχείλιση"</string>
</resources>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index 83f1977..3fe69cd 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</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">"This app pair isn\'t supported on this device"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uninstall app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Install"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to private space"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 4bf147c..dee4a30 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</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">"This app pair isn\'t supported on this device"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uninstall app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin Prediction"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space Transitioning"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Install"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to Private Space"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index 83f1977..3fe69cd 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</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">"This app pair isn\'t supported on this device"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uninstall app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Install"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to private space"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index 83f1977..3fe69cd 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</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">"This app pair isn\'t supported on this device"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uninstall app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin prediction"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space transitioning"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Install"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to private space"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index 24cc5ac..69added 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Save app pair"</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">"This app pair isn\'t supported on this device"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstall"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Install in private"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uninstall app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Don\'t suggest app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin Prediction"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space Transitioning"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Install"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Install apps to Private Space"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 2e6d840..75b6979 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Pantalla principal"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Guardar vinculación"</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">"No se admite esta vinculación de apps en este dispositivo"</string>
@@ -58,7 +59,7 @@
<string name="widgets_full_sheet_cancel_button_description" msgid="5766167035728653605">"Borra el texto del cuadro de búsqueda"</string>
<string name="no_widgets_available" msgid="4337693382501046170">"Los widgets y accesos directos no están disponibles"</string>
<string name="no_search_results" msgid="3787956167293097509">"No se encontraron widgets ni accesos directos"</string>
- <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Personales"</string>
+ <string name="widgets_full_sheet_personal_tab" msgid="2743540105607120182">"Personal"</string>
<string name="widgets_full_sheet_work_tab" msgid="3767150027110633765">"Trabajo"</string>
<string name="widget_category_conversations" msgid="8894438636213590446">"Conversaciones"</string>
<string name="widget_category_note_taking" msgid="3469689394504266039">"Tomar notas"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Información de app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar en privado"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalar app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
@@ -167,8 +169,8 @@
<string name="action_deep_shortcut" msgid="2864038805849372848">"Accesos directos"</string>
<string name="action_dismiss_notification" msgid="5909461085055959187">"Descartar"</string>
<string name="accessibility_close" msgid="2277148124685870734">"Cerrar"</string>
- <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personales"</string>
- <string name="all_apps_work_tab" msgid="4884822796154055118">"De trabajo"</string>
+ <string name="all_apps_personal_tab" msgid="4190252696685155002">"Personal"</string>
+ <string name="all_apps_work_tab" msgid="4884822796154055118">"Trabajo"</string>
<string name="work_profile_toggle_label" msgid="3081029915775481146">"Perfil de trabajo"</string>
<string name="work_profile_edu_work_apps" msgid="7895468576497746520">"Las apps de trabajo tienen una insignia y el administrador de TI las puede ver"</string>
<string name="work_profile_edu_accept" msgid="6069788082535149071">"Entendido"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Pasar a Espacio privado"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instalar"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instala las apps en el espacio privado"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ampliada"</string>
</resources>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 463509a..91e05a7 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Inicio"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Guardar apps emparejadas"</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">"El dispositivo no admite esta aplicación emparejada"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Información de la aplicación"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Descargar en privado"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalar aplicación"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"No sugerir aplicación"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fijar predicción"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Cambiar a espacio privado"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instalar"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Descargar aplicaciones en el espacio privado"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Desplegable"</string>
</resources>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 291831a..4ad9c9e 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Avakuva"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Salvesta rakendusepaar"</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">"See rakendusepaar ei ole selles seadmes toetatud"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalli"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Rakenduse teave"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privaatselt installimine"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalli rakendus"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installimine"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ära soovita rakendust"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Kinnita ennustus"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Privaatse ruumi üleviimine"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Installi"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Rakenduste installimine privaatses ruumis"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ületäide"</string>
</resources>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index 1a28d70..8e68ebd 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Orri nagusia"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Gorde aplikazio parea"</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">"Aplikazio pare hori ez da onartzen gailu honetan"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalatu"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Aplikazioaren informazioa"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalatu pribatuan"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalatu aplikazioa"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalatu"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ez iradoki aplikazioa"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ainguratu iragarpena"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Eremu pribaturako trantsizioa"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instalatu"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalatu aplikazioak eremu pribatuan"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Luzapena"</string>
</resources>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index 1ac2e9a..a191340 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"صفحه اصلی"</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>
<string name="save_app_pair" msgid="5647523853662686243">"ذخیره جفت برنامه"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"از این جفت برنامه در این دستگاه پشتیبانی نمیشود"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"حذف نصب"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"اطلاعات برنامه"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"نصب در نمایه خصوصی"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"حذف نصب برنامه"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"نصب"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"برنامه پیشنهاد داده نشود"</string>
<string name="pin_prediction" msgid="4196423321649756498">"سنجاق کردن پیشنهاد"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"سرریز"</string>
</resources>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index b4fa543..00880b0 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Etusivu"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Tallenna sovelluspari"</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">"Sovellusparia ei tueta tällä laitteella"</string>
@@ -47,7 +48,7 @@
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Kaikki tarvittava"</string>
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Uutiset ja aikakauslehdet"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Viihde"</string>
- <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Sosiaalinen"</string>
+ <string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Some"</string>
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sinulle ehdotetut"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> widgetit oikealla, haku ja vaihtoehdot vasemmalla"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# widget}other{# widgetiä}}"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Poista asennus"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Sovelluksen tiedot"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Asenna yksityisesti"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Poista sovellus"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Asenna"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Älä ehdota sovellusta"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Kiinnitä sovellus"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Yksityisen tilan siirtäminen"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Asenna"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Asenna sovelluksia yksityiseen tilaan"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ylivuoto"</string>
</resources>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index 9f07ffd..daa4b5f 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Accueil"</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>
@@ -84,6 +85,7 @@
<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>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer dans privé"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Désinstaller l\'appli"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'appli"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
@@ -192,5 +194,4 @@
<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="bubble_bar_overflow_description" msgid="7410995531938041192">"Menu à développer"</string>
</resources>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index dd9ec40..580d02f 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Accueil"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Enregistrer la 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>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Désinstaller"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Infos sur l\'appli"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer en mode privé"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Désinstaller l\'appli"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne pas suggérer d\'appli"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Épingler la prédiction"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Transition vers Espace privé"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Installer"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer des applis dans l\'espace privé"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Dépassement"</string>
</resources>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 8940daf..fc667bc 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Inicio"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Gardar parella de apps"</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">"O dispositivo non admite este emparellamento de aplicacións"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Información da app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar en privado"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalar aplicación"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suxerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar predición"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Transición ao espazo privado"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instalar"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalar as aplicacións no espazo privado"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menú adicional"</string>
</resources>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index e595588..ce411e6 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"હોમ સ્ક્રીન"</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>
<string name="save_app_pair" msgid="5647523853662686243">"ઍપની જોડી સાચવો"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"આ ડિવાઇસ પર, આ ઍપની જોડીને સપોર્ટ આપવામાં આવતો નથી"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"અનઇન્સ્ટૉલ કરો"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ઍપની માહિતી"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ખાનગીમાં ઇન્સ્ટૉલ કરો"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ઍપ અનઇન્સ્ટૉલ કરો"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ઇન્સ્ટૉલ કરો"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ઍપ સૂચવશો નહીં"</string>
<string name="pin_prediction" msgid="4196423321649756498">"પૂર્વાનુમાનને પિન કરો"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ઓવરફ્લો"</string>
</resources>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index 0c71db8..f1117ba 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"होम स्क्रीन"</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>
<string name="save_app_pair" msgid="5647523853662686243">"ऐप पेयर सेव करें"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"साथ में इस्तेमाल किए जा सकने वाले ये ऐप्लिकेशन, इस डिवाइस पर काम नहीं कर सकते"</string>
@@ -48,7 +49,7 @@
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"खबरों और पत्रिकाओं वाले ऐप्लिकेशन"</string>
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"मनोरंजन से जुड़े ऐप्लिकेशन"</string>
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"सोशल मीडिया ऐप्लिकेशन"</string>
- <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"आपके लिए सुझाए गए ऐप्लिकेशन"</string>
+ <string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"आपके लिए सुझाए गए"</string>
<string name="widget_picker_right_pane_accessibility_title" msgid="1673313931455067502">"<xliff:g id="SELECTED_HEADER">%1$s</xliff:g> के विजेट दाईं ओर, खोज का विजेट और अन्य विकल्प बाईं ओर"</string>
<string name="widgets_count" msgid="6467746476364652096">"{count,plural, =1{# विजेट}one{# विजेट}other{# विजेट}}"</string>
<string name="shortcuts_count" msgid="8471715556199592381">"{count,plural, =1{# शॉर्टकट}one{# शॉर्टकट}other{# शॉर्टकट}}"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइंस्टॉल करें"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ऐप्लिकेशन की जानकारी"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"निजी तौर पर इंस्टॉल करें"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ऐप्लिकेशन अनइंस्टॉल करें"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"इंस्टॉल करें"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ऐप्लिकेशन का सुझाव न दें"</string>
<string name="pin_prediction" msgid="4196423321649756498">"सुझाए गए ऐप्लिकेशन को पिन करें"</string>
@@ -123,7 +125,7 @@
<string name="title_missing_notification_access" msgid="7503287056163941064">"सूचना के ऐक्सेस की ज़रूरत है"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"सूचना बिंदु दिखाने के लिए, <xliff:g id="NAME">%1$s</xliff:g> के ऐप्लिकेशन सूचना चालू करें"</string>
<string name="title_change_settings" msgid="1376365968844349552">"सेटिंग बदलें"</string>
- <string name="notification_dots_service_title" msgid="4284221181793592871">"नई सूचनाएं बताने वाला गोल निशान दिखाएं"</string>
+ <string name="notification_dots_service_title" msgid="4284221181793592871">"सूचनाएं बताने वाले डॉट दिखाएं"</string>
<string name="developer_options_title" msgid="700788437593726194">"डेवलपर के लिए सेटिंग और टूल"</string>
<string name="auto_add_shortcuts_label" msgid="4926805029653694105">"होम स्क्रीन पर ऐप्लिकेशन के आइकॉन जोड़ें"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"नए ऐप्लिकेशन के लिए"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ओवरफ़्लो"</string>
</resources>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index d07775c..9d60495 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Početni zaslon"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Spremi par aplikacija"</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">"Taj par aplikacija nije podržan na ovom uređaju"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deinstaliraj"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Podaci o aplikaciji"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instaliraj u privatno"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Deinstaliraj aplikaciju"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instaliraj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlaži aplikaciju"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Prikvači predviđenu apl."</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Prelazak na privatni prostor"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instaliraj"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instaliranje aplikacija u privatni prostor"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Dodatni izbornik"</string>
</resources>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 86ec374..bb39c33 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Kezdőképernyő"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Alkalmazáspár mentése"</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">"Ezt az alkalmazáspárt nem támogatja az eszköz"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Eltávolítás"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Alkalmazásinfó"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privát telepítés"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Alkalmazás eltávolítása"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Telepítés"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne javasoljon appot"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Várható kitűzése"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Átállás privát területre…"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Telepítés"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Alkalmazások telepítése privát területre"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Túlcsordulás"</string>
</resources>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 4bc54ab..63b935d 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Հիմնական էկրան"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Պահել հավելվ. զույգը"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Հավելվածների զույգը չի աջակցվում այս սարքում"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Ապատեղադրել"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Հավելվածի մասին"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Տեղադրել մասնավորում"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Ապատեղադրել հավելվածը"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Տեղադրել"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Չառաջարկել"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ամրացնել առաջարկվող հավելվածը"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Լրացուցիչ ընտրացանկ"</string>
</resources>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index cd614d0..ca30b42 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Layar utama"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Simpan pasangan aplikasi"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Pasangan aplikasi ini tidak didukung di perangkat ini"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Uninstal"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info aplikasi"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instal di ruang privasi"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uninstal aplikasi"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instal"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan sarankan apl"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pin Prediksi"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Ruang Pribadi Bertransisi"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instal"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instal aplikasi ke Ruang Pribadi"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menu tambahan"</string>
</resources>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 53b8e90..aadb75e 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Heim"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Vista forritapar"</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">"Þetta forritapar er ekki stutt í þessu tæki"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Fjarlægja"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Forritsupplýsingar"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Setja upp á lokuðum prófíl"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Fjarlægja forrit"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Setja upp"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ekki fá tillögu að forriti"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Festa tillögu"</string>
@@ -182,15 +184,14 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Ljúka hléi"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Sía"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mistókst: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
- <string name="private_space_label" msgid="2359721649407947001">"Einkarými"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Leynirými"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Ýttu til að setja upp eða opna"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Lokað"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Stillingar einkarýmis"</string>
<string name="ps_container_unlock_button_content_description" msgid="9181551784092204234">"Lokað, ólæst."</string>
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"Lokað, læst."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"Læsa"</string>
- <string name="ps_container_transition" msgid="8667331812048014412">"Einkarými að breytast"</string>
+ <string name="ps_container_transition" msgid="8667331812048014412">"Leynirými að breytast"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Setja upp"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Setja upp forrit í leynirými"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Yfirflæði"</string>
</resources>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index af0e2b9..36950b8 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Salva coppia di app"</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">"Questa coppia di app non è supportata su questo dispositivo"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Disinstalla"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Informazioni app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installa in privato"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Disinstalla app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installa"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suggerire app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Blocca previsione"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Transizione dello Spazio privato in corso…"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Installa"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installa le app su spazi privati"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Extra"</string>
</resources>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 7075d59..e00e851 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"בית"</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>
<string name="save_app_pair" msgid="5647523853662686243">"שמירת צמד אפליקציות"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"צמד האפליקציות הזה לא נתמך במכשיר הזה"</string>
@@ -82,8 +83,9 @@
<string name="all_apps_button_work_label" msgid="7270707118948892488">"רשימת אפליקציות עבודה"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"הסרה"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"להסרת התקנה"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"פרטי אפליקציה"</string>
+ <string name="app_info_drop_target_label" msgid="692894985365717661">"פרטי האפליקציה"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"התקנה במרחב הפרטי"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"הסרת האפליקציה"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"התקנה"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"בלי להציע את האפליקציה"</string>
<string name="pin_prediction" msgid="4196423321649756498">"הצמדת החיזוי"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"אפשרויות נוספות"</string>
</resources>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index d957c5c..1f8a93f 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"ホーム"</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>
<string name="save_app_pair" msgid="5647523853662686243">"アプリのペア設定を保存"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"このデバイスは、このアプリのペア設定に対応していません"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"アンインストール"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"アプリ情報"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"非公開インストール"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"アプリをアンインストール"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"インストール"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"アプリを表示しない"</string>
<string name="pin_prediction" msgid="4196423321649756498">"アプリの候補を固定"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"オーバーフロー"</string>
</resources>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index 8a1eb21..eac12be 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"მთავარი გვერდი"</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>
<string name="save_app_pair" msgid="5647523853662686243">"აპთა წყვილის შენახვა"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ამ მოწყობილობაზე აღნიშნული აპთა წყვილი არ არის მხარდაჭერილი"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"დეინსტალაცია"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"აპის შესახებ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"კერძოში ინსტალაცია"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"აპის დეინსტალაცია"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ინსტალაცია"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"არ შემომთავაზო აპი"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ჩამაგრების პროგნოზირება"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"გადავსება"</string>
</resources>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index f70888a..383a507 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Негізгі экран"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Қолданбаларды жұптау әрекетін сақтау"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Бұл құрылғы қолданбаларды жұптау функциясын қолдамайды."</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Жою"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Қолданба ақпараты"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Құпия профильге орнату"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Қолданбаны жою"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Орнату"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Қолданба ұсынбау"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Болжанған қолданбаны бекіту"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Қосымша мәзір"</string>
</resources>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 14ff3c9..e319852 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"អេក្រង់ដើម"</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>
<string name="save_app_pair" msgid="5647523853662686243">"រក្សាទុកគូកម្មវិធី"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"មិនអាចប្រើគូកម្មវិធីនេះនៅលើឧបករណ៍នេះបានទេ"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"លុប"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ព័ត៌មានកម្មវិធី"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ដំឡើងជាលក្ខណៈឯកជន"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"លុបកម្មវិធី"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ដំឡើង"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"កុំណែនាំកម្មវិធី"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ខ្ទាស់ការព្យាករ"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"ការផ្លាស់ប្ដូរ Private Space"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"ដំឡើង"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"ដំឡើងកម្មវិធីទៅលំហឯកជន"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ម៉ឺនុយបន្ថែម"</string>
</resources>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index f918d18..758d47c 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"ಹೋಮ್"</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>
<string name="save_app_pair" msgid="5647523853662686243">"ಆ್ಯಪ್ ಪೇರ್ ಸೇವ್ ಮಾಡಿ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ಈ ಆ್ಯಪ್ ಜೋಡಿಯು ಈ ಸಾಧನದಲ್ಲಿ ಬೆಂಬಲಿತವಾಗಿಲ್ಲ"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ಅನ್ಇನ್ಸ್ಟಾಲ್"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ಆ್ಯಪ್ ಮಾಹಿತಿ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ಖಾಸಗಿಯಾಗಿ ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ಆ್ಯಪ್ ಅನ್ಇನ್ಸ್ಟಾಲ್ ಮಾಡಿ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ಸ್ಥಾಪಿಸಿ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ಆ್ಯಪ್ ಅನ್ನು ಸೂಚಿಸಬೇಡಿ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ಮುನ್ನೋಟ ಪಿನ್ ಮಾಡಿ"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ಓವರ್ಫ್ಲೋ"</string>
</resources>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index b59ccd6..4d623fa 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"홈"</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>
<string name="save_app_pair" msgid="5647523853662686243">"앱 페어링 저장"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"이 앱 페어링은 이 기기에서 지원되지 않습니다"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"제거"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"앱 정보"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"비공개 스페이스에 설치"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"앱 제거"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"설치"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"앱 제안 받지 않음"</string>
<string name="pin_prediction" msgid="4196423321649756498">"예상 앱 고정"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"오버플로"</string>
</resources>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index e4bbc01..98d1e73 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Башкы экран"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Колдонмолорду сактап коюу"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Бул эки колдонмону бул түзмөктө бир маалда пайдаланууга болбойт"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Чыгарып салуу"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Колдонмо тууралуу"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Жеке мейкиндикке орнотуу"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Колдонмону чыгарып салуу"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Орнотуу"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Cунушталбасын"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Божомолдонгон колдонмону кадап коюу"</string>
@@ -192,5 +194,4 @@
<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">"Колдонмолорду Жеке мейкиндикке орнотуe"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Кошумча меню"</string>
</resources>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 17f226e..e0bcfe0 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"ໂຮມສະກຣີນ"</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>
<string name="save_app_pair" msgid="5647523853662686243">"ບັນທຶກຈັບຄູ່ແອັບ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ການຈັບຄູ່ແອັບນີ້ບໍ່ຮອງຮັບຢູ່ອຸປະກອນນີ້"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ຖອນການຕິດຕັ້ງ"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ຂໍ້ມູນແອັບ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ຕິດຕັ້ງໃນສ່ວນຕົວ"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ຖອນການຕິດຕັ້ງແອັບ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ຕິດຕັ້ງ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ຢ່າແນະນຳແອັບ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ປັກໝຸດການຄາດເດົາ"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ການດຳເນີນການເພີ່ມເຕີມ"</string>
</resources>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 17cb3cf..6a2b8d7 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Pagrindinis"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Išsaugoti programų porą"</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">"Ši programų pora šiame įrenginyje nepalaikoma"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Pašalinti"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Programos inform."</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Įdiegti privačiai"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Pašalinti programą"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Įdiegti"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nesiūlyti programos"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Prisegti numatymą"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Privačios erdvės perkėlimas"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Įdiegti"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Įdiegti programas privačioje erdvėje"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Perpildymas"</string>
</resources>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index e514afc..cae6b6e 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Sākums"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Saglabāt lietotņu pāri"</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">"Šis lietotņu pāris netiek atbalstīts šajā ierīcē"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Atinstalēt"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Par lietotni"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalēt privāti"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Atinstalēt lietotni"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalēt"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Neieteikt lietotni"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Piespraust prognozēto lietotni"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Pāriet uz privāto mapi"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instalēt"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalējiet lietotnes privātajā telpā."</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Pārpilde"</string>
</resources>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index 3169f7d..46d8600 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Почетен екран"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Зачувај го парот апликации"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Паров апликации не е поддржан на уредов"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталирај"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Инф. за апликација"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Инстал. во приватен"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Деинсталирај ја апликацијата"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлагај апл."</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закачи го предвидувањето"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Проширено балонче"</string>
</resources>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 952e607..eec5f74 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"ഹോം"</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>
<string name="save_app_pair" msgid="5647523853662686243">"ആപ്പ് ജോടി സംരക്ഷിക്കുക"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ഈ ഉപകരണത്തിൽ ഈ ആപ്പ് ജോടിക്ക് പിന്തുണയില്ല"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"അൺഇൻസ്റ്റാൾ"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ആപ്പ് വിവരങ്ങൾ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"സ്വകാര്യമായി ഇൻസ്റ്റാൾ ചെയ്യൂ"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ആപ്പ് അൺഇൻസ്റ്റാൾ ചെയ്യുക"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ഇൻസ്റ്റാൾ ചെയ്യുക"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ആപ്പ് നിർദ്ദേശിക്കേണ്ട"</string>
<string name="pin_prediction" msgid="4196423321649756498">"പ്രവചനം പിൻ ചെയ്യുക"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ഓവർഫ്ലോ"</string>
</resources>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 7209c85..396589c 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Нүүр"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Апп хослуулалтыг хадгалах"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Энэ апп хослуулалтыг уг төхөөрөмж дээр дэмждэггүй"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Устгах"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Аппын мэдээлэл"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Хувийнхад суулгах"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Аппыг устгах"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Суулгах"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Апп бүү санал болго"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Таамаглалыг бэхлэх"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space-н шилжилт"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Суулгах"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Хувийн орон зайд аппууд суулгана уу"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Урт цэс"</string>
</resources>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 5c08f2e..972c9f2 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"होम"</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>
<string name="save_app_pair" msgid="5647523853662686243">"ॲपची जोडी सेव्ह करा"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"या ॲपची जोडीला या डिव्हाइसवर सपोर्ट नाही"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइंस्टॉल करा"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"अॅप माहिती"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"खाजगीत इंस्टॉल करा"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"अॅप अनइंस्टॉल करा"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"इंस्टॉल करा"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ॲप सुचवू नका"</string>
<string name="pin_prediction" msgid="4196423321649756498">"पूर्वानुमान पिन करा"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ओव्हरफ्लो"</string>
</resources>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 20627c8..c25e3df 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Rumah"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Simpan gandingan apl"</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">"Gandingan apl ini tidak disokong pada peranti ini"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Nyahpasang"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Maklumat apl"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Pasang dalam persendirian"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Nyahpasang apl"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Pasang"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Jangan cadangkan apl"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Sematkan Ramalan"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Peralihan Ruang Peribadi"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Pasang"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Pasang apl pada Ruang Peribadi"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Limpahan"</string>
</resources>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index b77ee98..700278a 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"ပင်မစာမျက်နှာ"</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>
<string name="save_app_pair" msgid="5647523853662686243">"အက်ပ်တွဲချိတ်ခြင်း သိမ်းရန်"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ဤအက်ပ်တွဲချိတ်ခြင်းကို ဤစက်တွင် ပံ့ပိုးမထားပါ"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ဖယ်ရှားရန်"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"အက်ပ်အချက်အလက်"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"သီးသန့်တွင် ထည့်သွင်းရန်"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"အက်ပ်ကို ဖယ်ရှားရန်"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ထည့်သွင်းရန်"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"အက်ပ်အကြံမပြုပါနှင့်"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ခန့်မှန်းချက်ကို ပင်ထိုးရန်"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"မီနူးအပို"</string>
</resources>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index c262517..c2f99aa 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Startskjerm"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Lagre apptilkoblingen"</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">"Denne apptilkoblingen støttes ikke på denne enheten"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Avinstaller"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info om appen"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installer privat"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Avinstaller appen"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ikke foreslå app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fest forslaget"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Private Space-overgang"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Installer"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installer apper i privat område"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflyt"</string>
</resources>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index c47d38e..5e93f89 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"होम"</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>
<string name="save_app_pair" msgid="5647523853662686243">"एपको पेयर सेभ गर्नुहोस्"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"यस डिभाइसमा यो एप पेयर प्रयोग गर्न मिल्दैन"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"अनइन्स्टल गर्नुहोस्"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"एपसम्बन्धी जानकारी"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"निजी प्रोफाइलमा इन्स्टल गर्नुहोस्"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"एप अनइन्स्टल गर्नुहोस्"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"स्थापना गर्नुहोस्"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"एप सिफारिस नगर्नुहोस्"</string>
<string name="pin_prediction" msgid="4196423321649756498">"सिफारिस गरिएको एप पिन गर्नुहोस्"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ओभरफ्लो"</string>
</resources>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index 09a4090..c2e5ebd 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Startscherm"</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>
<string name="save_app_pair" msgid="5647523853662686243">"App-paar opslaan"</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">"Dit app-paar wordt niet ondersteund op dit apparaat"</string>
@@ -84,9 +85,10 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deïnstalleren"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"App-info"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Privé installeren"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"App verwijderen"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installeren"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Geen app voorstellen"</string>
- <string name="pin_prediction" msgid="4196423321649756498">"Vastzetvoorspelling"</string>
+ <string name="pin_prediction" msgid="4196423321649756498">"Voorspelling vastzetten"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"Snelle links instellen"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"Een app toestaan snelkoppelingen toe te voegen zonder tussenkomst van de gebruiker."</string>
<string name="permlab_read_settings" msgid="5136500343007704955">"instellingen en snelkoppelingen op startscherm lezen"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Overschakelen naar privéruimte"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Installeren"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Apps installeren in privégedeelte"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overloop"</string>
</resources>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index ea68d8c..3c240ae 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"ହୋମ"</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>
<string name="save_app_pair" msgid="5647523853662686243">"ଆପ ପେୟାର ସେଭ କରନ୍ତୁ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ଏହି ଆପ ପେୟାର ଏ ଡିଭାଇସରେ ସମର୍ଥିତ ନୁହେଁ"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ଅନଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ଆପ ସୂଚନା"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ପ୍ରାଇଭେଟରେ ଇନଷ୍ଟଲ କର"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ଆପ ଅନଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ଆପ ପରାମର୍ଶ ଦିଅନ୍ତୁ ନାହିଁ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ପୂର୍ବାନୁମାନକୁ ପିନ୍ କରନ୍ତୁ"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ଓଭରଫ୍ଲୋ"</string>
</resources>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 073acfa..0df0c3f 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"ਮੁੱਖ ਪੰਨਾ"</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>
<string name="save_app_pair" msgid="5647523853662686243">"ਐਪ ਜੋੜਾਬੱਧ ਰੱਖਿਅਤ ਕਰੋ"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ਇਸ ਐਪ ਜੋੜਾਬੱਧ ਦਾ ਇਸ ਡੀਵਾਈਸ \'ਤੇ ਸਮਰਥਨ ਨਹੀਂ ਕੀਤਾ ਜਾਂਦਾ"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ਅਣਸਥਾਪਤ ਕਰੋ"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ਐਪ ਜਾਣਕਾਰੀ"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ਨਿੱਜੀ ਵਜੋਂ ਸਥਾਪਤ ਕਰੋ"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ਐਪ ਅਣਸਥਾਪਤ ਕਰੋ"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ਸਥਾਪਤ ਕਰੋ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ਐਪ ਦਾ ਸੁਝਾਅ ਨਾ ਦਿਓ"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ਪੂਰਵ-ਅਨੁਮਾਨ ਪਿੰਨ ਕਰੋ"</string>
@@ -124,7 +126,7 @@
<string name="msg_missing_notification_access" msgid="281113995110910548">"ਸੂਚਨਾ ਬਿੰਦੂਆਂ ਦਿਖਾਉਣ ਲਈ, <xliff:g id="NAME">%1$s</xliff:g> ਲਈ ਐਪ ਸੂਚਨਾਵਾਂ ਚਾਲੂ ਕਰੋ"</string>
<string name="title_change_settings" msgid="1376365968844349552">"ਸੈਟਿੰਗਾਂ ਬਦਲੋ"</string>
<string name="notification_dots_service_title" msgid="4284221181793592871">"ਸੂਚਨਾ ਬਿੰਦੂ ਦਿਖਾਓ"</string>
- <string name="developer_options_title" msgid="700788437593726194">"ਵਿਕਾਸਕਾਰ ਚੋਣਾਂ"</string>
+ <string name="developer_options_title" msgid="700788437593726194">"ਵਿਕਾਸਕਾਰ ਵਿਕਲਪ"</string>
<string name="auto_add_shortcuts_label" msgid="4926805029653694105">"ਹੋਮ ਸਕ੍ਰੀਨ \'ਤੇ ਐਪ ਪ੍ਰਤੀਕਾਂ ਨੂੰ ਸ਼ਾਮਲ ਕਰੋ"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"ਨਵੀਆਂ ਐਪਾਂ ਲਈ"</string>
<string name="package_state_unknown" msgid="7592128424511031410">"ਅਗਿਆਤ"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ਓਵਰਫ਼ਲੋ"</string>
</resources>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index 04a4419..a8e79e3 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Ekran główny"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Zapisz parę aplikacji"</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">"Ta para aplikacji nie jest obsługiwana na tym urządzeniu"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinstaluj"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"O aplikacji"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Zainstaluj prywatnie"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Odinstaluj aplikację"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Zainstaluj"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nie proponuj aplikacji"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Przypnij podpowiedź"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Przenoszenie obszaru prywatnego"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Zainstaluj"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Zainstaluj aplikacje w przestrzeni prywatnej"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Rozwiń menu"</string>
</resources>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 07b32b1..6e4a8e8 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Página inicial"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Guardar par de apps"</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">"Este par de apps não é suportado neste dispositivo"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info. da app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar em privado"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalar app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Não sugerir app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar previsão"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Transição do espaço privado"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instalar"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instale apps no espaço privado"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menu adicional"</string>
</resources>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index d06806d..a7eb0a7 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Início"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Salvar par de apps"</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">"Este Par de apps não está disponível no dispositivo"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Informações do app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalar em particular"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Desinstalar app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Não sugerir esse app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixar previsão"</string>
@@ -182,7 +184,7 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Ativar"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrar"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Falha: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
- <string name="private_space_label" msgid="2359721649407947001">"Espaço particular"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Espaço privado"</string>
<string name="private_space_secondary_label" msgid="9203933341714508907">"Toque para configurar ou abrir"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Particular"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Configurações do Espaço particular"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Espaço particular em transição"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instalar"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalar apps no espaço privado"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Balão flutuante"</string>
</resources>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index fdd1f27..bbade3c 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Pagina de pornire"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Salvează perechea de aplicații"</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">"Perechea de aplicații nu este acceptată pe acest dispozitiv"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Dezinstalează"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Informații despre aplicații"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalează în privat"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Dezinstalează aplicația"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalează"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nu sugera aplicația"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fixează predicția"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Tranziție pentru spațiul privat"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instalează"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalează aplicații în Spațiul privat"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Suplimentar"</string>
</resources>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index b797b32..995052e 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Главный экран"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Сохранить приложения"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Одновременно использовать эти два приложения на устройстве нельзя."</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Удалить"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"О приложении"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Частная установка"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Удалить приложение"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Установить"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не рекомендовать"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закрепить рекомендацию"</string>
@@ -184,7 +186,7 @@
<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_secondary_label" msgid="9203933341714508907">"Нажмите, чтобы настроить или открыть"</string>
- <string name="ps_container_title" msgid="4391796149519594205">"Доступно только вам"</string>
+ <string name="ps_container_title" msgid="4391796149519594205">"Частный профиль"</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>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Дополнительное меню"</string>
</resources>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 9d85606..9140854 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"මුල් පිටුව"</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>
<string name="save_app_pair" msgid="5647523853662686243">"යෙදුම් යුගල සුරකින්න"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"මෙම යෙදුම් යුගලය මෙම උපාංගයෙහි සහාය නොදක්වයි"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"අස්ථාපනය කරන්න"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"යෙදුම් තොරතුරු"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"පෞද්ගලිකව ස්ථාපනය කරන්න"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"යෙදුම අස්ථාපනය කරන්න"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ස්ථාපනය කරන්න"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"යෙදුම යෝජනා නොකරන්න"</string>
<string name="pin_prediction" msgid="4196423321649756498">"පුරෝකථනය අමුණන්න"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"පිටාර යාම"</string>
</resources>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index 0d9001a..1ba5771 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Domov"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Uložiť pár aplikácií"</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">"Tento pár aplikácií nie je v tomto zariadení podporovaný"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odinštalovať"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info o aplikácii"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Inštalovať v súkromí"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Odinštalovať aplikáciu"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Inštalovať"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Nenavrhovať aplikáciu"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Pripnúť predpoveď"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Prechod súkromného priestoru"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Inštalovať"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Inštalácia aplikácií v súkromnom priestore"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Rozšírená ponuka"</string>
</resources>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index e16ec59..cea6e18 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Začetni zaslon"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Shrani par aplikacij"</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">"Ta par aplikacij ni podprt v tej napravi"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Odmesti"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Podatki o aplikaciji"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Namesti v zasebno"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Odmesti aplikacijo"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Namesti"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ne predlagaj"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Predvidevanje pripenjanja"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Preklapljanje zasebnega prostora"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Namestitev"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Nameščanje aplikacij v zasebni prostor"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Oblaček z dodatnimi elementi"</string>
</resources>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 1f2aa26..f328557 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Ekrani bazë"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Ruaj çiftin e aplikacioneve"</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">"Ky çift aplikacionesh nuk mbështetet në këtë pajisje"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Çinstalo"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info mbi aplikacionin"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Instalo në private"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Çinstalo aplikacionin"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Instalo"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Mos sugjero aplikacion"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Gozhdo parashikimin"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Kalimi te \"Hapësira private\""</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Instalo"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Instalo aplikacionet në hapësirën private"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Tejkalimi"</string>
</resources>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 3d0ad3b..6fdeb41 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Почетни екран"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Сачувај пар апликација"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Овај пар апликација није подржан на овом уређају"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Деинсталирај"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Подаци о апликацији"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Инсталирај на приватни"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Деинсталирајте апликацију"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Инсталирај"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не предлажи апликацију"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закачи предвиђање"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Преклопно"</string>
</resources>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index ee2b328..1866f95 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Startskärm"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Spara app-par"</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">"De här apparna som ska användas tillsammans stöds inte på den här enheten"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Avinstallera"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Info om appen"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Installera i privat"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Avinstallera appen"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Installera"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Föreslå inte app"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Fäst förslag"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Överföring av privat rum"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Installera"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Installera appar i privat rum"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Fler alternativ"</string>
</resources>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index a7f5fdd..5c02beb 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Skrini ya kwanza"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Hifadhi jozi ya programu"</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">"Jozi hii ya programu haitumiki kwenye kifaa hiki"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Ondoa"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Maelezo ya programu"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Sakinisha faraghani"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Ondoa programu"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Sakinisha"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Isipendekeze programu"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Bandika Utabiri"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Mabadiliko ya Nafasi ya Faragha"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Weka"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Sakinisha programu kwenye Sehemu ya Faragha"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Menyu ya vipengee vya ziada"</string>
</resources>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 06eaa44..c45b3dd 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"முகப்பு"</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>
<string name="save_app_pair" msgid="5647523853662686243">"ஆப்ஸ் ஜோடியைச் சேமி"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"இந்தச் சாதனத்தில் இந்த ஆப்ஸ் ஜோடி ஆதரிக்கப்படவில்லை"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"நிறுவல் நீக்கு"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ஆப்ஸ் தகவல்"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"தனிப்பட்டதில் நிறுவு"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ஆப்ஸை நிறுவல் நீக்கு"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"நிறுவு"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"பரிந்துரைக்காதே"</string>
<string name="pin_prediction" msgid="4196423321649756498">"கணிக்கப்பட்ட ஆப்ஸைப் பின் செய்தல்"</string>
@@ -190,7 +192,6 @@
<string name="ps_container_lock_button_content_description" msgid="5961993384382649530">"தனிப்பட்டது, லாக் செய்யப்பட்டுள்ளது."</string>
<string name="ps_container_lock_title" msgid="2640257399982364682">"பூட்டு"</string>
<string name="ps_container_transition" msgid="8667331812048014412">"தனிப்பட்ட சேமிப்பிடத்திற்கு மாற்றுகிறது"</string>
- <string name="ps_add_button_label" msgid="8127988716897128773">"நிறுவுதல்"</string>
+ <string name="ps_add_button_label" msgid="8127988716897128773">"நிறுவுக"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"தனிப்பட்ட சேமிப்பிடத்தில் ஆப்ஸை நிறுவும்"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"கூடுதல் விருப்பங்களைக் காட்டும்"</string>
</resources>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 55aae20..e1c4668 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"మొదటి ట్యాబ్"</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>
<string name="save_app_pair" msgid="5647523853662686243">"యాప్ పెయిర్ను సేవ్ చేయండి"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ఈ పరికరంలో ఈ యాప్ పెయిర్ సపోర్ట్ చేయదు"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"అన్ఇన్స్టాల్ చేయండి"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"యాప్ సమాచారం"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ప్రైవేట్ ఇన్స్టాల్"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"యాప్ను అన్ఇన్స్టాల్ చేయండి"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ఇన్స్టాల్ చేయండి"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"యాప్ సూచించకు"</string>
<string name="pin_prediction" msgid="4196423321649756498">"సూచనను పిన్ చేయండి"</string>
@@ -123,7 +125,7 @@
<string name="title_missing_notification_access" msgid="7503287056163941064">"నోటిఫికేషన్ యాక్సెస్ అవసరం"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"నోటిఫికేషన్ డాట్లను చూపించడానికి <xliff:g id="NAME">%1$s</xliff:g>కు యాప్ నోటిఫికేషన్లను ఆన్ చేయండి"</string>
<string name="title_change_settings" msgid="1376365968844349552">"సెట్టింగ్లను మార్చు"</string>
- <string name="notification_dots_service_title" msgid="4284221181793592871">"నోటిఫికేషన్ డాట్లను చూపు"</string>
+ <string name="notification_dots_service_title" msgid="4284221181793592871">"నోటిఫికేషన్ డాట్లను చూపండి"</string>
<string name="developer_options_title" msgid="700788437593726194">"డెవలపర్ ఆప్షన్లు"</string>
<string name="auto_add_shortcuts_label" msgid="4926805029653694105">"యాప్ చిహ్నాలను మొదటి స్క్రీన్కు జోడించండి"</string>
<string name="auto_add_shortcuts_description" msgid="7117251166066978730">"కొత్త యాప్ల కోసం"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"ఓవర్ఫ్లో"</string>
</resources>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index 56864a6..4288c24 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"หน้าแรก"</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>
<string name="save_app_pair" msgid="5647523853662686243">"บันทึกคู่แอป"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ไม่รองรับคู่แอปนี้ในอุปกรณ์เครื่องนี้"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ถอนการติดตั้ง"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ข้อมูลแอป"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ติดตั้งในแบบส่วนตัว"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ถอนการติดตั้งแอป"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ติดตั้ง"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ไม่ต้องแนะนำแอป"</string>
<string name="pin_prediction" msgid="4196423321649756498">"ปักหมุดแอปที่คาดการณ์ไว้"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"การดำเนินการเพิ่มเติม"</string>
</resources>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 1a3d719..305f532 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Home"</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>
<string name="save_app_pair" msgid="5647523853662686243">"I-save ang app pair"</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">"Hindi sinusuportahan sa device na ito ang pares ng app na ito"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"I-uninstall"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Impormasyon ng app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Pribadong i-install"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"I-uninstall ang app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"I-install"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Huwag magmungkahi"</string>
<string name="pin_prediction" msgid="4196423321649756498">"I-pin ang Hula"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Pag-transition ng Pribadong Space"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"I-install"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Mag-install ng mga app sa Pribadong Space"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Overflow"</string>
</resources>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 6d3fc6f..e8c7593 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Ana ekran"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Uygulama çiftini kaydedin"</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">"Bu uygulama çifti bu cihazda desteklenmiyor"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Kaldır"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Uygulama bilgileri"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Özel olarak yükle"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Uygulamayı kaldır"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Yükle"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Uygulamayı önerme"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Tahmini Sabitle"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Gizli Alana Geçiş"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Yükle"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Uygulamaları özel alana yükleyin"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Taşma"</string>
</resources>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index a69f4b0..c1d6b2f 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Головний екран"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Зберегти пару додатків"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Ці два додатки не можна одночасно використовувати на цьому пристрої"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Видалити додаток"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Про додаток"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Установити приватно"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Видалити додаток"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Установити"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Не пропонувати додаток"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Закріпити передбачений додаток"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Додаткове меню"</string>
</resources>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 99d3a7b..6c1a88e 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"ہوم"</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>
<string name="save_app_pair" msgid="5647523853662686243">"ایپس کے جوڑے کو محفوظ کریں"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"ایپس کا یہ جوڑا اس آلے پر تعاون یافتہ نہیں ہے"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"اَن انسٹال کریں"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"ایپ کی معلومات"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"پرائیویٹ میں انسٹال کریں"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"ایپ کو اَن انسٹال کریں"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"انسٹال کریں"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ایپ تجویز نہ کریں"</string>
<string name="pin_prediction" msgid="4196423321649756498">"پیشگوئی پن کریں"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"اوورفلو"</string>
</resources>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 2334a61..18431cc 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Bosh ekran"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Ilova juftini saqlash"</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">"Bu ilova jufti ushbu qurilmada ishlamaydi"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"O‘chirib tashlash"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Ilova haqida"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Maxfiy oʻrnatish"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Ilovani oʻchirish"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"O‘rnatish"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Tavsiya qilinmasin"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Tavsiyani mahkamlash"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Maxfiy joyga almashtirish"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Oʻrnatish"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Ilovalarni Maxfiy makonga oʻrnatish"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Kengaytirish"</string>
</resources>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index feaddcd..b5fb1d7 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Màn hình chính"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Lưu cặp ứng dụng"</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">"Cặp ứng dụng này không hoạt động được trên thiết bị này"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Gỡ cài đặt"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Thông tin ứng dụng"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Cài đặt ở chế độ riêng tư"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Gỡ cài đặt ứng dụng"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Cài đặt"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Không gợi ý ứng dụng"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ghim ứng dụng dự đoán"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Chuyển đổi sang không gian riêng tư"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Cài đặt"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Cài đặt ứng dụng vào Không gian riêng tư"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Bong bóng bổ sung"</string>
</resources>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 58533c3..d51f8fd 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"主屏幕"</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>
<string name="save_app_pair" msgid="5647523853662686243">"保存应用组合"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"在该设备上无法使用此应用对"</string>
@@ -84,8 +85,9 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"卸载"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"应用信息"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安装到私密个人资料中"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"卸载应用"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"安装"</string>
- <string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供应用建议"</string>
+ <string name="dismiss_prediction_label" msgid="3357562989568808658">"不要推荐此应用"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定预测的应用"</string>
<string name="permlab_install_shortcut" msgid="5632423390354674437">"安装快捷方式"</string>
<string name="permdesc_install_shortcut" msgid="923466509822011139">"允许应用自行添加快捷方式。"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"菜单"</string>
</resources>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 6070b4e..90ff515 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"主畫面"</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>
<string name="save_app_pair" msgid="5647523853662686243">"儲存應用程式配對"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"此裝置不支援此應用程式配對"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"解除安裝"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"應用程式資料"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安裝在私人資料夾中"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"解除安裝應用程式"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供應用程式建議"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定預測"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"顯示更多"</string>
</resources>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index 0b40dd0..023a526 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"主畫面"</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>
<string name="save_app_pair" msgid="5647523853662686243">"儲存應用程式配對"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"這部裝置不支援這組應用程式配對"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"解除安裝"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"應用程式資訊"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"安裝在私人空間中"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"解除安裝應用程式"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"安裝"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"不要提供應用程式建議"</string>
<string name="pin_prediction" msgid="4196423321649756498">"固定預測的應用程式"</string>
@@ -192,5 +194,4 @@
<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>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"溢位"</string>
</resources>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 99abe05..a936725 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -29,6 +29,7 @@
<string name="home_screen" msgid="5629429142036709174">"Ikhaya"</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>
<string name="save_app_pair" msgid="5647523853662686243">"Londoloza i-app ebhangqiwe"</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">"Lokhu kubhanqwa kwe-app akusekelwa kule divayisi"</string>
@@ -84,6 +85,7 @@
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Khipha"</string>
<string name="app_info_drop_target_label" msgid="692894985365717661">"Ulwazi nge-app"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"Faka ngokugodliwe"</string>
+ <string name="uninstall_private_system_shortcut_label" msgid="8423460530441627982">"Khipha i-app"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"Faka"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Ungaphakamisi uhlelo lokusebenza"</string>
<string name="pin_prediction" msgid="4196423321649756498">"Ukubikezela Iphinikhodi"</string>
@@ -122,7 +124,7 @@
<string name="notification_dots_desc_off" msgid="1760796511504341095">"Valiwe"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"Ukufinyelela izaziso kuyadingeka"</string>
<string name="msg_missing_notification_access" msgid="281113995110910548">"Ukuze ubonisa amcashazi esaziso, vula izaziso zohlelo lokusebenza ze-<xliff:g id="NAME">%1$s</xliff:g>"</string>
- <string name="title_change_settings" msgid="1376365968844349552">"Shintsha izilungiselelo"</string>
+ <string name="title_change_settings" msgid="1376365968844349552">"Shintsha amasethingi"</string>
<string name="notification_dots_service_title" msgid="4284221181793592871">"Bonisa amacashazi esaziso"</string>
<string name="developer_options_title" msgid="700788437593726194">"Izinketho zonjiniyela"</string>
<string name="auto_add_shortcuts_label" msgid="4926805029653694105">"Engeza izithonjana ze-app kusikrini sasekhaya"</string>
@@ -192,5 +194,4 @@
<string name="ps_container_transition" msgid="8667331812048014412">"Ukuguqulwa Kwendawo Yangasese"</string>
<string name="ps_add_button_label" msgid="8127988716897128773">"Faka"</string>
<string name="ps_add_button_content_description" msgid="3254274107740952556">"Faka ama-app Endaweni Engasese"</string>
- <string name="bubble_bar_overflow_description" msgid="7410995531938041192">"Ukugcwala kakhulu"</string>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index e31a35f..aa83c01 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -320,6 +320,8 @@
<dimen name="bg_popup_item_height">52dp</dimen>
<dimen name="bg_popup_item_vertical_padding">12dp</dimen>
<dimen name="pre_drag_view_scale">6dp</dimen>
+ <!-- Minimum size of the widget dragged view to keep it visible under the finger. -->
+ <dimen name="widget_drag_view_min_scale_down_size">70dp</dimen>
<!-- an icon with shortcuts must be dragged this far before the container is removed. -->
<dimen name="deep_shortcuts_start_drag_threshold">16dp</dimen>
<!-- Possibly related to b/235886078, icon needs to be scaled up to match expected visual size of 32 dp -->
@@ -416,6 +418,9 @@
<dimen name="taskbar_running_app_indicator_height">0dp</dimen>
<dimen name="taskbar_running_app_indicator_width">0dp</dimen>
<dimen name="taskbar_running_app_indicator_top_margin">0dp</dimen>
+ <dimen name="taskbar_minimized_app_indicator_height">0dp</dimen>
+ <dimen name="taskbar_minimized_app_indicator_width">0dp</dimen>
+ <dimen name="taskbar_minimized_app_indicator_top_margin">0dp</dimen>
<!-- Transient taskbar (placeholders to compile in Launcher3 without Quickstep) -->
<dimen name="transient_taskbar_padding">0dp</dimen>
diff --git a/res/values/id.xml b/res/values/id.xml
index 7bb9396..28496b5 100644
--- a/res/values/id.xml
+++ b/res/values/id.xml
@@ -19,9 +19,6 @@
<item type="id" name="view_type_widgets_space" />
<item type="id" name="view_type_widgets_list" />
<item type="id" name="view_type_widgets_header" />
- <!-- Used for A11y actions in staged split to identify each task uniquely -->
- <item type="id" name="split_topLeft_appInfo" />
- <item type="id" name="split_bottomRight_appInfo" />
<!-- Accessibility actions -->
<item type="id" name="action_remove" />
@@ -37,6 +34,12 @@
<item type="id" name="action_remote_action_shortcut" />
<item type="id" name="action_dismiss_prediction" />
<item type="id" name="action_pin_prediction"/>
+ <item type="id" name="action_close"/>
+ <!-- Used for A11y actions in staged split to identify each task uniquely -->
+ <item type="id" name="action_app_info_top_left" />
+ <item type="id" name="action_app_info_bottom_right" />
+ <item type="id" name="action_digital_wellbeing_top_left" />
+ <item type="id" name="action_digital_wellbeing_bottom_right" />
<!-- QSB IDs. DO not change -->
<item type="id" name="search_container_workspace" />
diff --git a/res/values/strings.xml b/res/values/strings.xml
index ef0f0d8..d33adc4 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -36,11 +36,14 @@
<string name="shortcut_not_available">Shortcut isn\'t available</string>
<!-- User visible name for the launcher/home screen. [CHAR_LIMIT=30] -->
<string name="home_screen">Home</string>
+ <!-- Description for setting the current launcher as the default home app. [CHAR_LIMIT=none]-->
+ <string name="set_default_home_app">Set <xliff:g id="launcher_name" example="Launcher3">%1$s</xliff:g> as default home app in Settings</string>
<!-- Options for recent tasks -->
<!-- Title for an option to enter split screen mode for a given app -->
<string name="recent_task_option_split_screen">Split screen</string>
<string name="split_app_info_accessibility">App info for %1$s</string>
+ <string name="split_app_usage_settings">Usage settings for %1$s</string>
<!-- App pairs -->
<string name="save_app_pair">Save app pair</string>
@@ -497,8 +500,4 @@
<string name="ps_add_button_label">Install</string>
<!-- Content description for install app icon -->
<string name="ps_add_button_content_description">Install apps to Private Space</string>
-
- <!-- Strings for bubble bar -->
- <!-- content description for the overflow bubble [CHAR_LIMIT=none] -->
- <string name="bubble_bar_overflow_description">Overflow</string>
</resources>
diff --git a/src/com/android/launcher3/BaseDraggingActivity.java b/src/com/android/launcher3/BaseDraggingActivity.java
index cf93a79..8585b66 100644
--- a/src/com/android/launcher3/BaseDraggingActivity.java
+++ b/src/com/android/launcher3/BaseDraggingActivity.java
@@ -147,7 +147,8 @@
@Override
public void onDisplayInfoChanged(Context context, Info info, int flags) {
- if ((flags & CHANGE_ROTATION) != 0 && mDeviceProfile.updateIsSeascape(this)) {
+ if ((flags & CHANGE_ROTATION) != 0 && mDeviceProfile.isVerticalBarLayout()) {
+ mDeviceProfile.updateIsSeascape(this);
reapplyUi();
}
}
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 2a8298f..7d09164 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -186,9 +186,20 @@
// These fields, related to showing running apps, are only used for Taskbar.
private final Size mRunningAppIndicatorSize;
private final int mRunningAppIndicatorTopMargin;
+ private final Size mMinimizedAppIndicatorSize;
+ private final int mMinimizedAppIndicatorTopMargin;
private final Paint mRunningAppIndicatorPaint;
private final Rect mRunningAppIconBounds = new Rect();
- private boolean mIsRunning;
+ private RunningAppState mRunningAppState;
+
+ /**
+ * Various options for the running state of an app.
+ */
+ public enum RunningAppState {
+ NOT_RUNNING,
+ RUNNING,
+ MINIMIZED,
+ }
@ViewDebug.ExportedProperty(category = "launcher")
private boolean mStayPressed;
@@ -259,9 +270,16 @@
mRunningAppIndicatorSize = new Size(
getResources().getDimensionPixelSize(R.dimen.taskbar_running_app_indicator_width),
getResources().getDimensionPixelSize(R.dimen.taskbar_running_app_indicator_height));
+ mMinimizedAppIndicatorSize = new Size(
+ getResources().getDimensionPixelSize(R.dimen.taskbar_minimized_app_indicator_width),
+ getResources().getDimensionPixelSize(
+ R.dimen.taskbar_minimized_app_indicator_height));
mRunningAppIndicatorTopMargin =
getResources().getDimensionPixelSize(
R.dimen.taskbar_running_app_indicator_top_margin);
+ mMinimizedAppIndicatorTopMargin =
+ getResources().getDimensionPixelSize(
+ R.dimen.taskbar_minimized_app_indicator_top_margin);
mRunningAppIndicatorPaint = new Paint();
mRunningAppIndicatorPaint.setColor(getResources().getColor(
R.color.taskbar_running_app_indicator_color, context.getTheme()));
@@ -414,8 +432,8 @@
/** Updates whether the app this view represents is currently running. */
@UiThread
- public void updateRunningState(boolean isRunning) {
- mIsRunning = isRunning;
+ public void updateRunningState(RunningAppState runningAppState) {
+ mRunningAppState = runningAppState;
}
protected void setItemInfo(ItemInfoWithIcon itemInfo) {
@@ -667,18 +685,20 @@
/** Draws a line under the app icon if this is representing a running app in Desktop Mode. */
protected void drawRunningAppIndicatorIfNecessary(Canvas canvas) {
- if (!mIsRunning || mDisplay != DISPLAY_TASKBAR) {
+ if (mRunningAppState == RunningAppState.NOT_RUNNING || mDisplay != DISPLAY_TASKBAR) {
return;
}
getIconBounds(mRunningAppIconBounds);
// TODO(b/333872717): update color, shape, and size of indicator
- int indicatorTop = mRunningAppIconBounds.bottom + mRunningAppIndicatorTopMargin;
- canvas.drawRect(
- mRunningAppIconBounds.centerX() - mRunningAppIndicatorSize.getWidth() / 2,
- indicatorTop,
- mRunningAppIconBounds.centerX() + mRunningAppIndicatorSize.getWidth() / 2,
- indicatorTop + mRunningAppIndicatorSize.getHeight(),
- mRunningAppIndicatorPaint);
+ boolean isMinimized = mRunningAppState == RunningAppState.MINIMIZED;
+ int indicatorTop =
+ mRunningAppIconBounds.bottom + (isMinimized ? mMinimizedAppIndicatorTopMargin
+ : mRunningAppIndicatorTopMargin);
+ final Size indicatorSize =
+ isMinimized ? mMinimizedAppIndicatorSize : mRunningAppIndicatorSize;
+ canvas.drawRect(mRunningAppIconBounds.centerX() - indicatorSize.getWidth() / 2,
+ indicatorTop, mRunningAppIconBounds.centerX() + indicatorSize.getWidth() / 2,
+ indicatorTop + indicatorSize.getHeight(), mRunningAppIndicatorPaint);
}
@Override
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index a667c96..00db3a3 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -32,6 +32,7 @@
import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE;
import static com.android.launcher3.testing.shared.ResourceUtils.pxFromDp;
import static com.android.launcher3.testing.shared.ResourceUtils.roundPxValueFromFloat;
+import static com.android.wm.shell.Flags.enableTinyTaskbar;
import android.annotation.SuppressLint;
import android.content.Context;
@@ -52,7 +53,6 @@
import com.android.launcher3.CellLayout.ContainerType;
import com.android.launcher3.DevicePaddings.DevicePadding;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.DotRenderer;
import com.android.launcher3.icons.IconNormalizer;
import com.android.launcher3.model.data.ItemInfo;
@@ -353,7 +353,7 @@
isTablet = info.isTablet(windowBounds);
isPhone = !isTablet;
isTwoPanels = isTablet && isMultiDisplay;
- isTaskbarPresent = isTablet
+ isTaskbarPresent = (isTablet || (enableTinyTaskbar() && isGestureMode))
&& WindowManagerProxy.INSTANCE.get(context).isTaskbarDrawnInProcess();
// Some more constants.
@@ -713,7 +713,7 @@
overviewTaskThumbnailTopMarginPx =
enableOverviewIconMenu() ? 0 : overviewTaskIconSizePx + overviewTaskMarginPx;
// Don't add margin with floating search bar to minimize risk of overlapping.
- overviewActionsTopMarginPx = FeatureFlags.ENABLE_FLOATING_SEARCH_BAR.get() ? 0
+ overviewActionsTopMarginPx = Flags.floatingSearchBar() ? 0
: res.getDimensionPixelSize(R.dimen.overview_actions_top_margin);
overviewPageSpacing = res.getDimensionPixelSize(R.dimen.overview_page_spacing);
overviewActionsButtonSpacing = res.getDimensionPixelSize(
@@ -2402,7 +2402,7 @@
mTransposeLayoutWithOrientation = !mInfo.isTablet(mWindowBounds);
}
if (mIsGestureMode == null) {
- mIsGestureMode = mInfo.navigationMode.hasGestures;
+ mIsGestureMode = mInfo.getNavigationMode().hasGestures;
}
if (mDotRendererCache == null) {
mDotRendererCache = new SparseArray<>();
diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java
index 37737d8..8546454 100644
--- a/src/com/android/launcher3/Hotseat.java
+++ b/src/com/android/launcher3/Hotseat.java
@@ -82,6 +82,10 @@
return mHasVerticalHotseat ? (getCountY() - (rank + 1)) : 0;
}
+ boolean isHasVerticalHotseat() {
+ return mHasVerticalHotseat;
+ }
+
public void resetLayout(boolean hasVerticalHotseat) {
ActivityContext activityContext = ActivityContext.lookupContext(getContext());
boolean bubbleBarEnabled = activityContext.isBubbleBarEnabled();
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index b89d05e..6c9d4c0 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -38,6 +38,7 @@
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_BIND_PENDING_APPWIDGET;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_CREATE_APPWIDGET;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_CREATE_SHORTCUT;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_HOME_ROLE;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_PICK_APPWIDGET;
import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_RECONFIGURE_APPWIDGET;
import static com.android.launcher3.LauncherConstants.SavedInstanceKeys.RUNTIME_STATE;
@@ -96,9 +97,7 @@
import static com.android.launcher3.popup.SystemShortcut.WIDGETS;
import static com.android.launcher3.states.RotationHelper.REQUEST_LOCK;
import static com.android.launcher3.states.RotationHelper.REQUEST_NONE;
-import static com.android.launcher3.testing.shared.TestProtocol.CLOCK_ICON_DRAWABLE_LEAKING;
import static com.android.launcher3.testing.shared.TestProtocol.LAUNCHER_ACTIVITY_STOPPED_MESSAGE;
-import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.ItemInfoMatcher.forFolderMatch;
import static com.android.launcher3.util.SettingsCache.TOUCHPAD_NATURAL_SCROLLING;
@@ -153,6 +152,7 @@
import android.view.WindowManager.LayoutParams;
import android.view.accessibility.AccessibilityEvent;
import android.view.animation.OvershootInterpolator;
+import android.widget.Toast;
import android.window.BackEvent;
import android.window.OnBackAnimationCallback;
@@ -163,8 +163,10 @@
import androidx.annotation.StringRes;
import androidx.annotation.UiThread;
import androidx.annotation.VisibleForTesting;
+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;
@@ -423,7 +425,6 @@
@Override
@TargetApi(Build.VERSION_CODES.S)
protected void onCreate(Bundle savedInstanceState) {
- testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onCreate: instance=" + this);
mStartupLatencyLogger = createStartupLatencyLogger(
sIsNewProcess
? LockedUserState.get(this).isUserUnlockedAtLauncherStartup()
@@ -589,7 +590,8 @@
setTitle(R.string.home_screen);
mStartupLatencyLogger.logEnd(LAUNCHER_LATENCY_STARTUP_ACTIVITY_ON_CREATE);
- if (com.android.launcher3.Flags.enableTwoPaneLauncherSettings()) {
+ if (BuildCompat.isAtLeastV()
+ && com.android.launcher3.Flags.enableTwoPaneLauncherSettings()) {
RuleController.getInstance(this).setRules(
RuleController.parseRules(this, R.xml.split_configuration));
}
@@ -892,6 +894,17 @@
}
mPendingActivityResult = null;
+ if (requestCode == REQUEST_HOME_ROLE) {
+ if (resultCode != RESULT_OK) {
+ Toast.makeText(
+ this,
+ this.getString(R.string.set_default_home_app,
+ this.getString(R.string.derived_app_name)),
+ Toast.LENGTH_LONG).show();
+ }
+ return;
+ }
+
// Reset the startActivity waiting flag
final PendingRequestArgs requestArgs = mPendingRequestArgs;
setWaitingForResult(null);
@@ -1082,7 +1095,6 @@
@Override
protected void onStart() {
- testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onStart: instance=" + this);
TraceHelper.INSTANCE.beginSection(ON_START_EVT);
super.onStart();
if (!mDeferOverlayCallbacks) {
@@ -1096,7 +1108,6 @@
@Override
@CallSuper
protected void onDeferredResumed() {
- testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onDeferredResumed: instance=" + this);
logStopAndResume(true /* isResume */);
// Process any items that were added while Launcher was away.
@@ -1268,11 +1279,7 @@
}
// Set screen title for Talkback
- if (state == ALL_APPS) {
- setTitle(R.string.all_apps_label);
- } else {
- setTitle(R.string.home_screen);
- }
+ setTitle(state.getTitle());
}
/**
@@ -1284,7 +1291,6 @@
@Override
protected void onResume() {
- testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onResume: instance=" + this);
TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT);
super.onResume();
@@ -1300,7 +1306,6 @@
@Override
protected void onPause() {
- testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onPause: instance=" + this);
// Ensure that items added to Launcher are queued until Launcher returns
ItemInstallQueue.INSTANCE.get(this).pauseModelPush(FLAG_ACTIVITY_PAUSED);
@@ -1783,7 +1788,6 @@
@Override
public void onDestroy() {
- testLogD(CLOCK_ICON_DRAWABLE_LEAKING, "onDestroy: instance=" + this);
super.onDestroy();
ACTIVITY_TRACKER.onActivityDestroyed(this);
@@ -2793,7 +2797,8 @@
}
private void updateDisallowBack() {
- if (Flags.enableDesktopWindowingMode()) {
+ if (BuildCompat.isAtLeastV() && Flags.enableDesktopWindowingMode()
+ && mDeviceProfile.isTablet) {
// TODO(b/330183377) disable back in launcher when when we productionize
return;
}
@@ -3150,4 +3155,4 @@
}
// End of Getters and Setters
-}
\ No newline at end of file
+}
diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java
index a4ae1c8..3b8ff62 100644
--- a/src/com/android/launcher3/LauncherAppState.java
+++ b/src/com/android/launcher3/LauncherAppState.java
@@ -39,6 +39,7 @@
import android.util.Log;
import androidx.annotation.Nullable;
+import androidx.core.os.BuildCompat;
import com.android.launcher3.graphics.IconShape;
import com.android.launcher3.icons.IconCache;
@@ -107,7 +108,7 @@
mOnTerminateCallback.add(() ->
mContext.getSystemService(LauncherApps.class).unregisterCallback(callbacks));
- if (Flags.enableSupportForArchiving()) {
+ if (BuildCompat.isAtLeastV() && Flags.enableSupportForArchiving()) {
ArchiveCompatibilityParams params = new ArchiveCompatibilityParams();
params.setEnableUnarchivalConfirmation(false);
launcherApps.setArchiveCompatibility(params);
diff --git a/src/com/android/launcher3/LauncherConstants.java b/src/com/android/launcher3/LauncherConstants.java
index 1abfeb9..445fb41 100644
--- a/src/com/android/launcher3/LauncherConstants.java
+++ b/src/com/android/launcher3/LauncherConstants.java
@@ -41,6 +41,7 @@
public static final int REQUEST_BIND_PENDING_APPWIDGET = 12;
public static final int REQUEST_RECONFIGURE_APPWIDGET = 13;
+ public static final int REQUEST_HOME_ROLE = 14;
static final int REQUEST_CREATE_SHORTCUT = 1;
static final int REQUEST_CREATE_APPWIDGET = 5;
static final int REQUEST_PICK_APPWIDGET = 9;
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 72a3c53..d2d56f2 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -38,6 +38,7 @@
import android.view.animation.Interpolator;
import androidx.annotation.FloatRange;
+import androidx.annotation.StringRes;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StateManager;
@@ -369,6 +370,10 @@
return launcher.getWorkspace().getCurrentPageDescription();
}
+ public @StringRes int getTitle() {
+ return R.string.home_screen;
+ }
+
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
if ((this != NORMAL && this != HINT_STATE)
|| !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
diff --git a/src/com/android/launcher3/ModelCallbacks.kt b/src/com/android/launcher3/ModelCallbacks.kt
index 7d6d154..13062b6 100644
--- a/src/com/android/launcher3/ModelCallbacks.kt
+++ b/src/com/android/launcher3/ModelCallbacks.kt
@@ -3,6 +3,7 @@
import android.annotation.TargetApi
import android.os.Build
import android.os.Trace
+import android.util.Log
import androidx.annotation.UiThread
import com.android.launcher3.Flags.enableSmartspaceRemovalToggle
import com.android.launcher3.LauncherConstants.TraceEvents
@@ -29,6 +30,8 @@
import com.android.launcher3.widget.model.WidgetsListBaseEntry
import java.util.function.Predicate
+private const val TAG = "ModelCallbacks"
+
class ModelCallbacks(private var launcher: Launcher) : BgDataModel.Callbacks {
var synchronouslyBoundPages = LIntSet()
@@ -66,6 +69,13 @@
launcher.workspace.removeAllWorkspaceScreens()
// Avoid clearing the widget update listeners for staying up-to-date with widget info
launcher.appWidgetHolder.clearWidgetViews()
+ // TODO(b/335141365): Remove this log after the bug is fixed.
+ Log.d(
+ TAG,
+ "startBinding: " +
+ "hotseat layout was vertical: ${launcher.hotseat?.isHasVerticalHotseat}" +
+ " and is setting to ${launcher.deviceProfile.isVerticalBarLayout}"
+ )
launcher.hotseat?.resetLayout(launcher.deviceProfile.isVerticalBarLayout)
TraceHelper.INSTANCE.endSection()
}
@@ -142,7 +152,10 @@
launcher.viewCache.setCacheSize(R.layout.folder_page, 2)
TraceHelper.INSTANCE.endSection()
launcher.workspace.removeExtraEmptyScreen(/* stripEmptyScreens= */ true)
- launcher.workspace.pageIndicator.setPauseScroll(/*pause=*/ false, deviceProfile.isTwoPanels)
+ launcher.workspace.pageIndicator.setPauseScroll(
+ /*pause=*/ false,
+ deviceProfile.isTwoPanels
+ )
}
/**
@@ -290,8 +303,7 @@
val widgetsListBaseEntry: WidgetsListBaseEntry =
launcher.popupDataProvider.allWidgets.firstOrNull { item: WidgetsListBaseEntry ->
item.mPkgItem.packageName == BuildConfig.APPLICATION_ID
- }
- ?: return
+ } ?: return
val info =
PendingAddWidgetInfo(
@@ -315,16 +327,14 @@
)
val firstScreenPosition = 0
if (
- (isFirstPagePinnedItemEnabled &&
- !SHOULD_SHOW_FIRST_PAGE_WIDGET) &&
+ (isFirstPagePinnedItemEnabled && !SHOULD_SHOW_FIRST_PAGE_WIDGET) &&
orderedScreenIds.indexOf(FIRST_SCREEN_ID) != firstScreenPosition
) {
orderedScreenIds.removeValue(FIRST_SCREEN_ID)
orderedScreenIds.add(firstScreenPosition, FIRST_SCREEN_ID)
} else if (
- (!isFirstPagePinnedItemEnabled ||
- SHOULD_SHOW_FIRST_PAGE_WIDGET)
- && orderedScreenIds.isEmpty
+ (!isFirstPagePinnedItemEnabled || SHOULD_SHOW_FIRST_PAGE_WIDGET) &&
+ orderedScreenIds.isEmpty
) {
// If there are no screens, we need to have an empty screen
launcher.workspace.addExtraEmptyScreens()
@@ -380,7 +390,7 @@
}
orderedScreenIds
.filterNot { screenId ->
- isFirstPagePinnedItemEnabled &&
+ isFirstPagePinnedItemEnabled &&
!SHOULD_SHOW_FIRST_PAGE_WIDGET &&
screenId == WorkspaceLayoutManager.FIRST_SCREEN_ID
}
diff --git a/src/com/android/launcher3/ShortcutAndWidgetContainer.java b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
index b22b690..7484b64 100644
--- a/src/com/android/launcher3/ShortcutAndWidgetContainer.java
+++ b/src/com/android/launcher3/ShortcutAndWidgetContainer.java
@@ -158,6 +158,11 @@
final PointF appWidgetScale = dp.getAppWidgetScale((ItemInfo) child.getTag());
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
appWidgetScale.x, appWidgetScale.y, mBorderSpace, dp.widgetPadding);
+ } else if (isChildQsb(child)) {
+ lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
+ mBorderSpace);
+ // No need to add padding for Qsb, which is either Smartspace (actual or preview), or
+ // QsbContainerView.
} else {
lp.setup(mCellWidth, mCellHeight, invertLayoutHorizontally(), mCountX, mCountY,
mBorderSpace);
@@ -185,6 +190,10 @@
child.measure(childWidthMeasureSpec, childheightMeasureSpec);
}
+ private boolean isChildQsb(View child) {
+ return child.getId() == R.id.search_container_workspace;
+ }
+
public boolean invertLayoutHorizontally() {
return mInvertIfRtl && Utilities.isRtl(getResources());
}
diff --git a/src/com/android/launcher3/WorkspaceLayoutManager.java b/src/com/android/launcher3/WorkspaceLayoutManager.java
index 4768773..f11a88f 100644
--- a/src/com/android/launcher3/WorkspaceLayoutManager.java
+++ b/src/com/android/launcher3/WorkspaceLayoutManager.java
@@ -58,6 +58,9 @@
int screenId = presenterPos.screenId;
x = getHotseat().getCellXFromOrder(screenId);
y = getHotseat().getCellYFromOrder(screenId);
+ // TODO(b/335141365): Remove this log after the bug is fixed.
+ Log.d(TAG, "addInScreenFromBind: hotseat inflation with x = " + x
+ + " and y = " + y);
}
addInScreen(child, info.container, presenterPos.screenId, x, y, info.spanX, info.spanY);
}
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index a810331..5d03a93 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -337,6 +337,8 @@
&& !mPrivateApps.isEmpty()) {
// Always add PS Header if Space is present and visible.
position = mPrivateProviderManager.addPrivateSpaceHeader(mAdapterItems);
+ mFastScrollerSections.add(new FastScrollSectionInfo(
+ mPrivateProfileAppScrollerBadge, position));
int privateSpaceState = mPrivateProviderManager.getCurrentState();
switch (privateSpaceState) {
case PrivateProfileManager.STATE_DISABLED:
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 16630967..98ca420 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -267,13 +267,15 @@
PrivateProfileManager privateProfileManager = mApps.getPrivateProfileManager();
if (privateProfileManager != null) {
// Set the alpha of the private space icon to 0 upon expanding the header so the
- // alpha can animate -> 1.
+ // alpha can animate -> 1. This should only be in effect when doing a
+ // transitioning between Locked/Unlocked state.
boolean isPrivateSpaceItem =
privateProfileManager.isPrivateSpaceItem(adapterItem);
if (icon.getAlpha() == 0 || icon.getAlpha() == 1) {
icon.setAlpha(isPrivateSpaceItem
- && (privateProfileManager.getAnimationScrolling() ||
- privateProfileManager.getAnimate())
+ && privateProfileManager.isStateTransitioning()
+ && (privateProfileManager.isScrolling() ||
+ privateProfileManager.getReadyToAnimate())
&& privateProfileManager.getCurrentState() == STATE_ENABLED
? 0 : 1);
}
@@ -298,7 +300,7 @@
case VIEW_TYPE_PRIVATE_SPACE_HEADER:
RelativeLayout psHeaderLayout = holder.itemView.findViewById(
R.id.ps_header_layout);
- mApps.getPrivateProfileManager().addPrivateSpaceHeaderViewElements(psHeaderLayout);
+ mApps.getPrivateProfileManager().bindPrivateSpaceHeaderViewElements(psHeaderLayout);
AdapterItem adapterItem = mApps.getAdapterItems().get(position);
int roundRegions = ROUND_TOP_LEFT | ROUND_TOP_RIGHT;
if (mApps.getPrivateProfileManager().getCurrentState() == STATE_DISABLED) {
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index 27340a3..6f021ea 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -20,7 +20,6 @@
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
-import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PRIVATESPACE;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
@@ -30,7 +29,6 @@
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_BEGIN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_LOCK_TAP;
-import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_BEGIN;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_ANIMATION_END;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP;
@@ -52,7 +50,6 @@
import android.os.UserManager;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
@@ -104,6 +101,7 @@
private static final int LOCK_TEXT_OPACITY_DELAY = 500;
private static final int MASK_VIEW_DELAY = 400;
private static final int NO_DELAY = 0;
+ private static final int CONTAINER_OPACITY_DURATION = 150;
private final ActivityAllAppsContainerView<?> mAllApps;
private final Predicate<UserHandle> mPrivateProfileMatcher;
private final int mPsHeaderHeight;
@@ -114,16 +112,21 @@
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
if (newState == RecyclerView.SCROLL_STATE_IDLE) {
- mAnimationScrolling = false;
+ mIsScrolling = false;
}
}
};
private Intent mAppInstallerIntent = new Intent();
private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
private boolean mPrivateSpaceSettingsAvailable;
+ // Returns if the animation is currently running.
private boolean mIsAnimationRunning;
- private boolean mAnimate;
- private boolean mAnimationScrolling;
+ // mAnimate denotes if private space is ready to be animated.
+ private boolean mReadyToAnimate;
+ // Returns when the recyclerView is currently scrolling.
+ private boolean mIsScrolling;
+ // mIsStateTransitioning indicates that private space is transitioning between states.
+ private boolean mIsStateTransitioning;
private Runnable mOnPSHeaderAdded;
@Nullable
private RelativeLayout mPSHeader;
@@ -191,23 +194,6 @@
mAllApps.mAH.get(MAIN).mAdapter.notifyItemInserted(adapterItems.size() - 1);
}
- /**
- * Disables quiet mode for Private Space User Profile.
- * When called from search, a runnable is set and executed in the {@link #reset()} method, when
- * Launcher receives update about profile availability.
- * The runnable is only executed once, and reset after execution.
- * In case the method is called again, before the previously set runnable was executed,
- * the runnable will be updated.
- */
- public void unlockPrivateProfile() {
- setQuietMode(false);
- }
-
- /** Enables quiet mode for Private Space User Profile. */
- void lockPrivateProfile() {
- setQuietMode(true);
- }
-
/** Whether private profile should be hidden on Launcher. */
public boolean isPrivateSpaceHidden() {
return getCurrentState() == STATE_DISABLED && SettingsCache.INSTANCE
@@ -220,46 +206,25 @@
* when animation is not running.
*/
public void reset() {
+ // Ensure the state of the header views is what it should be before animating.
+ updateView();
getMainRecyclerView().setChildAttachedConsumer(null);
int previousState = getCurrentState();
boolean isEnabled = !mAllApps.getAppsStore()
.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED);
int updatedState = isEnabled ? STATE_ENABLED : STATE_DISABLED;
setCurrentState(updatedState);
- mFloatingMaskView = null;
- if (mPSHeader != null) {
- mPSHeader.setAlpha(1);
+ if (Flags.privateSpaceAddFloatingMaskView()) {
+ mFloatingMaskView = null;
}
- if (transitioningFromLockedToUnlocked(previousState, updatedState)) {
+ // It's possible that previousState is 0 when reset is first called.
+ mIsStateTransitioning = previousState != STATE_UNKNOWN && previousState != updatedState;
+ if (previousState == STATE_DISABLED && updatedState == STATE_ENABLED) {
postUnlock();
- } else if (transitioningFromUnlockedToLocked(previousState, updatedState)){
+ } else if (previousState == STATE_ENABLED && updatedState == STATE_DISABLED){
executeLock();
}
- resetPrivateSpaceDecorator(updatedState);
- }
-
- /**
- * Opens the Private Space Settings Page.
- *
- * @param view the view that was clicked to open the settings page and which will be the same
- * view to animate back. Otherwise if there is no view, simply start the activity.
- */
- public void openPrivateSpaceSettings(View view) {
- if (mPrivateSpaceSettingsAvailable) {
- Context context = mAllApps.getContext();
- Intent intent = ApiWrapper.INSTANCE.get(context).getPrivateSpaceSettingsIntent();
- if (view == null) {
- context.startActivity(intent);
- return;
- }
- ActivityContext activityContext = ActivityContext.lookupContext(context);
- AppInfo itemInfo = new AppInfo();
- itemInfo.id = CONTAINER_PRIVATESPACE;
- itemInfo.componentName = intent.getComponent();
- itemInfo.container = CONTAINER_PRIVATESPACE;
- view.setTag(itemInfo);
- activityContext.startActivitySafely(view, intent, itemInfo);
- }
+ addPrivateSpaceDecorator(updatedState);
}
/** Returns whether or not Private Space Settings Page is available. */
@@ -292,8 +257,9 @@
setPrivateSpaceSettingsAvailable(apiWrapper.getPrivateSpaceSettingsIntent() != null);
}
+ /** Adds a private space decorator only when STATE_ENABLED. */
@VisibleForTesting
- void resetPrivateSpaceDecorator(int updatedState) {
+ void addPrivateSpaceDecorator(int updatedState) {
ActivityAllAppsContainerView<?>.AdapterHolder mainAdapterHolder = mAllApps.mAH.get(MAIN);
if (updatedState == STATE_ENABLED) {
// Create a new decorator instance if not already available.
@@ -310,18 +276,31 @@
}
// Add Private Space Decorator to the Recycler view.
mainAdapterHolder.mRecyclerView.addItemDecoration(mPrivateAppsSectionDecorator);
- } else {
- // Remove Private Space Decorator from the Recycler view.
- if (mPrivateAppsSectionDecorator != null && !mIsAnimationRunning) {
- mainAdapterHolder.mRecyclerView.removeItemDecoration(mPrivateAppsSectionDecorator);
- }
}
}
@Override
public void setQuietMode(boolean enable) {
- super.setQuietMode(enable);
- mAnimate = true;
+ UI_HELPER_EXECUTOR.post(() ->
+ mUserCache.getUserProfiles()
+ .stream()
+ .filter(getUserMatcher())
+ .findFirst()
+ .ifPresent(userHandle -> setQuietModeSafely(enable, userHandle)));
+ mReadyToAnimate = true;
+ }
+
+ /**
+ * Sets Quiet Mode for Private Profile.
+ * If {@link SecurityException} is thrown, prompts the user to set this launcher as HOME app.
+ */
+ private void setQuietModeSafely(boolean enable, UserHandle userHandle) {
+ try {
+ mUserManager.requestQuietModeEnabled(enable, userHandle);
+ } catch (SecurityException ex) {
+ ApiWrapper.INSTANCE.get(mAllApps.mActivityContext)
+ .assignDefaultHomeRole(mAllApps.mActivityContext);
+ }
}
/**
@@ -343,7 +322,7 @@
void setAnimationRunning(boolean isAnimationRunning) {
if (!isAnimationRunning) {
- mAnimate = false;
+ mReadyToAnimate = false;
}
mIsAnimationRunning = isAnimationRunning;
}
@@ -352,14 +331,6 @@
return mIsAnimationRunning;
}
- private boolean transitioningFromLockedToUnlocked(int previousState, int updatedState) {
- return previousState == STATE_DISABLED && updatedState == STATE_ENABLED;
- }
-
- private boolean transitioningFromUnlockedToLocked(int previousState, int updatedState) {
- return previousState == STATE_ENABLED && updatedState == STATE_DISABLED;
- }
-
@Override
public Predicate<UserHandle> getUserMatcher() {
return mPrivateProfileMatcher;
@@ -378,7 +349,7 @@
}
/** Add Private Space Header view elements based upon {@link UserProfileState} */
- public void addPrivateSpaceHeaderViewElements(RelativeLayout parent) {
+ public void bindPrivateSpaceHeaderViewElements(RelativeLayout parent) {
mPSHeader = parent;
if (mOnPSHeaderAdded != null) {
MAIN_EXECUTOR.execute(mOnPSHeaderAdded);
@@ -386,100 +357,70 @@
}
// Set the transition duration for the settings and lock button to animate.
ViewGroup settingAndLockGroup = mPSHeader.findViewById(R.id.settingsAndLockGroup);
- if (mAnimate) {
+ if (mReadyToAnimate) {
enableLayoutTransition(settingAndLockGroup);
} else {
// Ensure any unwanted animations to not happen.
settingAndLockGroup.setLayoutTransition(null);
}
-
- //Add quietMode image and action for lock/unlock button
- ViewGroup lockButton = mPSHeader.findViewById(R.id.ps_lock_unlock_button);
- assert lockButton != null;
- addLockButton(lockButton);
-
- //Trigger lock/unlock action from header.
- addHeaderOnClickListener(mPSHeader);
-
- //Add image and action for private space settings button
- ImageButton settingsButton = mPSHeader.findViewById(R.id.ps_settings_button);
- assert settingsButton != null;
- addPrivateSpaceSettingsButton(settingsButton);
-
- //Add image for private space transitioning view
- ImageView transitionView = parent.findViewById(R.id.ps_transition_image);
- assert transitionView != null;
- addTransitionImage(transitionView);
+ updateView();
}
- /**
- * Adds the quietModeButton and attach onClickListener for the header to animate different
- * states when clicked.
- */
- private void addLockButton(ViewGroup lockButton) {
- TextView lockText = lockButton.findViewById(R.id.lock_text);
- switch (getCurrentState()) {
+ /** Update the states of the views that make up the header at the state it is called in. */
+ private void updateView() {
+ if (mPSHeader == null) {
+ return;
+ }
+ mPSHeader.setAlpha(1);
+ ViewGroup lockPill = mPSHeader.findViewById(R.id.ps_lock_unlock_button);
+ assert lockPill != null;
+ TextView lockText = lockPill.findViewById(R.id.lock_text);
+ PrivateSpaceSettingsButton settingsButton = mPSHeader.findViewById(R.id.ps_settings_button);
+ assert settingsButton != null;
+ //Add image for private space transitioning view
+ ImageView transitionView = mPSHeader.findViewById(R.id.ps_transition_image);
+ assert transitionView != null;
+ switch(getCurrentState()) {
case STATE_ENABLED -> {
+ mPSHeader.setOnClickListener(null);
+ mPSHeader.setClickable(false);
+ // Remove header from accessibility target when enabled.
+ mPSHeader.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+
lockText.setVisibility(VISIBLE);
- lockButton.setVisibility(VISIBLE);
- lockButton.setOnClickListener(view -> lockingAction(/* lock */ true));
- lockButton.setContentDescription(mUnLockedStateContentDesc);
+ lockPill.setVisibility(VISIBLE);
+ lockPill.setOnClickListener(view -> lockingAction(/* lock */ true));
+ lockPill.setContentDescription(mUnLockedStateContentDesc);
+
+ settingsButton.setVisibility(isPrivateSpaceSettingsAvailable() ? VISIBLE : GONE);
+ transitionView.setVisibility(GONE);
}
case STATE_DISABLED -> {
- lockText.setVisibility(GONE);
- lockButton.setVisibility(VISIBLE);
- lockButton.setOnClickListener(view -> lockingAction(/* lock */ false));
- lockButton.setContentDescription(mLockedStateContentDesc);
- }
- default -> lockButton.setVisibility(GONE);
- }
- }
+ mPSHeader.setOnClickListener(view -> lockingAction(/* lock */ false));
+ mPSHeader.setClickable(true);
+ // Add header as accessibility target when disabled.
+ mPSHeader.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+ mPSHeader.setContentDescription(mLockedStateContentDesc);
- private void addHeaderOnClickListener(RelativeLayout header) {
- if (getCurrentState() == STATE_DISABLED) {
- header.setOnClickListener(view -> lockingAction(/* lock */ false));
- header.setClickable(true);
- // Add header as accessibility target when disabled.
- header.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
- header.setContentDescription(mLockedStateContentDesc);
- } else {
- header.setOnClickListener(null);
- header.setClickable(false);
- // Remove header from accessibility target when enabled.
- header.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO);
+ lockText.setVisibility(GONE);
+ lockPill.setVisibility(VISIBLE);
+ lockPill.setOnClickListener(view -> lockingAction(/* lock */ false));
+ lockPill.setContentDescription(mLockedStateContentDesc);
+
+ settingsButton.setVisibility(GONE);
+ transitionView.setVisibility(GONE);
+ }
+ case STATE_TRANSITION -> {
+ transitionView.setVisibility(VISIBLE);
+ lockPill.setVisibility(GONE);
+ }
}
}
/** Sets the enablement of the profile when header or button is clicked. */
private void lockingAction(boolean lock) {
logEvents(lock ? LAUNCHER_PRIVATE_SPACE_LOCK_TAP : LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP);
- if (lock) {
- lockPrivateProfile();
- } else {
- unlockPrivateProfile();
- }
- }
-
- private void addPrivateSpaceSettingsButton(ImageButton settingsButton) {
- if (getCurrentState() == STATE_ENABLED
- && isPrivateSpaceSettingsAvailable()) {
- settingsButton.setVisibility(VISIBLE);
- settingsButton.setOnClickListener(
- view -> {
- logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
- openPrivateSpaceSettings(view);
- });
- } else {
- settingsButton.setVisibility(GONE);
- }
- }
-
- private void addTransitionImage(ImageView transitionImage) {
- if (getCurrentState() == STATE_TRANSITION) {
- transitionImage.setVisibility(VISIBLE);
- } else {
- transitionImage.setVisibility(GONE);
- }
+ setQuietMode(lock);
}
/** Finds the private space header to scroll to and set the private space icons to GONE. */
@@ -498,7 +439,10 @@
return LinearSmoothScroller.SNAP_TO_END;
}
};
- smoothScroller.setTargetPosition(i);
+ // If privateSpaceHidden() then the entire container decorator will be invisible and
+ // we can directly move to an element above the header. There should always be one
+ // element, as PS is present in the bottom of All Apps.
+ smoothScroller.setTargetPosition(isPrivateSpaceHidden() ? i - 1 : i);
RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
if (layoutManager != null) {
startAnimationScroll(allAppsRecyclerView, layoutManager, smoothScroller);
@@ -620,8 +564,11 @@
float newAlpha = (float) valueAnimator.getAnimatedValue();
for (int i = 0; i < allAppsAdapterItems.size(); i++) {
BaseAllAppsAdapter.AdapterItem currentItem = allAppsAdapterItems.get(i);
+ // When not hidden: Fade all PS items except header.
+ // When hidden: Fade all items.
if (isPrivateSpaceItem(currentItem) &&
- currentItem.viewType != VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+ (currentItem.viewType != VIEW_TYPE_PRIVATE_SPACE_HEADER
+ || isPrivateSpaceHidden())) {
RecyclerView.ViewHolder viewHolder =
allAppsRecyclerView.findViewHolderForAdapterPosition(i);
if (viewHolder != null) {
@@ -681,6 +628,7 @@
}
});
animatorSet.addListener(forEndCallback(() -> {
+ mIsStateTransitioning = false;
setAnimationRunning(false);
getMainRecyclerView().setChildAttachedConsumer(child -> child.setAlpha(1));
mStatsLogManager.logger().sendToInteractionJankMonitor(
@@ -689,6 +637,8 @@
: LAUNCHER_PRIVATE_SPACE_LOCK_ANIMATION_END,
mAllApps.getActiveRecyclerView());
if (!expand) {
+ mAllApps.mAH.get(MAIN).mRecyclerView.removeItemDecoration(
+ mPrivateAppsSectionDecorator);
// Call onAppsUpdated() because it may be canceled when this animation occurs.
mAllApps.getPersonalAppList().onAppsUpdated();
if (isPrivateSpaceHidden()) {
@@ -702,43 +652,42 @@
translateFloatingMaskView(false));
} else {
if (isPrivateSpaceHidden()) {
- animatorSet.playSequentially(translateFloatingMaskView(false),
- animateAlphaOfIcons(false),
- animateCollapseAnimation(),
- fadeOutHeaderAlpha());
+ animatorSet.playSequentially(animateAlphaOfIcons(false),
+ animateAlphaOfPrivateSpaceContainer(),
+ animateCollapseAnimation());
} else {
animatorSet.playSequentially(translateFloatingMaskView(true),
animateAlphaOfIcons(false),
animateCollapseAnimation());
}
}
- animatorSet.setDuration(EXPAND_COLLAPSE_DURATION);
animatorSet.start();
}
- /** Fades out the private space container. */
- private ValueAnimator fadeOutHeaderAlpha() {
- if (mPSHeader == null) {
- return new ValueAnimator();
- }
- float from = 1;
- float to = 0;
- ValueAnimator alphaAnim = ObjectAnimator.ofFloat(from, to);
- alphaAnim.setDuration(EXPAND_COLLAPSE_DURATION);
- alphaAnim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator valueAnimator) {
- if (mPSHeader != null) {
- mPSHeader.setAlpha((float) valueAnimator.getAnimatedValue());
+ /** Fades out the private space container (defined by its items' decorators). */
+ private ValueAnimator animateAlphaOfPrivateSpaceContainer() {
+ int from = 255; // 100% opacity.
+ int to = 0; // No opacity.
+ ValueAnimator alphaAnim = ObjectAnimator.ofInt(from, to);
+ AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
+ List<BaseAllAppsAdapter.AdapterItem> allAppsAdapterItems =
+ allAppsRecyclerView.getApps().getAdapterItems();
+ alphaAnim.setDuration(CONTAINER_OPACITY_DURATION);
+ alphaAnim.addUpdateListener(valueAnimator -> {
+ for (BaseAllAppsAdapter.AdapterItem currentItem : allAppsAdapterItems) {
+ if (isPrivateSpaceItem(currentItem)) {
+ currentItem.setDecorationFillAlpha((int) valueAnimator.getAnimatedValue());
}
}
+ // Invalidate the parent view, to redraw the decorations with changed alpha.
+ allAppsRecyclerView.invalidate();
});
return alphaAnim;
}
/** Fades out the private space container. */
private ValueAnimator translateFloatingMaskView(boolean animateIn) {
- if (!Flags.privateSpaceFloatingMaskView() || mFloatingMaskView == null) {
+ if (!Flags.privateSpaceAddFloatingMaskView() || mFloatingMaskView == null) {
return new ValueAnimator();
}
// Translate base on the height amount. Translates out on expand and in on collapse.
@@ -773,7 +722,7 @@
public void endTransition(LayoutTransition transition, ViewGroup viewGroup,
View view, int i) {
settingsAndLockGroup.setLayoutTransition(null);
- mAnimate = false;
+ mReadyToAnimate = false;
}
});
settingsAndLockGroup.setLayoutTransition(settingsAndLockTransition);
@@ -849,7 +798,7 @@
}
private void attachFloatingMaskView(boolean expand) {
- if (!Flags.privateSpaceFloatingMaskView()) {
+ if (!Flags.privateSpaceAddFloatingMaskView()) {
return;
}
mFloatingMaskView = (FloatingMaskView) mAllApps.getLayoutInflater().inflate(
@@ -873,7 +822,7 @@
/** Starts the smooth scroll with the provided smoothScroller and add idle listener. */
private void startAnimationScroll(AllAppsRecyclerView allAppsRecyclerView,
RecyclerView.LayoutManager layoutManager, RecyclerView.SmoothScroller smoothScroller) {
- mAnimationScrolling = true;
+ mIsScrolling = true;
layoutManager.startSmoothScroll(smoothScroller);
allAppsRecyclerView.removeOnScrollListener(mOnIdleScrollListener);
allAppsRecyclerView.addOnScrollListener(mOnIdleScrollListener);
@@ -887,12 +836,24 @@
return mAllApps.mAH.get(ActivityAllAppsContainerView.AdapterHolder.MAIN).mRecyclerView;
}
- boolean getAnimate() {
- return mAnimate;
+ /** Returns if private space is readily available to be animated. */
+ boolean getReadyToAnimate() {
+ return mReadyToAnimate;
}
- boolean getAnimationScrolling() {
- return mAnimationScrolling;
+ /** Returns when a smooth scroll is happening. */
+ boolean isScrolling() {
+ return mIsScrolling;
+ }
+
+ /**
+ * Returns when private space is in the process of transitioning. This is different from
+ * getAnimate() since mStateTransitioning checks from the time transitioning starts happening
+ * in reset() as oppose to when private space is animating. This should be used to ensure
+ * Private Space state during onBind().
+ */
+ boolean isStateTransitioning() {
+ return mIsStateTransitioning;
}
int getPsHeaderHeight() {
diff --git a/src/com/android/launcher3/allapps/PrivateSpaceSettingsButton.java b/src/com/android/launcher3/allapps/PrivateSpaceSettingsButton.java
new file mode 100644
index 0000000..43e42ff
--- /dev/null
+++ b/src/com/android/launcher3/allapps/PrivateSpaceSettingsButton.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.allapps;
+
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PRIVATESPACE;
+import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP;
+
+import android.content.Context;
+import android.content.Intent;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.ImageButton;
+
+import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.util.ApiWrapper;
+import com.android.launcher3.views.ActivityContext;
+
+public class PrivateSpaceSettingsButton extends ImageButton implements View.OnClickListener {
+
+ private final ActivityContext mActivityContext;
+ private final StatsLogManager mStatsLogManager;
+ private final Intent mPrivateSpaceSettingsIntent;
+
+ public PrivateSpaceSettingsButton(Context context) {
+ this(context, null, 0);
+ }
+
+ public PrivateSpaceSettingsButton(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public PrivateSpaceSettingsButton(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mActivityContext = ActivityContext.lookupContext(context);
+ mStatsLogManager = mActivityContext.getStatsLogManager();
+ mPrivateSpaceSettingsIntent =
+ ApiWrapper.INSTANCE.get(context).getPrivateSpaceSettingsIntent();
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ setOnClickListener(this);
+ }
+
+ @Override
+ public void onClick(View view) {
+ mStatsLogManager.logger().log(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
+ AppInfo privateSpaceSettingsItemInfo = createPrivateSpaceSettingsAppInfo();
+ view.setTag(privateSpaceSettingsItemInfo);
+ mActivityContext.startActivitySafely(
+ view,
+ mPrivateSpaceSettingsIntent,
+ privateSpaceSettingsItemInfo);
+ }
+
+ AppInfo createPrivateSpaceSettingsAppInfo() {
+ AppInfo itemInfo = new AppInfo();
+ itemInfo.id = CONTAINER_PRIVATESPACE;
+ if (mPrivateSpaceSettingsIntent != null) {
+ itemInfo.componentName = mPrivateSpaceSettingsIntent.getComponent();
+ }
+ itemInfo.container = CONTAINER_PRIVATESPACE;
+ return itemInfo;
+ }
+}
diff --git a/src/com/android/launcher3/allapps/UserProfileManager.java b/src/com/android/launcher3/allapps/UserProfileManager.java
index 3351ee3..93b6b29 100644
--- a/src/com/android/launcher3/allapps/UserProfileManager.java
+++ b/src/com/android/launcher3/allapps/UserProfileManager.java
@@ -40,11 +40,13 @@
* {@link PrivateProfileManager} which manages private profile state.
*/
public abstract class UserProfileManager {
+ public static final int STATE_UNKNOWN = 0;
public static final int STATE_ENABLED = 1;
public static final int STATE_DISABLED = 2;
public static final int STATE_TRANSITION = 3;
@IntDef(value = {
+ STATE_UNKNOWN,
STATE_ENABLED,
STATE_DISABLED,
STATE_TRANSITION
@@ -53,12 +55,11 @@
public @interface UserProfileState { }
protected final StatsLogManager mStatsLogManager;
+ protected final UserManager mUserManager;
+ protected final UserCache mUserCache;
+
@UserProfileState
private int mCurrentState;
-
- private final UserManager mUserManager;
- private final UserCache mUserCache;
-
protected UserProfileManager(UserManager userManager,
StatsLogManager statsLogManager,
UserCache userCache) {
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 4b908bf..33e6f91 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -84,11 +84,6 @@
+ "data preparation for loading the home screen");
// TODO(Block 4): Cleanup flags
- public static final BooleanFlag ENABLE_FLOATING_SEARCH_BAR =
- getReleaseFlag(268388460, "ENABLE_FLOATING_SEARCH_BAR", DISABLED,
- "Allow search bar to persist and animate across states, and attach to"
- + " the keyboard from the bottom of the screen");
-
public static final BooleanFlag ENABLE_ALL_APPS_FROM_OVERVIEW =
getDebugFlag(275132633, "ENABLE_ALL_APPS_FROM_OVERVIEW", DISABLED,
"Allow entering All Apps from Overview (e.g. long swipe up from app)");
diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java
index ec0a222..85eb39b 100644
--- a/src/com/android/launcher3/dragndrop/AddItemActivity.java
+++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java
@@ -91,7 +91,8 @@
*/
@TargetApi(Build.VERSION_CODES.O)
public class AddItemActivity extends BaseActivity
- implements OnLongClickListener, OnTouchListener, AbstractSlideInView.OnCloseListener {
+ implements OnLongClickListener, OnTouchListener, AbstractSlideInView.OnCloseListener,
+ WidgetCell.PreviewReadyListener {
private static final int SHADOW_SIZE = 10;
@@ -142,6 +143,7 @@
mDragLayer = findViewById(R.id.add_item_drag_layer);
mDragLayer.recreateControllers();
mWidgetCell = findViewById(R.id.widget_cell);
+ mWidgetCell.addPreviewReadyListener(this);
mAccessibilityManager =
getApplicationContext().getSystemService(AccessibilityManager.class);
@@ -454,4 +456,11 @@
.withItemInfo((ItemInfo) mWidgetCell.getWidgetView().getTag())
.log(command);
}
+
+ @Override
+ public void onPreviewAvailable() {
+ // Set the preview height based on "the only" widget's preview.
+ mWidgetCell.setParentAlignedPreviewHeight(mWidgetCell.getPreviewContentHeight());
+ mWidgetCell.post(mWidgetCell::requestLayout);
+ }
}
diff --git a/src/com/android/launcher3/dragndrop/LauncherDragController.java b/src/com/android/launcher3/dragndrop/LauncherDragController.java
index f3708a2..29fc613 100644
--- a/src/com/android/launcher3/dragndrop/LauncherDragController.java
+++ b/src/com/android/launcher3/dragndrop/LauncherDragController.java
@@ -28,6 +28,7 @@
import android.view.View;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DragSource;
@@ -36,6 +37,7 @@
import com.android.launcher3.R;
import com.android.launcher3.accessibility.DragViewStateAnnouncer;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.widget.util.WidgetDragScaleUtils;
/**
* Drag controller for Launcher activity
@@ -43,7 +45,6 @@
public class LauncherDragController extends DragController<Launcher> {
private static final boolean PROFILE_DRAWING_DURING_DRAG = false;
-
private final FlingToDeleteHelper mFlingToDeleteHelper;
public LauncherDragController(Launcher launcher) {
@@ -92,8 +93,13 @@
&& !mOptions.preDragCondition.shouldStartDrag(0);
final Resources res = mActivity.getResources();
- final float scaleDps = mIsInPreDrag
- ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f;
+
+ final float scalePx;
+ if (originalView.getViewType() == DraggableView.DRAGGABLE_WIDGET) {
+ scalePx = mIsInPreDrag ? 0f : getWidgetDragScalePx(drawable, view, dragInfo);
+ } else {
+ scalePx = mIsInPreDrag ? res.getDimensionPixelSize(R.dimen.pre_drag_view_scale) : 0f;
+ }
final DragView dragView = mDragObject.dragView = drawable != null
? new LauncherDragView(
mActivity,
@@ -102,7 +108,7 @@
registrationY,
initialDragViewScale,
dragViewScaleOnDrop,
- scaleDps)
+ scalePx)
: new LauncherDragView(
mActivity,
view,
@@ -112,7 +118,7 @@
registrationY,
initialDragViewScale,
dragViewScaleOnDrop,
- scaleDps);
+ scalePx);
dragView.setItemInfo(dragInfo);
mDragObject.dragComplete = false;
@@ -157,6 +163,29 @@
return dragView;
}
+
+ /**
+ * Returns the scale in terms of pixels (to be applied on width) to scale the preview
+ * during drag and drop.
+ */
+ @VisibleForTesting
+ float getWidgetDragScalePx(@Nullable Drawable drawable, @Nullable View view,
+ ItemInfo dragInfo) {
+ float draggedViewWidthPx = 0;
+ float draggedViewHeightPx = 0;
+
+ if (view != null) {
+ draggedViewWidthPx = view.getMeasuredWidth();
+ draggedViewHeightPx = view.getMeasuredHeight();
+ } else if (drawable != null) {
+ draggedViewWidthPx = drawable.getIntrinsicWidth();
+ draggedViewHeightPx = drawable.getIntrinsicHeight();
+ }
+
+ return WidgetDragScaleUtils.getWidgetDragScalePx(mActivity, mActivity.getDeviceProfile(),
+ draggedViewWidthPx, draggedViewHeightPx, dragInfo);
+ }
+
@Override
protected void exitDrag() {
if (!mActivity.isInState(EDIT_MODE)) {
diff --git a/src/com/android/launcher3/folder/FolderAnimationManager.java b/src/com/android/launcher3/folder/FolderAnimationManager.java
index 7ef3209..9824992 100644
--- a/src/com/android/launcher3/folder/FolderAnimationManager.java
+++ b/src/com/android/launcher3/folder/FolderAnimationManager.java
@@ -242,11 +242,26 @@
// Create reveal animator for the folder content (capture the top 4 icons 2x2)
int width = mDeviceProfile.folderCellLayoutBorderSpacePx.x
+ mDeviceProfile.folderCellWidthPx * 2;
+ int rtlExtraWidth = 0;
int height = mDeviceProfile.folderCellLayoutBorderSpacePx.y
+ mDeviceProfile.folderCellHeightPx * 2;
int page = mIsOpening ? mContent.getCurrentPage() : mContent.getDestinationPage();
+ // In RTL we want to move to the last 2 columns of icons in the folder.
+ if (Utilities.isRtl(mContext.getResources())) {
+ page = (mContent.getPageCount() - 1) - page;
+ CellLayout clAtPage = mContent.getPageAt(page);
+ if (clAtPage != null) {
+ int numExtraRows = clAtPage.getCountX() - 2;
+ rtlExtraWidth = (int) Math.max(numExtraRows * (mDeviceProfile.folderCellWidthPx
+ + mDeviceProfile.folderCellLayoutBorderSpacePx.x), rtlExtraWidth);
+ }
+ }
int left = mContent.getPaddingLeft() + page * lp.width;
- Rect contentStart = new Rect(left, 0, left + width, height);
+ Rect contentStart = new Rect(
+ left + rtlExtraWidth,
+ 0,
+ left + width + mContent.getPaddingRight() + rtlExtraWidth,
+ height);
Rect contentEnd = new Rect(left, 0, left + lp.width, lp.height);
play(a, shapeDelegate.createRevealAnimator(
mFolder.getContent(), contentStart, contentEnd, finalRadius, !mIsOpening));
diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java
index 04d8ac0..44e448e 100644
--- a/src/com/android/launcher3/icons/IconCache.java
+++ b/src/com/android/launcher3/icons/IconCache.java
@@ -57,6 +57,7 @@
import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic;
import com.android.launcher3.icons.cache.BaseIconCache;
import com.android.launcher3.icons.cache.CachingLogic;
+import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.IconRequestInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -641,4 +642,10 @@
void reapplyItemInfo(ItemInfoWithIcon info);
}
+
+ /** Log persistently to FileLog.d for debugging. */
+ @Override
+ protected void logdPersistently(String tag, String message, @Nullable Exception e) {
+ FileLog.d(tag, message, e);
+ }
}
diff --git a/src/com/android/launcher3/model/WidgetsModel.java b/src/com/android/launcher3/model/WidgetsModel.java
index 5e0edb3..4cba0b5 100644
--- a/src/com/android/launcher3/model/WidgetsModel.java
+++ b/src/com/android/launcher3/model/WidgetsModel.java
@@ -32,6 +32,7 @@
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.pm.ShortcutConfigActivityInfo;
+import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Preconditions;
@@ -130,6 +131,22 @@
}
/**
+ * Returns a map of widget component keys to corresponding widget items. Excludes the
+ * shortcuts.
+ */
+ public synchronized Map<ComponentKey, WidgetItem> getAllWidgetComponentsWithoutShortcuts() {
+ if (!WIDGETS_ENABLED) {
+ return Collections.emptyMap();
+ }
+ Map<ComponentKey, WidgetItem> widgetsMap = new HashMap<>();
+ mWidgetsList.forEach((packageItemInfo, widgetsAndShortcuts) ->
+ widgetsAndShortcuts.stream().filter(item -> item.widgetInfo != null).forEach(
+ item -> widgetsMap.put(new ComponentKey(item.componentName, item.user),
+ item)));
+ return widgetsMap;
+ }
+
+ /**
* @param packageUser If null, all widgets and shortcuts are updated and returned, otherwise
* only widgets and shortcuts associated with the package/user are.
*/
diff --git a/src/com/android/launcher3/popup/RoundedArrowDrawable.java b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
index 575052c..2610bd6 100644
--- a/src/com/android/launcher3/popup/RoundedArrowDrawable.java
+++ b/src/com/android/launcher3/popup/RoundedArrowDrawable.java
@@ -175,7 +175,10 @@
mPaint.setShadowLayer(shadowBlur, dx, dy, shadowColor);
}
- private static void addDownPointingRoundedTriangleToPath(float width, float height,
+ /**
+ * Adds rounded triangle pointing down to the provided {@link Path path} argument
+ */
+ public static void addDownPointingRoundedTriangleToPath(float width, float height,
float radius, Path path) {
// Calculated for the arrow pointing down, will be flipped later if needed.
diff --git a/src/com/android/launcher3/qsb/QsbContainerView.java b/src/com/android/launcher3/qsb/QsbContainerView.java
index 8e53aff..d6b41b0 100644
--- a/src/com/android/launcher3/qsb/QsbContainerView.java
+++ b/src/com/android/launcher3/qsb/QsbContainerView.java
@@ -61,7 +61,7 @@
*/
public class QsbContainerView extends FrameLayout {
- public static final String SEARCH_PROVIDER_SETTINGS_KEY = "SEARCH_PROVIDER_PACKAGE_NAME";
+ public static final String SEARCH_ENGINE_SETTINGS_KEY = "selected_search_engine";
/**
* Returns the package name for user configured search provider or from searchManager
@@ -71,8 +71,8 @@
@WorkerThread
@Nullable
public static String getSearchWidgetPackageName(@NonNull Context context) {
- String providerPkg = Settings.Global.getString(context.getContentResolver(),
- SEARCH_PROVIDER_SETTINGS_KEY);
+ String providerPkg = Settings.Secure.getString(context.getContentResolver(),
+ SEARCH_ENGINE_SETTINGS_KEY);
if (providerPkg == null) {
SearchManager searchManager = context.getSystemService(SearchManager.class);
ComponentName componentName = searchManager.getGlobalSearchActivity();
diff --git a/src/com/android/launcher3/util/ApiWrapper.java b/src/com/android/launcher3/util/ApiWrapper.java
index 6429a43..095518c 100644
--- a/src/com/android/launcher3/util/ApiWrapper.java
+++ b/src/com/android/launcher3/util/ApiWrapper.java
@@ -16,10 +16,12 @@
package com.android.launcher3.util;
+import static com.android.launcher3.LauncherConstants.ActivityCodes.REQUEST_HOME_ROLE;
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
import android.app.ActivityOptions;
import android.app.Person;
+import android.app.role.RoleManager;
import android.content.Context;
import android.content.Intent;
import android.content.pm.LauncherActivityInfo;
@@ -33,6 +35,7 @@
import androidx.annotation.Nullable;
import com.android.launcher3.BuildConfig;
+import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
@@ -136,6 +139,23 @@
return false;
}
+ /**
+ * Starts an Activity which can be used to set this Launcher as the HOME app, via a consent
+ * screen. In case the consent screen cannot be shown, or the user does not set current Launcher
+ * as HOME app, a toast asking the user to do the latter is shown.
+ */
+ public void assignDefaultHomeRole(Context context) {
+ RoleManager roleManager = context.getSystemService(RoleManager.class);
+ assert roleManager != null;
+ if (roleManager.isRoleAvailable(RoleManager.ROLE_HOME)
+ && !roleManager.isRoleHeld(RoleManager.ROLE_HOME)) {
+ Intent roleRequestIntent = roleManager.createRequestRoleIntent(
+ RoleManager.ROLE_HOME);
+ Launcher launcher = Launcher.getLauncher(context);
+ launcher.startActivityForResult(roleRequestIntent, REQUEST_HOME_ROLE);
+ }
+ }
+
@Override
public void close() { }
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 92fc38f..16fabe2 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -170,11 +170,13 @@
* Returns the current navigation mode
*/
public static NavigationMode getNavigationMode(Context context) {
- return INSTANCE.get(context).getInfo().navigationMode;
+ return INSTANCE.get(context).getInfo().getNavigationMode();
}
/**
- * Returns whether taskbar is transient.
+ * Returns whether taskbar is transient or persistent.
+ *
+ * @return {@code true} if transient, {@code false} if persistent.
*/
public static boolean isTransientTaskbar(Context context) {
return INSTANCE.get(context).getInfo().isTransientTaskbar();
@@ -302,7 +304,7 @@
Info newInfo = new Info(displayInfoContext, wmProxy, oldInfo.mPerDisplayBounds);
if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale
- || newInfo.navigationMode != oldInfo.navigationMode) {
+ || newInfo.getNavigationMode() != oldInfo.getNavigationMode()) {
// Cache may not be valid anymore, recreate without cache
newInfo = new Info(displayInfoContext, wmProxy,
wmProxy.estimateInternalDisplayBounds(displayInfoContext));
@@ -318,7 +320,7 @@
if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale) {
change |= CHANGE_DENSITY;
}
- if (newInfo.navigationMode != oldInfo.navigationMode) {
+ if (newInfo.getNavigationMode() != oldInfo.getNavigationMode()) {
change |= CHANGE_NAVIGATION_MODE;
}
if (!newInfo.supportedBounds.equals(oldInfo.supportedBounds)
@@ -369,7 +371,7 @@
// Configuration property
public final float fontScale;
private final int densityDpi;
- public final NavigationMode navigationMode;
+ private final NavigationMode navigationMode;
private final PortraitSize mScreenSizeDp;
// WindowBounds
@@ -405,7 +407,7 @@
navigationMode = wmProxy.getNavigationMode(displayInfoContext);
mPerDisplayBounds.putAll(perDisplayBoundsCache);
- List<WindowBounds> cachedValue = mPerDisplayBounds.get(normalizedDisplayInfo);
+ List<WindowBounds> cachedValue = getCurrentBounds();
realBounds = wmProxy.getRealBounds(displayInfoContext, displayInfo);
if (cachedValue == null) {
@@ -415,7 +417,7 @@
FileLog.e(TAG, "(Invalid Cache) perDisplayBounds : " + mPerDisplayBounds);
mPerDisplayBounds.clear();
mPerDisplayBounds.putAll(wmProxy.estimateInternalDisplayBounds(displayInfoContext));
- cachedValue = mPerDisplayBounds.get(normalizedDisplayInfo);
+ cachedValue = getCurrentBounds();
if (cachedValue == null) {
FileLog.e(TAG, "normalizedDisplayInfo not found in estimation: "
+ normalizedDisplayInfo);
@@ -505,6 +507,13 @@
return Collections.unmodifiableSet(mPerDisplayBounds.keySet());
}
+ /**
+ * Returns all {@link WindowBounds}s for the current display.
+ */
+ public List<WindowBounds> getCurrentBounds() {
+ return mPerDisplayBounds.get(normalizedDisplayInfo);
+ }
+
public int getDensityDpi() {
return densityDpi;
}
@@ -553,7 +562,7 @@
pw.println(" rotation=" + info.rotation);
pw.println(" fontScale=" + info.fontScale);
pw.println(" densityDpi=" + info.densityDpi);
- pw.println(" navigationMode=" + info.navigationMode.name());
+ pw.println(" navigationMode=" + info.getNavigationMode().name());
pw.println(" isTaskbarPinned=" + info.mIsTaskbarPinned);
pw.println(" isTaskbarPinnedInDesktopMode=" + info.mIsTaskbarPinnedInDesktopMode);
pw.println(" isInDesktopMode=" + info.mIsInDesktopMode);
diff --git a/src/com/android/launcher3/util/SplitConfigurationOptions.java b/src/com/android/launcher3/util/SplitConfigurationOptions.java
index 837d7bc..95624b1 100644
--- a/src/com/android/launcher3/util/SplitConfigurationOptions.java
+++ b/src/com/android/launcher3/util/SplitConfigurationOptions.java
@@ -186,6 +186,12 @@
public int stagePosition = STAGE_POSITION_UNDEFINED;
@StageType
public int stageType = STAGE_TYPE_UNDEFINED;
+
+ @Override
+ public String toString() {
+ return "SplitStageInfo { taskId=" + taskId
+ + ", stagePosition=" + stagePosition + ", stageType=" + stageType + " }";
+ }
}
public static StatsLogManager.EventEnum getLogEventForPosition(@StagePosition int position) {
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index df8f635..fa17b7b 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -109,6 +109,13 @@
private float mLastTouchY;
private boolean mIsDragging;
+ /**
+ * Tracks whether a keyboard hide request has been sent due to downward scrolling.
+ * <p>
+ * Set to true when scrolling down and reset when scrolling up to prevents redundant hide
+ * requests during continuous downward scrolls.
+ */
+ private boolean mRequestedHideKeyboard;
private boolean mIsThumbDetached;
private final boolean mCanThumbDetach;
private boolean mIgnoreDragGesture;
@@ -127,6 +134,7 @@
protected FastScrollRecyclerView mRv;
private RecyclerView.OnScrollListener mOnScrollListener;
+ private final ActivityContext mActivityContext;
private int mDownX;
private int mDownY;
@@ -163,7 +171,7 @@
mDeltaThreshold = res.getDisplayMetrics().density * SCROLL_DELTA_THRESHOLD_DP;
mScrollbarLeftOffsetTouchDelegate = res.getDisplayMetrics().density
* SCROLLBAR_LEFT_OFFSET_TOUCH_DELEGATE_DP;
-
+ mActivityContext = ActivityContext.lookupContext(context);
TypedArray ta =
context.obtainStyledAttributes(attrs, R.styleable.RecyclerViewFastScroller, defStyleAttr, 0);
mCanThumbDetach = ta.getBoolean(R.styleable.RecyclerViewFastScroller_canThumbDetach, false);
@@ -248,6 +256,7 @@
mDownX = x;
mDownY = mLastY = y;
mDownTimeStampMillis = ev.getDownTime();
+ mRequestedHideKeyboard = false;
if ((Math.abs(mDy) < mDeltaThreshold &&
mRv.getScrollState() != SCROLL_STATE_IDLE)) {
@@ -260,6 +269,7 @@
}
break;
case MotionEvent.ACTION_MOVE:
+ boolean isScrollingDown = y > mLastY;
mLastY = y;
int absDeltaY = Math.abs(y - mDownY);
int absDeltaX = Math.abs(x - mDownX);
@@ -275,6 +285,14 @@
}
}
if (mIsDragging) {
+ if (isScrollingDown) {
+ if (!mRequestedHideKeyboard) {
+ mActivityContext.hideKeyboard();
+ }
+ mRequestedHideKeyboard = true;
+ } else {
+ mRequestedHideKeyboard = false;
+ }
updateFastScrollSectionNameAndThumbOffset(y);
}
break;
@@ -294,7 +312,6 @@
}
private void calcTouchOffsetAndPrepToFastScroll(int downY, int lastY) {
- ActivityContext.lookupContext(getContext()).hideKeyboard();
mIsDragging = true;
if (mCanThumbDetach) {
mIsThumbDetached = true;
diff --git a/src/com/android/launcher3/widget/WidgetCell.java b/src/com/android/launcher3/widget/WidgetCell.java
index eac2ce7..35372d3 100644
--- a/src/com/android/launcher3/widget/WidgetCell.java
+++ b/src/com/android/launcher3/widget/WidgetCell.java
@@ -103,6 +103,8 @@
private Size mWidgetSize;
private final DatabaseWidgetPreviewLoader mWidgetPreviewLoader;
+ @Nullable
+ private PreviewReadyListener mPreviewReadyListener = null;
protected CancellableTask mActiveRequest;
private boolean mAnimatePreview = true;
@@ -118,7 +120,8 @@
private CancellableTask mIconLoadRequest;
private boolean mIsShowingAddButton = false;
-
+ // Height enforced by the parent to align all widget cells displayed by it.
+ private int mParentAlignedPreviewHeight;
public WidgetCell(Context context) {
this(context, null);
}
@@ -190,6 +193,8 @@
mWidgetDims.setText(null);
mWidgetDescription.setText(null);
mWidgetDescription.setVisibility(GONE);
+ mPreviewReadyListener = null;
+ mParentAlignedPreviewHeight = 0;
showDescription(true);
showDimensions(true);
@@ -338,8 +343,8 @@
private void updateAppWidgetHostScale(NavigableAppWidgetHostView view) {
// Scale the content such that all of the content is visible
- int contentWidth = view.getWidth();
- int contentHeight = view.getHeight();
+ float contentWidth = view.getWidth();
+ float contentHeight = view.getHeight();
if (view.getChildCount() == 1) {
View content = view.getChildAt(0);
@@ -359,6 +364,19 @@
mAppWidgetHostViewScale = Math.min(pWidth / contentWidth, pHeight / contentHeight);
}
view.setScaleToFit(mAppWidgetHostViewScale);
+
+ // layout based previews maybe ready at this point to inspect their inner height.
+ if (mPreviewReadyListener != null) {
+ mPreviewReadyListener.onPreviewAvailable();
+ mPreviewReadyListener = null;
+ }
+ }
+
+ /**
+ * Returns a view (holding the previews) that can be dragged and dropped.
+ */
+ public View getDragAndDropView() {
+ return mWidgetImageContainer;
}
public WidgetImageView getWidgetView() {
@@ -384,6 +402,12 @@
removeView(mAppWidgetHostViewPreview);
mAppWidgetHostViewPreview = null;
}
+
+ // Drawables of the image previews are available at this point to measure.
+ if (mPreviewReadyListener != null) {
+ mPreviewReadyListener.onPreviewAvailable();
+ mPreviewReadyListener = null;
+ }
}
if (mAnimatePreview) {
@@ -489,14 +513,20 @@
// mPreviewContainerScale ensures the needed scaling with respect to original widget size.
mAppWidgetHostViewScale = mPreviewContainerScale;
containerLp.width = mPreviewContainerSize.getWidth();
- containerLp.height = mPreviewContainerSize.getHeight();
+ int height = mPreviewContainerSize.getHeight();
// If we don't have enough available width, scale the preview container to fit.
if (containerLp.width > maxWidth) {
containerLp.width = maxWidth;
mAppWidgetHostViewScale = (float) containerLp.width / mPreviewContainerSize.getWidth();
- containerLp.height = Math.round(
- mPreviewContainerSize.getHeight() * mAppWidgetHostViewScale);
+ height = Math.round(mPreviewContainerSize.getHeight() * mAppWidgetHostViewScale);
+ }
+
+ // Use parent aligned height in set.
+ if (mParentAlignedPreviewHeight > 0) {
+ containerLp.height = Math.min(height, mParentAlignedPreviewHeight);
+ } else {
+ containerLp.height = height;
}
// No need to call mWidgetImageContainer.setLayoutParams as we are in measure pass
@@ -513,6 +543,42 @@
}
/**
+ * Sets the height of the preview as adjusted by the parent to have this cell's content aligned
+ * with other cells displayed by the parent.
+ */
+ public void setParentAlignedPreviewHeight(int previewHeight) {
+ mParentAlignedPreviewHeight = previewHeight;
+ }
+
+ /**
+ * Returns the height of the preview without any empty space.
+ * In case of appwidget host views, it returns the height of first child. This way, if preview
+ * view provided by an app doesn't fill bounds, this will return actual height without white
+ * space.
+ */
+ public int getPreviewContentHeight() {
+ // By default assume scaled height.
+ int height = Math.round(mPreviewContainerScale * mWidgetSize.getHeight());
+
+ if (mWidgetImage != null && mWidgetImage.getDrawable() != null) {
+ // getBitmapBounds returns the scaled bounds.
+ Rect bitmapBounds = mWidgetImage.getBitmapBounds();
+ height = bitmapBounds.height();
+ } else if (mAppWidgetHostViewPreview != null
+ && mAppWidgetHostViewPreview.getChildCount() == 1) {
+ int contentHeight = Math.round(
+ mPreviewContainerScale * mWidgetSize.getHeight());
+ int previewInnerHeight = Math.round(
+ mAppWidgetHostViewScale * mAppWidgetHostViewPreview.getChildAt(
+ 0).getMeasuredHeight());
+ // Use either of the inner scaled height or the scaled widget height
+ height = Math.min(contentHeight, previewInnerHeight);
+ }
+
+ return height;
+ }
+
+ /**
* Loads a high resolution package icon to show next to the widget title.
*/
public void loadHighResPackageIcon() {
@@ -651,4 +717,19 @@
}
return false;
}
+
+ /**
+ * Listener to notify when previews are available.
+ */
+ public void addPreviewReadyListener(PreviewReadyListener previewReadyListener) {
+ mPreviewReadyListener = previewReadyListener;
+ }
+
+ /**
+ * Listener interface for subscribers to listen to preview's availability.
+ */
+ public interface PreviewReadyListener {
+ /** Handler on to invoke when previews are available. */
+ void onPreviewAvailable();
+ }
}
diff --git a/src/com/android/launcher3/widget/WidgetTableRow.java b/src/com/android/launcher3/widget/WidgetTableRow.java
new file mode 100644
index 0000000..a5312ce
--- /dev/null
+++ b/src/com/android/launcher3/widget/WidgetTableRow.java
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.widget.TableRow;
+
+/**
+ * A row of {@link WidgetCell}s that can be displayed in a table.
+ */
+public class WidgetTableRow extends TableRow implements WidgetCell.PreviewReadyListener {
+ private int mNumOfReadyCells;
+ private int mNumOfCells;
+ private int mResizeDelay;
+
+ public WidgetTableRow(Context context) {
+ super(context);
+ }
+ public WidgetTableRow(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void onPreviewAvailable() {
+ mNumOfReadyCells++;
+
+ // Once all previews are loaded, find max visible height and adjust the preview containers.
+ if (mNumOfReadyCells == mNumOfCells) {
+ resize();
+ }
+ }
+
+ private void resize() {
+ int previewHeight = 0;
+ // get the maximum height of each widget preview
+ for (int i = 0; i < getChildCount(); i++) {
+ WidgetCell widgetCell = (WidgetCell) getChildAt(i);
+ previewHeight = Math.max(widgetCell.getPreviewContentHeight(), previewHeight);
+ }
+ if (mResizeDelay > 0) {
+ postDelayed(() -> setAlpha(1f), mResizeDelay);
+ }
+ if (previewHeight > 0) {
+ for (int i = 0; i < getChildCount(); i++) {
+ WidgetCell widgetCell = (WidgetCell) getChildAt(i);
+ widgetCell.setParentAlignedPreviewHeight(previewHeight);
+ widgetCell.postDelayed(widgetCell::requestLayout, mResizeDelay);
+ }
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ }
+
+ /**
+ * Sets up the row to display the provided number of numOfCells.
+ *
+ * @param numOfCells number of numOfCells in the row
+ * @param resizeDelayMs time to wait in millis before making any layout size adjustments e.g. we
+ * want to wait for list expand collapse animation before resizing the
+ * cell previews.
+ */
+ public void setupRow(int numOfCells, int resizeDelayMs) {
+ mNumOfCells = numOfCells;
+ mNumOfReadyCells = 0;
+
+ mResizeDelay = resizeDelayMs;
+ // For delayed resize, reveal contents only after resize is done.
+ if (mResizeDelay > 0) {
+ setAlpha(0);
+ }
+ }
+}
diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
index 4ea2426..894099d 100644
--- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java
@@ -31,7 +31,6 @@
import android.view.animation.Interpolator;
import android.widget.ScrollView;
import android.widget.TableLayout;
-import android.widget.TableRow;
import android.widget.TextView;
import androidx.annotation.Px;
@@ -137,8 +136,9 @@
mActivityContext.getDeviceProfile(), mMaxHorizontalSpan,
mWidgetCellHorizontalPadding)
.forEach(row -> {
- TableRow tableRow = new TableRow(getContext());
+ WidgetTableRow tableRow = new WidgetTableRow(getContext());
tableRow.setGravity(Gravity.TOP);
+ tableRow.setupRow(row.size(), /*resizeDelayMs=*/ 0);
row.forEach(widgetItem -> {
WidgetCell widget = addItemCell(tableRow);
widget.applyFromCellItem(widgetItem);
@@ -163,9 +163,10 @@
return super.onControllerInterceptTouchEvent(ev);
}
- protected WidgetCell addItemCell(ViewGroup parent) {
+ protected WidgetCell addItemCell(WidgetTableRow parent) {
WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext())
.inflate(R.layout.widget_cell, parent, false);
+ widget.addPreviewReadyListener(parent);
widget.setOnClickListener(this);
View previewContainer = widget.findViewById(R.id.widget_preview_container);
diff --git a/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java b/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
index 4f73e66..9260af9 100644
--- a/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
+++ b/src/com/android/launcher3/widget/picker/WidgetRecommendationsView.java
@@ -53,6 +53,7 @@
*/
public final class WidgetRecommendationsView extends PagedView<PageIndicatorDots> {
private @Px float mAvailableHeight = Float.MAX_VALUE;
+ private @Px float mAvailableWidth = 0;
private static final String INITIALLY_DISPLAYED_WIDGETS_STATE_KEY =
"widgetRecommendationsView:mDisplayedWidgets";
private static final int MAX_CATEGORIES = 3;
@@ -152,6 +153,7 @@
final @Px float availableHeight, final @Px int availableWidth,
final @Px int cellPadding) {
this.mAvailableHeight = availableHeight;
+ this.mAvailableWidth = availableWidth;
clear();
Set<ComponentName> displayedWidgets = maybeDisplayInTable(recommendedWidgets,
@@ -187,6 +189,7 @@
DeviceProfile deviceProfile, final @Px float availableHeight,
final @Px int availableWidth, final @Px int cellPadding, final int requestedPage) {
this.mAvailableHeight = availableHeight;
+ this.mAvailableWidth = availableWidth;
Context context = getContext();
// For purpose of recommendations section, we don't want paging dots to be halved in two
// pane display, so, we always provide isTwoPanels = "false".
@@ -280,17 +283,24 @@
boolean hasMultiplePages = getChildCount() > 0;
if (hasMultiplePages) {
- int finalWidth = MeasureSpec.getSize(widthMeasureSpec);
int desiredHeight = 0;
+ int desiredWidth = Math.round(mAvailableWidth);
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
- measureChild(child, widthMeasureSpec, heightMeasureSpec);
+ // Measure children based on available height and width.
+ measureChild(child,
+ MeasureSpec.makeMeasureSpec(desiredWidth, MeasureSpec.EXACTLY),
+ MeasureSpec.makeMeasureSpec(Math.round(mAvailableHeight),
+ MeasureSpec.AT_MOST));
// Use height of tallest child as we have limited height.
- desiredHeight = Math.max(desiredHeight, child.getMeasuredHeight());
+ int childHeight = child.getMeasuredHeight();
+ desiredHeight = Math.max(desiredHeight, childHeight);
}
int finalHeight = resolveSizeAndState(desiredHeight, heightMeasureSpec, 0);
+ int finalWidth = resolveSizeAndState(desiredWidth, widthMeasureSpec, 0);
+
setMeasuredDimension(finalWidth, finalHeight);
} else {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index 6aaa7d2..9929892 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.SEARCH;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_SEARCHED;
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
-import static com.android.launcher3.widget.picker.WidgetsListAdapter.VIEW_TYPE_WIDGETS_LIST;
import android.animation.Animator;
import android.content.Context;
@@ -331,8 +330,7 @@
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- LauncherAppState.getInstance(mActivityContext).getModel()
- .refreshAndBindWidgetsAndShortcuts(null);
+ onWidgetsBound();
}
@Override
@@ -1023,35 +1021,7 @@
default:
break;
}
- mWidgetsListItemAnimator = new DefaultItemAnimator() {
- @Override
- public boolean animateChange(RecyclerView.ViewHolder oldHolder,
- RecyclerView.ViewHolder newHolder, int fromLeft, int fromTop, int toLeft,
- int toTop) {
- // As we expand an item, the content / widgets list that appears (with add
- // event) also gets change events as its previews load asynchronously. The
- // super implementation of animateChange cancels the animations on it - breaking
- // the "add animation". Instead, here, we skip "change" animation for content
- // list - because we want it to either appear or disappear. And, the previews
- // themselves have their own animation when loaded, so, we don't need change
- // animations for them anyway. Below, we do-nothing.
- if (oldHolder.getItemViewType() == VIEW_TYPE_WIDGETS_LIST) {
- dispatchChangeStarting(oldHolder, true);
- dispatchChangeFinished(oldHolder, true);
- return true;
- }
- return super.animateChange(oldHolder, newHolder, fromLeft, fromTop, toLeft,
- toTop);
- }
- };
- // Disable change animations because it disrupts the item focus upon adapter item
- // change.
- mWidgetsListItemAnimator.setSupportsChangeAnimations(false);
- // Make the moves a bit faster, so that the amount of time for which user sees the
- // bottom-sheet background before "add" animation starts is less making it smoother.
- mWidgetsListItemAnimator.setChangeDuration(90);
- mWidgetsListItemAnimator.setMoveDuration(90);
- mWidgetsListItemAnimator.setAddDuration(300);
+ mWidgetsListItemAnimator = new WidgetsListItemAnimator();
}
private int getEmptySpaceHeight() {
@@ -1065,7 +1035,7 @@
mWidgetsRecyclerView.setClipChildren(false);
mWidgetsRecyclerView.setAdapter(mWidgetsListAdapter);
mWidgetsRecyclerView.bindFastScrollbar(mFastScroller);
- mWidgetsRecyclerView.setItemAnimator(mWidgetsListItemAnimator);
+ mWidgetsRecyclerView.setItemAnimator(isTwoPane() ? null : mWidgetsListItemAnimator);
mWidgetsRecyclerView.setHeaderViewDimensionsProvider(WidgetsFullSheet.this);
if (!isTwoPane()) {
mWidgetsRecyclerView.setEdgeEffectFactory(
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
index d373a3b..d164dd0 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListHeader.java
@@ -15,6 +15,8 @@
*/
package com.android.launcher3.widget.picker;
+import static android.animation.ValueAnimator.areAnimatorsEnabled;
+
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.drawable.Drawable;
@@ -201,7 +203,7 @@
public void reapplyItemInfo(ItemInfoWithIcon info) {
if (getTag() == info) {
mIconLoadRequest = null;
- mEnableIconUpdateAnimation = true;
+ mEnableIconUpdateAnimation = areAnimatorsEnabled();
// Optimization: Starting in N, pre-uploads the bitmap to RenderThread.
info.bitmap.icon.prepareToDraw();
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListItemAnimator.java b/src/com/android/launcher3/widget/picker/WidgetsListItemAnimator.java
new file mode 100644
index 0000000..854700f
--- /dev/null
+++ b/src/com/android/launcher3/widget/picker/WidgetsListItemAnimator.java
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.widget.picker;
+
+import static com.android.launcher3.widget.picker.WidgetsListAdapter.VIEW_TYPE_WIDGETS_LIST;
+
+import androidx.recyclerview.widget.DefaultItemAnimator;
+import androidx.recyclerview.widget.RecyclerView;
+
+public class WidgetsListItemAnimator extends DefaultItemAnimator {
+ public static final int CHANGE_DURATION_MS = 90;
+ public static final int MOVE_DURATION_MS = 90;
+ public static final int ADD_DURATION_MS = 120;
+
+ public WidgetsListItemAnimator() {
+ super();
+
+ // Disable change animations because it disrupts the item focus upon adapter item
+ // change.
+ setSupportsChangeAnimations(false);
+ // Make the moves a bit faster, so that the amount of time for which user sees the
+ // bottom-sheet background before "add" animation starts is less making it smoother.
+ setChangeDuration(CHANGE_DURATION_MS);
+ setMoveDuration(MOVE_DURATION_MS);
+ setAddDuration(ADD_DURATION_MS);
+ }
+ @Override
+ public boolean animateChange(RecyclerView.ViewHolder oldHolder,
+ RecyclerView.ViewHolder newHolder, int fromLeft, int fromTop, int toLeft,
+ int toTop) {
+ // As we expand an item, the content / widgets list that appears (with add
+ // event) also gets change events as its previews load asynchronously. The
+ // super implementation of animateChange cancels the animations on it - breaking
+ // the "add animation". Instead, here, we skip "change" animation for content
+ // list - because we want it to either appear or disappear. And, the previews
+ // themselves have their own animation when loaded, so, we don't need change
+ // animations for them anyway. Below, we do-nothing.
+ if (oldHolder.getItemViewType() == VIEW_TYPE_WIDGETS_LIST) {
+ dispatchChangeStarting(oldHolder, true);
+ dispatchChangeFinished(oldHolder, true);
+ return true;
+ }
+ return super.animateChange(oldHolder, newHolder, fromLeft, fromTop, toLeft,
+ toTop);
+ }
+}
diff --git a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
index 56352cc..45d733a 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsListTableViewHolderBinder.java
@@ -15,6 +15,11 @@
*/
package com.android.launcher3.widget.picker;
+import static com.android.launcher3.widget.picker.WidgetsListItemAnimator.CHANGE_DURATION_MS;
+import static com.android.launcher3.widget.picker.WidgetsListItemAnimator.MOVE_DURATION_MS;
+
+import static android.animation.ValueAnimator.areAnimatorsEnabled;
+
import android.content.Context;
import android.graphics.Bitmap;
import android.util.Log;
@@ -26,7 +31,6 @@
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.TableLayout;
-import android.widget.TableRow;
import androidx.annotation.NonNull;
import androidx.annotation.Px;
@@ -36,6 +40,7 @@
import com.android.launcher3.recyclerview.ViewHolderBinder;
import com.android.launcher3.views.ActivityContext;
import com.android.launcher3.widget.WidgetCell;
+import com.android.launcher3.widget.WidgetTableRow;
import com.android.launcher3.widget.model.WidgetsListContentEntry;
import com.android.launcher3.widget.util.WidgetsTableUtils;
@@ -111,17 +116,15 @@
for (int i = 0; i < widgetItemsTable.size(); i++) {
List<WidgetItem> widgetItemsPerRow = widgetItemsTable.get(i);
for (int j = 0; j < widgetItemsPerRow.size(); j++) {
- TableRow row = (TableRow) table.getChildAt(i);
+ WidgetTableRow row = (WidgetTableRow) table.getChildAt(i);
row.setVisibility(View.VISIBLE);
WidgetCell widget = (WidgetCell) row.getChildAt(j);
widget.clear();
+ widget.addPreviewReadyListener(row);
WidgetItem widgetItem = widgetItemsPerRow.get(j);
widget.setVisibility(View.VISIBLE);
- // When preview loads, notify adapter to rebind the item and possibly animate
- widget.applyFromCellItem(widgetItem,
- bitmap -> holder.onPreviewLoaded(Pair.create(widgetItem, bitmap)),
- holder.previewCache.get(widgetItem));
+ widget.applyFromCellItem(widgetItem);
widget.requestLayout();
}
}
@@ -143,14 +146,19 @@
for (int i = 0; i < widgetItemsTable.size(); i++) {
List<WidgetItem> widgetItems = widgetItemsTable.get(i);
- TableRow tableRow;
+ WidgetTableRow tableRow;
if (i < table.getChildCount()) {
- tableRow = (TableRow) table.getChildAt(i);
+ tableRow = (WidgetTableRow) table.getChildAt(i);
} else {
- tableRow = new TableRow(table.getContext());
+ tableRow = new WidgetTableRow(table.getContext());
tableRow.setGravity(Gravity.TOP);
table.addView(tableRow);
}
+ // Pass resize delay to let the "move" and "change" animations run before resizing the
+ // row.
+ tableRow.setupRow(widgetItems.size(),
+ /*resizeDelayMs=*/
+ areAnimatorsEnabled() ? (CHANGE_DURATION_MS + MOVE_DURATION_MS) : 0);
if (tableRow.getChildCount() > widgetItems.size()) {
for (int j = widgetItems.size(); j < tableRow.getChildCount(); j++) {
tableRow.getChildAt(j).setVisibility(View.GONE);
@@ -161,6 +169,7 @@
R.layout.widget_cell, tableRow, false);
// set up touch.
widget.setOnClickListener(mIconClickListener);
+ widget.addPreviewReadyListener(tableRow);
View preview = widget.findViewById(R.id.widget_preview_container);
preview.setOnClickListener(mIconClickListener);
preview.setOnLongClickListener(mIconLongClickListener);
@@ -176,7 +185,7 @@
int numOfRows = holder.tableContainer.getChildCount();
holder.previewCache.clear();
for (int i = 0; i < numOfRows; i++) {
- TableRow tableRow = (TableRow) holder.tableContainer.getChildAt(i);
+ WidgetTableRow tableRow = (WidgetTableRow) holder.tableContainer.getChildAt(i);
int numOfCols = tableRow.getChildCount();
for (int j = 0; j < numOfCols; j++) {
WidgetCell widget = (WidgetCell) tableRow.getChildAt(j);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
index 6dbad5c..1ed3d88 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsRecommendationTableLayout.java
@@ -27,9 +27,7 @@
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
-import android.view.ViewGroup;
import android.widget.TableLayout;
-import android.widget.TableRow;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
@@ -38,6 +36,7 @@
import com.android.launcher3.R;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.widget.WidgetCell;
+import com.android.launcher3.widget.WidgetTableRow;
import com.android.launcher3.widget.picker.util.WidgetPreviewContainerSize;
import java.util.ArrayList;
@@ -105,7 +104,8 @@
for (int i = 0; i < recommendationTable.size(); i++) {
List<WidgetItem> widgetItems = recommendationTable.get(i);
- TableRow tableRow = new TableRow(getContext());
+ WidgetTableRow tableRow = new WidgetTableRow(getContext());
+ tableRow.setupRow(widgetItems.size(), /*resizeDelayMs=*/ 0);
tableRow.setGravity(Gravity.TOP);
for (WidgetItem widgetItem : widgetItems) {
WidgetCell widgetCell = addItemCell(tableRow);
@@ -121,9 +121,10 @@
setVisibility(VISIBLE);
}
- private WidgetCell addItemCell(ViewGroup parent) {
+ private WidgetCell addItemCell(WidgetTableRow parent) {
WidgetCell widget = (WidgetCell) LayoutInflater.from(
getContext()).inflate(R.layout.widget_cell, parent, false);
+ widget.addPreviewReadyListener(parent);
widget.setOnClickListener(mWidgetCellOnClickListener);
View previewContainer = widget.findViewById(R.id.widget_preview_container);
diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
index f835e18..5d71db6 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java
@@ -67,7 +67,7 @@
// This ratio defines the max percentage of content area that the recommendations can display
// with respect to the bottom sheet's height.
- private static final float RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE = 0.60f;
+ private static final float RECOMMENDATION_SECTION_HEIGHT_RATIO_TWO_PANE = 0.70f;
private FrameLayout mSuggestedWidgetsContainer;
private WidgetsListHeader mSuggestedWidgetsHeader;
private PackageUserKey mSuggestedWidgetsPackageUserKey;
diff --git a/src/com/android/launcher3/widget/util/WidgetDragScaleUtils.java b/src/com/android/launcher3/widget/util/WidgetDragScaleUtils.java
new file mode 100644
index 0000000..b8e7248
--- /dev/null
+++ b/src/com/android/launcher3/widget/util/WidgetDragScaleUtils.java
@@ -0,0 +1,68 @@
+/*
+ * 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.util;
+
+import static com.android.launcher3.widget.util.WidgetSizes.getWidgetSizePx;
+
+import android.content.Context;
+import android.util.Size;
+
+import androidx.annotation.Px;
+
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.R;
+import com.android.launcher3.model.data.ItemInfo;
+
+/** Utility classes to evaluate widget scale during drag and drops. **/
+public final class WidgetDragScaleUtils {
+ // Widgets are 5% scaled down relative to their size to have shadow display well inside the
+ // drop target frame (if its possible to scale it down within visible area under the finger).
+ private static final float WIDGET_SCALE_DOWN = 0.05f;
+
+ /**
+ * Returns the scale to be applied to given dragged view to scale it down relative to the
+ * spring loaded workspace. Applies additional scale down offset to get it a little inside
+ * the drop target frame. If the relative scale is smaller than minimum size needed to keep the
+ * view visible under the finger, scale down is performed only until the minimum size.
+ */
+ @Px
+ public static float getWidgetDragScalePx(Context context, DeviceProfile deviceProfile,
+ @Px float draggedViewWidthPx, @Px float draggedViewHeightPx, ItemInfo itemInfo) {
+ int minSize = context.getResources().getDimensionPixelSize(
+ R.dimen.widget_drag_view_min_scale_down_size);
+ Size widgetSizesPx = getWidgetSizePx(deviceProfile, itemInfo.spanX, itemInfo.spanY);
+
+ // We add workspace spring load scale, since the widget's drop target is also scaled, so
+ // the widget size is essentially that smaller.
+ float desiredWidgetScale = deviceProfile.getWorkspaceSpringLoadScale(context)
+ - WIDGET_SCALE_DOWN;
+ float desiredWidgetWidthPx = Math.max(minSize,
+ (desiredWidgetScale * widgetSizesPx.getWidth()));
+ float desiredWidgetHeightPx = Math.max(minSize,
+ desiredWidgetScale * widgetSizesPx.getHeight());
+
+ final float bitmapAspectRatio = draggedViewWidthPx / draggedViewHeightPx;
+ final float containerAspectRatio = desiredWidgetWidthPx / desiredWidgetHeightPx;
+
+ // This downscales large views to fit inside drop target frame. Smaller drawable views may
+ // be up-scaled if they are smaller than the min size;
+ final float scale = bitmapAspectRatio >= containerAspectRatio ? desiredWidgetWidthPx
+ / draggedViewWidthPx : desiredWidgetHeightPx / draggedViewHeightPx;
+ // scale in terms of dp to be applied to the drag shadow during drag and drop
+ return (draggedViewWidthPx * scale) - draggedViewWidthPx;
+ }
+}
diff --git a/src_no_quickstep/com/android/launcher3/uioverrides/states/AllAppsState.java b/src_no_quickstep/com/android/launcher3/uioverrides/states/AllAppsState.java
index b62dbd1..9865516 100644
--- a/src_no_quickstep/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/src_no_quickstep/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -53,6 +53,11 @@
}
@Override
+ public int getTitle() {
+ return R.string.all_apps_label;
+ }
+
+ @Override
public int getVisibleElements(Launcher launcher) {
return ALL_APPS_CONTENT;
}
diff --git a/tests/Android.bp b/tests/Android.bp
index 5794cce..e51242f 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -198,6 +198,9 @@
"androidx.test.uiautomator_uiautomator",
"androidx.core_core-animation-testing",
"androidx.test.ext.junit",
+ "androidx.test.espresso.core",
+ "androidx.test.espresso.contrib",
+ "androidx.test.espresso.intents",
"androidx.test.rules",
"uiautomator-helpers",
"inline-mockito-robolectric-prebuilt",
@@ -208,6 +211,7 @@
"Launcher3TestResources",
"SystemUISharedLib",
"launcher-testing-shared",
+ "android.appwidget.flags-aconfig-java",
],
libs: [
"android.test.runner",
@@ -217,4 +221,5 @@
],
instrumentation_for: "Launcher3",
upstream: true,
+ strict_mode: false,
}
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 c3b7a2a..59d0de6 100644
--- a/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
+++ b/tests/multivalentTests/shared/com/android/launcher3/testing/shared/TestProtocol.java
@@ -169,13 +169,11 @@
public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
- public static final String TWO_NEXUS_LAUNCHER_ACTIVITY_WHILE_UNLOCKING = "b/273347463";
public static final String ICON_MISSING = "b/282963545";
public static final String UIOBJECT_STALE_ELEMENT = "b/319501259";
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 CLOCK_ICON_DRAWABLE_LEAKING = "b/319168409";
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";
@@ -183,6 +181,9 @@
public static final String REQUEST_UNSTASH_BUBBLE_BAR_IF_STASHED =
"unstash-bubble-bar-if-stashed";
+ public static final String REQUEST_INJECT_FAKE_TRACKPAD = "inject-fake-trackpad";
+ public static final String REQUEST_EJECT_FAKE_TRACKPAD = "eject-fake-trackpad";
+
/** Logs {@link Log#d(String, String)} if {@link #sDebugTracing} is true. */
public static void testLogD(String tag, String message) {
if (!sDebugTracing) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt b/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
index e378733..3405635 100644
--- a/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/AbstractDeviceProfileTest.kt
@@ -57,7 +57,7 @@
*
* For an implementation that mocks InvariantDeviceProfile, use [FakeInvariantDeviceProfileTest]
*/
-@AllowedDevices(allowed = [DeviceProduct.CF_PHONE])
+@AllowedDevices(allowed = [DeviceProduct.CF_PHONE, DeviceProduct.HOST_SIDE_X86_64])
@IgnoreLimit(ignoreLimit = BuildConfig.IS_STUDIO_BUILD)
abstract class AbstractDeviceProfileTest {
protected val testContext: Context = InstrumentationRegistry.getInstrumentation().context
diff --git a/tests/src/com/android/launcher3/AbstractFloatingViewHelperTest.kt b/tests/multivalentTests/src/com/android/launcher3/AbstractFloatingViewHelperTest.kt
similarity index 91%
rename from tests/src/com/android/launcher3/AbstractFloatingViewHelperTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/AbstractFloatingViewHelperTest.kt
index 7ff544d..5344d5c 100644
--- a/tests/src/com/android/launcher3/AbstractFloatingViewHelperTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/AbstractFloatingViewHelperTest.kt
@@ -25,7 +25,7 @@
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.verify
-import org.mockito.kotlin.verifyZeroInteractions
+import org.mockito.kotlin.verifyNoMoreInteractions
import org.mockito.kotlin.whenever
/** Test for AbstractFloatingViewHelper */
@@ -60,7 +60,8 @@
AbstractFloatingView.TYPE_ALL
)
- verifyZeroInteractions(view)
+ // b/343530737
+ verifyNoMoreInteractions(view)
verify(folderView).close(true)
verify(taskMenuView).close(true)
}
@@ -73,7 +74,8 @@
AbstractFloatingView.TYPE_TASK_MENU
)
- verifyZeroInteractions(view)
+ // b/343530737
+ verifyNoMoreInteractions(view)
verify(folderView, never()).close(any())
verify(taskMenuView).close(true)
}
@@ -86,7 +88,8 @@
AbstractFloatingView.TYPE_PIN_IME_POPUP
)
- verifyZeroInteractions(view)
+ // b/343530737
+ verifyNoMoreInteractions(view)
verify(folderView, never()).close(any())
verify(taskMenuView, never()).close(any())
}
@@ -99,7 +102,8 @@
AbstractFloatingView.TYPE_FOLDER or AbstractFloatingView.TYPE_TASK_MENU
)
- verifyZeroInteractions(view)
+ // b/343530737
+ verifyNoMoreInteractions(view)
verify(folderView).close(false)
verify(taskMenuView).close(false)
}
diff --git a/tests/src/com/android/launcher3/AppFilterTest.kt b/tests/multivalentTests/src/com/android/launcher3/AppFilterTest.kt
similarity index 89%
rename from tests/src/com/android/launcher3/AppFilterTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/AppFilterTest.kt
index f2150a2..f1c6343 100644
--- a/tests/src/com/android/launcher3/AppFilterTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/AppFilterTest.kt
@@ -19,15 +19,18 @@
import android.content.ComponentName
import android.content.Context
import android.content.res.Resources
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mock
import org.mockito.Mockito.`when`
-import org.mockito.junit.MockitoJUnitRunner
+import org.mockito.MockitoAnnotations
-@RunWith(MockitoJUnitRunner::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
class AppFilterTest {
@Mock private lateinit var mockContext: Context
@@ -39,6 +42,7 @@
@Before
fun setUp() {
+ MockitoAnnotations.initMocks(this)
`when`(mockContext.resources).thenReturn(mockResources) // Link the context and resources
`when`(mockResources.getStringArray(R.array.filtered_components))
.thenReturn(arrayOf("com.example.app1/Activity1"))
diff --git a/tests/src/com/android/launcher3/UtilitiesKtTest.kt b/tests/multivalentTests/src/com/android/launcher3/UtilitiesKtTest.kt
similarity index 86%
rename from tests/src/com/android/launcher3/UtilitiesKtTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/UtilitiesKtTest.kt
index 9aa0369..0d13e77 100644
--- a/tests/src/com/android/launcher3/UtilitiesKtTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/UtilitiesKtTest.kt
@@ -17,9 +17,8 @@
package com.android.launcher3
import android.content.Context
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
+import android.widget.LinearLayout
+import android.widget.TextView
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import androidx.test.platform.app.InstrumentationRegistry
@@ -27,28 +26,20 @@
import com.android.launcher3.UtilitiesKt.CLIP_TO_PADDING_FALSE_MODIFIER
import com.android.launcher3.UtilitiesKt.modifyAttributesOnViewTree
import com.android.launcher3.UtilitiesKt.restoreAttributesOnViewTree
-import com.android.launcher3.tests.R
import com.google.common.truth.Truth.assertThat
-import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@SmallTest
@RunWith(AndroidJUnit4::class)
class UtilitiesKtTest {
-
val context: Context = InstrumentationRegistry.getInstrumentation().context
- private lateinit var rootView: ViewGroup
- private lateinit var midView: ViewGroup
- private lateinit var childView: View
- @Before
- fun setup() {
- rootView =
- LayoutInflater.from(context).inflate(R.layout.utilities_test_view, null) as ViewGroup
- midView = rootView.requireViewById(R.id.mid_view)
- childView = rootView.requireViewById(R.id.child_view)
- }
+ private val childView = TextView(context)
+
+ private val midView = LinearLayout(context).apply { addView(childView) }
+
+ private val rootView = LinearLayout(context).apply { addView(midView) }
@Test
fun set_clipChildren_false() {
diff --git a/tests/multivalentTests/src/com/android/launcher3/UtilitiesTest.kt b/tests/multivalentTests/src/com/android/launcher3/UtilitiesTest.kt
new file mode 100644
index 0000000..60a4197
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/UtilitiesTest.kt
@@ -0,0 +1,97 @@
+/*
+ * 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
+
+import android.content.Context
+import android.view.View
+import android.view.ViewGroup
+import androidx.test.core.app.ApplicationProvider.getApplicationContext
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.launcher3.util.ActivityContextWrapper
+import org.junit.Assert.*
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+class UtilitiesTest {
+
+ private lateinit var mContext: Context
+
+ @Before
+ fun setUp() {
+ mContext = ActivityContextWrapper(getApplicationContext())
+ }
+
+ @Test
+ fun testIsPropertyEnabled() {
+ // This assumes the property "propertyName" is not enabled by default
+ assertFalse(Utilities.isPropertyEnabled("propertyName"))
+ }
+
+ @Test
+ fun testGetDescendantCoordRelativeToAncestor() {
+ val ancestor =
+ object : ViewGroup(mContext) {
+ override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {}
+ }
+ val descendant = View(mContext)
+
+ descendant.x = 50f
+ descendant.y = 30f
+ descendant.scaleX = 2f
+ descendant.scaleY = 2f
+
+ ancestor.addView(descendant)
+
+ val coord = floatArrayOf(10f, 15f)
+ val scale =
+ Utilities.getDescendantCoordRelativeToAncestor(descendant, ancestor, coord, false)
+
+ assertEquals(2f, scale) // Expecting scale to be 2f
+ assertEquals(70f, coord[0])
+ assertEquals(60f, coord[1])
+ }
+
+ @Test
+ fun testRoundArray() {
+ val floatArray = floatArrayOf(1.2f, 3.7f, 5.5f)
+ val intArray = IntArray(3)
+ Utilities.roundArray(floatArray, intArray)
+ assertArrayEquals(intArrayOf(1, 4, 6), intArray)
+ }
+
+ @Test
+ fun testOffsetPoints() {
+ val points = floatArrayOf(1f, 2f, 3f, 4f)
+ Utilities.offsetPoints(points, 5f, 6f)
+
+ val expected = listOf(6f, 8f, 8f, 10f)
+ assertEquals(expected, points.toList())
+ }
+
+ @Test
+ fun testPointInView() {
+ val view = View(mContext)
+ view.layout(0, 0, 100, 100)
+
+ assertTrue(Utilities.pointInView(view, 50f, 50f, 0f)) // Inside view
+ assertFalse(Utilities.pointInView(view, -10f, -10f, 0f)) // Outside view
+ assertTrue(Utilities.pointInView(view, -5f, -5f, 10f)) // Inside slop
+ assertFalse(Utilities.pointInView(view, 115f, 115f, 10f)) // Outside slop
+ }
+}
diff --git a/tests/multivalentTests/src/com/android/launcher3/icons/UserBadgeDrawableTest.kt b/tests/multivalentTests/src/com/android/launcher3/icons/UserBadgeDrawableTest.kt
new file mode 100644
index 0000000..d611ae8
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/icons/UserBadgeDrawableTest.kt
@@ -0,0 +1,76 @@
+/*
+ * 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.icons
+
+import android.graphics.Canvas
+import android.graphics.Color
+import android.graphics.Paint
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.icons.UserBadgeDrawable.SHADOW_COLOR
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+/** Test for [UserBadgeDrawable] */
+@RunWith(AndroidJUnit4::class)
+class UserBadgeDrawableTest {
+ private val context = InstrumentationRegistry.getInstrumentation().targetContext
+ private val canvas = mock<Canvas>()
+ private val systemUnderTest =
+ UserBadgeDrawable(context, R.drawable.ic_work_app_badge, R.color.badge_tint_work, false)
+
+ @Test
+ fun draw_opaque() {
+ val colorList = mutableListOf<Int>()
+ whenever(
+ canvas.drawCircle(
+ any(),
+ any(),
+ any(),
+ any()
+ )
+ ).then { colorList.add(it.getArgument<Paint>(3).color) }
+
+ systemUnderTest.alpha = 255
+ systemUnderTest.draw(canvas)
+
+ assertThat(colorList).containsExactly(SHADOW_COLOR, Color.WHITE)
+ }
+
+ @Test
+ fun draw_transparent() {
+ val colorList = mutableListOf<Int>()
+ whenever(
+ canvas.drawCircle(
+ any(),
+ any(),
+ any(),
+ any()
+ )
+ ).then { colorList.add(it.getArgument<Paint>(3).color) }
+
+ systemUnderTest.alpha = 0
+ systemUnderTest.draw(canvas)
+
+ assertThat(colorList).hasSize(2)
+ assertThat(Color.valueOf(colorList[0]).alpha()).isEqualTo(0)
+ assertThat(Color.valueOf(colorList[1]).alpha()).isEqualTo(0)
+ }
+}
diff --git a/tests/src/com/android/launcher3/settings/SettingsActivityTest.java b/tests/multivalentTests/src/com/android/launcher3/settings/SettingsActivityTest.java
similarity index 100%
rename from tests/src/com/android/launcher3/settings/SettingsActivityTest.java
rename to tests/multivalentTests/src/com/android/launcher3/settings/SettingsActivityTest.java
diff --git a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
similarity index 98%
rename from tests/src/com/android/launcher3/util/DisplayControllerTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
index 273f0c4..41effa2 100644
--- a/tests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -27,7 +27,6 @@
import android.view.Surface
import androidx.test.annotation.UiThreadTest
import androidx.test.core.app.ApplicationProvider
-import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
@@ -55,7 +54,7 @@
/** Unit tests for {@link DisplayController} */
@SmallTest
-@RunWith(AndroidJUnit4::class)
+@RunWith(LauncherMultivalentJUnit::class)
class DisplayControllerTest {
private val appContext: Context = ApplicationProvider.getApplicationContext()
diff --git a/tests/src/com/android/launcher3/util/LockedUserStateTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/LockedUserStateTest.kt
similarity index 95%
rename from tests/src/com/android/launcher3/util/LockedUserStateTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/util/LockedUserStateTest.kt
index 2c4a54f..2711d7a 100644
--- a/tests/src/com/android/launcher3/util/LockedUserStateTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/LockedUserStateTest.kt
@@ -28,7 +28,7 @@
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
import org.mockito.kotlin.verify
-import org.mockito.kotlin.verifyZeroInteractions
+import org.mockito.kotlin.verifyNoMoreInteractions
import org.mockito.kotlin.whenever
/** Unit tests for {@link LockedUserState} */
@@ -58,7 +58,8 @@
val action: Runnable = mock()
val state = LockedUserState(context)
state.runOnUserUnlocked(action)
- verifyZeroInteractions(action)
+ // b/343530737
+ verifyNoMoreInteractions(action)
state.mUserUnlockedReceiver.onReceive(context, Intent(Intent.ACTION_USER_UNLOCKED))
verify(action).run()
}
diff --git a/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
similarity index 94%
rename from tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
rename to tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
index 460058b..b239aed 100644
--- a/tests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/GeneratedPreviewTest.kt
@@ -18,12 +18,12 @@
import androidx.test.core.app.ApplicationProvider.getApplicationContext
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
import com.android.launcher3.Flags.FLAG_ENABLE_GENERATED_PREVIEWS
import com.android.launcher3.InvariantDeviceProfile
import com.android.launcher3.icons.IconCache
import com.android.launcher3.icons.IconProvider
import com.android.launcher3.model.WidgetItem
-import com.android.launcher3.tests.R
import com.android.launcher3.util.ActivityContextWrapper
import com.android.launcher3.util.Executors
import com.google.common.truth.Truth.assertThat
@@ -41,7 +41,10 @@
"com.android.launcher3.tests",
"com.android.launcher3.testcomponent.AppWidgetNoConfig"
)
- private val generatedPreviewLayout = R.layout.test_layout_appwidget_blue
+ private val generatedPreviewLayout =
+ getInstrumentation().context.run {
+ resources.getIdentifier("test_layout_appwidget_blue", "layout", packageName)
+ }
private lateinit var context: Context
private lateinit var generatedPreview: RemoteViews
private lateinit var widgetCell: WidgetCell
@@ -137,6 +140,7 @@
assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_KEYGUARD)).isFalse()
assertThat(widgetItem.hasGeneratedPreview(WIDGET_CATEGORY_SEARCHBOX)).isFalse()
}
+
@Test
@RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
fun widgetItem_getGeneratedPreview() {
@@ -148,6 +152,7 @@
@RequiresFlagsEnabled(FLAG_ENABLE_GENERATED_PREVIEWS)
fun widgetCell_showGeneratedPreview() {
widgetCell.applyFromCellItem(widgetItem)
+ DatabaseWidgetPreviewLoader.getLoaderExecutor().submit {}.get()
assertThat(widgetCell.appWidgetHostViewPreview).isNotNull()
assertThat(widgetCell.appWidgetHostViewPreview?.appWidgetInfo)
.isEqualTo(appWidgetProviderInfo)
@@ -157,6 +162,7 @@
@RequiresFlagsDisabled(FLAG_ENABLE_GENERATED_PREVIEWS)
fun widgetCell_showGeneratedPreview_flagDisabled() {
widgetCell.applyFromCellItem(widgetItem)
+ DatabaseWidgetPreviewLoader.getLoaderExecutor().submit {}.get()
assertThat(widgetCell.appWidgetHostViewPreview).isNull()
}
}
diff --git a/tests/multivalentTests/src/com/android/launcher3/widget/util/WidgetDragScaleUtilsTest.kt b/tests/multivalentTests/src/com/android/launcher3/widget/util/WidgetDragScaleUtilsTest.kt
new file mode 100644
index 0000000..63833e4
--- /dev/null
+++ b/tests/multivalentTests/src/com/android/launcher3/widget/util/WidgetDragScaleUtilsTest.kt
@@ -0,0 +1,150 @@
+/*
+ * 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.util
+
+import android.content.Context
+import android.graphics.Point
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.launcher3.DeviceProfile
+import com.android.launcher3.LauncherAppState
+import com.android.launcher3.R
+import com.android.launcher3.model.data.ItemInfo
+import com.android.launcher3.util.ActivityContextWrapper
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assume.assumeTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.any
+import org.mockito.Mockito
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class WidgetDragScaleUtilsTest {
+ private lateinit var context: Context
+ private lateinit var itemInfo: ItemInfo
+ private lateinit var deviceProfile: DeviceProfile
+
+ @Before
+ fun setup() {
+ context = ActivityContextWrapper(ApplicationProvider.getApplicationContext())
+
+ itemInfo = ItemInfo()
+
+ deviceProfile =
+ Mockito.spy(LauncherAppState.getIDP(context).getDeviceProfile(context).copy(context))
+
+ doReturn(0.8f)
+ .whenever(deviceProfile).getWorkspaceSpringLoadScale(any(Context::class.java))
+ deviceProfile.cellLayoutBorderSpacePx = Point(CELL_SPACING, CELL_SPACING)
+ deviceProfile.widgetPadding.setEmpty()
+ }
+
+ @Test
+ fun getWidgetDragScalePx_largeDraggedView_downScaled() {
+ val minSize = context.resources.getDimensionPixelSize(
+ R.dimen.widget_drag_view_min_scale_down_size)
+ whenever(deviceProfile.cellSize).thenReturn(Point(minSize * 2, minSize * 2))
+
+ itemInfo.spanX = 2
+ itemInfo.spanY = 2
+
+ val widgetSize = WidgetSizes.getWidgetSizePx(deviceProfile, itemInfo.spanX, itemInfo.spanY)
+ // Assume dragged view was a drawable which was larger than widget's size.
+ val draggedViewWidthPx = widgetSize.width + 0.5f * widgetSize.width
+ val draggedViewHeightPx = widgetSize.height + 0.5f * widgetSize.height
+ // Returns negative scale pixels - i.e. downscaled
+ assertThat(
+ WidgetDragScaleUtils.getWidgetDragScalePx(
+ context,
+ deviceProfile,
+ draggedViewWidthPx,
+ draggedViewHeightPx,
+ itemInfo
+ )
+ )
+ .isLessThan(0)
+ }
+
+ @Test
+ fun getWidgetDragScalePx_draggedViewSameAsWidgetSize_downScaled() {
+ val minSize = context.resources.getDimensionPixelSize(
+ R.dimen.widget_drag_view_min_scale_down_size)
+ whenever(deviceProfile.cellSize).thenReturn(Point(minSize * 2, minSize * 2))
+ itemInfo.spanX = 4
+ itemInfo.spanY = 2
+
+ val widgetSize = WidgetSizes.getWidgetSizePx(deviceProfile, itemInfo.spanX, itemInfo.spanY)
+ // Assume dragged view was a drawable which was larger than widget's size.
+ val draggedViewWidthPx = widgetSize.width.toFloat()
+ val draggedViewHeightPx = widgetSize.height.toFloat()
+ // Returns negative scale pixels - i.e. downscaled
+ // Even if dragged view was of same size as widget's drop target, to accommodate the spring
+ // load scaling of workspace and additionally getting the view inside of drop target frame,
+ // widget would be downscaled.
+ assertThat(
+ WidgetDragScaleUtils.getWidgetDragScalePx(
+ context,
+ deviceProfile,
+ draggedViewWidthPx,
+ draggedViewHeightPx,
+ itemInfo
+ )
+ )
+ .isLessThan(0)
+ }
+
+ @Test
+ fun getWidgetDragScalePx_draggedViewSmallerThanMinSize_scaledSizeIsAtLeastMinSize() {
+ val minSizePx =
+ context.resources.getDimensionPixelSize(R.dimen.widget_drag_view_min_scale_down_size)
+ // Assume min size is greater than cell size, so that, we know the upscale of dragged view
+ // is due to min size enforcement.
+ whenever(deviceProfile.cellSize).thenReturn(Point(minSizePx / 2, minSizePx / 2))
+ itemInfo.spanX = 1
+ itemInfo.spanY = 1
+
+ val draggedViewWidthPx = minSizePx - 15f
+ val draggedViewHeightPx = minSizePx - 15f
+
+ // Returns positive scale pixels - i.e. up-scaled
+ val finalScalePx =
+ WidgetDragScaleUtils.getWidgetDragScalePx(
+ context,
+ deviceProfile,
+ draggedViewWidthPx,
+ draggedViewHeightPx,
+ itemInfo
+ )
+
+ val effectiveWidthPx = draggedViewWidthPx + finalScalePx
+ val scaleFactor = (draggedViewWidthPx + finalScalePx) / draggedViewWidthPx
+ val effectiveHeightPx = scaleFactor * draggedViewHeightPx
+ // Both original height and width were smaller than min size, scaling them down below min
+ // size would have made them not visible under the finger. Here, as expected, widget is
+ // at least as large as min size.
+ assertThat(effectiveWidthPx).isAtLeast(minSizePx)
+ assertThat(effectiveHeightPx).isAtLeast(minSizePx)
+ }
+
+ companion object {
+ const val CELL_SPACING = 10
+ }
+}
diff --git a/tests/multivalentTestsForDeviceless b/tests/multivalentTestsForDeviceless
deleted file mode 120000
index 20ee34a..0000000
--- a/tests/multivalentTestsForDeviceless
+++ /dev/null
@@ -1 +0,0 @@
-multivalentTests
\ No newline at end of file
diff --git a/tests/res/layout/utilities_test_view.xml b/tests/res/layout/utilities_test_view.xml
deleted file mode 100644
index dc2a515..0000000
--- a/tests/res/layout/utilities_test_view.xml
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?><!--
- ~ Copyright (C) 2024 The Android Open Source Project
- ~
- ~ Licensed under the Apache License, Version 2.0 (the "License");
- ~ you may not use this file except in compliance with the License.
- ~ You may obtain a copy of the License at
- ~
- ~ http://www.apache.org/licenses/LICENSE-2.0
- ~
- ~ Unless required by applicable law or agreed to in writing, software
- ~ distributed under the License is distributed on an "AS IS" BASIS,
- ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- ~ See the License for the specific language governing permissions and
- ~ limitations under the License.
- -->
-
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:id="@+id/root_view">
- <LinearLayout
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:orientation="vertical"
- android:id="@+id/mid_view">
- <TextView
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:id="@+id/child_view" />
- </LinearLayout>
-
-</LinearLayout>
\ No newline at end of file
diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
index 4cd2a07..57117cb 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -130,7 +130,7 @@
public void lockPrivateProfile_requestsQuietModeAsTrue() throws Exception {
when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED)).thenReturn(false);
- mPrivateProfileManager.lockPrivateProfile();
+ mPrivateProfileManager.setQuietMode(true /* lock */);
awaitTasksCompleted();
Mockito.verify(mUserManager).requestQuietModeEnabled(true, PRIVATE_HANDLE);
@@ -140,7 +140,7 @@
public void unlockPrivateProfile_requestsQuietModeAsFalse() throws Exception {
when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED)).thenReturn(true);
- mPrivateProfileManager.unlockPrivateProfile();
+ mPrivateProfileManager.setQuietMode(false /* unlock */);
awaitTasksCompleted();
Mockito.verify(mUserManager).requestQuietModeEnabled(false, PRIVATE_HANDLE);
@@ -149,7 +149,7 @@
@Test
public void quietModeFlagPresent_privateSpaceIsResetToDisabled() {
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
- doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
+ doNothing().when(privateProfileManager).addPrivateSpaceDecorator(anyInt());
doNothing().when(privateProfileManager).executeLock();
doReturn(mAllAppsRecyclerView).when(privateProfileManager).getMainRecyclerView();
when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
@@ -169,14 +169,14 @@
@Test
public void transitioningToUnlocked_resetCallsPostUnlock() throws Exception {
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
- doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
+ doNothing().when(privateProfileManager).addPrivateSpaceDecorator(anyInt());
doReturn(mAllAppsRecyclerView).when(privateProfileManager).getMainRecyclerView();
when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
.thenReturn(false);
doNothing().when(privateProfileManager).expandPrivateSpace();
when(privateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
- privateProfileManager.unlockPrivateProfile();
+ privateProfileManager.setQuietMode(false /* unlock */);
privateProfileManager.reset();
awaitTasksCompleted();
@@ -186,7 +186,7 @@
@Test
public void transitioningToLocked_resetCallsExecuteLock() throws Exception {
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
- doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
+ doNothing().when(privateProfileManager).addPrivateSpaceDecorator(anyInt());
doNothing().when(privateProfileManager).executeLock();
doReturn(mAllAppsRecyclerView).when(privateProfileManager).getMainRecyclerView();
when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
@@ -194,7 +194,7 @@
doNothing().when(privateProfileManager).expandPrivateSpace();
when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
- privateProfileManager.lockPrivateProfile();
+ privateProfileManager.setQuietMode(true /* lock */);
privateProfileManager.reset();
awaitTasksCompleted();
@@ -208,7 +208,7 @@
ArgumentCaptor<Intent> acIntent = ArgumentCaptor.forClass(Intent.class);
mPrivateProfileManager.setPrivateSpaceSettingsAvailable(true);
- mPrivateProfileManager.openPrivateSpaceSettings(null);
+ mContext.startActivity(expectedIntent);
Mockito.verify(mContext).startActivity(acIntent.capture());
assertEquals("Intent Action is different",
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
index 512b2ac..eac7f63 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
@@ -133,7 +133,7 @@
Bitmap unlockButton = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
when(privateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
- privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+ privateProfileManager.bindPrivateSpaceHeaderViewElements(mPsHeaderLayout);
awaitTasksCompleted();
int totalContainerHeaderView = 0;
@@ -168,7 +168,7 @@
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
when(privateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(true);
- privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+ privateProfileManager.bindPrivateSpaceHeaderViewElements(mPsHeaderLayout);
awaitTasksCompleted();
int totalContainerHeaderView = 0;
@@ -210,7 +210,7 @@
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
when(privateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(false);
- privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+ privateProfileManager.bindPrivateSpaceHeaderViewElements(mPsHeaderLayout);
awaitTasksCompleted();
int totalContainerHeaderView = 0;
@@ -248,7 +248,7 @@
Bitmap transitionImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_transition_image));
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
when(privateProfileManager.getCurrentState()).thenReturn(STATE_TRANSITION);
- privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+ privateProfileManager.bindPrivateSpaceHeaderViewElements(mPsHeaderLayout);
awaitTasksCompleted();
int totalContainerHeaderView = 0;
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceSettingsButtonTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceSettingsButtonTest.java
new file mode 100644
index 0000000..9537e1c
--- /dev/null
+++ b/tests/src/com/android/launcher3/allapps/PrivateSpaceSettingsButtonTest.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.allapps;
+
+import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
+
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PRIVATESPACE;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import android.content.Context;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.util.ActivityContextWrapper;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class PrivateSpaceSettingsButtonTest {
+
+ private PrivateSpaceSettingsButton mVut;
+
+ @Before
+ public void setUp() {
+ MockitoAnnotations.initMocks(this);
+ Context context = new ActivityContextWrapper(getApplicationContext());
+ mVut = new PrivateSpaceSettingsButton(context);
+ }
+
+ @Test
+ public void privateSpaceSettingsAppInfo_hasCorrectIdAndContainer() {
+ AppInfo appInfo = mVut.createPrivateSpaceSettingsAppInfo();
+
+ assertThat(appInfo.id).isEqualTo(CONTAINER_PRIVATESPACE);
+ assertThat(appInfo.container).isEqualTo(CONTAINER_PRIVATESPACE);
+ }
+}
diff --git a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
index f3f6fa5..05a1224 100644
--- a/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
+++ b/tests/src/com/android/launcher3/allapps/TaplOpenCloseAllAppsTest.java
@@ -120,7 +120,6 @@
@Test
@PortraitLandscape
@PlatinumTest(focusArea = "launcher")
- @ScreenRecordRule.ScreenRecord // b/322228038
public void testAllAppsFromHome() {
// Test opening all apps
assertNotNull("switchToAllApps() returned null",
diff --git a/tests/src/com/android/launcher3/dragging/TaplDragTest.java b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
index 1c41ded..41abcf8 100644
--- a/tests/src/com/android/launcher3/dragging/TaplDragTest.java
+++ b/tests/src/com/android/launcher3/dragging/TaplDragTest.java
@@ -41,6 +41,7 @@
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.ui.PortraitLandscapeRunner.PortraitLandscape;
import com.android.launcher3.util.TestUtil;
+import com.android.launcher3.util.rule.ScreenRecordRule;
import org.junit.Test;
@@ -194,6 +195,7 @@
@PlatinumTest(focusArea = "launcher")
@Test
@PortraitLandscape
+ @ScreenRecordRule.ScreenRecord // b/343953783
public void testDragAppIcon() {
final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
@@ -221,24 +223,7 @@
public void testDragAppIconToMultipleWorkspaceCells() throws Exception {
long startTime, endTime, elapsedTime;
Point[] targets = TestUtil.getCornersAndCenterPositions(mLauncher);
-
- for (Point target : targets) {
- startTime = SystemClock.uptimeMillis();
- final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
- allApps.freeze();
- try {
- allApps.getAppIcon(TEST_APP_NAME).dragToWorkspace(target.x, target.y);
- } finally {
- allApps.unfreeze();
- }
- // Reset the workspace for the next shortcut creation.
- reinitializeLauncherData(true);
- endTime = SystemClock.uptimeMillis();
- elapsedTime = endTime - startTime;
- Log.d("testDragAppIconToWorkspaceCellTime",
- "Milliseconds taken to drag app icon to workspace cell: " + elapsedTime);
- }
-
+ reinitializeLauncherData(true);
// test to move a shortcut to other cell.
final HomeAppIcon launcherTestAppIcon = createShortcutInCenterIfNotExist(TEST_APP_NAME);
for (Point target : targets) {
diff --git a/tests/multivalentTests/src/com/android/launcher3/folder/FolderNameProviderTest.java b/tests/src/com/android/launcher3/folder/FolderNameProviderTest.java
similarity index 100%
rename from tests/multivalentTests/src/com/android/launcher3/folder/FolderNameProviderTest.java
rename to tests/src/com/android/launcher3/folder/FolderNameProviderTest.java
diff --git a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
index 78c61d5..370af0c 100644
--- a/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/AddWorkspaceItemsTaskTest.kt
@@ -35,7 +35,7 @@
import org.mockito.kotlin.mock
import org.mockito.kotlin.same
import org.mockito.kotlin.verify
-import org.mockito.kotlin.verifyZeroInteractions
+import org.mockito.kotlin.verifyNoMoreInteractions
import org.mockito.kotlin.whenever
/** Tests for [AddWorkspaceItemsTask] */
@@ -97,7 +97,8 @@
val addedItems = testAddItems(nonEmptyScreenIds, itemToAdd)
assertThat(addedItems.size).isEqualTo(0)
- verifyZeroInteractions(mWorkspaceItemSpaceFinder)
+ // b/343530737
+ verifyNoMoreInteractions(mWorkspaceItemSpaceFinder)
}
@Test
diff --git a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
index c663be0..98b6b4b 100644
--- a/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
+++ b/tests/src/com/android/launcher3/popup/SystemShortcutTest.java
@@ -49,7 +49,6 @@
import android.view.View;
import androidx.test.annotation.UiThreadTest;
-import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;
import com.android.launcher3.allapps.PrivateProfileManager;
@@ -60,6 +59,7 @@
import com.android.launcher3.util.ApiWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext;
+import com.android.launcher3.util.LauncherMultivalentJUnit;
import com.android.launcher3.util.TestSandboxModelContextWrapper;
import com.android.launcher3.util.UserIconInfo;
import com.android.launcher3.views.BaseDragLayer;
@@ -76,7 +76,7 @@
import java.util.ArrayList;
@SmallTest
-@RunWith(AndroidJUnit4.class)
+@RunWith(LauncherMultivalentJUnit.class)
public class SystemShortcutTest {
@Rule public final SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
private static final UserHandle PRIVATE_HANDLE = new UserHandle(11);
diff --git a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
index 733f1e9..b3675a6 100644
--- a/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
+++ b/tests/src/com/android/launcher3/provider/RestoreDbTaskTest.java
@@ -38,7 +38,7 @@
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import android.app.backup.BackupManager;
@@ -243,7 +243,8 @@
// Then
assertThat(expectedHost.getAppWidgetIds()).isEqualTo(expectedOldIds);
assertThat(mPrefs.has(OLD_APP_WIDGET_IDS, APP_WIDGET_IDS)).isFalse();
- verifyZeroInteractions(mMockController);
+ // b/343530737
+ verifyNoMoreInteractions(mMockController);
}
@Test
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 115a6e6..a6f4441 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -699,4 +699,11 @@
UiDevice.getInstance(getInstrumentation()).pressHome();
mLauncher.waitForLauncherInitialized();
}
+
+ /** Clears all recent tasks */
+ protected void clearAllRecentTasks() {
+ if (!mLauncher.getRecentTasks().isEmpty()) {
+ mLauncher.goHome().switchToOverview().dismissAllTasks();
+ }
+ }
}
diff --git a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
index a672c01..e92d641 100644
--- a/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/TaplTwoPanelWorkspaceTest.java
@@ -113,6 +113,8 @@
@Test
@PortraitLandscape
+ @ScreenRecordRule.ScreenRecord // b/329935119
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/329935119
public void testSinglePageDragIconWhenMultiplePageScrollingIsPossible() {
Workspace workspace = mLauncher.getWorkspace();
diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
index 2e3944d..27f6c16 100644
--- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
+++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java
@@ -23,6 +23,7 @@
import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL;
import android.graphics.Rect;
+import android.util.Log;
import android.view.KeyEvent;
import androidx.annotation.NonNull;
@@ -359,21 +360,6 @@
}
/**
- * Gets Overview Actions specific to grouped tasks.
- *
- * @return The Overview group actions bar
- */
- @NonNull
- public OverviewActions getOverviewGroupActions() {
- try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- "want to get overview group actions")) {
- verifyActiveContainer();
- UiObject2 groupActions = mLauncher.waitForOverviewObject("group_action_buttons");
- return new OverviewActions(groupActions, mLauncher);
- }
- }
-
- /**
* Returns if clear all button is visible.
*/
public boolean isClearAllVisible() {
@@ -398,26 +384,39 @@
}
protected boolean isActionsViewVisible() {
- if (!hasTasks() || isClearAllVisible()) {
+ boolean hasTasks = hasTasks();
+ if (!hasTasks || isClearAllVisible()) {
+ LauncherInstrumentation.log("Not expecting an actions bar:"
+ + (!hasTasks ? "no recent tasks" : "clear all button is visible"));
return false;
}
boolean isTablet = mLauncher.isTablet();
if (isTablet && mLauncher.isGridOnlyOverviewEnabled()) {
+ LauncherInstrumentation.log("Not expecting an actions bar: "
+ + "device is tablet with grid-only Overview");
return false;
}
OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
if (task == null) {
+ LauncherInstrumentation.log("Not expecting an actions bar: no focused task");
return false;
}
+ float centerOffset = Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX());
// In tablets, if focused task is not in center, overview actions aren't visible.
- if (isTablet && Math.abs(task.getExactCenterX() - mLauncher.getExactScreenCenterX()) >= 1) {
+ if (isTablet && centerOffset >= 1) {
+ LauncherInstrumentation.log("Not expecting an actions bar: "
+ + "device is tablet and task is not centered; center offset by "
+ + centerOffset + "px");
return false;
}
if (task.isTaskSplit() && (!mLauncher.isAppPairsEnabled() || !isTablet)) {
+ LauncherInstrumentation.log("Not expecting an actions bar: "
+ + "device is phone and task is split");
// Overview actions aren't visible for split screen tasks, except for save app pair
// button on tablets.
return false;
}
+ LauncherInstrumentation.log("Expecting an actions bar");
return true;
}
@@ -462,20 +461,30 @@
}
private void verifyActionsViewVisibility() {
+ // If no running tasks, no need to verify actions view visibility.
+ if (getTasks().isEmpty()) {
+ return;
+ }
+
+ boolean isTablet = mLauncher.isTablet();
+ OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
+
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- "want to assert overview actions view visibility")) {
- boolean isTablet = mLauncher.isTablet();
- OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
+ "want to assert overview actions view visibility="
+ + isActionsViewVisible()
+ + ", focused task is "
+ + (task == null ? "null" : (task.isTaskSplit() ? "split" : "not split"))
+ )) {
if (isActionsViewVisible()) {
if (task.isTaskSplit()) {
- mLauncher.waitForOverviewObject("group_action_buttons");
+ mLauncher.waitForOverviewObject("action_save_app_pair");
} else {
mLauncher.waitForOverviewObject("action_buttons");
}
} else {
mLauncher.waitUntilOverviewObjectGone("action_buttons");
- mLauncher.waitUntilOverviewObjectGone("group_action_buttons");
+ mLauncher.waitUntilOverviewObjectGone("action_save_app_pair");
}
}
}
@@ -490,13 +499,18 @@
throw new IllegalStateException("Must be run on tablet device.");
}
final List<UiObject2> taskViews = getTasks();
- if (taskViews.size() == 0) {
+ if (!hasTasks()) {
+ LauncherInstrumentation.log("no recent tasks");
return null;
}
int focusedTaskHeight = mLauncher.getFocusedTaskHeightForTablet();
for (UiObject2 task : taskViews) {
OverviewTask overviewTask = new OverviewTask(mLauncher, task, this);
+ LauncherInstrumentation.log("checking task height ("
+ + overviewTask.getVisibleHeight()
+ + ") against defined focused task height ("
+ + focusedTaskHeight + ")");
if (overviewTask.getVisibleHeight() == focusedTaskHeight) {
return overviewTask;
}
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index 68b0a36..f02a0c2 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -711,7 +711,7 @@
final LogEventChecker eventChecker = mEventChecker;
mEventChecker = null;
if (checkEvents) {
- final String eventMismatch = eventChecker.verify(0, false);
+ final String eventMismatch = eventChecker.verify(0);
if (eventMismatch != null) {
message = message + ";\n" + eventMismatch;
}
@@ -2318,6 +2318,14 @@
getTestInfo(TestProtocol.REQUEST_UNSTASH_BUBBLE_BAR_IF_STASHED);
}
+ public void injectFakeTrackpad() {
+ getTestInfo(TestProtocol.REQUEST_INJECT_FAKE_TRACKPAD);
+ }
+
+ public void ejectFakeTrackpad() {
+ getTestInfo(TestProtocol.REQUEST_EJECT_FAKE_TRACKPAD);
+ }
+
/** Blocks the taskbar from automatically stashing based on time. */
public void enableBlockTimeout(boolean enable) {
getTestInfo(enable
@@ -2408,7 +2416,7 @@
if (mEventChecker != null) {
mEventChecker = null;
if (mCheckEventsForSuccessfulGestures) {
- final String message = eventChecker.verify(WAIT_TIME_MS, true);
+ final String message = eventChecker.verify(WAIT_TIME_MS);
if (message != null) {
dumpDiagnostics(message);
checkForAnomaly();
diff --git a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
index 672c6e0..055a357 100644
--- a/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
+++ b/tests/tapl/com/android/launcher3/tapl/LogEventChecker.java
@@ -15,10 +15,6 @@
*/
package com.android.launcher3.tapl;
-import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_MAIN;
-import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_PILFER;
-import static com.android.launcher3.testing.shared.TestProtocol.SEQUENCE_TIS;
-
import android.os.SystemClock;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -87,25 +83,11 @@
mLauncher.getTestInfo(TestProtocol.REQUEST_STOP_EVENT_LOGGING);
}
- String verify(long waitForExpectedCountMs, boolean successfulGesture) {
+ String verify(long waitForExpectedCountMs) {
final ListMap<String> actualEvents = finishSync(waitForExpectedCountMs);
if (actualEvents == null) return "null event sequences because launcher likely died";
- final String lowLevelDiags = lowLevelMismatchDiagnostics(actualEvents);
- // If we have a sequence mismatch for a successful gesture, we want to provide all low-level
- // details.
- if (successfulGesture) {
- return lowLevelDiags;
- }
-
- final String sequenceMismatchInEnglish = highLevelMismatchDiagnostics(actualEvents);
-
- if (sequenceMismatchInEnglish != null) {
- LauncherInstrumentation.log(lowLevelDiags);
- return "Hint: " + sequenceMismatchInEnglish;
- } else {
- return lowLevelDiags;
- }
+ return lowLevelMismatchDiagnostics(actualEvents);
}
private String lowLevelMismatchDiagnostics(ListMap<String> actualEvents) {
@@ -140,42 +122,6 @@
return hasMismatches ? "Mismatching events: " + sb.toString() : null;
}
- private String highLevelMismatchDiagnostics(ListMap<String> actualEvents) {
- if (!mExpectedEvents.getNonNull(SEQUENCE_TIS).isEmpty()
- && actualEvents.getNonNull(SEQUENCE_TIS).isEmpty()) {
- return "TouchInteractionService didn't receive any of the touch events sent by the "
- + "test";
- }
- if (getMismatchPosition(mExpectedEvents.getNonNull(SEQUENCE_TIS),
- actualEvents.getNonNull(SEQUENCE_TIS)) != -1) {
- // If TIS has a mismatch that we can't convert to high-level diags, don't convert
- // other sequences either.
- return null;
- }
-
- if (mExpectedEvents.getNonNull(SEQUENCE_PILFER).size() == 1
- && actualEvents.getNonNull(SEQUENCE_PILFER).isEmpty()) {
- return "Launcher didn't detect the navigation gesture sent by the test";
- }
- if (mExpectedEvents.getNonNull(SEQUENCE_PILFER).isEmpty()
- && actualEvents.getNonNull(SEQUENCE_PILFER).size() == 1) {
- return "Launcher detected a navigation gesture, but the test didn't send one";
- }
- if (getMismatchPosition(mExpectedEvents.getNonNull(SEQUENCE_PILFER),
- actualEvents.getNonNull(SEQUENCE_PILFER)) != -1) {
- // If Pilfer has a mismatch that we can't convert to high-level diags, don't analyze
- // other sequences.
- return null;
- }
-
- if (!mExpectedEvents.getNonNull(SEQUENCE_MAIN).isEmpty()
- && actualEvents.getNonNull(SEQUENCE_MAIN).isEmpty()) {
- return "None of the touch or keyboard events sent by the test was received by "
- + "Launcher's main thread";
- }
- return null;
- }
-
// If the list of actual events matches the list of expected events, returns -1, otherwise
// the position of the mismatch.
private static int getMismatchPosition(List<Pattern> expected, List<String> actual) {
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
index 486a63b..d7c40a0 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewActions.java
@@ -17,7 +17,6 @@
package com.android.launcher3.tapl;
import androidx.annotation.NonNull;
-import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiObject2;
/**
@@ -111,12 +110,4 @@
}
}
}
-
- /** Asserts that an item matching the given string is present in the overview actions. */
- public void assertHasAction(String text) {
- try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
- "want to check if the action [" + text + "] is present")) {
- mLauncher.waitForObjectInContainer(mOverviewActions, By.text(text));
- }
- }
}