Merge "Initial animation of new bubble bar bubble" into main
diff --git a/Android.bp b/Android.bp
index 79c1b9f..877f7bb 100644
--- a/Android.bp
+++ b/Android.bp
@@ -155,6 +155,11 @@
"animationlib",
"SystemUI-statsd",
"launcher-testing-shared",
+ "androidx.lifecycle_lifecycle-common-java8",
+ "androidx.lifecycle_lifecycle-extensions",
+ "androidx.lifecycle_lifecycle-runtime-ktx",
+ "kotlinx_coroutines_android",
+ "kotlinx_coroutines",
"com_android_launcher3_flags_lib",
"com_android_wm_shell_flags_lib",
"android.appwidget.flags-aconfig-java",
diff --git a/go/quickstep/res/layout/overview_actions_container.xml b/go/quickstep/res/layout/overview_actions_container.xml
index 077cfae..df09124 100644
--- a/go/quickstep/res/layout/overview_actions_container.xml
+++ b/go/quickstep/res/layout/overview_actions_container.xml
@@ -126,7 +126,7 @@
style="@style/GoOverviewActionButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
- android:drawableStart="@drawable/ic_save_app_pair"
+ android:drawableStart="@drawable/ic_save_app_pair_up_down"
android:text="@string/action_save_app_pair"
android:theme="@style/ThemeControlHighlightWorkspaceColor"
android:visibility="gone" />
diff --git a/quickstep/res/color/bubblebar_drop_target_bg_color.xml b/quickstep/res/color/bubblebar_drop_target_bg_color.xml
new file mode 100644
index 0000000..ca37c7f
--- /dev/null
+++ b/quickstep/res/color/bubblebar_drop_target_bg_color.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"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:alpha="0.35" android:color="?androidprv:attr/materialColorPrimaryContainer" />
+</selector>
\ No newline at end of file
diff --git a/quickstep/res/drawable/bg_bubble_bar_drop_target.xml b/quickstep/res/drawable/bg_bubble_bar_drop_target.xml
new file mode 100644
index 0000000..79e4318
--- /dev/null
+++ b/quickstep/res/drawable/bg_bubble_bar_drop_target.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
+ android:shape="rectangle">
+ <corners android:radius="@dimen/bubblebar_drop_target_corner_radius" />
+ <solid android:color="@color/bubblebar_drop_target_bg_color" />
+ <stroke
+ android:width="1dp"
+ android:color="?androidprv:attr/materialColorPrimaryContainer" />
+</shape>
diff --git a/quickstep/res/drawable/ic_save_app_pair.xml b/quickstep/res/drawable/ic_save_app_pair.xml
deleted file mode 100644
index 4a7ee1a..0000000
--- a/quickstep/res/drawable/ic_save_app_pair.xml
+++ /dev/null
@@ -1,28 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-
-<!--
- Copyright (C) 2023 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
- android:width="24dp"
- android:height="24dp"
- android:viewportWidth="24"
- android:viewportHeight="24">
- <path
- android:pathData="M13.329,2.305H4.242C2.751,2.305 1.542,3.514 1.542,5.005V13.005C1.542,14.496 2.751,15.705 4.242,15.705H7.875V19.011C7.875,20.502 9.084,21.711 10.575,21.711H19.662C21.153,21.711 22.362,20.502 22.362,19.011V10.011C22.362,8.52 21.153,7.311 19.662,7.311H16.029V5.005C16.029,3.514 14.821,2.305 13.329,2.305ZM14.329,7.311V5.005C14.329,4.452 13.882,4.005 13.329,4.005H4.242C3.69,4.005 3.242,4.452 3.242,5.005V13.005C3.242,13.557 3.69,14.005 4.242,14.005H7.875V10.011C7.875,8.52 9.084,7.311 10.575,7.311H14.329ZM9.575,14.005V10.011C9.575,9.611 9.81,9.266 10.15,9.106C10.285,9.037 10.438,8.999 10.6,8.999H19.687C20.239,8.999 20.687,9.447 20.687,9.999V18.999C20.687,19.399 20.452,19.744 20.113,19.904C19.977,19.972 19.824,20.011 19.662,20.011H10.575C10.023,20.011 9.575,19.563 9.575,19.011V15.705H9.6V14.005H9.575ZM15.542,11.996V14H17.588V15H15.542V16.996H14.542V15H12.464V14H14.542V11.996H15.542Z"
- android:fillColor="#000000"
- android:fillType="evenOdd"/>
-</vector>
diff --git a/quickstep/res/drawable/ic_save_app_pair_left_right.xml b/quickstep/res/drawable/ic_save_app_pair_left_right.xml
new file mode 100644
index 0000000..b104f44
--- /dev/null
+++ b/quickstep/res/drawable/ic_save_app_pair_left_right.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M8.5,4.5H3.5C2.4,4.5 1.5,5.4 1.5,6.5V18.5C1.5,19.6 2.4,20.5 3.5,20.5H8.5C9.6,20.5 10.5,19.6 10.5,18.5V6.5C10.5,5.4 9.6,4.5 8.5,4.5ZM8.5,18.5H3.5V6.5H8.5V18.5ZM14.5,6.5H19.5V13.5H21.5V6.5C21.5,5.4 20.6,4.5 19.5,4.5H14.5C13.4,4.5 12.5,5.4 12.5,6.5V18.5C12.5,19.6 13.4,20.5 14.5,20.5H15.5V18.5H14.5V6.5ZM20.5,14.5V16.5H22.5V18.5H20.5V20.5H18.5V18.5H16.5V16.5H18.5V14.5H20.5Z"
+ android:fillColor="#48473A"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/quickstep/res/drawable/ic_save_app_pair_up_down.xml b/quickstep/res/drawable/ic_save_app_pair_up_down.xml
new file mode 100644
index 0000000..86f110c
--- /dev/null
+++ b/quickstep/res/drawable/ic_save_app_pair_up_down.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ Copyright (C) 2024 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24">
+ <path
+ android:pathData="M18,2L6,2C4.9,2 4,2.9 4,4L4,9C4,10.1 4.9,11 6,11L18,11C19.1,11 20,10.1 20,9L20,4C20,2.9 19.1,2 18,2ZM18,9L6,9L6,4L18,4L18,9ZM18,13L6,13C4.9,13 4,13.9 4,15L4,20C4,21.1 4.9,22 6,22L13,22L13,20L6,20L6,15L18,15L18,16L20,16L20,15C20,13.9 19.1,13 18,13ZM16,17L18,17L18,19L20,19L20,21L18,21L18,23L16,23L16,21L14,21L14,19L16,19L16,17Z"
+ android:fillColor="#48473A"
+ android:fillType="evenOdd"/>
+</vector>
diff --git a/quickstep/res/layout/bubble_bar_drop_target.xml b/quickstep/res/layout/bubble_bar_drop_target.xml
new file mode 100644
index 0000000..23f240c
--- /dev/null
+++ b/quickstep/res/layout/bubble_bar_drop_target.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?><!--
+ ~ Copyright (C) 2024 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="@dimen/bubblebar_size"
+ android:layout_height="@dimen/bubblebar_size"
+ android:background="@drawable/bg_bubble_bar_drop_target"
+ android:elevation="@dimen/bubblebar_elevation" />
\ No newline at end of file
diff --git a/quickstep/res/layout/overview_actions_container.xml b/quickstep/res/layout/overview_actions_container.xml
index 758622b..5d489f5 100644
--- a/quickstep/res/layout/overview_actions_container.xml
+++ b/quickstep/res/layout/overview_actions_container.xml
@@ -23,6 +23,7 @@
android:id="@+id/action_buttons"
android:layout_width="match_parent"
android:layout_height="@dimen/overview_actions_height"
+ android:layout_gravity="bottom"
android:gravity="center_horizontal"
android:orientation="horizontal">
diff --git a/quickstep/res/layout/task_view_menu_option.xml b/quickstep/res/layout/task_view_menu_option.xml
index 30ab4b1..ffe2401 100644
--- a/quickstep/res/layout/task_view_menu_option.xml
+++ b/quickstep/res/layout/task_view_menu_option.xml
@@ -41,6 +41,8 @@
android:layout_marginStart="@dimen/task_menu_option_text_start_margin"
android:textSize="14sp"
android:textColor="?androidprv:attr/materialColorOnSurface"
- android:focusable="false" />
+ android:focusable="false"
+ android:gravity="start"
+ android:ellipsize="end" />
</LinearLayout>
diff --git a/quickstep/res/layout/taskbar_all_apps_button.xml b/quickstep/res/layout/taskbar_all_apps_button.xml
index c50db2e..94596cb 100644
--- a/quickstep/res/layout/taskbar_all_apps_button.xml
+++ b/quickstep/res/layout/taskbar_all_apps_button.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2022 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2022 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -15,10 +14,9 @@
-->
<!-- Note: The actual size will match the taskbar icon sizes in TaskbarView#onLayout(). -->
-<com.android.launcher3.views.IconButtonView
- xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.views.IconButtonView xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/BaseIcon.Workspace.Taskbar"
android:layout_width="@dimen/taskbar_icon_min_touch_size"
android:layout_height="@dimen/taskbar_icon_min_touch_size"
- android:contentDescription="@string/all_apps_button_label"
android:backgroundTint="@android:color/transparent"
- />
+ android:contentDescription="@string/all_apps_button_label" />
diff --git a/quickstep/res/layout/taskbar_divider.xml b/quickstep/res/layout/taskbar_divider.xml
index 0a92fa9..330f85f 100644
--- a/quickstep/res/layout/taskbar_divider.xml
+++ b/quickstep/res/layout/taskbar_divider.xml
@@ -1,5 +1,4 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2023 The Android Open Source Project
+<?xml version="1.0" encoding="utf-8"?><!-- Copyright (C) 2023 The Android Open Source Project
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -13,9 +12,9 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<com.android.launcher3.views.IconButtonView
- xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.launcher3.views.IconButtonView xmlns:android="http://schemas.android.com/apk/res/android"
+ style="@style/BaseIcon.Workspace.Taskbar"
android:layout_width="@dimen/taskbar_icon_min_touch_size"
android:layout_height="@dimen/taskbar_icon_min_touch_size"
- android:contentDescription="@string/taskbar_divider_a11y_title"
- android:backgroundTint="@android:color/transparent" />
\ No newline at end of file
+ android:backgroundTint="@android:color/transparent"
+ android:contentDescription="@string/taskbar_divider_a11y_title" />
\ No newline at end of file
diff --git a/quickstep/res/values-b+sr+Latn/strings.xml b/quickstep/res/values-b+sr+Latn/strings.xml
index 8eed155..1afde8f 100644
--- a/quickstep/res/values-b+sr+Latn/strings.xml
+++ b/quickstep/res/values-b+sr+Latn/strings.xml
@@ -95,7 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Deli"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Snimak ekrana"</string>
<string name="action_split" msgid="2098009717623550676">"Podeli"</string>
- <string name="action_save_app_pair" msgid="5974823919237645229">"Čuvaj par aplikacija"</string>
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Sačuvaj par aplikacija"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Dodirnite drugu aplikaciju za podeljeni ekran"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Odaberite drugu aplikaciju da biste koristili podeljeni ekran"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Otkaži"</b></string>
diff --git a/quickstep/res/values-de/strings.xml b/quickstep/res/values-de/strings.xml
index 499a3d5..c4371ee 100644
--- a/quickstep/res/values-de/strings.xml
+++ b/quickstep/res/values-de/strings.xml
@@ -134,7 +134,7 @@
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Taskleisten-Teiler"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Nach oben / Nach links verschieben"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Nach unten / Nach rechts verschieben"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# weitere App anzeigen.}other{# weitere Apps anzeigen.}}"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{# weitere App anzeigen}other{# weitere 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="desktop_select_app_toast" msgid="2306057322833956910">"Hinzufügen einer App zum Desktop"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Abbrechen"</string>
diff --git a/quickstep/res/values-et/strings.xml b/quickstep/res/values-et/strings.xml
index f8e2ecd..65f02eb 100644
--- a/quickstep/res/values-et/strings.xml
+++ b/quickstep/res/values-et/strings.xml
@@ -95,7 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Jaga"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
<string name="action_split" msgid="2098009717623550676">"Eralda"</string>
- <string name="action_save_app_pair" msgid="5974823919237645229">"Salv. rakendusepaar"</string>
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Salvesta rakendusepaar"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Jagatud ekraanikuva kasutamiseks puudutage muud rakendust"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Tühista"</b></string>
diff --git a/quickstep/res/values-gl/strings.xml b/quickstep/res/values-gl/strings.xml
index b266263..9875823 100644
--- a/quickstep/res/values-gl/strings.xml
+++ b/quickstep/res/values-gl/strings.xml
@@ -95,7 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Compartir"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Facer captura"</string>
<string name="action_split" msgid="2098009717623550676">"Dividir"</string>
- <string name="action_save_app_pair" msgid="5974823919237645229">"Gardar empar. apps"</string>
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Gardar parella apps"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Para usar a pantalla dividida, toca outra app"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Escolle outra aplicación para usar a pantalla dividida."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Cancelar"</b></string>
diff --git a/quickstep/res/values-hi/strings.xml b/quickstep/res/values-hi/strings.xml
index 5814779..368cc0a 100644
--- a/quickstep/res/values-hi/strings.xml
+++ b/quickstep/res/values-hi/strings.xml
@@ -95,7 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"शेयर करें"</string>
<string name="action_screenshot" msgid="8171125848358142917">"स्क्रीनशॉट लें"</string>
<string name="action_split" msgid="2098009717623550676">"स्प्लिट स्क्रीन मोड"</string>
- <string name="action_save_app_pair" msgid="5974823919237645229">"ऐप पेयर को सेव करें"</string>
+ <string name="action_save_app_pair" msgid="5974823919237645229">"ऐप पेयर सेव करें"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"स्प्लिट स्क्रीन के लिए दूसरे ऐप्लिकेशन पर टैप करें"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"स्प्लिट स्क्रीन इस्तेमाल करने के लिए, दूसरा ऐप्लिकेशन चुनें"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"अभी नहीं"</b></string>
diff --git a/quickstep/res/values-hr/strings.xml b/quickstep/res/values-hr/strings.xml
index b25c1c5..34030dd 100644
--- a/quickstep/res/values-hr/strings.xml
+++ b/quickstep/res/values-hr/strings.xml
@@ -134,7 +134,7 @@
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Razdjelnik trake sa zadacima"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Premjesti gore/lijevo"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Premjesti dolje/desno"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Prikaži više aplikacija (još #).}one{Prikaži više aplikacija (još #).}few{Prikaži više aplikacija (još #).}other{Prikaži više aplikacija (još #).}}"</string>
+ <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_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="desktop_select_app_toast" msgid="2306057322833956910">"Dodavanje aplikacije na radnu površinu"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Odustani"</string>
diff --git a/quickstep/res/values-in/strings.xml b/quickstep/res/values-in/strings.xml
index 44ab9b9..7fefe9c 100644
--- a/quickstep/res/values-in/strings.xml
+++ b/quickstep/res/values-in/strings.xml
@@ -134,7 +134,7 @@
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"Pemisah Taskbar"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"Pindahkan ke atas/kiri"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"Pindahkan ke bawah/kanan"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tampilkan # aplikasi lain.}other{Tampilkan # aplikasi lain.}}"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{Tampilkan # aplikasi lainnya.}other{Tampilkan # aplikasi lainnya.}}"</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="desktop_select_app_toast" msgid="2306057322833956910">"Menambahkan aplikasi ke Desktop"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"Batalkan"</string>
diff --git a/quickstep/res/values-ky/strings.xml b/quickstep/res/values-ky/strings.xml
index 58235bf..5fa61fb 100644
--- a/quickstep/res/values-ky/strings.xml
+++ b/quickstep/res/values-ky/strings.xml
@@ -95,7 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Бөлүшүү"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="action_split" msgid="2098009717623550676">"Бөлүү"</string>
- <string name="action_save_app_pair" msgid="5974823919237645229">"Эки колдонмону бир маалда пайдаланууну сактоо"</string>
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Колдонмолорду сактап коюу"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Экранды бөлүү үчүн башка колдонмону таптап коюңуз"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Экранды бөлүү үчүн башка колдонмону тандаңыз"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Жокко чыгаруу"</b></string>
diff --git a/quickstep/res/values-my/strings.xml b/quickstep/res/values-my/strings.xml
index 747c96b..762f669 100644
--- a/quickstep/res/values-my/strings.xml
+++ b/quickstep/res/values-my/strings.xml
@@ -95,7 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"မျှဝေရန်"</string>
<string name="action_screenshot" msgid="8171125848358142917">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
<string name="action_split" msgid="2098009717623550676">"ခွဲထုတ်ရန်"</string>
- <string name="action_save_app_pair" msgid="5974823919237645229">"အက်ပ်တွဲချိတ်ခြင်း သိမ်းရန်"</string>
+ <string name="action_save_app_pair" msgid="5974823919237645229">"အက်ပ်အတွဲ သိမ်းရန်"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"မျက်နှာပြင် ခွဲ၍ပြသရန် အက်ပ်နောက်တစ်ခုကို တို့ပါ"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းသုံးရန် နောက်အက်ပ်တစ်ခုရွေးပါ"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"မလုပ်တော့"</b></string>
diff --git a/quickstep/res/values-ne/strings.xml b/quickstep/res/values-ne/strings.xml
index 28f0bbe..fb5ebb3 100644
--- a/quickstep/res/values-ne/strings.xml
+++ b/quickstep/res/values-ne/strings.xml
@@ -45,7 +45,7 @@
<string name="hotsaet_tip_prediction_disabled" msgid="1506426298884658491">"सिफारिस गरिएका एपहरू देखाउने सुविधा असक्षम पारिएको छ"</string>
<string name="hotseat_prediction_content_description" msgid="4582028296938078419">"पूर्वानुमान गरिएको एप: <xliff:g id="TITLE">%1$s</xliff:g>"</string>
<string name="gesture_tutorial_rotation_prompt_title" msgid="7537946781362766964">"आफ्नो डिभाइस रोटेट गर्नुहोस्"</string>
- <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"इसारामार्फत गरिने नेभिगेसनको ट्युटोरियल पूरा गर्न कृपया आफ्नो डिभाइस रोटेट गर्नुहोस्"</string>
+ <string name="gesture_tutorial_rotation_prompt" msgid="1664493449851960691">"जेस्चर नेभिगेसनको ट्युटोरियल पूरा गर्न कृपया आफ्नो डिभाइस रोटेट गर्नुहोस्"</string>
<string name="back_gesture_feedback_swipe_too_far_from_edge" msgid="4175100312909721217">"स्क्रिनको सबैभन्दा दायाँ किनारा वा सबैभन्दा बायाँ किनाराबाट स्वाइप गर्नुहोस्"</string>
<string name="back_gesture_feedback_cancelled" msgid="762621530959111290">"स्क्रिनको दायाँ वा बायाँ किनाराबाट मध्य भागसम्म स्वाइप गर्नुहोस् अनि औँला उठाउनुहोस्"</string>
<string name="back_gesture_feedback_complete_with_overview_follow_up" msgid="9176400654037014471">"तपाईंले स्क्रिनको दायाँ किनाराबाट स्वाइप गरेर अघिल्लो स्क्रिनमा फर्कने तरिका सिक्नुभयो। अब एउटा एपबाट अर्को एपमा जाने तरिका सिक्नुहोस्।"</string>
diff --git a/quickstep/res/values-pt-rPT/strings.xml b/quickstep/res/values-pt-rPT/strings.xml
index b7af90d..ce13890 100644
--- a/quickstep/res/values-pt-rPT/strings.xml
+++ b/quickstep/res/values-pt-rPT/strings.xml
@@ -36,7 +36,7 @@
<string name="hotseat_edu_message_migrate" msgid="8927179260533775320">"Aceda facilmente às suas apps mais utilizadas, diretamente no ecrã principal. As sugestões mudam em função das suas rotinas. As apps na última fila passam para o ecrã principal."</string>
<string name="hotseat_edu_message_migrate_landscape" msgid="4248943380443387697">"Aceda facilmente às suas apps mais utilizadas no ecrã principal. As sugestões mudam em função das suas rotinas. As apps na fila dos favoritos passam para o ecrã principal."</string>
<string name="hotseat_edu_accept" msgid="1611544083278999837">"Obter sugestões de apps"</string>
- <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Não, obrigado"</string>
+ <string name="hotseat_edu_dismiss" msgid="2781161822780201689">"Não"</string>
<string name="hotseat_prediction_settings" msgid="6246554993566070818">"Definições"</string>
<string name="hotseat_auto_enrolled" msgid="522100018967146807">"As apps mais utilizadas aparecem aqui e mudam em função das rotinas."</string>
<string name="hotseat_tip_no_empty_slots" msgid="1325212677738179185">"Arraste as apps para fora da última fila para ver sugestões de apps."</string>
diff --git a/quickstep/res/values-ru/strings.xml b/quickstep/res/values-ru/strings.xml
index c4ea90d..4e1a213 100644
--- a/quickstep/res/values-ru/strings.xml
+++ b/quickstep/res/values-ru/strings.xml
@@ -95,7 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Поделиться"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Скриншот"</string>
<string name="action_split" msgid="2098009717623550676">"Разделить"</string>
- <string name="action_save_app_pair" msgid="5974823919237645229">"Сохр. одновр. исп."</string>
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Сохранить приложения"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Для разделения экрана выберите другое приложение."</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Чтобы использовать разделенный экран, выберите другое приложение."</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Отмена"</b></string>
diff --git a/quickstep/res/values-sr/strings.xml b/quickstep/res/values-sr/strings.xml
index 716e043..822d25c 100644
--- a/quickstep/res/values-sr/strings.xml
+++ b/quickstep/res/values-sr/strings.xml
@@ -95,7 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Дели"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Снимак екрана"</string>
<string name="action_split" msgid="2098009717623550676">"Подели"</string>
- <string name="action_save_app_pair" msgid="5974823919237645229">"Чувај пар апликација"</string>
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Сачувај пар апликација"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Додирните другу апликацију за подељени екран"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Одаберите другу апликацију да бисте користили подељени екран"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Откажи"</b></string>
diff --git a/quickstep/res/values-sv/strings.xml b/quickstep/res/values-sv/strings.xml
index 290ef9c..0464246 100644
--- a/quickstep/res/values-sv/strings.xml
+++ b/quickstep/res/values-sv/strings.xml
@@ -95,7 +95,7 @@
<string name="action_share" msgid="2648470652637092375">"Dela"</string>
<string name="action_screenshot" msgid="8171125848358142917">"Skärmbild"</string>
<string name="action_split" msgid="2098009717623550676">"Delat"</string>
- <string name="action_save_app_pair" msgid="5974823919237645229">"Spara par av appar"</string>
+ <string name="action_save_app_pair" msgid="5974823919237645229">"Spara app-par"</string>
<string name="toast_split_select_app" msgid="8464310533320556058">"Tryck på en annan app för att använda delad skärm"</string>
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Välj en annan app för att använda delad skärm"</string>
<string name="toast_split_select_app_cancel" msgid="1532690483356445639"><b>"Avbryt"</b></string>
diff --git a/quickstep/res/values-zh-rTW/strings.xml b/quickstep/res/values-zh-rTW/strings.xml
index c7d79c1..2e89466 100644
--- a/quickstep/res/values-zh-rTW/strings.xml
+++ b/quickstep/res/values-zh-rTW/strings.xml
@@ -134,7 +134,7 @@
<string name="taskbar_divider_a11y_title" msgid="6608690309720242080">"工作列分隔線"</string>
<string name="move_drop_target_top_or_left" msgid="2988702185049595807">"移到上方/左側"</string>
<string name="move_drop_target_bottom_or_right" msgid="5431393418797620162">"移到底部/右側"</string>
- <string name="quick_switch_overflow" msgid="6935266023013283353">"{count,plural, =1{顯示另外 # 個應用程式。}other{顯示另外 # 個應用程式。}}"</string>
+ <string name="quick_switch_overflow" msgid="6935266023013283353">"{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="desktop_select_app_toast" msgid="2306057322833956910">"新增應用程式至桌面"</string>
<string name="desktop_button_close_app_toast" msgid="5283096349579408560">"取消"</string>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 93ef735..caa949e 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -417,6 +417,7 @@
<!-- Container size with pointer included: bubblebar_size + bubblebar_pointer_size -->
<dimen name="bubblebar_size_with_pointer">80dp</dimen>
<dimen name="bubblebar_elevation">1dp</dimen>
+ <dimen name="bubblebar_drag_elevation">2dp</dimen>
<dimen name="bubblebar_hotseat_adjustment_threshold">90dp</dimen>
<dimen name="bubblebar_icon_size">50dp</dimen>
@@ -432,6 +433,11 @@
<dimen name="bubblebar_dismiss_target_icon_size">24dp</dimen>
<dimen name="bubblebar_dismiss_target_bottom_margin">50dp</dimen>
<dimen name="bubblebar_dismiss_floating_gradient_height">548dp</dimen>
+ <dimen name="bubblebar_dismiss_zone_width">192dp</dimen>
+ <dimen name="bubblebar_dismiss_zone_height">242dp</dimen>
+
+ <!-- Bubble bar drop target -->
+ <dimen name="bubblebar_drop_target_corner_radius">36dp</dimen>
<!-- Launcher splash screen -->
<!-- Note: keep this value in sync with the WindowManager/Shell dimens.xml -->
diff --git a/quickstep/src/com/android/launcher3/HomeTransitionController.java b/quickstep/src/com/android/launcher3/HomeTransitionController.java
index 2b50283..c4a2e9e 100644
--- a/quickstep/src/com/android/launcher3/HomeTransitionController.java
+++ b/quickstep/src/com/android/launcher3/HomeTransitionController.java
@@ -21,7 +21,7 @@
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.quickstep.SystemUiProxy;
-import com.android.wm.shell.transition.IHomeTransitionListener;
+import com.android.wm.shell.shared.IHomeTransitionListener;
/**
* Controls launcher response to home activity visibility changing.
diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
index 0ce1cb8..c0e0587 100644
--- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
+++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java
@@ -18,8 +18,8 @@
import static android.text.format.DateUtils.DAY_IN_MILLIS;
import static android.text.format.DateUtils.formatElapsedTime;
-import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
import static com.android.launcher3.EncryptionType.ENCRYPTED;
+import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_WIDGETS_PREDICTION;
@@ -65,7 +65,7 @@
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.UserCache;
@@ -233,7 +233,7 @@
}
InstanceId instanceId = new InstanceIdSequence().newInstanceId();
for (ItemInfo info : itemsIdMap) {
- FolderInfo parent = getContainer(info, itemsIdMap);
+ CollectionInfo parent = getContainer(info, itemsIdMap);
StatsLogCompatManager.writeSnapshot(info.buildProto(parent), instanceId);
}
additionalSnapshotEvents(instanceId);
@@ -270,7 +270,7 @@
}
for (ItemInfo info : itemsIdMap) {
- FolderInfo parent = getContainer(info, itemsIdMap);
+ CollectionInfo parent = getContainer(info, itemsIdMap);
LauncherAtom.ItemInfo itemInfo = info.buildProto(parent);
Log.d(TAG, itemInfo.toString());
StatsEvent statsEvent = StatsLogCompatManager.buildStatsEvent(itemInfo,
@@ -293,18 +293,19 @@
}
}
- private static FolderInfo getContainer(ItemInfo info, IntSparseArrayMap<ItemInfo> itemsIdMap) {
+ private static CollectionInfo getContainer(
+ ItemInfo info, IntSparseArrayMap<ItemInfo> itemsIdMap) {
if (info.container > 0) {
ItemInfo containerInfo = itemsIdMap.get(info.container);
- if (!(containerInfo instanceof FolderInfo)) {
+ if (!(containerInfo instanceof CollectionInfo)) {
Log.e(TAG, String.format(
"Item info: %s found with invalid container: %s",
info,
containerInfo));
}
// Allow crash to help debug b/173838775
- return (FolderInfo) containerInfo;
+ return (CollectionInfo) containerInfo;
}
return null;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 26212c1..8769f11 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -89,6 +89,7 @@
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -98,6 +99,7 @@
import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
import com.android.launcher3.taskbar.bubbles.BubbleBarController;
+import com.android.launcher3.taskbar.bubbles.BubbleBarPinController;
import com.android.launcher3.taskbar.bubbles.BubbleBarView;
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
@@ -254,7 +256,10 @@
new BubbleStashController(this),
new BubbleStashedHandleViewController(this, bubbleHandleView),
new BubbleDragController(this),
- new BubbleDismissController(this, mDragLayer)));
+ new BubbleDismissController(this, mDragLayer),
+ new BubbleBarPinController(this, mDragLayer,
+ () -> getDeviceProfile().getDisplayInfo().currentSize)
+ ));
}
// Construct controllers.
@@ -1082,19 +1087,19 @@
ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key,
ActivityOptions.makeBasic());
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
- } else if (tag instanceof FolderInfo fi && fi.itemType == Favorites.ITEM_TYPE_FOLDER) {
+ } else if (tag instanceof FolderInfo) {
// Tapping an expandable folder icon on Taskbar
shouldCloseAllOpenViews = false;
expandFolder((FolderIcon) view);
- } else if (tag instanceof FolderInfo fi && fi.itemType == Favorites.ITEM_TYPE_APP_PAIR) {
+ } else if (tag instanceof AppPairInfo api) {
// Tapping an app pair icon on Taskbar
if (recents != null && recents.isSplitSelectionActive()) {
Toast.makeText(this, "Unable to split with an app pair. Select another app.",
Toast.LENGTH_SHORT).show();
} else {
// Else launch the selected app pair
- launchFromTaskbar(recents, view, fi.contents);
- mControllers.uiController.onTaskbarIconLaunched(fi);
+ launchFromTaskbar(recents, view, api.getContents());
+ mControllers.uiController.onTaskbarIconLaunched(api);
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
}
} else if (tag instanceof WorkspaceItemInfo) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
index ca192c8..4462f20 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPopupController.java
@@ -116,9 +116,9 @@
}
} else if (info instanceof FolderInfo && v instanceof FolderIcon) {
FolderInfo fi = (FolderInfo) info;
- if (fi.contents.stream().anyMatch(matcher)) {
+ if (fi.anyMatch(matcher)) {
FolderDotInfo folderDotInfo = new FolderDotInfo();
- for (WorkspaceItemInfo si : fi.contents) {
+ for (WorkspaceItemInfo si : fi.getContents()) {
folderDotInfo.addDotInfo(mPopupDataProvider.getDotInfoForItem(si));
}
((FolderIcon) v).setDotInfo(folderDotInfo);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index c81bf7a..dc2684e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -18,6 +18,7 @@
import static android.content.pm.PackageManager.FEATURE_PC;
import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED;
+import static com.android.launcher3.BubbleTextView.DISPLAY_TASKBAR;
import static com.android.launcher3.Flags.enableCursorHoverStates;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
@@ -52,6 +53,8 @@
import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.folder.PreviewBackground;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -270,7 +273,7 @@
mAllAppsButton.setHapticFeedbackEnabled(
mControllerCallbacks.isAllAppsButtonHapticFeedbackEnabled());
}
- if (mTaskbarDivider != null) {
+ if (mTaskbarDivider != null && !mActivityContext.isThreeButtonNav()) {
mTaskbarDivider.setOnLongClickListener(
mControllerCallbacks.getTaskbarDividerLongClickListener());
mTaskbarDivider.setOnTouchListener(
@@ -282,7 +285,7 @@
removeView(view);
view.setOnClickListener(null);
view.setOnLongClickListener(null);
- if (!(view.getTag() instanceof FolderInfo)) {
+ if (!(view.getTag() instanceof CollectionInfo)) {
mActivityContext.getViewCache().recycleView(view.getSourceLayoutResId(), view);
}
view.setTag(null);
@@ -316,8 +319,8 @@
boolean isCollection = false;
if (hotseatItemInfo.isPredictedItem()) {
expectedLayoutResId = R.layout.taskbar_predicted_app_icon;
- } else if (hotseatItemInfo instanceof FolderInfo fi) {
- expectedLayoutResId = fi.itemType == ITEM_TYPE_APP_PAIR
+ } else if (hotseatItemInfo instanceof CollectionInfo ci) {
+ expectedLayoutResId = ci.itemType == ITEM_TYPE_APP_PAIR
? R.layout.app_pair_icon
: R.layout.folder_icon;
isCollection = true;
@@ -345,17 +348,18 @@
if (hotseatView == null) {
if (isCollection) {
- FolderInfo folderInfo = (FolderInfo) hotseatItemInfo;
+ CollectionInfo collectionInfo = (CollectionInfo) hotseatItemInfo;
switch (hotseatItemInfo.itemType) {
case ITEM_TYPE_FOLDER:
hotseatView = FolderIcon.inflateFolderAndIcon(
- expectedLayoutResId, mActivityContext, this, folderInfo);
+ expectedLayoutResId, mActivityContext, this,
+ (FolderInfo) collectionInfo);
((FolderIcon) hotseatView).setTextVisible(false);
break;
case ITEM_TYPE_APP_PAIR:
hotseatView = AppPairIcon.inflateIcon(
- expectedLayoutResId, mActivityContext, this, folderInfo,
- BubbleTextView.DISPLAY_TASKBAR);
+ expectedLayoutResId, mActivityContext, this,
+ (AppPairInfo) collectionInfo, DISPLAY_TASKBAR);
((AppPairIcon) hotseatView).setTextVisible(false);
break;
default:
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 4b1963b..1f7f0a7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -813,8 +813,8 @@
* 3) All Apps button
*/
public View getFirstIconMatch(Predicate<ItemInfo> matcher) {
- Predicate<ItemInfo> folderMatcher = ItemInfoMatcher.forFolderMatch(matcher);
- return mTaskbarView.getFirstMatch(matcher, folderMatcher);
+ Predicate<ItemInfo> collectionMatcher = ItemInfoMatcher.forFolderMatch(matcher);
+ return mTaskbarView.getFirstMatch(matcher, collectionMatcher);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
index e0e78f9..3b04602 100644
--- a/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/allapps/TaskbarAllAppsSlideInView.java
@@ -35,7 +35,6 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Insettable;
import com.android.launcher3.R;
-import com.android.launcher3.allapps.AllAppsRecyclerView;
import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.PendingAnimation;
import com.android.launcher3.config.FeatureFlags;
@@ -212,11 +211,6 @@
super.onScaleProgressChanged();
mAppsView.setClipChildren(!mIsBackProgressing);
mAppsView.getAppsRecyclerViewContainer().setClipChildren(!mIsBackProgressing);
- AllAppsRecyclerView rv = mAppsView.getActiveRecyclerView();
- if (rv != null && rv.getScrollbar() != null) {
- rv.getScrollbar().setVisibility(
- mIsBackProgressing ? INVISIBLE : VISIBLE);
- }
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
new file mode 100644
index 0000000..8ed9949
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarPinController.kt
@@ -0,0 +1,104 @@
+/*
+ * 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.bubbles
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.graphics.Point
+import android.graphics.RectF
+import android.view.Gravity.BOTTOM
+import android.view.Gravity.LEFT
+import android.view.Gravity.RIGHT
+import android.view.LayoutInflater
+import android.view.View
+import android.widget.FrameLayout
+import androidx.core.view.updateLayoutParams
+import com.android.launcher3.R
+import com.android.wm.shell.common.bubbles.BaseBubblePinController
+import com.android.wm.shell.common.bubbles.BubbleBarLocation
+
+/**
+ * Controller to manage pinning bubble bar to left or right when dragging starts from the bubble bar
+ */
+class BubbleBarPinController(
+ private val context: Context,
+ private val container: FrameLayout,
+ private val screenSizeProvider: () -> Point
+) : BaseBubblePinController() {
+
+ private lateinit var bubbleBarViewController: BubbleBarViewController
+ private lateinit var bubbleStashController: BubbleStashController
+ private var dropTargetView: View? = null
+
+ fun init(bubbleControllers: BubbleControllers) {
+ bubbleBarViewController = bubbleControllers.bubbleBarViewController
+ bubbleStashController = bubbleControllers.bubbleStashController
+ }
+
+ override fun getScreenCenterX(): Int {
+ return screenSizeProvider.invoke().x / 2
+ }
+
+ override fun getExclusionRect(): RectF {
+ val rect =
+ RectF(
+ 0f,
+ 0f,
+ context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_width),
+ context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_height)
+ )
+ val screenSize = screenSizeProvider.invoke()
+ val middleX = screenSize.x / 2
+ // Center it around the bottom center of the screen
+ rect.offsetTo(middleX - rect.width() / 2, screenSize.y - rect.height())
+ return rect
+ }
+
+ override fun createDropTargetView(): View {
+ return LayoutInflater.from(context)
+ .inflate(R.layout.bubble_bar_drop_target, container, false)
+ .also { view ->
+ dropTargetView = view
+ container.addView(view)
+ }
+ }
+
+ override fun getDropTargetView(): View? {
+ return dropTargetView
+ }
+
+ override fun removeDropTargetView(view: View) {
+ container.removeView(view)
+ dropTargetView = null
+ }
+
+ @SuppressLint("RtlHardcoded")
+ override fun updateLocation(location: BubbleBarLocation) {
+ val onLeft = location.isOnLeft(container.isLayoutRtl)
+
+ val bounds = bubbleBarViewController.bubbleBarBounds
+ val horizontalMargin = bubbleBarViewController.horizontalMargin
+ dropTargetView?.updateLayoutParams<FrameLayout.LayoutParams> {
+ width = bounds.width()
+ height = bounds.height()
+ gravity = BOTTOM or (if (onLeft) LEFT else RIGHT)
+ leftMargin = horizontalMargin
+ rightMargin = horizontalMargin
+ bottomMargin = -bubbleStashController.bubbleBarTranslationY.toInt()
+ }
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
index c47427d..90f1be3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java
@@ -29,6 +29,7 @@
public final BubbleStashedHandleViewController bubbleStashedHandleViewController;
public final BubbleDragController bubbleDragController;
public final BubbleDismissController bubbleDismissController;
+ public final BubbleBarPinController bubbleBarPinController;
private final RunnableList mPostInitRunnables = new RunnableList();
@@ -43,13 +44,15 @@
BubbleStashController bubbleStashController,
BubbleStashedHandleViewController bubbleStashedHandleViewController,
BubbleDragController bubbleDragController,
- BubbleDismissController bubbleDismissController) {
+ BubbleDismissController bubbleDismissController,
+ BubbleBarPinController bubbleBarPinController) {
this.bubbleBarController = bubbleBarController;
this.bubbleBarViewController = bubbleBarViewController;
this.bubbleStashController = bubbleStashController;
this.bubbleStashedHandleViewController = bubbleStashedHandleViewController;
this.bubbleDragController = bubbleDragController;
this.bubbleDismissController = bubbleDismissController;
+ this.bubbleBarPinController = bubbleBarPinController;
}
/**
@@ -64,6 +67,7 @@
bubbleStashController.init(taskbarControllers, this);
bubbleDragController.init(/* bubbleControllers = */ this);
bubbleDismissController.init(/* bubbleControllers = */ this);
+ bubbleBarPinController.init(this);
mPostInitRunnables.executeAllAndDestroy();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
index 73c71c8..a40f33c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java
@@ -67,6 +67,9 @@
@Nullable
private BubbleDragAnimator mAnimator;
+ @Nullable
+ private Listener mListener;
+
public BubbleDismissController(TaskbarActivityContext activity, TaskbarDragLayer dragLayer) {
mActivity = activity;
mDragLayer = dragLayer;
@@ -82,6 +85,13 @@
}
/**
+ * Set listener to be notified of dismiss events
+ */
+ public void setListener(@Nullable Listener listener) {
+ mListener = listener;
+ }
+
+ /**
* Setup the dismiss view and magnetized object that will be attracted to magnetic target.
* Should be called before handling events or showing/hiding dismiss view.
*
@@ -189,6 +199,9 @@
@NonNull MagnetizedObject<?> draggedObject) {
if (mAnimator == null) return;
mAnimator.animateDismissCaptured();
+ if (mListener != null) {
+ mListener.onStuckToDismissChanged(true /* stuck */);
+ }
}
@Override
@@ -197,6 +210,9 @@
float velX, float velY, boolean wasFlungOut) {
if (mAnimator == null) return;
mAnimator.animateDismissReleased();
+ if (mListener != null) {
+ mListener.onStuckToDismissChanged(false /* stuck */);
+ }
}
@Override
@@ -206,4 +222,10 @@
}
});
}
+
+ /** Interface to receive updates about the dismiss state */
+ public interface Listener {
+ /** Called when view is stuck or unstuck from dismiss target */
+ void onStuckToDismissChanged(boolean stuck);
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
index 08fd681..dab7d9d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDragController.java
@@ -25,10 +25,11 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import com.android.launcher3.R;
import com.android.launcher3.taskbar.TaskbarActivityContext;
/**
- * Controls bubble bar drag to dismiss interaction.
+ * Controls bubble bar drag interactions.
* Interacts with {@link BubbleDismissController}, used by {@link BubbleBarViewController}.
* Supported interactions:
* - Drag a single bubble view into dismiss target to remove it.
@@ -39,6 +40,7 @@
private final TaskbarActivityContext mActivity;
private BubbleBarViewController mBubbleBarViewController;
private BubbleDismissController mBubbleDismissController;
+ private BubbleBarPinController mBubbleBarPinController;
public BubbleDragController(TaskbarActivityContext activity) {
mActivity = activity;
@@ -52,6 +54,12 @@
public void init(@NonNull BubbleControllers bubbleControllers) {
mBubbleBarViewController = bubbleControllers.bubbleBarViewController;
mBubbleDismissController = bubbleControllers.bubbleDismissController;
+ mBubbleBarPinController = bubbleControllers.bubbleBarPinController;
+ mBubbleBarPinController.setListener(location -> {
+ // TODO(b/330585397): update bubble bar location in shell
+ });
+ mBubbleDismissController.setListener(
+ stuck -> mBubbleBarPinController.setDropTargetHidden(stuck));
}
/**
@@ -88,6 +96,10 @@
@SuppressLint("ClickableViewAccessibility")
public void setupBubbleBarView(@NonNull BubbleBarView bubbleBarView) {
PointF initialRelativePivot = new PointF();
+ final int restingElevation = bubbleBarView.getResources().getDimensionPixelSize(
+ R.dimen.bubblebar_elevation);
+ final int dragElevation = bubbleBarView.getResources().getDimensionPixelSize(
+ R.dimen.bubblebar_drag_elevation);
bubbleBarView.setOnTouchListener(new BubbleTouchListener() {
@Override
protected boolean onTouchDown(@NonNull View view, @NonNull MotionEvent event) {
@@ -102,12 +114,31 @@
// By default the bubble bar view pivot is in bottom right corner, while dragging
// it should be centered in order to align it with the dismiss target view
bubbleBarView.setRelativePivot(/* x = */ 0.5f, /* y = */ 0.5f);
+ bubbleBarView.setElevation(dragElevation);
+ mBubbleBarPinController.onDragStart(
+ bubbleBarView.getBubbleBarLocation().isOnLeft(bubbleBarView.isLayoutRtl()));
+ }
+
+ @Override
+ protected void onDragUpdate(float x, float y) {
+ mBubbleBarPinController.onDragUpdate(x, y);
+ }
+
+ @Override
+ protected void onDragRelease() {
+ mBubbleBarPinController.onDragEnd();
+ }
+
+ @Override
+ protected void onDragDismiss() {
+ mBubbleBarPinController.onDragEnd();
}
@Override
void onDragEnd() {
// Restoring the initial pivot for the bubble bar view
bubbleBarView.setRelativePivot(initialRelativePivot.x, initialRelativePivot.y);
+ bubbleBarView.setElevation(restingElevation);
}
});
}
@@ -170,6 +201,13 @@
abstract void onDragStart();
/**
+ * Called when bubble is dragged to new coordinates.
+ * Not called while bubble is stuck to the dismiss target.
+ */
+ protected void onDragUpdate(float x, float y) {
+ }
+
+ /**
* Called when the dragging interaction has ended and all the animations have completed
*/
abstract void onDragEnd();
@@ -232,8 +270,10 @@
* @param event the motion event
*/
protected void onTouchMove(@NonNull View view, @NonNull MotionEvent event) {
- final float dx = event.getRawX() - mTouchDownLocation.x;
- final float dy = event.getRawY() - mTouchDownLocation.y;
+ float rawX = event.getRawX();
+ float rawY = event.getRawY();
+ final float dx = rawX - mTouchDownLocation.x;
+ final float dy = rawY - mTouchDownLocation.y;
switch (mState) {
case TOUCHED:
final boolean movedOut = Math.hypot(dx, dy) > mTouchSlop;
@@ -244,7 +284,7 @@
}
break;
case DRAGGING:
- drag(view, event, dx, dy);
+ drag(view, event, dx, dy, rawX, rawY);
break;
}
}
@@ -293,10 +333,12 @@
mBubbleDismissController.showDismissView();
}
- private void drag(@NonNull View view, @NonNull MotionEvent event, float dx, float dy) {
+ private void drag(@NonNull View view, @NonNull MotionEvent event, float dx, float dy,
+ float x, float y) {
if (mBubbleDismissController.handleTouchEvent(event)) return;
view.setTranslationX(mViewInitialPosition.x + dx);
view.setTranslationY(mViewInitialPosition.y + dy);
+ onDragUpdate(x, y);
}
private void stopDragging(@NonNull View view, @NonNull MotionEvent event) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
index b6002e8..7875dae 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/AllAppsState.java
@@ -32,6 +32,8 @@
import com.android.quickstep.util.BaseDepthController;
import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
+import java.util.concurrent.TimeUnit;
+
/**
* Definition for AllApps state
*/
@@ -39,6 +41,8 @@
private static final int STATE_FLAGS =
FLAG_WORKSPACE_INACCESSIBLE | FLAG_CLOSE_POPUPS | FLAG_HOTSEAT_INACCESSIBLE;
+ private static final long BACK_CUJ_TIMEOUT_MS = TimeUnit.SECONDS.toMillis(5);
+
public AllAppsState(int id) {
super(id, LAUNCHER_STATE_ALLAPPS, STATE_FLAGS);
@@ -53,14 +57,33 @@
}
@Override
- public void onBackPressed(Launcher launcher) {
+ public void onBackStarted(Launcher launcher) {
+ // Because the back gesture can take longer time depending on when user release the finger,
+ // we pass BACK_CUJ_TIMEOUT_MS as timeout to the jank monitor.
InteractionJankMonitorWrapper.begin(launcher.getAppsView(),
- Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
- super.onBackPressed(launcher);
+ Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK, BACK_CUJ_TIMEOUT_MS);
+ super.onBackStarted(launcher);
}
@Override
- protected void onBackPressCompleted(boolean success) {
+ public void onBackInvoked(Launcher launcher) {
+ // In predictive back swipe, onBackInvoked() will be called after onBackStarted().
+ // Because the 2nd InteractionJankMonitor.begin() will be ignore within timeout, it's safe
+ // to call InteractionJankMonitorWrapper.begin here.
+ InteractionJankMonitorWrapper.begin(launcher.getAppsView(),
+ Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
+ super.onBackInvoked(launcher);
+ }
+
+ /** Called when predictive back swipe is cancelled. */
+ @Override
+ public void onBackCancelled(Launcher launcher) {
+ super.onBackCancelled(launcher);
+ InteractionJankMonitorWrapper.cancel(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
+ }
+
+ @Override
+ protected void onBackAnimationCompleted(boolean success) {
if (success) {
// Animation was successful.
InteractionJankMonitorWrapper.end(Cuj.CUJ_LAUNCHER_CLOSE_ALL_APPS_BACK);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
index 856b519..c63eaeb 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewModalTaskState.java
@@ -60,7 +60,7 @@
}
@Override
- public void onBackPressed(Launcher launcher) {
+ public void onBackInvoked(Launcher launcher) {
launcher.getStateManager().goToState(LauncherState.OVERVIEW);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
index 8c2efc2..d0eef8e 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/OverviewState.java
@@ -199,7 +199,7 @@
}
@Override
- public void onBackPressed(Launcher launcher) {
+ public void onBackInvoked(Launcher launcher) {
RecentsView recentsView = launcher.getOverviewPanel();
TaskView taskView = recentsView.getRunningTaskView();
if (taskView != null) {
@@ -209,7 +209,7 @@
recentsView.snapToPage(recentsView.indexOfChild(taskView));
}
} else {
- super.onBackPressed(launcher);
+ super.onBackInvoked(launcher);
}
}
diff --git a/quickstep/src/com/android/quickstep/AllAppsActionManager.kt b/quickstep/src/com/android/quickstep/AllAppsActionManager.kt
index fd2ed3a..6fd68d5 100644
--- a/quickstep/src/com/android/quickstep/AllAppsActionManager.kt
+++ b/quickstep/src/com/android/quickstep/AllAppsActionManager.kt
@@ -81,6 +81,7 @@
}
fun onDestroy() {
+ isActionRegistered = false
context
.getSystemService(AccessibilityManager::class.java)
?.unregisterSystemAction(
diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java
index 72f67fc..b6272da 100644
--- a/quickstep/src/com/android/quickstep/SystemUiProxy.java
+++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java
@@ -91,13 +91,13 @@
import com.android.wm.shell.onehanded.IOneHanded;
import com.android.wm.shell.recents.IRecentTasks;
import com.android.wm.shell.recents.IRecentTasksListener;
+import com.android.wm.shell.shared.IHomeTransitionListener;
+import com.android.wm.shell.shared.IShellTransitions;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
import com.android.wm.shell.splitscreen.ISplitSelectListener;
import com.android.wm.shell.startingsurface.IStartingWindow;
import com.android.wm.shell.startingsurface.IStartingWindowListener;
-import com.android.wm.shell.transition.IHomeTransitionListener;
-import com.android.wm.shell.transition.IShellTransitions;
import com.android.wm.shell.util.GroupedRecentTaskInfo;
import java.io.PrintWriter;
diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
index 7f1883d..147a3e2 100644
--- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java
@@ -136,8 +136,9 @@
class SaveAppPairSystemShortcut extends SystemShortcut<BaseDraggingActivity> {
private final GroupedTaskView mTaskView;
- public SaveAppPairSystemShortcut(BaseDraggingActivity activity, GroupedTaskView taskView) {
- super(R.drawable.ic_save_app_pair, R.string.save_app_pair, activity,
+ public SaveAppPairSystemShortcut(BaseDraggingActivity activity, GroupedTaskView taskView,
+ int iconResId) {
+ super(iconResId, R.string.save_app_pair, activity,
taskView.getItemInfo(), taskView);
mTaskView = taskView;
}
@@ -342,8 +343,12 @@
return null;
}
+ int iconResId = deviceProfile.isLeftRightSplit
+ ? R.drawable.ic_save_app_pair_left_right
+ : R.drawable.ic_save_app_pair_up_down;
+
return Collections.singletonList(
- new SaveAppPairSystemShortcut(activity, (GroupedTaskView) taskView));
+ new SaveAppPairSystemShortcut(activity, (GroupedTaskView) taskView, iconResId));
}
@Override
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index b43c520..66d7144 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -135,9 +135,9 @@
import com.android.wm.shell.draganddrop.IDragAndDrop;
import com.android.wm.shell.onehanded.IOneHanded;
import com.android.wm.shell.recents.IRecentTasks;
+import com.android.wm.shell.shared.IShellTransitions;
import com.android.wm.shell.splitscreen.ISplitScreen;
import com.android.wm.shell.startingsurface.IStartingWindow;
-import com.android.wm.shell.transition.IShellTransitions;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -442,8 +442,10 @@
/** Refreshes the current overview target. */
public void refreshOverviewTarget() {
- executeForTouchInteractionService(tis -> tis.onOverviewTargetChange(
- tis.mOverviewComponentObserver.isHomeAndOverviewSame()));
+ executeForTouchInteractionService(tis -> {
+ tis.mAllAppsActionManager.onDestroy();
+ tis.onOverviewTargetChange(tis.mOverviewComponentObserver.isHomeAndOverviewSame());
+ });
}
}
diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
index d265918..e078a49 100644
--- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
+++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java
@@ -61,7 +61,7 @@
import com.android.launcher3.model.AllAppsList;
import com.android.launcher3.model.BaseModelUpdateTask;
import com.android.launcher3.model.BgDataModel;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.LogConfig;
@@ -375,7 +375,7 @@
Executors.MODEL_EXECUTOR.execute(
() -> write(event, applyOverwrites(mItemInfo.buildProto())));
} else {
- // Item is inside the folder, fetch folder info in a BG thread
+ // Item is inside a collection, fetch collection info in a BG thread
// and then write to StatsLog.
appState.getModel().enqueueModelUpdateTask(
new BaseModelUpdateTask() {
@@ -383,8 +383,9 @@
public void execute(@NonNull final LauncherAppState app,
@NonNull final BgDataModel dataModel,
@NonNull final AllAppsList apps) {
- FolderInfo folderInfo = dataModel.folders.get(mItemInfo.container);
- write(event, applyOverwrites(mItemInfo.buildProto(folderInfo)));
+ CollectionInfo collectionInfo =
+ dataModel.collections.get(mItemInfo.container);
+ write(event, applyOverwrites(mItemInfo.buildProto(collectionInfo)));
}
});
}
diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java
index ecb6118..f4da867 100644
--- a/quickstep/src/com/android/quickstep/util/AppPairsController.java
+++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java
@@ -53,7 +53,7 @@
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.taskbar.TaskbarActivityContext;
@@ -149,25 +149,17 @@
app1.rank = encodeRank(SPLIT_POSITION_TOP_OR_LEFT, snapPosition);
app2.rank = encodeRank(SPLIT_POSITION_BOTTOM_OR_RIGHT, snapPosition);
- FolderInfo newAppPair = FolderInfo.createAppPair(app1, app2);
-
- if (newAppPair.contents.size() != 2) {
- // if app pair doesn't have exactly 2 members, log an error and do not create the app
- // pair.
- Log.wtf(TAG,
- "tried to save an app pair with " + newAppPair.contents.size() + " members");
- return;
- }
+ AppPairInfo newAppPair = new AppPairInfo(app1, app2);
IconCache iconCache = LauncherAppState.getInstance(mContext).getIconCache();
MODEL_EXECUTOR.execute(() -> {
- newAppPair.contents.forEach(member -> {
+ newAppPair.getContents().forEach(member -> {
member.title = "";
member.bitmap = iconCache.getDefaultIcon(newAppPair.user);
iconCache.getTitleAndIcon(member, member.usingLowResIcon());
});
- newAppPair.title = getDefaultTitle(newAppPair.contents.get(0).title,
- newAppPair.contents.get(1).title);
+ newAppPair.title = getDefaultTitle(newAppPair.getFirstApp().title,
+ newAppPair.getSecondApp().title);
MAIN_EXECUTOR.execute(() -> {
LauncherAccessibilityDelegate delegate =
Launcher.getLauncher(mContext).getAccessibilityDelegate();
@@ -194,8 +186,8 @@
* monitoring
*/
public void launchAppPair(AppPairIcon appPairIcon, int cuj) {
- WorkspaceItemInfo app1 = appPairIcon.getInfo().contents.get(0);
- WorkspaceItemInfo app2 = appPairIcon.getInfo().contents.get(1);
+ WorkspaceItemInfo app1 = appPairIcon.getInfo().getFirstApp();
+ WorkspaceItemInfo app2 = appPairIcon.getInfo().getSecondApp();
ComponentKey app1Key = new ComponentKey(app1.getTargetComponent(), app1.user);
ComponentKey app2Key = new ComponentKey(app2.getTargetComponent(), app2.user);
mSplitSelectStateController.setLaunchingCuj(cuj);
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index 8f5c9c1..6b27004 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -659,8 +659,8 @@
// Create a new floating view in Launcher, positioned above the launching icon
val drawableArea = launchingIconView.iconDrawableArea
- val appIcon1 = launchingIconView.info.contents[0].newIcon(launchingIconView.context)
- val appIcon2 = launchingIconView.info.contents[1].newIcon(launchingIconView.context)
+ val appIcon1 = launchingIconView.info.getFirstApp().newIcon(launchingIconView.context)
+ val appIcon2 = launchingIconView.info.getSecondApp().newIcon(launchingIconView.context)
appIcon1.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
appIcon2.setBounds(0, 0, dp.iconSizePx, dp.iconSizePx)
val floatingView =
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index 87be091..2282c46 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -16,7 +16,6 @@
package com.android.quickstep.util;
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static com.android.window.flags.Flags.enableDesktopWindowingMode;
@@ -44,7 +43,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconCache;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.PackageItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -126,7 +125,7 @@
intent = appInfo.intent;
user = appInfo.user;
bitmapInfo = appInfo.bitmap;
- } else if (tag instanceof FolderInfo fi && fi.itemType == ITEM_TYPE_APP_PAIR) {
+ } else if (tag instanceof AppPairInfo) {
// Prompt the user to select something else by wiggling the instructions view
mController.getSplitInstructionsView().goBoing();
return true;
diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
index e0091a5..384a8d8 100644
--- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
+++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java
@@ -20,7 +20,6 @@
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;
@@ -43,8 +42,6 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
-import java.util.Arrays;
-import java.util.stream.Collectors;
/**
* View for showing action buttons in Overview
@@ -297,17 +294,6 @@
int desiredVisibility = mSplitButtonHiddenFlags == 0 ? VISIBLE : GONE;
mSplitButton.setVisibility(desiredVisibility);
findViewById(R.id.action_split_space).setVisibility(desiredVisibility);
-
- String callStack = Arrays.stream(
- Log.getStackTraceString(new Exception("thread stacktrace"))
- .split("\\n"))
- .limit(5)
- .skip(1) // Removes the line "java.lang.Exception: thread stacktrace"
- .collect(Collectors.joining("\n"));
- Log.d("b/321291049", "updateSplitButtonHiddenFlags called with flag: " + flag
- + " enabled: " + enable
- + " visibility: " + desiredVisibility
- + " partial trace: \n" + callStack);
}
/**
@@ -407,7 +393,11 @@
? R.drawable.ic_split_horizontal
: R.drawable.ic_split_vertical;
mSplitButton.setCompoundDrawablesRelativeWithIntrinsicBounds(splitIconRes, 0, 0, 0);
+
+ int appPairIconRes = dp.isLeftRightSplit
+ ? R.drawable.ic_save_app_pair_left_right
+ : R.drawable.ic_save_app_pair_up_down;
mSaveAppPairButton.setCompoundDrawablesRelativeWithIntrinsicBounds(
- R.drawable.ic_save_app_pair, 0, 0, 0);
+ appPairIconRes, 0, 0, 0);
}
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index abd4ec4..79bd107 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -135,8 +135,6 @@
public class TaskView extends FrameLayout implements Reusable {
private static final String TAG = TaskView.class.getSimpleName();
- private static final boolean DEBUG = false;
-
public static final int FLAG_UPDATE_ICON = 1;
public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1;
public static final int FLAG_UPDATE_CORNER_RADIUS = FLAG_UPDATE_THUMBNAIL << 1;
@@ -184,7 +182,7 @@
Collections.singletonList(new Rect());
public static final FloatProperty<TaskView> FOCUS_TRANSITION =
- new FloatProperty<TaskView>("focusTransition") {
+ new FloatProperty<>("focusTransition") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setIconsAndBannersTransitionProgress(v, false /* invert */);
@@ -197,7 +195,7 @@
};
private static final FloatProperty<TaskView> SPLIT_SELECT_TRANSLATION_X =
- new FloatProperty<TaskView>("splitSelectTranslationX") {
+ new FloatProperty<>("splitSelectTranslationX") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setSplitSelectTranslationX(v);
@@ -210,7 +208,7 @@
};
private static final FloatProperty<TaskView> SPLIT_SELECT_TRANSLATION_Y =
- new FloatProperty<TaskView>("splitSelectTranslationY") {
+ new FloatProperty<>("splitSelectTranslationY") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setSplitSelectTranslationY(v);
@@ -223,7 +221,7 @@
};
private static final FloatProperty<TaskView> DISMISS_TRANSLATION_X =
- new FloatProperty<TaskView>("dismissTranslationX") {
+ new FloatProperty<>("dismissTranslationX") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setDismissTranslationX(v);
@@ -236,7 +234,7 @@
};
private static final FloatProperty<TaskView> DISMISS_TRANSLATION_Y =
- new FloatProperty<TaskView>("dismissTranslationY") {
+ new FloatProperty<>("dismissTranslationY") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setDismissTranslationY(v);
@@ -249,7 +247,7 @@
};
private static final FloatProperty<TaskView> TASK_OFFSET_TRANSLATION_X =
- new FloatProperty<TaskView>("taskOffsetTranslationX") {
+ new FloatProperty<>("taskOffsetTranslationX") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setTaskOffsetTranslationX(v);
@@ -262,7 +260,7 @@
};
private static final FloatProperty<TaskView> TASK_OFFSET_TRANSLATION_Y =
- new FloatProperty<TaskView>("taskOffsetTranslationY") {
+ new FloatProperty<>("taskOffsetTranslationY") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setTaskOffsetTranslationY(v);
@@ -275,7 +273,7 @@
};
private static final FloatProperty<TaskView> TASK_RESISTANCE_TRANSLATION_X =
- new FloatProperty<TaskView>("taskResistanceTranslationX") {
+ new FloatProperty<>("taskResistanceTranslationX") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setTaskResistanceTranslationX(v);
@@ -288,7 +286,7 @@
};
private static final FloatProperty<TaskView> TASK_RESISTANCE_TRANSLATION_Y =
- new FloatProperty<TaskView>("taskResistanceTranslationY") {
+ new FloatProperty<>("taskResistanceTranslationY") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setTaskResistanceTranslationY(v);
@@ -301,7 +299,7 @@
};
public static final FloatProperty<TaskView> GRID_END_TRANSLATION_X =
- new FloatProperty<TaskView>("gridEndTranslationX") {
+ new FloatProperty<>("gridEndTranslationX") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setGridEndTranslationX(v);
@@ -314,7 +312,7 @@
};
public static final FloatProperty<TaskView> SNAPSHOT_SCALE =
- new FloatProperty<TaskView>("snapshotScale") {
+ new FloatProperty<>("snapshotScale") {
@Override
public void setValue(TaskView taskView, float v) {
taskView.setSnapshotScale(v);
@@ -602,10 +600,7 @@
if (event.getAction() == MotionEvent.ACTION_DOWN) {
computeAndSetIconTouchDelegate(mIconView, mIconCenterCoords, mIconTouchDelegate);
}
- if (mIconTouchDelegate != null && mIconTouchDelegate.onTouchEvent(event)) {
- return true;
- }
- return false;
+ return mIconTouchDelegate != null && mIconTouchDelegate.onTouchEvent(event);
}
protected void computeAndSetIconTouchDelegate(TaskViewIcon view, float[] tempCenterCoords,
@@ -647,9 +642,6 @@
/**
* Updates this task view to the given {@param task}.
- *
- * TODO(b/142282126) Re-evaluate if we need to pass in isMultiWindowMode after
- * that issue is fixed
*/
public void bind(Task task, RecentsOrientedState orientedState) {
cancelPendingLoadTasks();
@@ -1594,19 +1586,6 @@
mEndQuickswitchCuj = endQuickswitchCuj;
}
- private int getExpectedViewHeight(View view) {
- int expectedHeight;
- int h = view.getLayoutParams().height;
- if (h > 0) {
- expectedHeight = h;
- } else {
- int m = MeasureSpec.makeMeasureSpec(MeasureSpec.EXACTLY - 1, MeasureSpec.AT_MOST);
- view.measure(m, m);
- expectedHeight = view.getMeasuredHeight();
- }
- return expectedHeight;
- }
-
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
diff --git a/res/layout/hotseat.xml b/res/layout/hotseat.xml
index 82b0b8d..d14dcd5 100644
--- a/res/layout/hotseat.xml
+++ b/res/layout/hotseat.xml
@@ -21,4 +21,6 @@
android:layout_height="match_parent"
android:theme="@style/HomeScreenElementTheme"
android:importantForAccessibility="no"
+ android:clickable="false"
+ android:longClickable="false"
launcher:containerType="hotseat" />
\ No newline at end of file
diff --git a/res/layout/private_space_header.xml b/res/layout/private_space_header.xml
index 2b5db48..185207b 100644
--- a/res/layout/private_space_header.xml
+++ b/res/layout/private_space_header.xml
@@ -33,7 +33,7 @@
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:layout_alignParentEnd="true"
- android:animateLayoutChanges="true">
+ android:animateLayoutChanges="false">
<ImageButton
android:id="@+id/ps_settings_button"
android:layout_width="@dimen/ps_header_image_height"
diff --git a/res/layout/snackbar.xml b/res/layout/snackbar.xml
index b818943..6bc1729 100644
--- a/res/layout/snackbar.xml
+++ b/res/layout/snackbar.xml
@@ -39,6 +39,7 @@
android:paddingLeft="8dp"
android:paddingRight="8dp"
android:background="?android:attr/selectableItemBackground"
+ android:longClickable="false"
android:textStyle="bold"
android:textSize="@dimen/snackbar_max_text_size"
android:textColor="?android:attr/colorAccent"
diff --git a/res/values-af/strings.xml b/res/values-af/strings.xml
index 8902033..9718479 100644
--- a/res/values-af/strings.xml
+++ b/res/values-af/strings.xml
@@ -87,7 +87,7 @@
<string name="all_apps_button_work_label" msgid="7270707118948892488">"Lys werkprogramme"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Verwyder"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Deïnstalleer"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Programinligting"</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="install_drop_target_label" msgid="2539096853673231757">"Installeer"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Moenie voorstel nie"</string>
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Misluk: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privaat ruimte"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Hou privaat apps gesluit en versteek"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privaat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Privaat Ruimte-instellings"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Sluit/ontsluit Privaat Ruimte"</string>
diff --git a/res/values-am/strings.xml b/res/values-am/strings.xml
index 0b94a4c..a19ea97 100644
--- a/res/values-am/strings.xml
+++ b/res/values-am/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"የግል መተግበሪያዎች እንደተቆለፉ እና እንደተበቁ እንዲቆዩ ያድርጉ"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"የግል"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"የግል ቦታ ቅንብሮች"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"የግል ቦታን ቆልፍ/ክፈት"</string>
diff --git a/res/values-ar/strings.xml b/res/values-ar/strings.xml
index 7ae39e3..dfd23da 100644
--- a/res/values-ar/strings.xml
+++ b/res/values-ar/strings.xml
@@ -39,7 +39,7 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"العرض %1$d الطول %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"أداة <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"التطبيق المصغّرة \"<xliff:g id="WIDGET_NAME">%1$s</xliff:g>\"، بعرض %2$d وارتفاع %3$d"</string>
- <string name="add_item_request_drag_hint" msgid="8730547755622776606">"انقر مع الاستمرار على التطبيق المصغّر لنقله إلى الشاشة الرئيسية."</string>
+ <string name="add_item_request_drag_hint" msgid="8730547755622776606">"انقر مع الاستمرار على التطبيق المصغّر لنقله إلى الشاشة الرئيسية"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"إضافة إلى الشاشة الرئيسية"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"تمت إضافة الأداة <xliff:g id="WIDGET_NAME">%1$s</xliff:g> إلى الشاشة الرئيسية."</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"اقتراحات"</string>
@@ -188,7 +188,8 @@
<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="611902414159280263">"إبقاء التطبيقات الخاصة مقفلة ومخفية"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"المساحة الخاصة"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"إعدادات المساحة الخاصة"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"قفل المساحة الخاصة أو فتح قفلها"</string>
diff --git a/res/values-as/strings.xml b/res/values-as/strings.xml
index 47586d9..898b9d6 100644
--- a/res/values-as/strings.xml
+++ b/res/values-as/strings.xml
@@ -187,11 +187,12 @@
<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_secondary_label" msgid="611902414159280263">"ব্যক্তিগত এপ্সমূহ লক কৰি লুকুৱাই ৰাখক"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"প্ৰাইভেট স্পে\'চ"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"ব্যক্তিগত"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ব্যক্তিগত স্পে’চৰ ছেটিং"</string>
- <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ব্যক্তিগত স্পে’চ লক/আনলক কৰক"</string>
+ <string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"প্ৰাইভেট স্পে\'চ লক/আনলক কৰক"</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="8611055839242385935">"এপ্ ইনষ্টল কৰক"</string>
diff --git a/res/values-az/strings.xml b/res/values-az/strings.xml
index 4631f61..b714613 100644
--- a/res/values-az/strings.xml
+++ b/res/values-az/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtr"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Alınmadı: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Şəxsi yer"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Şəxsi tətbiqləri kilidli və gizli saxlayın"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Şəxsi"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Şəxsi məkan ayarları"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Şəxsi məkanı kilidləyin/kiliddən çıxarın"</string>
diff --git a/res/values-b+sr+Latn/strings.xml b/res/values-b+sr+Latn/strings.xml
index d96d660..6ff7970 100644
--- a/res/values-b+sr+Latn/strings.xml
+++ b/res/values-b+sr+Latn/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Neka privatne aplikacije budu zaključane i sakrivene"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Podešavanja privatnog prostora"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključaj/otključaj privatni prostor"</string>
diff --git a/res/values-be/strings.xml b/res/values-be/strings.xml
index 7c33ff6..22642d7 100644
--- a/res/values-be/strings.xml
+++ b/res/values-be/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"Схавайце прыватныя праграмы ў асобную прастору і закрыйце доступ да яе"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Прыватная"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Налады прыватнай вобласці"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заблакіраваць (разблакіраваць) прыватную вобласць"</string>
diff --git a/res/values-bg/strings.xml b/res/values-bg/strings.xml
index 2a9ac1b..a9e4a26 100644
--- a/res/values-bg/strings.xml
+++ b/res/values-bg/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"Заключване и скриване на частните приложения"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Лично"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Настройки за личното пространство"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заключване/отключване на личното пространство"</string>
diff --git a/res/values-bn/strings.xml b/res/values-bn/strings.xml
index ca6ee84..f20416b 100644
--- a/res/values-bn/strings.xml
+++ b/res/values-bn/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"ব্যক্তিগত অ্যাপ লক করে লুকিয়ে রাখুন"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"ব্যক্তিগত"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ব্যক্তিগত স্পেসের সেটিংস"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ব্যক্তিগত স্পেস লক/আনলক করুন"</string>
diff --git a/res/values-bs/strings.xml b/res/values-bs/strings.xml
index 96f45c1..3e2ed4d 100644
--- a/res/values-bs/strings.xml
+++ b/res/values-bs/strings.xml
@@ -39,7 +39,7 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"Širina %1$d, visina %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, širina %2$d, visina %3$d"</string>
- <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i držite vidžet da ga pomjerate po početnom ekranu"</string>
+ <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Dodirnite i zadržite vidžet da ga pomjerate po početnom ekranu"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> je dodan na početni ekran"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Prijedlozi"</string>
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrirajte"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privatan prostor"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Ostavite privatne aplikacije zaključane i sakrivene"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključavanje/otključavanje privatnog prostora"</string>
diff --git a/res/values-ca/strings.xml b/res/values-ca/strings.xml
index 666cb15..4ffd4bb 100644
--- a/res/values-ca/strings.xml
+++ b/res/values-ca/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtra"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espai privat"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Mantén les aplicacions privades bloquejades i amagades"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Configuració d\'Espai privat"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloqueja o desbloqueja Espai privat"</string>
diff --git a/res/values-cs/strings.xml b/res/values-cs/strings.xml
index 1d02668..61521ae 100644
--- a/res/values-cs/strings.xml
+++ b/res/values-cs/strings.xml
@@ -29,7 +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="save_app_pair" msgid="5647523853662686243">"Uložit pár aplikací"</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>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"Pokud chcete použít tento pár aplikací, rozložte zařízení"</string>
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtr"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Selhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Soukromý prostor"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Mějte soukromé aplikace uzamknuté a skryté"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Soukromé"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Nastavení soukromého prostoru"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zamknout/odemknout soukromý prostor"</string>
diff --git a/res/values-da/strings.xml b/res/values-da/strings.xml
index 2f1aa65..f85a2a9 100644
--- a/res/values-da/strings.xml
+++ b/res/values-da/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mislykket: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privat område"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Hold private apps låste og skjulte"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Indstillinger for privat rum"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås/oplås det private område"</string>
diff --git a/res/values-de/strings.xml b/res/values-de/strings.xml
index e19a9b0..f6fd609 100644
--- a/res/values-de/strings.xml
+++ b/res/values-de/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Fehler: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privates Profil"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Hier kannst du deine privaten Apps verstecken und sperren"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Einstellungen für privaten Bereich"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privaten Bereich sperren/entsperren"</string>
diff --git a/res/values-el/strings.xml b/res/values-el/strings.xml
index 55575e7..04e42b2 100644
--- a/res/values-el/strings.xml
+++ b/res/values-el/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"Διατηρήστε τις ιδιωτικές εφαρμογές κλειδωμένες και κρυφές"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Ιδιωτικό"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Ρυθμίσεις Ιδιωτικού χώρου"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Κλείδωμα/Ξεκλείδωμα Ιδιωτικού χώρου"</string>
diff --git a/res/values-en-rAU/strings.xml b/res/values-en-rAU/strings.xml
index d86770a..6a7fbb7 100644
--- a/res/values-en-rAU/strings.xml
+++ b/res/values-en-rAU/strings.xml
@@ -188,7 +188,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Keep private apps locked and hidden"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
diff --git a/res/values-en-rCA/strings.xml b/res/values-en-rCA/strings.xml
index 2967941..53c0074 100644
--- a/res/values-en-rCA/strings.xml
+++ b/res/values-en-rCA/strings.xml
@@ -188,7 +188,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Keep private apps locked and hidden"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
diff --git a/res/values-en-rGB/strings.xml b/res/values-en-rGB/strings.xml
index d86770a..6a7fbb7 100644
--- a/res/values-en-rGB/strings.xml
+++ b/res/values-en-rGB/strings.xml
@@ -188,7 +188,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Keep private apps locked and hidden"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
diff --git a/res/values-en-rIN/strings.xml b/res/values-en-rIN/strings.xml
index d86770a..6a7fbb7 100644
--- a/res/values-en-rIN/strings.xml
+++ b/res/values-en-rIN/strings.xml
@@ -188,7 +188,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Keep private apps locked and hidden"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
diff --git a/res/values-en-rXC/strings.xml b/res/values-en-rXC/strings.xml
index dab6052..f95149f 100644
--- a/res/values-en-rXC/strings.xml
+++ b/res/values-en-rXC/strings.xml
@@ -188,7 +188,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Failed: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Private space"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Keep private apps locked and hidden"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Tap to set up or open"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space Settings"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lock/Unlock Private Space"</string>
diff --git a/res/values-es-rUS/strings.xml b/res/values-es-rUS/strings.xml
index 21325b9..c377990 100644
--- a/res/values-es-rUS/strings.xml
+++ b/res/values-es-rUS/strings.xml
@@ -29,7 +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="save_app_pair" msgid="5647523853662686243">"Guardar vinculación de apps"</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>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"Abre el dispositivo para usar esta vinculación de apps"</string>
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtro"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espacio privado"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Mantén las apps privadas bloqueadas y ocultas"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Configuración de Espacio privado"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear o desbloquear Espacio privado"</string>
diff --git a/res/values-es/strings.xml b/res/values-es/strings.xml
index 1858290..5c950b1 100644
--- a/res/values-es/strings.xml
+++ b/res/values-es/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtro"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Se ha producido un error: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espacio privado"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Bloquea y oculta tus aplicaciones privadas"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Ajustes del espacio privado"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/Desbloquear espacio privado"</string>
diff --git a/res/values-et/strings.xml b/res/values-et/strings.xml
index 26110ae..610c243 100644
--- a/res/values-et/strings.xml
+++ b/res/values-et/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nurjus: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privaatne ruum"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Hoidke privaatsed rakendused lukustatud ja peidetuna"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privaatne"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Privaatse ruumi seaded"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privaatse ruumi lukustamine/avamine"</string>
diff --git a/res/values-eu/strings.xml b/res/values-eu/strings.xml
index a722a58..1d25061 100644
--- a/res/values-eu/strings.xml
+++ b/res/values-eu/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Iragazi"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Huts egin du: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Eremu pribatua"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Mantendu aplikazio pribatuak blokeatuta eta ezkutatuta"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Pribatua"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Eremu pribatuaren ezarpenak"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blokeatu/Desblokeatu eremu pribatua"</string>
diff --git a/res/values-fa/strings.xml b/res/values-fa/strings.xml
index d69a590..dc48d82 100644
--- a/res/values-fa/strings.xml
+++ b/res/values-fa/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"برنامههای خصوصی قفل و پنهان نگه داشته میشود"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"خصوصی"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"تنظیمات «فضای خصوصی»"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"قفل/ باز کردن «فضای خصوصی»"</string>
diff --git a/res/values-fi/strings.xml b/res/values-fi/strings.xml
index 81790b9..820f7eb 100644
--- a/res/values-fi/strings.xml
+++ b/res/values-fi/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Suodatin"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Epäonnistui: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Yksityinen tila"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Pidä yksityiset sovellukset lukittuna ja piilossa"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Yksityinen"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Yksityisen tilan asetukset"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lukitse yksityinen tila / avaa sen lukitus"</string>
diff --git a/res/values-fr-rCA/strings.xml b/res/values-fr-rCA/strings.xml
index d21fef4..d47e63e 100644
--- a/res/values-fr-rCA/strings.xml
+++ b/res/values-fr-rCA/strings.xml
@@ -29,7 +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="save_app_pair" msgid="5647523853662686243">"Enregistrer la paire d\'applications"</string>
+ <string name="save_app_pair" msgid="5647523853662686243">"Enr. paire d\'applis"</string>
<string name="app_pair_default_title" msgid="4045241727446873529">"<xliff:g id="APP1">%1$s</xliff:g> | <xliff:g id="APP2">%2$s</xliff:g>"</string>
<string name="app_pair_unlaunchable_at_screen_size" msgid="3446551575502685376">"Cette paire d\'applications n\'est pas prise en charge sur cet appareil"</string>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"Déplier l\'appareil pour utiliser cette paire d\'applications"</string>
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrer"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espace privé"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Verrouiller et cacher les applications privées"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Paramètres de l\'Espace privé"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Verrouiller/Déverrouiller l\'Espace privé"</string>
diff --git a/res/values-fr/strings.xml b/res/values-fr/strings.xml
index 4244f23..54ad858 100644
--- a/res/values-fr/strings.xml
+++ b/res/values-fr/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtre"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Échec : <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espace privé"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Gardez les applications privées verrouillées et masquées."</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Paramètres d\'Espace privé"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Verrouiller/Déverrouiller Espace privé"</string>
diff --git a/res/values-gl/strings.xml b/res/values-gl/strings.xml
index 1089ecf..0a7c96c 100644
--- a/res/values-gl/strings.xml
+++ b/res/values-gl/strings.xml
@@ -29,7 +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="save_app_pair" msgid="5647523853662686243">"Gardar emparellamento de aplicacións"</string>
+ <string name="save_app_pair" msgid="5647523853662686243">"Gardar parella de aplicacións"</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>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"Desprega o dispositivo para usar este emparellamento de aplicacións"</string>
@@ -87,7 +87,7 @@
<string name="all_apps_button_work_label" msgid="7270707118948892488">"Lista de aplicacións de traballo"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"Quitar"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"Desinstalar"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"Info. da aplicación"</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="install_drop_target_label" msgid="2539096853673231757">"Instalar"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"Non suxerir aplicación"</string>
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtra"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Erro: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espazo privado"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Manter bloqueadas e ocultas as aplicacións privadas"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Configuración do espazo privado"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear ou desbloquear o espazo privado"</string>
diff --git a/res/values-gu/strings.xml b/res/values-gu/strings.xml
index a30af7e..c3be263 100644
--- a/res/values-gu/strings.xml
+++ b/res/values-gu/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"ખાનગી ઍપને લૉક કરેલી અને છુપાવેલી રાખો"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"ખાનગી"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ખાનગી સ્પેસના સેટિંગ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ખાનગી સ્પેસને લૉક/અનલૉક કરો"</string>
diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml
index f65584b..7b6a9f9 100644
--- a/res/values-hi/strings.xml
+++ b/res/values-hi/strings.xml
@@ -29,7 +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="save_app_pair" msgid="5647523853662686243">"साथ में इस्तेमाल किए जा सकने वाले ऐप्लिकेशन की जानकारी सेव करें"</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>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"साथ में इस्तेमाल किए जा सकने वाले ये ऐप्लिकेशन इस्तेमाल करने के लिए डिवाइस को अनफ़ोल्ड करें"</string>
@@ -188,7 +188,8 @@
<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="611902414159280263">"निजी ऐप्लिकेशन, लॉक करें और छिपाकर रखें"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"निजी"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"प्राइवेट स्पेस सेटिंग"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"प्राइवेट स्पेस को लॉक करें/अनलॉक करें"</string>
diff --git a/res/values-hr/strings.xml b/res/values-hr/strings.xml
index 5ae78a3..89f95f0 100644
--- a/res/values-hr/strings.xml
+++ b/res/values-hr/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrirajte"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nije uspjelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privatni prostor"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Neka privatne aplikacije ostanu zaključane i skrivene"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privatno"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Postavke privatnog prostora"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaključavanje/otključavanje privatnog prostora"</string>
diff --git a/res/values-hu/strings.xml b/res/values-hu/strings.xml
index 0a05ce4..626a79e 100644
--- a/res/values-hu/strings.xml
+++ b/res/values-hu/strings.xml
@@ -188,7 +188,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Szűrő"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Sikertelen: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privát terület"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Privát alkalmazások zárolásának és rejtve tartásának fenntartása"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Koppintson a beállításhoz vagy a megnyitáshoz"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privát"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Privát terület beállításai"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privát terület zárolása/zárolásának feloldása"</string>
diff --git a/res/values-hy/strings.xml b/res/values-hy/strings.xml
index 7bb79e5..bdb473b 100644
--- a/res/values-hy/strings.xml
+++ b/res/values-hy/strings.xml
@@ -29,7 +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="save_app_pair" msgid="5647523853662686243">"Պահել հավելվածների զույգը"</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>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"Բացեք սարքը՝ այս հավելվածների զույգն օգտագործելու համար"</string>
@@ -188,7 +188,8 @@
<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="611902414159280263">"Անձնական հավելվածները պահեք կողպված և թաքցված"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Անձնական"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Անձնական տարածքի կարգավորումներ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Կողպել/ապակողպել անձնական տարածքը"</string>
diff --git a/res/values-in/strings.xml b/res/values-in/strings.xml
index 246367d..b80f233 100644
--- a/res/values-in/strings.xml
+++ b/res/values-in/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Ruang pribadi"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Tetap kunci dan sembunyikan aplikasi pribadi"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Pribadi"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Setelan Ruang Pribadi"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kunci/Buka Kunci Ruang Pribadi"</string>
diff --git a/res/values-is/strings.xml b/res/values-is/strings.xml
index 23899ad..1287322 100644
--- a/res/values-is/strings.xml
+++ b/res/values-is/strings.xml
@@ -188,7 +188,8 @@
<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_secondary_label" msgid="611902414159280263">"Haltu einkaforritum læstum og földum"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Lokað"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Stillingar einkarýmis"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Læsaeinkarými/taka einkarými úr lás"</string>
diff --git a/res/values-it/strings.xml b/res/values-it/strings.xml
index e45f9dd..4805748 100644
--- a/res/values-it/strings.xml
+++ b/res/values-it/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtra"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Operazione non riuscita: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Spazio privato"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Mantieni le app private bloccate e nascoste"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privato"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Impostazioni dello Spazio privato"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blocca/sblocca Spazio privato"</string>
diff --git a/res/values-iw/strings.xml b/res/values-iw/strings.xml
index 41c08e2..2f10ef3 100644
--- a/res/values-iw/strings.xml
+++ b/res/values-iw/strings.xml
@@ -29,7 +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="save_app_pair" msgid="5647523853662686243">"שמירה של צמד אפליקציות"</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>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"צריך לפתוח את המכשיר כדי להשתמש בצמד האפליקציות הזה"</string>
@@ -188,7 +188,8 @@
<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="611902414159280263">"נעילה והסתרה של אפליקציות פרטיות"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"פרטי"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"הגדרות המרחב הפרטי"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"נעילה או ביטול הנעילה של המרחב הפרטי"</string>
diff --git a/res/values-ja/strings.xml b/res/values-ja/strings.xml
index d467f2c..3112a55 100644
--- a/res/values-ja/strings.xml
+++ b/res/values-ja/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"限定公開アプリをロックして非表示"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"プライベート"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"プライベート スペースの設定"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"プライベート スペースをロック / ロック解除する"</string>
diff --git a/res/values-ka/strings.xml b/res/values-ka/strings.xml
index e473052..ea5c207 100644
--- a/res/values-ka/strings.xml
+++ b/res/values-ka/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"პირადი აპების ჩაკეტვა და დამალვა"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"პირადი"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"პირადი სივრცის პარამეტრები"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"პირადი სივრცის ჩაკეტვა/განბლოკვა"</string>
diff --git a/res/values-kk/strings.xml b/res/values-kk/strings.xml
index fce1090..56895cb 100644
--- a/res/values-kk/strings.xml
+++ b/res/values-kk/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"Құпия кеңістіктегі қолданбаларды құлыптаулы және жасырын күйде қалдырыңыз."</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Жеке"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Жеке бөлме параметрлері"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Жеке бөлмені құлыптау/оның құлпын ашу"</string>
diff --git a/res/values-km/strings.xml b/res/values-km/strings.xml
index 817bb35..f955b54 100644
--- a/res/values-km/strings.xml
+++ b/res/values-km/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"រក្សាកម្មវិធីឯកជនឱ្យនៅជាប់សោ និងលាក់"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"ឯកជន"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ការកំណត់ Private Space"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ចាក់សោ/ដោះសោ Private Space"</string>
diff --git a/res/values-kn/strings.xml b/res/values-kn/strings.xml
index f0e61cf..3fd334a 100644
--- a/res/values-kn/strings.xml
+++ b/res/values-kn/strings.xml
@@ -29,7 +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="save_app_pair" msgid="5647523853662686243">"ಆ್ಯಪ್ ಜೋಡಿ ಉಳಿಸಿ"</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>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"ಈ ಆ್ಯಪ್ ಜೋಡಿಯನ್ನು ಬಳಸಲು ಸಾಧನವನ್ನು ಅನ್ಫೋಲ್ಡ್ ಮಾಡಿ"</string>
@@ -188,7 +188,8 @@
<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="611902414159280263">"ಖಾಸಗಿ ಆ್ಯಪ್ಗಳನ್ನು ಲಾಕ್ ಮಾಡಿ ಮತ್ತು ಮರೆಮಾಡಿ"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"ಖಾಸಗಿ"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಸೆಟ್ಟಿಂಗ್ಗಳು"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ಖಾಸಗಿ ಸ್ಪೇಸ್ ಅನ್ನು ಲಾಕ್/ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
diff --git a/res/values-ko/strings.xml b/res/values-ko/strings.xml
index e916cef..4814ede 100644
--- a/res/values-ko/strings.xml
+++ b/res/values-ko/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"비공개 앱을 잠그고 숨겨진 상태로 유지"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"비공개"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"비공개 스페이스 설정"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"비공개 스페이스 잠금/잠금 해제"</string>
diff --git a/res/values-ky/strings.xml b/res/values-ky/strings.xml
index 47eae5b..8d59747 100644
--- a/res/values-ky/strings.xml
+++ b/res/values-ky/strings.xml
@@ -29,7 +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="save_app_pair" msgid="5647523853662686243">"Эки колдонмону бир маалда пайдаланууну сактоо"</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>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"Бул эки колдонмону бир маалда пайдалануу үчүн түзмөктү ачыңыз"</string>
@@ -188,7 +188,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="611902414159280263">"Жеке колдонмолорду кулпулап жана жашырып коюңуз"</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_lock_unlock_button" msgid="7605602332253423755">"Жеке чөйрөнү кулпулоо/кулпусун ачуу"</string>
diff --git a/res/values-lo/strings.xml b/res/values-lo/strings.xml
index 658e8e3..5c0d6a8 100644
--- a/res/values-lo/strings.xml
+++ b/res/values-lo/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"ລັອກ ແລະ ເຊື່ອງແອັບສ່ວນຕົວໄວ້"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"ສ່ວນຕົວ"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ການຕັ້ງຄ່າພື້ນທີ່ສ່ວນຕົວ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ລັອກ/ປົດລັອກພື້ນທີ່ສ່ວນຕົວ"</string>
diff --git a/res/values-lt/strings.xml b/res/values-lt/strings.xml
index 4e8c453..abcbb25 100644
--- a/res/values-lt/strings.xml
+++ b/res/values-lt/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtruoti"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Nepavyko: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privati erdvė"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Privačių programų užrakinimas ir slėpimas"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privatus"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Privačios erdvės nustatymai"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Užrakinti ir (arba) atrakinti privačią erdvę"</string>
diff --git a/res/values-lv/strings.xml b/res/values-lv/strings.xml
index 3e1fcdb..b400b03 100644
--- a/res/values-lv/strings.xml
+++ b/res/values-lv/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrs"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Neizdevās: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privātā telpa"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Paslēpiet privātās lietotnes un bloķējiet piekļuvi tām"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privātā mape"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Privātās mapes iestatījumi"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloķēt/atbloķēt privāto mapi"</string>
diff --git a/res/values-mk/strings.xml b/res/values-mk/strings.xml
index cf9c954..6e09073 100644
--- a/res/values-mk/strings.xml
+++ b/res/values-mk/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"Чувајте ги приватните апликации заклучени и скриени"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Приватен"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Поставки за „Приватен простор“"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заклучување/отклучување на „Приватен простор“"</string>
diff --git a/res/values-ml/strings.xml b/res/values-ml/strings.xml
index 0b66a36..26bd635 100644
--- a/res/values-ml/strings.xml
+++ b/res/values-ml/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"സ്വകാര്യ ആപ്പുകൾ ലോക്ക് ചെയ്ത് മറയ്ക്കുക"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"സ്വകാര്യം"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"സ്വകാര്യ സ്പേസ് ക്രമീകരണം"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"സ്വകാര്യ സ്പേസ് ലോക്ക് ചെയ്യുക/അൺലോക്ക് ചെയ്യുക"</string>
diff --git a/res/values-mn/strings.xml b/res/values-mn/strings.xml
index 0feeb10..5e86120 100644
--- a/res/values-mn/strings.xml
+++ b/res/values-mn/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"Хувийн аппуудыг түгжээтэй бөгөөд нуугдсан байлгана уу"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Хувийн"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Private Space-н тохиргоо"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Private Space-г түгжих/түгжээг тайлах"</string>
diff --git a/res/values-mr/strings.xml b/res/values-mr/strings.xml
index 58f4f0e..9ec42c1 100644
--- a/res/values-mr/strings.xml
+++ b/res/values-mr/strings.xml
@@ -122,7 +122,7 @@
<string name="msg_disabled_by_admin" msgid="6898038085516271325">"आपल्या प्रशासकाने अक्षम केले"</string>
<string name="allow_rotation_title" msgid="7222049633713050106">"होम स्क्रीन फिरवण्याची अनुमती द्या"</string>
<string name="allow_rotation_desc" msgid="8662546029078692509">"फोन फिरवला जातो तेव्हा"</string>
- <string name="notification_dots_title" msgid="9062440428204120317">"सूचना बिंदू"</string>
+ <string name="notification_dots_title" msgid="9062440428204120317">"नोटिफिकेशन डॉट"</string>
<string name="notification_dots_desc_on" msgid="1679848116452218908">"सुरू"</string>
<string name="notification_dots_desc_off" msgid="1760796511504341095">"बंद"</string>
<string name="title_missing_notification_access" msgid="7503287056163941064">"सूचनांच्या अॅक्सेसची आवश्यकता आहे"</string>
@@ -150,8 +150,8 @@
<string name="action_add_to_workspace" msgid="215894119683164916">"होम स्क्रीनवर जोडा"</string>
<string name="action_move_here" msgid="2170188780612570250">"आयटम येथे हलवा"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"आयटम मुख्य स्क्रीनवर जोडला"</string>
- <string name="item_removed" msgid="851119963877842327">"आयटम काढला"</string>
- <string name="undo" msgid="4151576204245173321">"पूर्ववत करा"</string>
+ <string name="item_removed" msgid="851119963877842327">"आयटम काढून टाकला"</string>
+ <string name="undo" msgid="4151576204245173321">"पहिल्यासारखे करा"</string>
<string name="action_move" msgid="4339390619886385032">"आयटम हलवा"</string>
<string name="move_to_empty_cell_description" msgid="5254852678218206889">"<xliff:g id="STRING">%3$s</xliff:g> मधील <xliff:g id="NUMBER_0">%1$s</xliff:g> पंक्ती <xliff:g id="NUMBER_1">%2$s</xliff:g> स्तंभ यावर हलवा"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> स्थानावर हलवा"</string>
@@ -188,7 +188,8 @@
<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="611902414159280263">"खाजगी अॅप्स लॉक करून आणि लपवून ठेवा"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"खाजगी"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"खाजगी स्पेस ची सेटिंग्ज"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"खाजगी स्पेस लॉक/अनलॉक करा"</string>
diff --git a/res/values-ms/strings.xml b/res/values-ms/strings.xml
index 7832705..63f500a 100644
--- a/res/values-ms/strings.xml
+++ b/res/values-ms/strings.xml
@@ -187,8 +187,9 @@
<string name="work_apps_enable_btn_text" msgid="1736198302467317371">"Nyahjeda"</string>
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Tapis"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Gagal: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
- <string name="private_space_label" msgid="2359721649407947001">"Ruang peribadi"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Pastikan apl peribadi kekal dikunci dan disembunyikan"</string>
+ <string name="private_space_label" msgid="2359721649407947001">"Ruang privasi"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Peribadi"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Tetapan Ruang Peribadi"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kunci/Buka kunci Ruang Peribadi"</string>
diff --git a/res/values-my/strings.xml b/res/values-my/strings.xml
index 80fef4b..93b61f8 100644
--- a/res/values-my/strings.xml
+++ b/res/values-my/strings.xml
@@ -39,7 +39,7 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"အလျား %1$d နှင့် အမြင့် %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်"</string>
<string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်၊ အကျယ် %2$d နှင့် အမြင့် %3$d"</string>
- <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ပင်မစာမျက်နှာတွင်ရွှေ့ရန် ဝိဂျက်ကို တို့ထိ၍ ဖိထားပါ"</string>
+ <string name="add_item_request_drag_hint" msgid="8730547755622776606">"ဝိဂျက်ကို တို့ထိ၍ ဖိထားပြီး ပင်မစာမျက်နှာပေါ်တွင် နေရာအမျိုးမျိုးသို့ ရွှေ့နိုင်သည်"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"ပင်မစာမျက်နှာတွင် ထည့်ရန်"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"<xliff:g id="WIDGET_NAME">%1$s</xliff:g> ဝိဂျက်ကို ပင်မစာမျက်နှာတွင် ထည့်လိုက်ပြီ"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"အကြံပြုချက်"</string>
@@ -188,7 +188,8 @@
<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="611902414159280263">"သီးသန့်အက်ပ်များကို လော့ခ်ချပြီး ဖျောက်ထားပါ"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"သီးသန့်"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"သီးသန့်ချတ်ခန်း ဆက်တင်များ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"သီးသန့်ချတ်ခန်း လော့ခ်ချ/ဖွင့်ရန်"</string>
diff --git a/res/values-nb/strings.xml b/res/values-nb/strings.xml
index f0c947b..4a352f5 100644
--- a/res/values-nb/strings.xml
+++ b/res/values-nb/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mislyktes: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privat område"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Hold private apper låst og skjult"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Innstillinger for Private Space"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås / lås opp Private Space"</string>
diff --git a/res/values-ne/strings.xml b/res/values-ne/strings.xml
index e18dce4..0f5e1a5 100644
--- a/res/values-ne/strings.xml
+++ b/res/values-ne/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"निजी एपहरू लक गरिराख्नुहोस् र लुकाइराख्नुहोस्"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"निजी"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"निजी स्पेससम्बन्धी सेटिङ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"निजी स्पेस लक/अनलक गर्नुहोस्"</string>
diff --git a/res/values-nl/strings.xml b/res/values-nl/strings.xml
index c16fb3c..ace1d8e 100644
--- a/res/values-nl/strings.xml
+++ b/res/values-nl/strings.xml
@@ -39,7 +39,7 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"%1$d breed en %2$d hoog"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>"</string>
<string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g>, %2$d breed bij %3$d hoog"</string>
- <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Tik op de widget en houd vast om deze te verplaatsen op het startscherm"</string>
+ <string name="add_item_request_drag_hint" msgid="8730547755622776606">"Houd je vinger op de widget om deze te verplaatsen op het startscherm"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"Toevoegen aan startscherm"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> toegevoegd aan startscherm"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggesties"</string>
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filteren"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Mislukt: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privéruimte"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Privé-apps vergrendeld en verborgen houden"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privé"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Instellingen voor privéruimte"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Privéruimte vergrendelen/ontgrendelen"</string>
diff --git a/res/values-or/strings.xml b/res/values-or/strings.xml
index 21b5f03..2c03967 100644
--- a/res/values-or/strings.xml
+++ b/res/values-or/strings.xml
@@ -87,7 +87,7 @@
<string name="all_apps_button_work_label" msgid="7270707118948892488">"କାର୍ଯ୍ୟକାରୀ ଆପ୍ ତାଲିକା"</string>
<string name="remove_drop_target_label" msgid="7812859488053230776">"କାଢ଼ି ଦିଅନ୍ତୁ"</string>
<string name="uninstall_drop_target_label" msgid="4722034217958379417">"ଅନଇନଷ୍ଟଲ କରନ୍ତୁ"</string>
- <string name="app_info_drop_target_label" msgid="692894985365717661">"ଆପ୍ ସୂଚନା"</string>
+ <string name="app_info_drop_target_label" msgid="692894985365717661">"ଆପ ସୂଚନା"</string>
<string name="install_private_system_shortcut_label" msgid="1616889277073184841">"ପ୍ରାଇଭେଟରେ ଇନଷ୍ଟଲ କର"</string>
<string name="install_drop_target_label" msgid="2539096853673231757">"ଇନଷ୍ଟଲ୍ କରନ୍ତୁ"</string>
<string name="dismiss_prediction_label" msgid="3357562989568808658">"ଆପ ପରାମର୍ଶ ଦିଅନ୍ତୁ ନାହିଁ"</string>
@@ -151,7 +151,7 @@
<string name="action_move_here" msgid="2170188780612570250">"ଆଇଟମ୍କୁ ଏଠାକୁ ଘୁଞ୍ଚାନ୍ତୁ"</string>
<string name="item_added_to_workspace" msgid="4211073925752213539">"ହୋମ ସ୍କ୍ରିନରେ ଆଇଟମ ଯୋଗ କରାଗଲା"</string>
<string name="item_removed" msgid="851119963877842327">"ଆଇଟମକୁ କାଢ଼ି ଦିଆଯାଇଛି"</string>
- <string name="undo" msgid="4151576204245173321">"ପୂର୍ବବତ୍"</string>
+ <string name="undo" msgid="4151576204245173321">"ପୂର୍ବବତ କରନ୍ତୁ"</string>
<string name="action_move" msgid="4339390619886385032">"ଆଇଟମ୍ ଘୁଞ୍ଚାନ୍ତୁ"</string>
<string name="move_to_empty_cell_description" msgid="5254852678218206889">"<xliff:g id="STRING">%3$s</xliff:g>ରେ ଧାଡି <xliff:g id="NUMBER_0">%1$s</xliff:g> ସ୍ତମ୍ଭ <xliff:g id="NUMBER_1">%2$s</xliff:g>କୁ ମୁଭ କରନ୍ତୁ"</string>
<string name="move_to_position" msgid="6750008980455459790">"<xliff:g id="NUMBER">%1$s</xliff:g> ସ୍ଥିତିକୁ ନିଅନ୍ତୁ"</string>
@@ -188,7 +188,8 @@
<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="611902414159280263">"ପ୍ରାଇଭେଟ ଆପ୍ସକୁ ଲକ ଏବଂ ଲୁକ୍କାୟିତ ରଖନ୍ତୁ"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"ପ୍ରାଇଭେଟ"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ପ୍ରାଇଭେଟ ସ୍ପେସ ସେଟିଂସ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ପ୍ରାଇଭେଟ ସ୍ପେସକୁ ଲକ/ଅନଲକ କରନ୍ତୁ"</string>
diff --git a/res/values-pa/strings.xml b/res/values-pa/strings.xml
index 9ae784f..321d6c0 100644
--- a/res/values-pa/strings.xml
+++ b/res/values-pa/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"ਨਿੱਜੀ ਐਪਾਂ ਨੂੰ ਲਾਕ ਕਰ ਕੇ ਅਦਿੱਖ ਰੱਖੋ"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"ਨਿੱਜੀ"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ਨਿੱਜੀ ਸਪੇਸ ਸੰਬੰਧੀ ਸੈਟਿੰਗਾਂ"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ਨਿੱਜੀ ਸਪੇਸ ਨੂੰ ਲਾਕ/ਅਣਲਾਕ ਕਰੋ"</string>
diff --git a/res/values-pl/strings.xml b/res/values-pl/strings.xml
index a765377..7cc4f1f 100644
--- a/res/values-pl/strings.xml
+++ b/res/values-pl/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtruj"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Niepowodzenie: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Obszar prywatny"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Pozostaw aplikacje prywatne zablokowane i ukryte"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Prywatne"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Ustawienia obszaru prywatnego"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zablokuj/odblokuj obszar prywatny"</string>
diff --git a/res/values-pt-rPT/strings.xml b/res/values-pt-rPT/strings.xml
index 946ed1b..25a6562 100644
--- a/res/values-pt-rPT/strings.xml
+++ b/res/values-pt-rPT/strings.xml
@@ -188,7 +188,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrar"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Falhou: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Espaço privado"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Mantenha as apps privadas bloqueadas e ocultas"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Tocar para configurar ou abrir"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Privado"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Definições do espaço privado"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/desbloquear espaço privado"</string>
diff --git a/res/values-pt/strings.xml b/res/values-pt/strings.xml
index 04688d1..07fe3db 100644
--- a/res/values-pt/strings.xml
+++ b/res/values-pt/strings.xml
@@ -188,7 +188,8 @@
<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_secondary_label" msgid="611902414159280263">"Mantenha apps particulares bloqueados e ocultos"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Particular"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Configurações do Espaço particular"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Bloquear/desbloquear o Espaço particular"</string>
diff --git a/res/values-ro/strings.xml b/res/values-ro/strings.xml
index 4605871..30b2ea6 100644
--- a/res/values-ro/strings.xml
+++ b/res/values-ro/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtru"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Eșuare: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Spațiu privat"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Păstrează aplicațiile private blocate și ascunse"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Setări spațiu privat"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Blochează / deblochează spațiul privat"</string>
diff --git a/res/values-ru/strings.xml b/res/values-ru/strings.xml
index 9a40b84..a96e2e1 100644
--- a/res/values-ru/strings.xml
+++ b/res/values-ru/strings.xml
@@ -29,7 +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="save_app_pair" msgid="5647523853662686243">"Сохранить настройки одновременного использования двух приложений"</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>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"Чтобы одновременно использовать эти два приложения, разложите устройство."</string>
@@ -188,7 +188,8 @@
<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="611902414159280263">"Приложения в личном пространстве скрыты и доступны только вам"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Доступно только вам"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Настройки личного пространства"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Блокировка и разблокировка личного пространства"</string>
diff --git a/res/values-si/strings.xml b/res/values-si/strings.xml
index 8780527..53aee23 100644
--- a/res/values-si/strings.xml
+++ b/res/values-si/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"පෞද්ගලික යෙදුම් අගුලු දමා සඟවා තබා ගන්න"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"පෞද්ගලික"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"පෞද්ගලික අවකාශ සැකසීම්"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"පෞද්ගලික අවකාශය අගුළු දමන්න/අගුළු හරින්න"</string>
diff --git a/res/values-sk/strings.xml b/res/values-sk/strings.xml
index e513497..e058442 100644
--- a/res/values-sk/strings.xml
+++ b/res/values-sk/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtrujte"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Zlyhalo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Súkromný priestor"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Ponechajte súkromné aplikácie uzamknuté a skryté"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Súkromné"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Nastavenia súkromného priestoru"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Súkromný priestor zamykania a odomykania"</string>
diff --git a/res/values-sl/strings.xml b/res/values-sl/strings.xml
index 70a4c08..8b67004 100644
--- a/res/values-sl/strings.xml
+++ b/res/values-sl/strings.xml
@@ -188,7 +188,7 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtriranje"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Ni uspelo: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Zasebni prostor"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Naj vaše zasebne aplikacije ostanejo zaklenjene in skrite"</string>
+ <string name="private_space_secondary_label" msgid="9203933341714508907">"Dotaknite se, da nastavite ali odprete"</string>
<string name="ps_container_title" msgid="4391796149519594205">"Zasebno"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Nastavitve zasebnega prostora"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Zaklepanje/odklepanje zasebnega prostora"</string>
diff --git a/res/values-sq/strings.xml b/res/values-sq/strings.xml
index 51fcf13..062a5e1 100644
--- a/res/values-sq/strings.xml
+++ b/res/values-sq/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtro"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Dështoi: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Hapësira private"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Mbaji të kyçura dhe të fshehura aplikacionet private"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Private"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Cilësimet e \"Hapësirës private\""</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Kyç/Shkyç \"Hapësirën private\""</string>
diff --git a/res/values-sr/strings.xml b/res/values-sr/strings.xml
index 7a32a54..6b3a1ea 100644
--- a/res/values-sr/strings.xml
+++ b/res/values-sr/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"Нека приватне апликације буду закључане и сакривене"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Приватно"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Подешавања приватног простора"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Закључај/откључај приватни простор"</string>
diff --git a/res/values-sv/strings.xml b/res/values-sv/strings.xml
index df2539f..94a9ff0 100644
--- a/res/values-sv/strings.xml
+++ b/res/values-sv/strings.xml
@@ -29,7 +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="save_app_pair" msgid="5647523853662686243">"Spara appar som ska användas tillsammans"</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>
<string name="app_pair_needs_unfold" msgid="4588897528143807002">"Vik upp enheten för att använda de här apparna som ska användas tillsammans"</string>
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Misslyckades: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Privat rum"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Håll privata appar låsta och dolda"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Privat"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Inställningar för privat rum"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Lås eller lås upp ditt privata rum"</string>
diff --git a/res/values-sw/strings.xml b/res/values-sw/strings.xml
index 4d3b22f..069894b 100644
--- a/res/values-sw/strings.xml
+++ b/res/values-sw/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Kichujio"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Hitilafu: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Nafasi ya faragha"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Funga na ufiche programu za faragha"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Faragha"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Mipangilio ya Nafasi ya Faragha"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Funga/Fungua Nafasi ya Faragha"</string>
diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml
index 9e82389..043b654 100644
--- a/res/values-ta/strings.xml
+++ b/res/values-ta/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"தனிப்பட்ட ஆப்ஸை லாக் செய்தும் மறைத்தும் வைக்கலாம்"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"தனிப்பட்டது"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"தனிப்பட்ட சேமிப்பிட அமைப்புகள்"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"தனிப்பட்ட சேமிப்பிடத்தை லாக்/அன்லாக் செய்யும்"</string>
diff --git a/res/values-te/strings.xml b/res/values-te/strings.xml
index 9ad29c6..ef1cc44 100644
--- a/res/values-te/strings.xml
+++ b/res/values-te/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"ప్రైవేట్ యాప్లను లాక్ చేసి దాచి ఉంచండి"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"ప్రైవేట్"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"ప్రైవేట్ స్పేస్ సెట్టింగ్లు"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ప్రైవేట్ స్పేస్ను లాక్/అన్లాక్ చేయండి"</string>
diff --git a/res/values-th/strings.xml b/res/values-th/strings.xml
index dc92980..37e2c21 100644
--- a/res/values-th/strings.xml
+++ b/res/values-th/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"ล็อกและซ่อนแอปส่วนตัวไว้"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"ส่วนตัว"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"การตั้งค่าพื้นที่ส่วนตัว"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"ล็อก/ปลดล็อกพื้นที่ส่วนตัว"</string>
diff --git a/res/values-tl/strings.xml b/res/values-tl/strings.xml
index 36a7b5c..33dbecf 100644
--- a/res/values-tl/strings.xml
+++ b/res/values-tl/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filter"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Hindi nagawa: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Pribadong space"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Panatilihing naka-lock at nakatago ang mga pribadong app"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Pribado"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Mga Setting ng Pribadong Space"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"I-lock/I-unlock ang Pribadong Space"</string>
diff --git a/res/values-tr/strings.xml b/res/values-tr/strings.xml
index 8c00ec3..f299b2c 100644
--- a/res/values-tr/strings.xml
+++ b/res/values-tr/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Filtre"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Başarısız: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Gizli alan"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Özel uygulamaları kilitli ve gizli tutun"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Gizli"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Gizli Alan Ayarları"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Gizli Alanı Kilitleyin/Kilidini Açın"</string>
diff --git a/res/values-uk/strings.xml b/res/values-uk/strings.xml
index a8211f5..c1703f3 100644
--- a/res/values-uk/strings.xml
+++ b/res/values-uk/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"Зберігайте приватні додатки в прихованому й заблокованому сховищі"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Приватні"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Налаштування приватного простору"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Заблокувати/розблокувати приватний простір"</string>
diff --git a/res/values-ur/strings.xml b/res/values-ur/strings.xml
index 430c835..3169e03 100644
--- a/res/values-ur/strings.xml
+++ b/res/values-ur/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"نجی ایپس کو مقفل اور پوشیدہ رکھیں"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"نجی"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"نجی اسپیس کی ترتیبات"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"نجی اسپیس کو مقفل کریں/غیر مقفل کریں"</string>
diff --git a/res/values-uz/strings.xml b/res/values-uz/strings.xml
index 8e03a13..b80f4cd 100644
--- a/res/values-uz/strings.xml
+++ b/res/values-uz/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Saralash"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Xato: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Shaxsiy xona"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Maxfiy ilovalar qulflangan va yashirin saqlansin"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Yopiq"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Shaxsiy xona sozlamalari"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Shaxsiy xonani ochish/qulflash"</string>
diff --git a/res/values-vi/strings.xml b/res/values-vi/strings.xml
index 17817ac..a3e26d0 100644
--- a/res/values-vi/strings.xml
+++ b/res/values-vi/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Bộ lọc"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Không thực hiện được thao tác: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Không gian riêng tư"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Luôn khoá và ẩn các ứng dụng riêng tư"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Riêng tư"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Cài đặt không gian riêng tư"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Khoá/mở khoá không gian riêng tư"</string>
diff --git a/res/values-zh-rCN/strings.xml b/res/values-zh-rCN/strings.xml
index 4e77075..c8e524d 100644
--- a/res/values-zh-rCN/strings.xml
+++ b/res/values-zh-rCN/strings.xml
@@ -39,7 +39,7 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"宽 %1$d,高 %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件"</string>
<string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件,宽 %2$d,高 %3$d"</string>
- <string name="add_item_request_drag_hint" msgid="8730547755622776606">"轻触并按住此微件即可在主屏幕上随意移动它"</string>
+ <string name="add_item_request_drag_hint" msgid="8730547755622776606">"轻触并按住此微件即可在主屏幕上随意移动"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"添加到主屏幕"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已将“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件添加到主屏幕"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"建议"</string>
@@ -188,7 +188,8 @@
<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="611902414159280263">"让专用应用保持锁定状态并隐藏"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"私密"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"私密空间设置"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"锁定/解锁私密空间"</string>
diff --git a/res/values-zh-rHK/strings.xml b/res/values-zh-rHK/strings.xml
index 735ff2f..46669eb 100644
--- a/res/values-zh-rHK/strings.xml
+++ b/res/values-zh-rHK/strings.xml
@@ -188,7 +188,8 @@
<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="611902414159280263">"讓私人應用程式保持鎖定及隱藏"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"私人"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"「私人空間」設定"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"鎖定/解鎖「私人空間」"</string>
diff --git a/res/values-zh-rTW/strings.xml b/res/values-zh-rTW/strings.xml
index b74bde2..8fddcc4 100644
--- a/res/values-zh-rTW/strings.xml
+++ b/res/values-zh-rTW/strings.xml
@@ -39,7 +39,7 @@
<string name="widget_accessible_dims_format" msgid="3640149169885301790">"寬度為 %1$d,高度為 %2$d"</string>
<string name="widget_preview_context_description" msgid="9045841361655787574">"「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具"</string>
<string name="widget_preview_name_and_dims_content_description" msgid="8489038126122831595">"「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具 (寬 %2$d,高 %3$d)"</string>
- <string name="add_item_request_drag_hint" msgid="8730547755622776606">"按住小工具即可將它移到主畫面上的任何位置"</string>
+ <string name="add_item_request_drag_hint" msgid="8730547755622776606">"按住小工具即可拖曳到主畫面的任何位置"</string>
<string name="add_to_home_screen" msgid="9168649446635919791">"新增至主畫面"</string>
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已將「<xliff:g id="WIDGET_NAME">%1$s</xliff:g>」小工具新增到主畫面"</string>
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"建議"</string>
@@ -188,7 +188,8 @@
<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="611902414159280263">"讓私人應用程式保持鎖定及隱藏的狀態"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"私人"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"私人空間設定"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"鎖定/取消鎖定私人空間"</string>
diff --git a/res/values-zu/strings.xml b/res/values-zu/strings.xml
index 3fdb6a7..308e6e0 100644
--- a/res/values-zu/strings.xml
+++ b/res/values-zu/strings.xml
@@ -188,7 +188,8 @@
<string name="developer_options_filter_hint" msgid="5896817443635989056">"Hlunga"</string>
<string name="remote_action_failed" msgid="1383965239183576790">"Yehlulekile: <xliff:g id="WHAT">%1$s</xliff:g>"</string>
<string name="private_space_label" msgid="2359721649407947001">"Isikhala esiyimfihlo"</string>
- <string name="private_space_secondary_label" msgid="611902414159280263">"Gcina ama-app angasese ekhiyiwe futhi efihliwe"</string>
+ <!-- no translation found for private_space_secondary_label (9203933341714508907) -->
+ <skip />
<string name="ps_container_title" msgid="4391796149519594205">"Okuyimfihlo"</string>
<string name="ps_container_settings" msgid="6059734123353320479">"Amasethingi Esikhala Esiyimfihlo"</string>
<string name="ps_container_lock_unlock_button" msgid="7605602332253423755">"Khiya/Vula Isikhala Esiyimfihlo"</string>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index 9b4460a..8c58931 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -492,7 +492,7 @@
<dimen name="ps_header_image_height">48dp</dimen>
<dimen name="ps_header_text_height">24dp</dimen>
<dimen name="ps_header_layout_margin">16dp</dimen>
- <dimen name="ps_header_settings_icon_margin_end">8dp</dimen>
+ <dimen name="ps_header_settings_icon_margin_end">4dp</dimen>
<dimen name="ps_header_text_size">16sp</dimen>
<dimen name="ps_button_height">40dp</dimen>
<dimen name="ps_button_width">40dp</dimen>
diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java
index 1285aca..4c8ed15 100644
--- a/src/com/android/launcher3/BubbleTextView.java
+++ b/src/com/android/launcher3/BubbleTextView.java
@@ -237,7 +237,7 @@
defaultIconSize = getResources().getDimensionPixelSize(
R.dimen.search_row_small_icon_size);
} else if (mDisplay == DISPLAY_TASKBAR) {
- defaultIconSize = mDeviceProfile.iconSizePx;
+ defaultIconSize = mDeviceProfile.taskbarIconSize;
} else {
// widget_selection or shortcut_popup
defaultIconSize = mDeviceProfile.iconSizePx;
@@ -435,8 +435,7 @@
}
@UiThread
- @VisibleForTesting
- public void applyLabel(ItemInfoWithIcon info) {
+ public void applyLabel(ItemInfo info) {
CharSequence label = info.title;
if (label != null) {
mLastOriginalText = label;
diff --git a/src/com/android/launcher3/DeleteDropTarget.java b/src/com/android/launcher3/DeleteDropTarget.java
index 9a5627a..58789fd 100644
--- a/src/com/android/launcher3/DeleteDropTarget.java
+++ b/src/com/android/launcher3/DeleteDropTarget.java
@@ -27,7 +27,7 @@
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.logging.StatsLogManager;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -75,7 +75,7 @@
}
return (info instanceof LauncherAppWidgetInfo)
- || (info instanceof FolderInfo);
+ || (info instanceof CollectionInfo);
}
@Override
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 269603c..cfa8967 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -202,6 +202,8 @@
import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -661,6 +663,11 @@
// #5 state handler
return new OnBackAnimationCallback() {
@Override
+ public void onBackStarted(BackEvent backEvent) {
+ Launcher.this.onBackStarted();
+ }
+
+ @Override
public void onBackInvoked() {
onStateBack();
}
@@ -798,13 +805,19 @@
@Override
public void invalidateParent(ItemInfo info) {
if (info.container >= 0) {
- View folderIcon = getWorkspace().getHomescreenIconByItemId(info.container);
- if (folderIcon instanceof FolderIcon && folderIcon.getTag() instanceof FolderInfo) {
+ View collectionIcon = getWorkspace().getHomescreenIconByItemId(info.container);
+ if (collectionIcon instanceof FolderIcon folderIcon
+ && collectionIcon.getTag() instanceof FolderInfo) {
if (new FolderGridOrganizer(getDeviceProfile())
.setFolderInfo((FolderInfo) folderIcon.getTag())
.isItemInPreview(info.rank)) {
folderIcon.invalidate();
}
+ } else if (collectionIcon instanceof AppPairIcon appPairIcon
+ && collectionIcon.getTag() instanceof AppPairInfo appPairInfo) {
+ if (appPairInfo.getContents().contains(info)) {
+ appPairIcon.getIconDrawableArea().redraw();
+ }
}
}
}
@@ -2003,24 +2016,26 @@
public boolean removeItem(View v, final ItemInfo itemInfo, boolean deleteFromDb,
@Nullable final String reason) {
if (itemInfo instanceof WorkspaceItemInfo) {
- // Remove the shortcut from the folder before removing it from launcher
- View folderIcon = mWorkspace.getHomescreenIconByItemId(itemInfo.container);
- if (folderIcon instanceof FolderIcon) {
- ((FolderInfo) folderIcon.getTag()).remove((WorkspaceItemInfo) itemInfo, true);
+ View collectionIcon = mWorkspace.getHomescreenIconByItemId(itemInfo.container);
+ if (collectionIcon instanceof FolderIcon) {
+ // Remove the shortcut from the folder before removing it from launcher
+ ((FolderInfo) collectionIcon.getTag()).remove((WorkspaceItemInfo) itemInfo, true);
+ } else if (collectionIcon instanceof AppPairIcon appPairIcon) {
+ removeItem(appPairIcon, appPairIcon.getInfo(), deleteFromDb,
+ "removing app pair because one of its member apps was removed");
} else {
mWorkspace.removeWorkspaceItem(v);
}
if (deleteFromDb) {
getModelWriter().deleteItemFromDatabase(itemInfo, reason);
}
- } else if (itemInfo instanceof FolderInfo) {
- final FolderInfo folderInfo = (FolderInfo) itemInfo;
+ } else if (itemInfo instanceof CollectionInfo ci) {
if (v instanceof FolderIcon) {
((FolderIcon) v).removeListeners();
}
mWorkspace.removeWorkspaceItem(v);
if (deleteFromDb) {
- getModelWriter().deleteFolderAndContentsFromDatabase(folderInfo);
+ getModelWriter().deleteCollectionAndContentsFromDatabase(ci);
}
} else if (itemInfo instanceof LauncherAppWidgetInfo) {
final LauncherAppWidgetInfo widgetInfo = (LauncherAppWidgetInfo) itemInfo;
@@ -2063,8 +2078,12 @@
getOnBackAnimationCallback().onBackInvoked();
}
+ protected void onBackStarted() {
+ mStateManager.getState().onBackStarted(this);
+ }
+
protected void onStateBack() {
- mStateManager.getState().onBackPressed(this);
+ mStateManager.getState().onBackInvoked(this);
}
protected void onScreenOnChanged(boolean isOn) {
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index 6e66c14..3bdd863 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -424,20 +424,29 @@
return TestProtocol.stateOrdinalToString(ordinal);
}
- public void onBackPressed(Launcher launcher) {
+ /** Called when predictive back gesture is started. */
+ public void onBackStarted(Launcher launcher) {}
+
+ /**
+ * Called when back action is invoked. This can happen when:
+ * 1. back button is pressed in 3-button navigation.
+ * 2. when back is committed during back swiped (predictive or non-predictive).
+ * 3. when we programmatically perform back action.
+ */
+ public void onBackInvoked(Launcher launcher) {
if (this != NORMAL) {
StateManager<LauncherState> lsm = launcher.getStateManager();
LauncherState lastState = lsm.getLastState();
- lsm.goToState(lastState, forEndCallback(this::onBackPressCompleted));
+ lsm.goToState(lastState, forEndCallback(this::onBackAnimationCompleted));
}
}
/**
- * To be called if back press is completed in a launcher state.
+ * To be called if back animation is completed in a launcher state.
*
- * @param success whether back press animation was successful or canceled.
+ * @param success whether back animation was successful or canceled.
*/
- protected void onBackPressCompleted(boolean success) {
+ protected void onBackAnimationCompleted(boolean success) {
// Do nothing. To be overridden by child class.
}
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index ca34dd1..ce3c55a 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -95,6 +95,7 @@
import com.android.launcher3.logging.InstanceId;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
+import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -3313,7 +3314,7 @@
}
} else if (child instanceof FolderIcon) {
FolderInfo folderInfo = (FolderInfo) info;
- List<WorkspaceItemInfo> matches = folderInfo.contents.stream()
+ List<WorkspaceItemInfo> matches = folderInfo.getContents().stream()
.filter(matcher)
.collect(Collectors.toList());
if (!matches.isEmpty()) {
@@ -3322,6 +3323,11 @@
((FolderIcon) child).getFolder().close(false /* animate */);
}
}
+ } else if (info instanceof AppPairInfo api) {
+ // If an app pair's member apps are being removed, delete the whole app pair.
+ if (api.anyMatch(matcher)) {
+ mLauncher.removeItem(child, info, true);
+ }
}
}
}
@@ -3373,9 +3379,9 @@
}
} else if (info instanceof FolderInfo && v instanceof FolderIcon) {
FolderInfo fi = (FolderInfo) info;
- if (fi.contents.stream().anyMatch(matcher)) {
+ if (fi.anyMatch(matcher)) {
FolderDotInfo folderDotInfo = new FolderDotInfo();
- for (WorkspaceItemInfo si : fi.contents) {
+ for (WorkspaceItemInfo si : fi.getContents()) {
folderDotInfo.addDotInfo(mLauncher.getDotInfoForItem(si));
}
((FolderIcon) v).setDotInfo(folderDotInfo);
diff --git a/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
index 19d0421..29862ae 100644
--- a/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/BaseAccessibilityDelegate.java
@@ -28,7 +28,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragOptions;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -45,6 +45,7 @@
public enum DragType {
ICON,
FOLDER,
+ APP_PAIR,
WIDGET
}
@@ -103,7 +104,7 @@
&& item.container != LauncherSettings.Favorites.CONTAINER_HOTSEAT_PREDICTION;
}
return (item instanceof LauncherAppWidgetInfo)
- || (item instanceof FolderInfo);
+ || (item instanceof CollectionInfo);
}
@Override
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 66b8216..bb25b6d 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -39,6 +39,8 @@
import com.android.launcher3.folder.Folder;
import com.android.launcher3.keyboard.KeyboardDragAndDropView;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -317,6 +319,8 @@
mDragInfo.dragType = DragType.ICON;
if (info instanceof FolderInfo) {
mDragInfo.dragType = DragType.FOLDER;
+ } else if (info instanceof AppPairInfo) {
+ mDragInfo.dragType = DragType.APP_PAIR;
} else if (info instanceof LauncherAppWidgetInfo) {
mDragInfo.dragType = DragType.WIDGET;
}
@@ -430,16 +434,16 @@
LauncherSettings.Favorites.CONTAINER_DESKTOP,
screenId, coordinates[0], coordinates[1]);
bindItem(info, accessibility, finishCallback);
- } else if (item instanceof FolderInfo fi) {
+ } else if (item instanceof CollectionInfo ci) {
Workspace<?> workspace = mContext.getWorkspace();
workspace.snapToPage(workspace.getPageIndexForScreenId(screenId));
- mContext.getModelWriter().addItemToDatabase(fi,
+ mContext.getModelWriter().addItemToDatabase(ci,
LauncherSettings.Favorites.CONTAINER_DESKTOP, screenId, coordinates[0],
coordinates[1]);
- fi.contents.forEach(member -> {
- mContext.getModelWriter().addItemToDatabase(member, fi.id, -1, -1, -1);
- });
- bindItem(fi, accessibility, finishCallback);
+ ci.getContents().forEach(member ->
+ mContext.getModelWriter()
+ .addItemToDatabase(member, ci.id, -1, -1, -1));
+ bindItem(ci, accessibility, finishCallback);
}
}));
return true;
diff --git a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
index a8624dd..52073cc 100644
--- a/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
+++ b/src/com/android/launcher3/accessibility/WorkspaceAccessibilityHelper.java
@@ -149,7 +149,7 @@
// Find the first item in the folder.
FolderInfo folder = (FolderInfo) info;
WorkspaceItemInfo firstItem = null;
- for (WorkspaceItemInfo shortcut : folder.contents) {
+ for (WorkspaceItemInfo shortcut : folder.getContents()) {
if (firstItem == null || firstItem.rank > shortcut.rank) {
firstItem = shortcut;
}
diff --git a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
index fbeab4e..4b65b73 100644
--- a/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/ActivityAllAppsContainerView.java
@@ -70,7 +70,6 @@
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget.DragObject;
-import com.android.launcher3.Flags;
import com.android.launcher3.Insettable;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.R;
@@ -127,7 +126,6 @@
public static final float PULL_MULTIPLIER = .02f;
public static final float FLING_VELOCITY_MULTIPLIER = 1200f;
protected static final String BUNDLE_KEY_CURRENT_PAGE = "launcher.allapps.current_page";
- private static final int SCROLL_TO_BOTTOM_DURATION = 500;
private static final long DEFAULT_SEARCH_TRANSITION_DURATION_MS = 300;
// Render the header protection at all times to debug clipping issues.
private static final boolean DEBUG_HEADER_PROTECTION = false;
@@ -192,8 +190,6 @@
private float mTotalHeaderProtectionHeight;
@Nullable private AllAppsTransitionController mAllAppsTransitionController;
- private PrivateSpaceHeaderViewController mPrivateSpaceHeaderViewController;
-
public ActivityAllAppsContainerView(Context context) {
this(context, null);
}
@@ -261,10 +257,6 @@
*/
protected void initContent() {
mMainAdapterProvider = mSearchUiDelegate.createMainAdapterProvider();
- if (Flags.enablePrivateSpace()) {
- mPrivateSpaceHeaderViewController =
- new PrivateSpaceHeaderViewController(this, mPrivateProfileManager);
- }
mAH.set(AdapterHolder.MAIN, new AdapterHolder(AdapterHolder.MAIN,
new AlphabeticalAppsList<>(mActivityContext,
@@ -398,7 +390,7 @@
mAllAppsTransitionController = allAppsTransitionController;
}
- private void animateToSearchState(boolean goingToSearch, long durationMs) {
+ void animateToSearchState(boolean goingToSearch, long durationMs) {
if (!mSearchTransitionController.isRunning() && goingToSearch == isSearching()) {
return;
}
@@ -499,9 +491,9 @@
}
/**
- * Exits search and returns to A-Z apps list. Scroll to the bottom.
+ * Exits search and returns to A-Z apps list. Scroll to the private space header.
*/
- public void resetAndScrollToBottom() {
+ public void resetAndScrollToPrivateSpaceHeader() {
if (mTouchHandler != null) {
mTouchHandler.endFastScrolling();
}
@@ -518,7 +510,13 @@
// Switch to the main tab
switchToTab(ActivityAllAppsContainerView.AdapterHolder.MAIN);
// Scroll to bottom
- getActiveRecyclerView().scrollToBottomWithMotion(SCROLL_TO_BOTTOM_DURATION);
+ if (mPrivateProfileManager != null) {
+ mPrivateProfileManager.scrollForViewToBeVisibleInContainer(
+ getActiveAppsRecyclerView(),
+ getPersonalAppList().getAdapterItems(),
+ mPrivateProfileManager.getPsHeaderHeight(),
+ mActivityContext.getDeviceProfile().allAppsCellHeightPx);
+ }
});
}
@@ -906,7 +904,7 @@
protected BaseAllAppsAdapter<T> createAdapter(AlphabeticalAppsList<T> appsList) {
return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), appsList,
- mMainAdapterProvider, mPrivateSpaceHeaderViewController);
+ mMainAdapterProvider);
}
// TODO(b/216683257): Remove when Taskbar All Apps supports search.
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index 5f002b5..df383bf 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -73,9 +73,8 @@
public AllAppsGridAdapter(T activityContext, LayoutInflater inflater,
- AlphabeticalAppsList apps, SearchAdapterProvider<?> adapterProvider,
- PrivateSpaceHeaderViewController privateSpaceHeaderViewController) {
- super(activityContext, inflater, apps, adapterProvider, privateSpaceHeaderViewController);
+ AlphabeticalAppsList apps, SearchAdapterProvider<?> adapterProvider) {
+ super(activityContext, inflater, apps, adapterProvider);
mGridLayoutMgr = new AppsGridLayoutManager(mActivityContext);
mGridLayoutMgr.setSpanSizeLookup(new GridSpanSizer());
setAppsPerRow(activityContext.getDeviceProfile().numShownAllAppsColumns);
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index 3678109..63f6227 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -295,9 +295,6 @@
mLauncher.getScrimView().setScrimHeaderScale(scaleProgress);
AllAppsRecyclerView rv = mLauncher.getAppsView().getActiveRecyclerView();
- if (rv != null && rv.getScrollbar() != null) {
- rv.getScrollbar().setVisibility(scaleProgress < 1f ? View.INVISIBLE : View.VISIBLE);
- }
// Disable view clipping from all apps' RecyclerView up to all apps view during scale
// animation, and vice versa. The goal is to display extra roll(s) app icons (rendered in
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 81cfa86..4d4b8d2 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -206,7 +206,10 @@
*/
@Override
public void onAppsUpdated() {
- if (mAllAppsStore == null) {
+ // Don't update apps when the private profile animations are running, otherwise the motion
+ // is canceled.
+ if (mAllAppsStore == null || (mPrivateProviderManager != null &&
+ mPrivateProviderManager.getAnimationRunning())) {
return;
}
// Sort the list of apps
@@ -444,6 +447,10 @@
return roundRegion;
}
+ public PrivateProfileManager getPrivateProfileManager() {
+ return mPrivateProviderManager;
+ }
+
private static class MyDiffCallback extends DiffUtil.Callback {
private final List<AdapterItem> mOldList;
diff --git a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
index 5e5795d..2190e1a 100644
--- a/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
+++ b/src/com/android/launcher3/allapps/BaseAllAppsAdapter.java
@@ -169,16 +169,9 @@
protected final OnClickListener mOnIconClickListener;
protected final OnLongClickListener mOnIconLongClickListener;
protected OnFocusChangeListener mIconFocusListener;
- private final PrivateSpaceHeaderViewController mPrivateSpaceHeaderViewController;
public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
AlphabeticalAppsList<T> apps, SearchAdapterProvider<?> adapterProvider) {
- this(activityContext, inflater, apps, adapterProvider, null);
- }
-
- public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
- AlphabeticalAppsList<T> apps, SearchAdapterProvider<?> adapterProvider,
- PrivateSpaceHeaderViewController privateSpaceHeaderViewController) {
mActivityContext = activityContext;
mApps = apps;
mLayoutInflater = inflater;
@@ -187,7 +180,6 @@
mOnIconLongClickListener = mActivityContext.getAllAppsItemLongClickListener();
mAdapterProvider = adapterProvider;
- mPrivateSpaceHeaderViewController = privateSpaceHeaderViewController;
}
/** Checks if the passed viewType represents all apps divider. */
@@ -283,13 +275,10 @@
case VIEW_TYPE_PRIVATE_SPACE_HEADER:
RelativeLayout psHeaderLayout = holder.itemView.findViewById(
R.id.ps_header_layout);
- assert mPrivateSpaceHeaderViewController != null;
- assert psHeaderLayout != null;
- mPrivateSpaceHeaderViewController.addPrivateSpaceHeaderViewElements(psHeaderLayout);
+ mApps.getPrivateProfileManager().addPrivateSpaceHeaderViewElements(psHeaderLayout);
AdapterItem adapterItem = mApps.getAdapterItems().get(position);
int roundRegions = ROUND_TOP_LEFT | ROUND_TOP_RIGHT;
- if (mPrivateSpaceHeaderViewController.getPrivateProfileManager().getCurrentState()
- == STATE_DISABLED) {
+ if (mApps.getPrivateProfileManager().getCurrentState() == STATE_DISABLED) {
roundRegions |= (ROUND_BOTTOM_LEFT | ROUND_BOTTOM_RIGHT);
}
adapterItem.decorationInfo =
diff --git a/src/com/android/launcher3/allapps/PrivateProfileManager.java b/src/com/android/launcher3/allapps/PrivateProfileManager.java
index e7bb1d0..eb967bc 100644
--- a/src/com/android/launcher3/allapps/PrivateProfileManager.java
+++ b/src/com/android/launcher3/allapps/PrivateProfileManager.java
@@ -16,26 +16,54 @@
package com.android.launcher3.allapps;
+import static android.view.View.GONE;
+import static android.view.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_ICON;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_SYS_APPS_DIVIDER;
import static com.android.launcher3.allapps.SectionDecorationInfo.ROUND_NOTHING;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
+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_TAP;
import static com.android.launcher3.model.BgDataModel.Callbacks.FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED;
import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_NOT_PINNABLE;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.SettingsCache.PRIVATE_SPACE_HIDE_WHEN_LOCKED_URI;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.LayoutTransition;
+import android.animation.ValueAnimator;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
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;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import androidx.recyclerview.widget.LinearSmoothScroller;
+import androidx.recyclerview.widget.RecyclerView;
+import com.android.app.animation.Interpolators;
import com.android.launcher3.BuildConfig;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.R;
+import com.android.launcher3.anim.AnimatedPropertySetter;
+import com.android.launcher3.anim.PropertySetter;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.LauncherIcons;
import com.android.launcher3.logging.StatsLogManager;
@@ -45,6 +73,8 @@
import com.android.launcher3.uioverrides.ApiWrapper;
import com.android.launcher3.util.Preconditions;
import com.android.launcher3.util.SettingsCache;
+import com.android.launcher3.views.ActivityContext;
+import com.android.launcher3.views.RecyclerViewFastScroller;
import java.util.ArrayList;
import java.util.HashSet;
@@ -57,14 +87,17 @@
* logic in the Personal tab.
*/
public class PrivateProfileManager extends UserProfileManager {
-
+ private static final int EXPAND_COLLAPSE_DURATION = 800;
+ private static final int SETTINGS_OPACITY_DURATION = 160;
private final ActivityAllAppsContainerView<?> mAllApps;
private final Predicate<UserHandle> mPrivateProfileMatcher;
private Set<String> mPreInstalledSystemPackages = new HashSet<>();
private Intent mAppInstallerIntent = new Intent();
private PrivateAppsSectionDecorator mPrivateAppsSectionDecorator;
private boolean mPrivateSpaceSettingsAvailable;
- private Runnable mUnlockRunnable;
+ private boolean mIsAnimationRunning;
+ private int mHeaderHeight;
+ private boolean mAnimate;
public PrivateProfileManager(UserManager userManager,
ActivityAllAppsContainerView<?> allApps,
@@ -118,20 +151,19 @@
/**
* Disables quiet mode for Private Space User Profile.
- * The runnable passed will be executed in the {@link #reset()} method,
- * when Launcher receives update about profile availability.
- * The runnable passed is only executed once, and reset after execution.
+ * 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(Runnable runnable) {
- enableQuietMode(false);
- mUnlockRunnable = runnable;
+ public void unlockPrivateProfile() {
+ setQuietMode(false);
}
/** Enables quiet mode for Private Space User Profile. */
- public void lockPrivateProfile() {
- enableQuietMode(true);
+ void lockPrivateProfile() {
+ setQuietMode(true);
}
/** Whether private profile should be hidden on Launcher. */
@@ -149,7 +181,9 @@
setCurrentState(updatedState);
resetPrivateSpaceDecorator(updatedState);
if (transitioningFromLockedToUnlocked(previousState, updatedState)) {
- applyUnlockRunnable();
+ postUnlock();
+ } else if (transitioningFromUnlockedToLocked(previousState, updatedState)){
+ executeLock();
}
}
@@ -235,23 +269,45 @@
}
}
- /** Posts quiet mode enable/disable call for private profile. */
- private void enableQuietMode(boolean enable) {
- setQuietMode(enable);
+ @Override
+ public void setQuietMode(boolean enable) {
+ super.setQuietMode(enable);
+ mAnimate = true;
}
- void applyUnlockRunnable() {
- if (mUnlockRunnable != null) {
- // reset the runnable to prevent re-execution.
- MAIN_EXECUTOR.post(mUnlockRunnable);
- mUnlockRunnable = null;
+ /**
+ * Expand the private space after the app list has been added and updated from
+ * {@link AlphabeticalAppsList#onAppsUpdated()}
+ */
+ void postUnlock() {
+ if (mAllApps.isSearching()) {
+ MAIN_EXECUTOR.post(this::exitSearchAndExpand);
+ } else {
+ MAIN_EXECUTOR.post(this::expandPrivateSpace);
}
}
+ /** Collapses the private space before the app list has been updated. */
+ void executeLock() {
+ MAIN_EXECUTOR.execute(this::collapsePrivateSpace);
+ }
+
+ void setAnimationRunning(boolean isAnimationRunning) {
+ mIsAnimationRunning = isAnimationRunning;
+ }
+
+ boolean getAnimationRunning() {
+ 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;
@@ -266,4 +322,349 @@
&& (appInfo.componentName == null
|| !(mPreInstalledSystemPackages.contains(appInfo.componentName.getPackageName())));
}
+
+ /** Add Private Space Header view elements based upon {@link UserProfileState} */
+ public void addPrivateSpaceHeaderViewElements(RelativeLayout parent) {
+ // Set the transition duration for the settings and lock button to animate.
+ ViewGroup settingAndLockGroup = parent.findViewById(R.id.settingsAndLockGroup);
+ if (mAnimate) {
+ enableLayoutTransition(settingAndLockGroup);
+ } else {
+ // Ensure any unwanted animations to not happen.
+ settingAndLockGroup.setLayoutTransition(null);
+ }
+
+ //Add quietMode image and action for lock/unlock button
+ ViewGroup lockButton =
+ parent.findViewById(R.id.ps_lock_unlock_button);
+ assert lockButton != null;
+ addLockButton(lockButton);
+
+ //Trigger lock/unlock action from header.
+ addHeaderOnClickListener(parent);
+
+ //Add image and action for private space settings button
+ ImageButton settingsButton = parent.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);
+ mHeaderHeight = parent.getHeight();
+ }
+
+ /**
+ * 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()) {
+ case STATE_ENABLED -> {
+ lockText.setVisibility(VISIBLE);
+ lockButton.setVisibility(VISIBLE);
+ lockButton.setOnClickListener(view -> lockingAction(/* lock */ true));
+ }
+ case STATE_DISABLED -> {
+ lockText.setVisibility(GONE);
+ lockButton.setVisibility(VISIBLE);
+ lockButton.setOnClickListener(view -> lockingAction(/* lock */ false));
+ }
+ default -> lockButton.setVisibility(GONE);
+ }
+ }
+
+ private void addHeaderOnClickListener(RelativeLayout header) {
+ if (getCurrentState() == STATE_DISABLED) {
+ header.setOnClickListener(view -> lockingAction(/* lock */ false));
+ } else {
+ header.setOnClickListener(null);
+ }
+ }
+
+ /** 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.setAlpha(1f);
+ settingsButton.setOnClickListener(
+ view -> {
+ logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
+ openPrivateSpaceSettings();
+ });
+ } else {
+ settingsButton.setVisibility(GONE);
+ }
+ }
+
+ private void addTransitionImage(ImageView transitionImage) {
+ if (getCurrentState() == STATE_TRANSITION) {
+ transitionImage.setVisibility(VISIBLE);
+ } else {
+ transitionImage.setVisibility(GONE);
+ }
+ }
+
+ /** Finds the private space header to scroll to and set the private space icons to GONE. */
+ private void collapse() {
+ AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
+ List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems =
+ allAppsRecyclerView.getApps().getAdapterItems();
+ for (int i = appListAdapterItems.size() - 1; i > 0; i--) {
+ BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
+ // Scroll to the private space header.
+ if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+ // Note: SmoothScroller is meant to be used once.
+ RecyclerView.SmoothScroller smoothScroller =
+ new LinearSmoothScroller(mAllApps.getContext()) {
+ @Override protected int getVerticalSnapPreference() {
+ return LinearSmoothScroller.SNAP_TO_END;
+ }
+ };
+ smoothScroller.setTargetPosition(i);
+ RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
+ if (layoutManager != null) {
+ layoutManager.startSmoothScroll(smoothScroller);
+ }
+ break;
+ }
+ // Make the private space apps gone to "collapse".
+ if (currentItem.decorationInfo != null) {
+ RecyclerView.ViewHolder viewHolder =
+ allAppsRecyclerView.findViewHolderForAdapterPosition(i);
+ if (viewHolder != null) {
+ viewHolder.itemView.setVisibility(GONE);
+ }
+ }
+ }
+ }
+
+ /**
+ * Upon expanding, only scroll to the item position in the adapter that allows the header to be
+ * visible.
+ */
+ public int scrollForViewToBeVisibleInContainer(
+ AllAppsRecyclerView allAppsRecyclerView,
+ List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems,
+ int psHeaderHeight,
+ int allAppsCellHeight) {
+ int rowToExpandToWithRespectToHeader = -1;
+ int itemToScrollTo = -1;
+ // Looks for the item in the app list to scroll to so that the header is visible.
+ for (int i = 0; i < appListAdapterItems.size(); i++) {
+ BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
+ if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+ itemToScrollTo = i;
+ continue;
+ }
+ if (itemToScrollTo != -1) {
+ itemToScrollTo = i;
+ if (rowToExpandToWithRespectToHeader == -1) {
+ rowToExpandToWithRespectToHeader = currentItem.rowIndex;
+ }
+ int rowToScrollTo =
+ (int) Math.floor((double) (mAllApps.getHeight() - psHeaderHeight
+ - mAllApps.getHeaderProtectionHeight()) / allAppsCellHeight);
+ int currentRowDistance = currentItem.rowIndex - rowToExpandToWithRespectToHeader;
+ // rowToScrollTo - 1 since the item to scroll to is 0 indexed.
+ if (currentRowDistance == rowToScrollTo - 1) {
+ break;
+ }
+ }
+ }
+ if (itemToScrollTo != -1) {
+ // Note: SmoothScroller is meant to be used once.
+ RecyclerView.SmoothScroller smoothScroller =
+ new LinearSmoothScroller(mAllApps.getContext()) {
+ @Override protected int getVerticalSnapPreference() {
+ return LinearSmoothScroller.SNAP_TO_ANY;
+ }
+ };
+ smoothScroller.setTargetPosition(itemToScrollTo);
+ RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
+ if (layoutManager != null) {
+ layoutManager.startSmoothScroll(smoothScroller);
+ }
+ }
+ return itemToScrollTo;
+ }
+
+ /**
+ * Scrolls up to the private space header and animates the collapsing of the text.
+ */
+ private ValueAnimator animateCollapseAnimation() {
+ float from = 1;
+ float to = 0;
+ RecyclerViewFastScroller scrollBar = mAllApps.getActiveRecyclerView().getScrollbar();
+ ValueAnimator collapseAnim = ValueAnimator.ofFloat(from, to);
+ collapseAnim.setDuration(EXPAND_COLLAPSE_DURATION);
+ collapseAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ if (scrollBar != null) {
+ scrollBar.setVisibility(INVISIBLE);
+ }
+ // Scroll up to header.
+ collapse();
+ }
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ super.onAnimationEnd(animation);
+ if (scrollBar != null) {
+ scrollBar.setThumbOffsetY(-1);
+ scrollBar.setVisibility(VISIBLE);
+ }
+ }
+ });
+ return collapseAnim;
+ }
+
+ /**
+ * Using PropertySetter{@link PropertySetter}, we can update the view's attributes within an
+ * animation. At the moment, collapsing, setting alpha changes, and animating the text is done
+ * here.
+ */
+ private void updatePrivateStateAnimator(boolean expand, @Nullable ViewGroup psHeader) {
+ if (psHeader == null) {
+ return;
+ }
+ ViewGroup settingsAndLockGroup = psHeader.findViewById(R.id.settingsAndLockGroup);
+ ViewGroup lockButton = psHeader.findViewById(R.id.ps_lock_unlock_button);
+ if (settingsAndLockGroup.getLayoutTransition() == null) {
+ // Set a new transition if the current ViewGroup does not already contain one as each
+ // transition should only happen once when applied.
+ enableLayoutTransition(settingsAndLockGroup);
+ }
+
+ PropertySetter setter = new AnimatedPropertySetter();
+ ImageButton settingsButton = psHeader.findViewById(R.id.ps_settings_button);
+ updateSettingsGearAlpha(settingsButton, expand, setter);
+ AnimatorSet animatorSet = setter.buildAnim();
+ animatorSet.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ // Animate the collapsing of the text at the same time while updating lock button.
+ lockButton.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
+ setAnimationRunning(true);
+ }
+ });
+ animatorSet.addListener(forEndCallback(() -> {
+ setAnimationRunning(false);
+ mAnimate = false;
+ if (!expand) {
+ // Call onAppsUpdated() because it may be canceled when this animation occurs.
+ mAllApps.getPersonalAppList().onAppsUpdated();
+ }
+ }));
+ // Play the collapsing together of the stateAnimator to avoid being unable to scroll to the
+ // header. Otherwise the smooth scrolling will scroll higher when played with the state
+ // animator.
+ if (!expand) {
+ animatorSet.playTogether(animateCollapseAnimation());
+ }
+ animatorSet.setDuration(EXPAND_COLLAPSE_DURATION);
+ animatorSet.start();
+ }
+
+ /** Animates the layout changes when the text of the button becomes visible/gone. */
+ private void enableLayoutTransition(ViewGroup settingsAndLockGroup) {
+ LayoutTransition settingsAndLockTransition = new LayoutTransition();
+ settingsAndLockTransition.enableTransitionType(LayoutTransition.CHANGING);
+ settingsAndLockTransition.setDuration(EXPAND_COLLAPSE_DURATION);
+ settingsAndLockTransition.addTransitionListener(new LayoutTransition.TransitionListener() {
+ @Override
+ public void startTransition(LayoutTransition transition, ViewGroup viewGroup,
+ View view, int i) {
+ }
+ @Override
+ public void endTransition(LayoutTransition transition, ViewGroup viewGroup,
+ View view, int i) {
+ settingsAndLockGroup.setLayoutTransition(null);
+ mAnimate = false;
+ }
+ });
+ settingsAndLockGroup.setLayoutTransition(settingsAndLockTransition);
+ }
+
+ /** Change the settings gear alpha when expanded or collapsed. */
+ private void updateSettingsGearAlpha(ImageButton settingsButton, boolean expand,
+ PropertySetter setter) {
+ float toAlpha = expand ? 1 : 0;
+ setter.setFloat(settingsButton, VIEW_ALPHA, toAlpha, Interpolators.LINEAR)
+ .setDuration(SETTINGS_OPACITY_DURATION).setStartDelay(0);
+ }
+
+ void expandPrivateSpace() {
+ // If we are on main adapter view, we apply the PS Container expansion animation and
+ // scroll down to load the entire container, making animation visible.
+ ActivityAllAppsContainerView<?>.AdapterHolder mainAdapterHolder = mAllApps.mAH.get(MAIN);
+ List<BaseAllAppsAdapter.AdapterItem> adapterItems =
+ mainAdapterHolder.mAppsList.getAdapterItems();
+ if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()
+ && mAllApps.isPersonalTab()) {
+ // Animate the text and settings icon.
+ DeviceProfile deviceProfile =
+ ActivityContext.lookupContext(mAllApps.getContext()).getDeviceProfile();
+ scrollForViewToBeVisibleInContainer(mainAdapterHolder.mRecyclerView, adapterItems,
+ getPsHeaderHeight(), deviceProfile.allAppsCellHeightPx);
+ ViewGroup psHeader = getPsHeader(mainAdapterHolder.mRecyclerView, adapterItems);
+ updatePrivateStateAnimator(true, psHeader);
+ }
+ }
+
+ private void exitSearchAndExpand() {
+ mAllApps.updateHeaderScroll(0);
+ // Animate to A-Z with 0 time to reset the animation with proper state management.
+ mAllApps.animateToSearchState(false, 0);
+ MAIN_EXECUTOR.post(() -> {
+ mAllApps.mSearchUiManager.resetSearch();
+ mAllApps.switchToTab(ActivityAllAppsContainerView.AdapterHolder.MAIN);
+ expandPrivateSpace();
+ });
+ }
+
+ private void collapsePrivateSpace() {
+ AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
+ AlphabeticalAppsList<?> appList = allAppsRecyclerView.getApps();
+ if (appList == null) {
+ return;
+ }
+ ViewGroup psHeader = getPsHeader(allAppsRecyclerView, appList.getAdapterItems());
+ assert psHeader != null;
+ updatePrivateStateAnimator(false, psHeader);
+ }
+
+ int getPsHeaderHeight() {
+ return mHeaderHeight;
+ }
+
+ /** Get the private space header from the adapter items. */
+ @Nullable
+ private ViewGroup getPsHeader(AllAppsRecyclerView allAppsRecyclerView,
+ List<BaseAllAppsAdapter.AdapterItem> adapterItems){
+ ViewGroup psHeader = null;
+ for (int i = 0; i < adapterItems.size(); i++) {
+ BaseAllAppsAdapter.AdapterItem currentItem = adapterItems.get(i);
+ if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
+ RecyclerView.ViewHolder viewHolder =
+ allAppsRecyclerView.findViewHolderForAdapterPosition(i);
+ if (viewHolder != null) {
+ psHeader = (ViewGroup) viewHolder.itemView;
+ }
+ }
+ }
+ return psHeader;
+ }
}
diff --git a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java b/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
deleted file mode 100644
index fdc035e..0000000
--- a/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewController.java
+++ /dev/null
@@ -1,345 +0,0 @@
-/*
- * Copyright (C) 2023 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.launcher3.allapps;
-
-import static android.view.View.GONE;
-import static android.view.View.INVISIBLE;
-import static android.view.View.VISIBLE;
-
-import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
-import static com.android.launcher3.allapps.ActivityAllAppsContainerView.AdapterHolder.MAIN;
-import static com.android.launcher3.allapps.BaseAllAppsAdapter.VIEW_TYPE_PRIVATE_SPACE_HEADER;
-import static com.android.launcher3.allapps.PrivateProfileManager.STATE_DISABLED;
-import static com.android.launcher3.allapps.PrivateProfileManager.STATE_ENABLED;
-import static com.android.launcher3.allapps.PrivateProfileManager.STATE_TRANSITION;
-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_TAP;
-
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.AnimatorSet;
-import android.animation.LayoutTransition;
-import android.animation.ValueAnimator;
-import android.view.ViewGroup;
-import android.widget.ImageButton;
-import android.widget.ImageView;
-import android.widget.RelativeLayout;
-import android.widget.TextView;
-
-import androidx.annotation.VisibleForTesting;
-import androidx.recyclerview.widget.LinearSmoothScroller;
-import androidx.recyclerview.widget.RecyclerView;
-
-import com.android.app.animation.Interpolators;
-import com.android.launcher3.DeviceProfile;
-import com.android.launcher3.Flags;
-import com.android.launcher3.R;
-import com.android.launcher3.allapps.UserProfileManager.UserProfileState;
-import com.android.launcher3.anim.AnimatedPropertySetter;
-import com.android.launcher3.anim.PropertySetter;
-import com.android.launcher3.views.ActivityContext;
-import com.android.launcher3.views.RecyclerViewFastScroller;
-
-import java.util.List;
-
-/**
- * Controller which returns views to be added to Private Space Header based upon
- * {@link UserProfileState}
- */
-public class PrivateSpaceHeaderViewController {
- private static final int EXPAND_COLLAPSE_DURATION = 800;
- private static final int SETTINGS_OPACITY_DURATION = 160;
- private final ActivityAllAppsContainerView mAllApps;
- private final PrivateProfileManager mPrivateProfileManager;
-
- public PrivateSpaceHeaderViewController(ActivityAllAppsContainerView allApps,
- PrivateProfileManager privateProfileManager) {
- this.mAllApps = allApps;
- this.mPrivateProfileManager = privateProfileManager;
- }
-
- /** Add Private Space Header view elements based upon {@link UserProfileState} */
- public void addPrivateSpaceHeaderViewElements(RelativeLayout parent) {
- // Set the transition duration for the settings and lock button to animate.
- ViewGroup settingsAndLockGroup = parent.findViewById(R.id.settingsAndLockGroup);
- LayoutTransition settingsAndLockTransition = settingsAndLockGroup.getLayoutTransition();
- settingsAndLockTransition.enableTransitionType(LayoutTransition.CHANGING);
- settingsAndLockTransition.setDuration(EXPAND_COLLAPSE_DURATION);
-
- //Add quietMode image and action for lock/unlock button
- ViewGroup lockButton =
- parent.findViewById(R.id.ps_lock_unlock_button);
- assert lockButton != null;
- addLockButton(parent, lockButton);
-
- //Trigger lock/unlock action from header.
- addHeaderOnClickListener(parent);
-
- //Add image and action for private space settings button
- ImageButton settingsButton = parent.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);
- }
-
- /**
- * Adds the quietModeButton and attach onClickListener for the header to animate different
- * states when clicked.
- */
- private void addLockButton(ViewGroup psHeader, ViewGroup lockButton) {
- TextView lockText = lockButton.findViewById(R.id.lock_text);
- switch (mPrivateProfileManager.getCurrentState()) {
- case STATE_ENABLED -> {
- lockText.setVisibility(VISIBLE);
- lockButton.setVisibility(VISIBLE);
- lockButton.setOnClickListener(view -> lockAction(psHeader));
- }
- case STATE_DISABLED -> {
- lockText.setVisibility(GONE);
- lockButton.setVisibility(VISIBLE);
- lockButton.setOnClickListener(view -> unlockAction(psHeader));
- }
- default -> lockButton.setVisibility(GONE);
- }
- }
-
- private void addHeaderOnClickListener(RelativeLayout header) {
- if (mPrivateProfileManager.getCurrentState() == STATE_DISABLED) {
- header.setOnClickListener(view -> unlockAction(header));
- } else {
- header.setOnClickListener(null);
- }
- }
-
- private void unlockAction(ViewGroup psHeader) {
- mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_UNLOCK_TAP);
- mPrivateProfileManager.unlockPrivateProfile((() -> onPrivateProfileUnlocked(psHeader)));
- }
-
- private void lockAction(ViewGroup psHeader) {
- mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_LOCK_TAP);
- if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()) {
- updatePrivateStateAnimator(false, psHeader);
- } else {
- mPrivateProfileManager.lockPrivateProfile();
- }
- }
-
- private void addPrivateSpaceSettingsButton(ImageButton settingsButton) {
- if (mPrivateProfileManager.getCurrentState() == STATE_ENABLED
- && mPrivateProfileManager.isPrivateSpaceSettingsAvailable()) {
- settingsButton.setVisibility(VISIBLE);
- settingsButton.setAlpha(1f);
- settingsButton.setOnClickListener(
- view -> {
- mPrivateProfileManager.logEvents(LAUNCHER_PRIVATE_SPACE_SETTINGS_TAP);
- mPrivateProfileManager.openPrivateSpaceSettings();
- });
- } else {
- settingsButton.setVisibility(GONE);
- }
- }
-
- private void addTransitionImage(ImageView transitionImage) {
- if (mPrivateProfileManager.getCurrentState() == STATE_TRANSITION) {
- transitionImage.setVisibility(VISIBLE);
- } else {
- transitionImage.setVisibility(GONE);
- }
- }
-
- private void onPrivateProfileUnlocked(ViewGroup header) {
- // If we are on main adapter view, we apply the PS Container expansion animation and
- // then scroll down to load the entire container, making animation visible.
- ActivityAllAppsContainerView<?>.AdapterHolder mainAdapterHolder =
- (ActivityAllAppsContainerView<?>.AdapterHolder) mAllApps.mAH.get(MAIN);
- if (Flags.enablePrivateSpace() && Flags.privateSpaceAnimation()
- && mAllApps.getActiveRecyclerView() == mainAdapterHolder.mRecyclerView) {
- // Animate the text and settings icon.
- updatePrivateStateAnimator(true, header);
- DeviceProfile deviceProfile =
- ActivityContext.lookupContext(mAllApps.getContext()).getDeviceProfile();
- AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
- scrollForViewToBeVisibleInContainer(allAppsRecyclerView,
- allAppsRecyclerView.getApps().getAdapterItems(),
- header.getHeight(), deviceProfile.allAppsCellHeightPx);
- }
- }
-
- /** Finds the private space header to scroll to and set the private space icons to GONE. */
- private void collapse() {
- AllAppsRecyclerView allAppsRecyclerView = mAllApps.getActiveRecyclerView();
- List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems =
- allAppsRecyclerView.getApps().getAdapterItems();
- for (int i = appListAdapterItems.size() - 1; i > 0; i--) {
- BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
- // Scroll to the private space header.
- if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
- // Note: SmoothScroller is meant to be used once.
- RecyclerView.SmoothScroller smoothScroller =
- new LinearSmoothScroller(mAllApps.getContext()) {
- @Override protected int getVerticalSnapPreference() {
- return LinearSmoothScroller.SNAP_TO_END;
- }
- };
- smoothScroller.setTargetPosition(i);
- RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
- if (layoutManager != null) {
- layoutManager.startSmoothScroll(smoothScroller);
- }
- break;
- }
- // Make the private space apps gone to "collapse".
- if (currentItem.decorationInfo != null) {
- RecyclerView.ViewHolder viewHolder =
- allAppsRecyclerView.findViewHolderForAdapterPosition(i);
- if (viewHolder != null) {
- viewHolder.itemView.setVisibility(GONE);
- }
- }
- }
- }
-
- /**
- * Upon expanding, only scroll to the item position in the adapter that allows the header to be
- * visible.
- */
- @VisibleForTesting
- public int scrollForViewToBeVisibleInContainer(
- AllAppsRecyclerView allAppsRecyclerView,
- List<BaseAllAppsAdapter.AdapterItem> appListAdapterItems,
- int psHeaderHeight,
- int allAppsCellHeight) {
- int rowToExpandToWithRespectToHeader = -1;
- int itemToScrollTo = -1;
- // Looks for the item in the app list to scroll to so that the header is visible.
- for (int i = 0; i < appListAdapterItems.size(); i++) {
- BaseAllAppsAdapter.AdapterItem currentItem = appListAdapterItems.get(i);
- if (currentItem.viewType == VIEW_TYPE_PRIVATE_SPACE_HEADER) {
- itemToScrollTo = i;
- continue;
- }
- if (itemToScrollTo != -1) {
- if (rowToExpandToWithRespectToHeader == -1) {
- rowToExpandToWithRespectToHeader = currentItem.rowIndex;
- }
- int rowToScrollTo =
- (int) Math.floor((double) (mAllApps.getHeight() - psHeaderHeight
- - mAllApps.getHeaderProtectionHeight()) / allAppsCellHeight);
- int currentRowDistance = currentItem.rowIndex - rowToExpandToWithRespectToHeader;
- // rowToScrollTo - 1 since the item to scroll to is 0 indexed.
- if (currentRowDistance == rowToScrollTo - 1) {
- itemToScrollTo = i;
- break;
- }
- }
- }
- if (itemToScrollTo != -1) {
- // Note: SmoothScroller is meant to be used once.
- RecyclerView.SmoothScroller smoothScroller =
- new LinearSmoothScroller(mAllApps.getContext()) {
- @Override protected int getVerticalSnapPreference() {
- return LinearSmoothScroller.SNAP_TO_ANY;
- }
- };
- smoothScroller.setTargetPosition(itemToScrollTo);
- RecyclerView.LayoutManager layoutManager = allAppsRecyclerView.getLayoutManager();
- if (layoutManager != null) {
- layoutManager.startSmoothScroll(smoothScroller);
- }
- }
- return itemToScrollTo;
- }
-
- PrivateProfileManager getPrivateProfileManager() {
- return mPrivateProfileManager;
- }
-
- /**
- * Scrolls up to the private space header and animates the collapsing of the text.
- */
- private ValueAnimator animateCollapseAnimation(ViewGroup lockButton) {
- float from = 1;
- float to = 0;
- RecyclerViewFastScroller scrollBar = mAllApps.getActiveRecyclerView().getScrollbar();
- ValueAnimator collapseAnim = ValueAnimator.ofFloat(from, to);
- collapseAnim.setDuration(EXPAND_COLLAPSE_DURATION);
- collapseAnim.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- if (scrollBar != null) {
- scrollBar.setVisibility(INVISIBLE);
- }
- // scroll up
- collapse();
- // Animate the collapsing of the text.
- lockButton.findViewById(R.id.lock_text).setVisibility(GONE);
- }
- @Override
- public void onAnimationEnd(Animator animation) {
- super.onAnimationEnd(animation);
- if (scrollBar != null) {
- scrollBar.setThumbOffsetY(-1);
- scrollBar.setVisibility(VISIBLE);
- }
- mPrivateProfileManager.lockPrivateProfile();
- }
- });
- return collapseAnim;
- }
-
- /**
- * Using PropertySetter{@link PropertySetter}, we can update the view's attributes within an
- * animation. At the moment, collapsing, setting alpha changes, and animating the text is done
- * here.
- */
- private void updatePrivateStateAnimator(boolean expand, ViewGroup psHeader) {
- PropertySetter setter = new AnimatedPropertySetter();
- ViewGroup lockButton = psHeader.findViewById(R.id.ps_lock_unlock_button);
- ImageButton settingsButton = psHeader.findViewById(R.id.ps_settings_button);
- updateSettingsGearAlpha(settingsButton, expand, setter);
- AnimatorSet animatorSet = setter.buildAnim();
- animatorSet.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animation) {
- // Animate the collapsing of the text at the same time while updating lock button.
- lockButton.findViewById(R.id.lock_text).setVisibility(expand ? VISIBLE : GONE);
- }
- });
- // Play the collapsing together of the stateAnimator to avoid being unable to scroll to the
- // header. Otherwise the smooth scrolling will scroll higher when played with the state
- // animator.
- if (!expand) {
- animatorSet.playTogether(animateCollapseAnimation(lockButton));
- }
- animatorSet.setDuration(EXPAND_COLLAPSE_DURATION);
- animatorSet.start();
- }
-
- /** Change the settings gear alpha when expanded or collapsed. */
- private void updateSettingsGearAlpha(ImageButton settingsButton, boolean expand,
- PropertySetter setter) {
- float toAlpha = expand ? 1 : 0;
- setter.setFloat(settingsButton, VIEW_ALPHA, toAlpha, Interpolators.LINEAR)
- .setDuration(SETTINGS_OPACITY_DURATION).setStartDelay(0);
- }
-}
diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java
index bbeb341..9010f82 100644
--- a/src/com/android/launcher3/apppairs/AppPairIcon.java
+++ b/src/com/android/launcher3/apppairs/AppPairIcon.java
@@ -33,7 +33,7 @@
import com.android.launcher3.R;
import com.android.launcher3.Reorderable;
import com.android.launcher3.dragndrop.DraggableView;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.views.ActivityContext;
@@ -50,17 +50,12 @@
public class AppPairIcon extends FrameLayout implements DraggableView, Reorderable {
private static final String TAG = "AppPairIcon";
- /**
- * Indicates that the app pair is currently launchable on the current screen.
- */
- private boolean mIsLaunchableAtScreenSize = true;
-
// A view that holds the app pair icon graphic.
private AppPairIconGraphic mIconGraphic;
// A view that holds the app pair's title.
private BubbleTextView mAppPairName;
// The underlying ItemInfo that stores info about the app pair members, etc.
- private FolderInfo mInfo;
+ private AppPairInfo mInfo;
// The containing element that holds this icon: workspace, taskbar, folder, etc. Affects certain
// aspects of how the icon is drawn.
private int mContainer;
@@ -81,7 +76,7 @@
* Builds an AppPairIcon to be added to the Launcher.
*/
public static AppPairIcon inflateIcon(int resId, ActivityContext activity,
- @Nullable ViewGroup group, FolderInfo appPairInfo, int container) {
+ @Nullable ViewGroup group, AppPairInfo appPairInfo, int container) {
DeviceProfile grid = activity.getDeviceProfile();
LayoutInflater inflater = (group != null)
? LayoutInflater.from(group.getContext())
@@ -89,7 +84,7 @@
AppPairIcon icon = (AppPairIcon) inflater.inflate(resId, group, false);
// Sort contents, so that left-hand app comes first
- appPairInfo.contents.sort(Comparator.comparingInt(a -> a.rank));
+ appPairInfo.getContents().sort(Comparator.comparingInt(a -> a.rank));
icon.setTag(appPairInfo);
icon.setOnClickListener(activity.getItemOnClickListener());
@@ -100,8 +95,6 @@
icon.mIconGraphic = icon.findViewById(R.id.app_pair_icon_graphic);
icon.mIconGraphic.init(icon, container);
- icon.checkDisabledState();
-
// Set up app pair title
icon.mAppPairName = icon.findViewById(R.id.app_pair_icon_name);
FrameLayout.LayoutParams lp =
@@ -115,7 +108,7 @@
// For some reason, app icons have setIncludeFontPadding(false) inside folders, so we set it
// here to match that.
icon.mAppPairName.setIncludeFontPadding(container != DISPLAY_FOLDER);
- icon.mAppPairName.setText(appPairInfo.title);
+ icon.mAppPairName.applyLabel(appPairInfo);
// Set up accessibility
icon.setContentDescription(icon.getAccessibilityTitle(appPairInfo));
@@ -127,9 +120,9 @@
/**
* Returns a formatted accessibility title for app pairs.
*/
- public String getAccessibilityTitle(FolderInfo appPairInfo) {
- CharSequence app1 = appPairInfo.contents.get(0).title;
- CharSequence app2 = appPairInfo.contents.get(1).title;
+ public String getAccessibilityTitle(AppPairInfo appPairInfo) {
+ CharSequence app1 = appPairInfo.getFirstApp().title;
+ CharSequence app2 = appPairInfo.getSecondApp().title;
return getContext().getString(R.string.app_pair_name_format, app1, app2);
}
@@ -174,7 +167,7 @@
return mScaleForReorderBounce;
}
- public FolderInfo getInfo() {
+ public AppPairInfo getInfo() {
return mInfo;
}
@@ -186,41 +179,20 @@
return mIconGraphic;
}
- public boolean isLaunchableAtScreenSize() {
- return mIsLaunchableAtScreenSize;
- }
-
- /**
- * Updates the "disabled" state of the app pair in the current device configuration.
- * App pairs can be "disabled" in two ways:
- * 1) One of the member WorkspaceItemInfos is disabled (i.e. the app software itself is paused
- * by the user or can't be launched for some other reason).
- * 2) This specific instance of an app pair can't be launched due to screen size requirements.
- */
- public void checkDisabledState() {
- DeviceProfile dp = ActivityContext.lookupContext(getContext()).getDeviceProfile();
- // If user is on a small screen, we can't launch if either of the apps is non-resizeable
- mIsLaunchableAtScreenSize =
- dp.isTablet || getInfo().contents.stream().noneMatch(
- wii -> wii.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE));
- // Invalidate to update icons
- mIconGraphic.redraw();
- }
-
/**
* Called when WorkspaceItemInfos get updated, and the app pair icon may need to be redrawn.
*/
public void maybeRedrawForWorkspaceUpdate(Predicate<WorkspaceItemInfo> itemCheck) {
// If either of the app pair icons return true on the predicate (i.e. in the list of
// updated apps), redraw the icon graphic (icon background and both icons).
- if (getInfo().contents.stream().anyMatch(itemCheck)) {
- checkDisabledState();
+ if (getInfo().anyMatch(itemCheck)) {
+ mIconGraphic.redraw();
}
}
/**
* Inside folders, icons are vertically centered in their rows. See
- * {@link BubbleTextView#onMeasure(int, int)} for comparison.
+ * {@link BubbleTextView} for comparison.
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
diff --git a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
index 04050b0..a3a1cfc 100644
--- a/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
+++ b/src/com/android/launcher3/apppairs/AppPairIconGraphic.kt
@@ -23,12 +23,12 @@
import android.util.AttributeSet
import android.view.Gravity
import android.widget.FrameLayout
+import androidx.annotation.OpenForTesting
import com.android.launcher3.DeviceProfile
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener
import com.android.launcher3.icons.BitmapInfo
import com.android.launcher3.icons.FastBitmapDrawable.getDisabledColorFilter
-import com.android.launcher3.model.data.FolderInfo
-import com.android.launcher3.model.data.WorkspaceItemInfo
+import com.android.launcher3.model.data.AppPairInfo
import com.android.launcher3.util.Themes
import com.android.launcher3.views.ActivityContext
@@ -36,29 +36,32 @@
* A FrameLayout marking the area on an [AppPairIcon] where the visual icon will be drawn. One of
* two child UI elements on an [AppPairIcon], along with a BubbleTextView holding the text title.
*/
-class AppPairIconGraphic @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null) :
+@OpenForTesting
+open class AppPairIconGraphic
+@JvmOverloads
+constructor(context: Context, attrs: AttributeSet? = null) :
FrameLayout(context, attrs), OnDeviceProfileChangeListener {
private val TAG = "AppPairIconGraphic"
companion object {
- /** Composes a drawable for this icon, consisting of a background and 2 app icons. */
+ /**
+ * Composes a drawable for this icon, consisting of a background and 2 app icons. The app
+ * pair will draw as "disabled" if either of the following is true:
+ * 1) One of the member WorkspaceItemInfos is disabled (i.e. the app software itself is
+ * paused or can't be launched for some other reason).
+ * 2) One of the member apps can't be launched due to screen size requirements.
+ */
@JvmStatic
- fun composeDrawable(appPairInfo: FolderInfo, p: AppPairIconDrawingParams): Drawable {
+ fun composeDrawable(appPairInfo: AppPairInfo, p: AppPairIconDrawingParams): Drawable {
// Generate new icons, using themed flag if needed.
val flags = if (Themes.isThemedIconEnabled(p.context)) BitmapInfo.FLAG_THEMED else 0
- val appIcon1 = appPairInfo.contents[0].newIcon(p.context, flags)
- val appIcon2 = appPairInfo.contents[1].newIcon(p.context, flags)
+ val appIcon1 = appPairInfo.getFirstApp().newIcon(p.context, flags)
+ val appIcon2 = appPairInfo.getSecondApp().newIcon(p.context, flags)
appIcon1.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt())
appIcon2.setBounds(0, 0, p.memberIconSize.toInt(), p.memberIconSize.toInt())
- // Check disabled status.
- val activity: ActivityContext = ActivityContext.lookupContext(p.context)
- val isLaunchableAtScreenSize =
- activity.deviceProfile.isTablet ||
- appPairInfo.contents.stream().noneMatch { wii: WorkspaceItemInfo ->
- wii.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE)
- }
- val shouldDrawAsDisabled = appPairInfo.isDisabled || !isLaunchableAtScreenSize
+ val shouldDrawAsDisabled =
+ appPairInfo.isDisabled || !appPairInfo.isLaunchable(p.context)
// Set disabled status on icons.
appIcon1.setIsDisabled(shouldDrawAsDisabled)
@@ -124,7 +127,6 @@
*/
fun getIconBounds(outBounds: Rect) {
outBounds.set(0, 0, drawParams.backgroundSize.toInt(), drawParams.backgroundSize.toInt())
-
outBounds.offset(
// x-coordinate in parent's coordinate system
((parentIcon.width - drawParams.backgroundSize) / 2).toInt(),
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 6d64c22..1c34c72 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -397,11 +397,6 @@
+ "waiting for SystemUI and then merging the SystemUI progress whenever we "
+ "start receiving the events");
- // TODO(Block 24): Clean up flags
- public static final BooleanFlag ENABLE_NEW_MIGRATION_LOGIC = getDebugFlag(270393455,
- "ENABLE_NEW_MIGRATION_LOGIC", ENABLED,
- "Enable the new grid migration logic, keeping pages when src < dest");
-
// TODO(Block 25): Clean up flags
public static final BooleanFlag ENABLE_NEW_GESTURE_NAV_TUTORIAL = getDebugFlag(270396257,
"ENABLE_NEW_GESTURE_NAV_TUTORIAL", ENABLED,
diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java
index b6e5977..bc5a164 100644
--- a/src/com/android/launcher3/dragndrop/DragController.java
+++ b/src/com/android/launcher3/dragndrop/DragController.java
@@ -33,6 +33,7 @@
import com.android.launcher3.DropTarget;
import com.android.launcher3.Flags;
import com.android.launcher3.logging.InstanceId;
+import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -289,7 +290,8 @@
// Cancel the current drag if we are removing an app that we are dragging
if (mDragObject != null) {
ItemInfo dragInfo = mDragObject.dragInfo;
- if (dragInfo instanceof WorkspaceItemInfo && matcher.test(dragInfo)) {
+ if ((dragInfo instanceof WorkspaceItemInfo && matcher.test(dragInfo))
+ || (dragInfo instanceof AppPairInfo api && api.anyMatch(matcher))) {
cancelDrag();
}
}
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index c8c634a..aa3c5ba 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -493,7 +493,7 @@
mInfo = info;
mFromTitle = info.title;
mFromLabelState = info.getFromLabelState();
- ArrayList<WorkspaceItemInfo> children = info.contents;
+ ArrayList<WorkspaceItemInfo> children = info.getContents();
Collections.sort(children, ITEM_POS_COMPARATOR);
updateItemLocationsInDatabaseBatch(true);
@@ -626,7 +626,7 @@
// onDropComplete. Perform cleanup once drag-n-drop ends.
mDragController.addDragListener(this);
- ArrayList<WorkspaceItemInfo> items = new ArrayList<>(mInfo.contents);
+ ArrayList<WorkspaceItemInfo> items = new ArrayList<>(mInfo.getContents());
mEmptyCellRank = items.size();
items.add(null); // Add an empty spot at the end
@@ -639,7 +639,7 @@
* is played.
*/
public void animateOpen() {
- animateOpen(mInfo.contents, 0);
+ animateOpen(mInfo.getContents(), 0);
}
/**
@@ -1097,9 +1097,9 @@
mActivityContext.getDeviceProfile()).setFolderInfo(mInfo);
ArrayList<ItemInfo> items = new ArrayList<>();
- int total = mInfo.contents.size();
+ int total = mInfo.getContents().size();
for (int i = 0; i < total; i++) {
- WorkspaceItemInfo itemInfo = mInfo.contents.get(i);
+ WorkspaceItemInfo itemInfo = mInfo.getContents().get(i);
if (verifier.updateRankAndPos(itemInfo, i)) {
items.add(itemInfo);
}
@@ -1113,7 +1113,7 @@
FolderNameInfos nameInfos = new FolderNameInfos();
FolderNameProvider fnp = FolderNameProvider.newInstance(getContext());
fnp.getSuggestedFolderName(
- getContext(), mInfo.contents, nameInfos);
+ getContext(), mInfo.getContents(), nameInfos);
mInfo.suggestedFolderNames = nameInfos;
});
}
@@ -1217,7 +1217,7 @@
}
public int getItemCount() {
- return mInfo.contents.size();
+ return mInfo.getContents().size();
}
void replaceFolderWithFinalItem() {
diff --git a/src/com/android/launcher3/folder/FolderGridOrganizer.java b/src/com/android/launcher3/folder/FolderGridOrganizer.java
index cc24761..593673d 100644
--- a/src/com/android/launcher3/folder/FolderGridOrganizer.java
+++ b/src/com/android/launcher3/folder/FolderGridOrganizer.java
@@ -57,7 +57,7 @@
* Updates the organizer with the provided folder info
*/
public FolderGridOrganizer setFolderInfo(FolderInfo info) {
- return setContentSize(info.contents.size());
+ return setContentSize(info.getContents().size());
}
/**
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index ee0d5fc..62ce311 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -215,7 +215,7 @@
// Keep the notification dot up to date with the sum of all the content's dots.
FolderDotInfo folderDotInfo = new FolderDotInfo();
- for (WorkspaceItemInfo si : folderInfo.contents) {
+ for (WorkspaceItemInfo si : folderInfo.getContents()) {
folderDotInfo.addDotInfo(activity.getDotInfoForItem(si));
}
icon.setDotInfo(folderDotInfo);
@@ -422,7 +422,7 @@
FolderNameInfos nameInfos = new FolderNameInfos();
Executors.MODEL_EXECUTOR.post(() -> {
d.folderNameProvider.getSuggestedFolderName(
- getContext(), mInfo.contents, nameInfos);
+ getContext(), mInfo.getContents(), nameInfos);
postDelayed(() -> {
setLabelSuggestion(nameInfos, d.logInstanceId);
invalidate();
@@ -487,7 +487,7 @@
}
mFolder.notifyDrop();
onDrop(item, d, null, 1.0f,
- itemReturnedOnFailedDrop ? item.rank : mInfo.contents.size(),
+ itemReturnedOnFailedDrop ? item.rank : mInfo.getContents().size(),
itemReturnedOnFailedDrop
);
}
@@ -666,7 +666,7 @@
* Returns the list of items which should be visible in the preview
*/
public List<WorkspaceItemInfo> getPreviewItemsOnPage(int page) {
- return mPreviewVerifier.setFolderInfo(mInfo).previewItemsForPage(page, mInfo.contents);
+ return mPreviewVerifier.setFolderInfo(mInfo).previewItemsForPage(page, mInfo.getContents());
}
@Override
@@ -809,7 +809,7 @@
* Returns a formatted accessibility title for folder
*/
public String getAccessiblityTitle(CharSequence title) {
- int size = mInfo.contents.size();
+ int size = mInfo.getContents().size();
if (size < MAX_NUM_ITEMS_IN_PREVIEW) {
return getContext().getString(R.string.folder_name_format_exact, title, size);
} else {
diff --git a/src/com/android/launcher3/folder/FolderNameProvider.java b/src/com/android/launcher3/folder/FolderNameProvider.java
index bf59594..5d2bb3a 100644
--- a/src/com/android/launcher3/folder/FolderNameProvider.java
+++ b/src/com/android/launcher3/folder/FolderNameProvider.java
@@ -35,7 +35,7 @@
import com.android.launcher3.model.BgDataModel;
import com.android.launcher3.model.StringCache;
import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.util.IntSparseArrayMap;
import com.android.launcher3.util.Preconditions;
@@ -62,7 +62,7 @@
* name edit box can also be used to provide suggestion.
*/
public static final int SUGGEST_MAX = 4;
- protected IntSparseArrayMap<FolderInfo> mFolderInfos;
+ protected IntSparseArrayMap<CollectionInfo> mCollectionInfos;
protected List<AppInfo> mAppInfos;
/**
@@ -79,7 +79,7 @@
}
public static FolderNameProvider newInstance(Context context, List<AppInfo> appInfos,
- IntSparseArrayMap<FolderInfo> folderInfos) {
+ IntSparseArrayMap<CollectionInfo> folderInfos) {
Preconditions.assertWorkerThread();
FolderNameProvider fnp = Overrides.getObject(FolderNameProvider.class,
context.getApplicationContext(), R.string.folder_name_provider_class);
@@ -93,9 +93,9 @@
new FolderNameWorker());
}
- private void load(List<AppInfo> appInfos, IntSparseArrayMap<FolderInfo> folderInfos) {
+ private void load(List<AppInfo> appInfos, IntSparseArrayMap<CollectionInfo> folderInfos) {
mAppInfos = appInfos;
- mFolderInfos = folderInfos;
+ mCollectionInfos = folderInfos;
}
/**
@@ -195,7 +195,7 @@
@Override
public void execute(@NonNull final LauncherAppState app,
@NonNull final BgDataModel dataModel, @NonNull final AllAppsList apps) {
- mFolderInfos = dataModel.folders.clone();
+ mCollectionInfos = dataModel.collections.clone();
mAppInfos = Arrays.asList(apps.copyData());
}
}
diff --git a/src/com/android/launcher3/folder/LauncherDelegate.java b/src/com/android/launcher3/folder/LauncherDelegate.java
index 78298b3..33bcf21 100644
--- a/src/com/android/launcher3/folder/LauncherDelegate.java
+++ b/src/com/android/launcher3/folder/LauncherDelegate.java
@@ -93,7 +93,7 @@
// folder
CellLayout cellLayout = mLauncher.getCellLayout(info.container,
mLauncher.getCellPosMapper().mapModelToPresenter(info).screenId);
- finalItem = info.contents.remove(0);
+ finalItem = info.getContents().remove(0);
newIcon = mLauncher.getItemInflater().inflateItem(
finalItem, mLauncher.getModelWriter(), cellLayout);
mLauncher.getModelWriter().addOrMoveItemInDatabase(finalItem,
diff --git a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
index 9aee379..6b3bb51 100644
--- a/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
+++ b/src/com/android/launcher3/graphics/LauncherPreviewRenderer.java
@@ -82,6 +82,8 @@
import com.android.launcher3.model.BgDataModel.FixedContainerItems;
import com.android.launcher3.model.WidgetItem;
import com.android.launcher3.model.WidgetsModel;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -388,16 +390,16 @@
addInScreenFromBind(icon, info);
}
- private void inflateAndAddCollectionIcon(FolderInfo info) {
+ private void inflateAndAddCollectionIcon(CollectionInfo info) {
boolean isOnDesktop = info.container == Favorites.CONTAINER_DESKTOP;
CellLayout screen = isOnDesktop
? mWorkspaceScreens.get(info.screenId)
: mHotseat;
- FrameLayout folderIcon = info.itemType == Favorites.ITEM_TYPE_FOLDER
- ? FolderIcon.inflateIcon(R.layout.folder_icon, this, screen, info)
- : AppPairIcon.inflateIcon(R.layout.app_pair_icon, this, screen, info,
+ FrameLayout collectionIcon = info.itemType == Favorites.ITEM_TYPE_FOLDER
+ ? FolderIcon.inflateIcon(R.layout.folder_icon, this, screen, (FolderInfo) info)
+ : AppPairIcon.inflateIcon(R.layout.app_pair_icon, this, screen, (AppPairInfo) info,
isOnDesktop ? DISPLAY_WORKSPACE : DISPLAY_TASKBAR);
- addInScreenFromBind(folderIcon, info);
+ addInScreenFromBind(collectionIcon, info);
}
private void inflateAndAddWidgets(
@@ -501,7 +503,7 @@
break;
case Favorites.ITEM_TYPE_FOLDER:
case Favorites.ITEM_TYPE_APP_PAIR:
- inflateAndAddCollectionIcon((FolderInfo) itemInfo);
+ inflateAndAddCollectionIcon((CollectionInfo) itemInfo);
break;
default:
break;
diff --git a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
index 96a8da9..ce563b7 100644
--- a/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
+++ b/src/com/android/launcher3/model/AddWorkspaceItemsTask.java
@@ -31,7 +31,7 @@
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.BgDataModel.Callbacks;
import com.android.launcher3.model.data.AppInfo;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -131,8 +131,8 @@
int screenId = coords[0];
ItemInfo itemInfo;
- if (item instanceof WorkspaceItemInfo || item instanceof FolderInfo ||
- item instanceof LauncherAppWidgetInfo) {
+ if (item instanceof WorkspaceItemInfo || item instanceof CollectionInfo
+ || item instanceof LauncherAppWidgetInfo) {
itemInfo = item;
} else if (item instanceof WorkspaceItemFactory) {
itemInfo = ((WorkspaceItemFactory) item).makeWorkspaceItem(app.getContext());
diff --git a/src/com/android/launcher3/model/BgDataModel.java b/src/com/android/launcher3/model/BgDataModel.java
index 0e1c8f4..44e45da 100644
--- a/src/com/android/launcher3/model/BgDataModel.java
+++ b/src/com/android/launcher3/model/BgDataModel.java
@@ -44,6 +44,7 @@
import com.android.launcher3.Workspace;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -102,9 +103,9 @@
public final ArrayList<LauncherAppWidgetInfo> appWidgets = new ArrayList<>();
/**
- * Map of id to FolderInfos of all the folders created by LauncherModel
+ * Map of id to CollectionInfos of all the folders or app pairs created by LauncherModel
*/
- public final IntSparseArrayMap<FolderInfo> folders = new IntSparseArrayMap<>();
+ public final IntSparseArrayMap<CollectionInfo> collections = new IntSparseArrayMap<>();
/**
* Extra container based items
@@ -144,7 +145,7 @@
public synchronized void clear() {
workspaceItems.clear();
appWidgets.clear();
- folders.clear();
+ collections.clear();
itemsIdMap.clear();
deepShortcutMap.clear();
extraItems.clear();
@@ -179,9 +180,9 @@
for (int i = 0; i < appWidgets.size(); i++) {
writer.println(prefix + '\t' + appWidgets.get(i).toString());
}
- writer.println(prefix + " ---- folder items ");
- for (int i = 0; i < folders.size(); i++) {
- writer.println(prefix + '\t' + folders.valueAt(i).toString());
+ writer.println(prefix + " ---- collection items ");
+ for (int i = 0; i < collections.size(); i++) {
+ writer.println(prefix + '\t' + collections.valueAt(i).toString());
}
writer.println(prefix + " ---- extra items ");
for (int i = 0; i < extraItems.size(); i++) {
@@ -211,12 +212,12 @@
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
- folders.remove(item.id);
+ collections.remove(item.id);
if (FeatureFlags.IS_STUDIO_BUILD) {
for (ItemInfo info : itemsIdMap) {
if (info.container == item.id) {
- // We are deleting a folder which still contains items that
- // think they are contained by that folder.
+ // We are deleting a collection which still contains items that
+ // think they are contained by that collection.
String msg = "deleting a collection (" + item + ") which still "
+ "contains items (" + info + ")";
Log.e(TAG, msg);
@@ -259,7 +260,7 @@
switch (item.itemType) {
case LauncherSettings.Favorites.ITEM_TYPE_FOLDER:
case LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR:
- folders.put(item.id, (FolderInfo) item);
+ collections.put(item.id, (CollectionInfo) item);
workspaceItems.add(item);
break;
case LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT:
@@ -269,14 +270,14 @@
workspaceItems.add(item);
} else {
if (newItem) {
- if (!folders.containsKey(item.container)) {
+ if (!collections.containsKey(item.container)) {
// Adding an item to a nonexistent collection.
String msg = "attempted to add item: " + item + " to a nonexistent app"
+ " collection";
Log.e(TAG, msg);
}
} else {
- findOrMakeFolder(item.container).add((WorkspaceItemInfo) item, false);
+ findOrMakeFolder(item.container).add((WorkspaceItemInfo) item);
}
}
break;
@@ -371,15 +372,18 @@
* Return an existing FolderInfo object if we have encountered this ID previously,
* or make a new one.
*/
- public synchronized FolderInfo findOrMakeFolder(int id) {
+ public synchronized CollectionInfo findOrMakeFolder(int id) {
// See if a placeholder was created for us already
- FolderInfo folderInfo = folders.get(id);
- if (folderInfo == null) {
- // No placeholder -- create a new instance
- folderInfo = new FolderInfo();
- folders.put(id, folderInfo);
+ CollectionInfo collectionInfo = collections.get(id);
+ if (collectionInfo == null) {
+ // No placeholder -- create a new blank folder instance. At this point, we don't know
+ // if the desired container is supposed to be a folder or an app pair. In the case that
+ // it is an app pair, the blank folder will be replaced by a blank app pair when the app
+ // pair is getting processed, in WorkspaceItemProcessor.processFolderOrAppPair().
+ collectionInfo = new FolderInfo();
+ collections.put(id, collectionInfo);
}
- return folderInfo;
+ return collectionInfo;
}
/**
diff --git a/src/com/android/launcher3/model/DeviceGridState.java b/src/com/android/launcher3/model/DeviceGridState.java
index 8c68eb8..729b381 100644
--- a/src/com/android/launcher3/model/DeviceGridState.java
+++ b/src/com/android/launcher3/model/DeviceGridState.java
@@ -156,11 +156,11 @@
}
public Integer getColumns() {
- return Integer.parseInt(String.valueOf(mGridSizeString.charAt(0)));
+ return Integer.parseInt(String.valueOf(mGridSizeString.split(",")[0]));
}
public Integer getRows() {
- return Integer.parseInt(String.valueOf(mGridSizeString.charAt(2)));
+ return Integer.parseInt(String.valueOf(mGridSizeString.split(",")[1]));
}
@Override
diff --git a/src/com/android/launcher3/model/FirstScreenBroadcast.java b/src/com/android/launcher3/model/FirstScreenBroadcast.java
index 9e91b9d..1deb665 100644
--- a/src/com/android/launcher3/model/FirstScreenBroadcast.java
+++ b/src/com/android/launcher3/model/FirstScreenBroadcast.java
@@ -36,6 +36,7 @@
import androidx.annotation.WorkerThread;
import com.android.launcher3.LauncherSettings;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -67,7 +68,8 @@
private static final String ACTION_FIRST_SCREEN_ACTIVE_INSTALLS
= "com.android.launcher3.action.FIRST_SCREEN_ACTIVE_INSTALLS";
- private static final String FOLDER_ITEM_EXTRA = "folderItem";
+ // String retained as "folderItem" for back-compatibility reasons.
+ private static final String COLLECTION_ITEM_EXTRA = "folderItem";
private static final String WORKSPACE_ITEM_EXTRA = "workspaceItem";
private static final String HOTSEAT_ITEM_EXTRA = "hotseatItem";
private static final String WIDGET_ITEM_EXTRA = "widgetItem";
@@ -105,20 +107,19 @@
@WorkerThread
private void sendBroadcastToInstaller(Context context, String installerPackageName,
Set<String> packages, List<ItemInfo> firstScreenItems) {
- Set<String> folderItems = new HashSet<>();
+ Set<String> collectionItems = new HashSet<>();
Set<String> workspaceItems = new HashSet<>();
Set<String> hotseatItems = new HashSet<>();
Set<String> widgetItems = new HashSet<>();
for (ItemInfo info : firstScreenItems) {
- if (info instanceof FolderInfo) {
- FolderInfo folderInfo = (FolderInfo) info;
- String folderItemInfoPackage;
- for (ItemInfo folderItemInfo : cloneOnMainThread(folderInfo.contents)) {
- folderItemInfoPackage = getPackageName(folderItemInfo);
- if (folderItemInfoPackage != null
- && packages.contains(folderItemInfoPackage)) {
- folderItems.add(folderItemInfoPackage);
+ if (info instanceof CollectionInfo ci) {
+ String collectionItemInfoPackage;
+ for (ItemInfo collectionItemInfo : cloneOnMainThread(ci.getContents())) {
+ collectionItemInfoPackage = getPackageName(collectionItemInfo);
+ if (collectionItemInfoPackage != null
+ && packages.contains(collectionItemInfoPackage)) {
+ collectionItems.add(collectionItemInfoPackage);
}
}
}
@@ -137,13 +138,13 @@
}
if (DEBUG) {
- printList(installerPackageName, "Folder item", folderItems);
+ printList(installerPackageName, "Collection item", collectionItems);
printList(installerPackageName, "Workspace item", workspaceItems);
printList(installerPackageName, "Hotseat item", hotseatItems);
printList(installerPackageName, "Widget item", widgetItems);
}
- if (folderItems.isEmpty()
+ if (collectionItems.isEmpty()
&& workspaceItems.isEmpty()
&& hotseatItems.isEmpty()
&& widgetItems.isEmpty()) {
@@ -152,7 +153,7 @@
}
context.sendBroadcast(new Intent(ACTION_FIRST_SCREEN_ACTIVE_INSTALLS)
.setPackage(installerPackageName)
- .putStringArrayListExtra(FOLDER_ITEM_EXTRA, new ArrayList<>(folderItems))
+ .putStringArrayListExtra(COLLECTION_ITEM_EXTRA, new ArrayList<>(collectionItems))
.putStringArrayListExtra(WORKSPACE_ITEM_EXTRA, new ArrayList<>(workspaceItems))
.putStringArrayListExtra(HOTSEAT_ITEM_EXTRA, new ArrayList<>(hotseatItems))
.putStringArrayListExtra(WIDGET_ITEM_EXTRA, new ArrayList<>(widgetItems))
@@ -180,7 +181,7 @@
}
/**
- * Clone the provided list on UI thread. This is used for {@link FolderInfo#contents} which
+ * Clone the provided list on UI thread. This is used for {@link FolderInfo#getContents()} which
* is always modified on UI thread.
*/
@AnyThread
diff --git a/src/com/android/launcher3/model/GridSizeMigrationUtil.java b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
index 15190c7..299c952 100644
--- a/src/com/android/launcher3/model/GridSizeMigrationUtil.java
+++ b/src/com/android/launcher3/model/GridSizeMigrationUtil.java
@@ -223,19 +223,13 @@
screens.add(screenId);
}
- boolean preservePages = false;
- if (screens.isEmpty() && FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC.get()) {
- preservePages = destDeviceState.compareTo(srcDeviceState) >= 0
- && destDeviceState.getColumns() - srcDeviceState.getColumns() <= 2;
- }
-
// Then we place the items on the screens
for (int screenId : screens) {
if (DEBUG) {
Log.d(TAG, "Migrating " + screenId);
}
solveGridPlacement(helper, srcReader,
- destReader, screenId, trgX, trgY, workspaceToBeAdded, false);
+ destReader, screenId, trgX, trgY, workspaceToBeAdded);
if (workspaceToBeAdded.isEmpty()) {
break;
}
@@ -245,8 +239,8 @@
// any of the screens, in this case we add them to new screens until all of them are placed.
int screenId = destReader.mLastScreenId + 1;
while (!workspaceToBeAdded.isEmpty()) {
- solveGridPlacement(helper, srcReader,
- destReader, screenId, trgX, trgY, workspaceToBeAdded, preservePages);
+ solveGridPlacement(helper, srcReader, destReader, screenId, trgX, trgY,
+ workspaceToBeAdded);
screenId++;
}
@@ -348,7 +342,7 @@
private static void solveGridPlacement(@NonNull final DatabaseHelper helper,
@NonNull final DbReader srcReader, @NonNull final DbReader destReader,
final int screenId, final int trgX, final int trgY,
- @NonNull final List<DbEntry> sortedItemsToPlace, final boolean matchingScreenIdOnly) {
+ @NonNull final List<DbEntry> sortedItemsToPlace) {
final GridOccupancy occupied = new GridOccupancy(trgX, trgY);
final Point trg = new Point(trgX, trgY);
final Point next = new Point(0, screenId == 0
@@ -366,8 +360,6 @@
Iterator<DbEntry> iterator = sortedItemsToPlace.iterator();
while (iterator.hasNext()) {
final DbEntry entry = iterator.next();
- if (matchingScreenIdOnly && entry.screenId < screenId) continue;
- if (matchingScreenIdOnly && entry.screenId > screenId) break;
if (entry.minSpanX > trgX || entry.minSpanY > trgY) {
iterator.remove();
continue;
@@ -435,7 +427,8 @@
}
}
- protected static class DbReader {
+ @VisibleForTesting
+ public static class DbReader {
private final SQLiteDatabase mDb;
private final String mTableName;
@@ -446,7 +439,7 @@
private final Map<Integer, ArrayList<DbEntry>> mWorkspaceEntriesByScreenId =
new ArrayMap<>();
- DbReader(SQLiteDatabase db, String tableName, Context context,
+ public DbReader(SQLiteDatabase db, String tableName, Context context,
Set<String> validPackages) {
mDb = db;
mTableName = tableName;
diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java
index f3d04b7..30cccd5 100644
--- a/src/com/android/launcher3/model/LoaderTask.java
+++ b/src/com/android/launcher3/model/LoaderTask.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.Flags.enableLauncherBrMetricsFixed;
import static com.android.launcher3.LauncherPrefs.IS_FIRST_LOAD_AFTER_RESTORE;
import static com.android.launcher3.LauncherPrefs.SHOULD_SHOW_SMARTSPACE;
-import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SMARTSPACE_REMOVAL;
import static com.android.launcher3.config.FeatureFlags.SMARTSPACE_AS_A_WIDGET;
@@ -77,9 +76,12 @@
import com.android.launcher3.icons.cache.IconCacheUpdateHandler;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.IconRequestInfo;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.ItemInfoWithIcon;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.pm.InstallSessionHelper;
@@ -99,7 +101,6 @@
import com.android.launcher3.widget.WidgetInflater;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -234,6 +235,7 @@
if (Objects.equals(mApp.getInvariantDeviceProfile().dbFile, mDbName)) {
verifyNotStopped();
sanitizeFolders(mItemsDeleted);
+ sanitizeAppPairs();
sanitizeWidgetsShortcutsAndPackages();
logASplit("sanitizeData");
}
@@ -482,14 +484,20 @@
}
/**
- * After all items have been processed and added to the BgDataModel, this method requests
- * high-res icons for the items that are part of an app pair
+ * After all items have been processed and added to the BgDataModel, this method sorts and
+ * requests high-res icons for the items that are part of an app pair.
*/
private void processAppPairItems() {
- mBgDataModel.workspaceItems.stream()
- .filter((itemInfo -> itemInfo.itemType == ITEM_TYPE_APP_PAIR))
- .forEach(fi -> ((FolderInfo) fi).contents.forEach(item ->
- mIconCache.getTitleAndIcon(item, false /*useLowResIcon*/)));
+ for (CollectionInfo collection : mBgDataModel.collections) {
+ if (!(collection instanceof AppPairInfo appPair)) {
+ continue;
+ }
+
+ appPair.getContents().sort(Folder.ITEM_POS_COMPARATOR);
+ // Fetch hi-res icons if needed.
+ appPair.getContents().stream().filter(ItemInfoWithIcon::usingLowResIcon)
+ .forEach(member -> mIconCache.getTitleAndIcon(member, false));
+ }
}
/**
@@ -545,20 +553,21 @@
// Sort the folder items, update ranks, and make sure all preview items are high res.
List<FolderGridOrganizer> verifiers = mApp.getInvariantDeviceProfile().supportedProfiles
.stream().map(FolderGridOrganizer::new).toList();
- for (FolderInfo folder : mBgDataModel.folders) {
- Collections.sort(folder.contents, Folder.ITEM_POS_COMPARATOR);
+ for (CollectionInfo collection : mBgDataModel.collections) {
+ if (!(collection instanceof FolderInfo folder)) {
+ continue;
+ }
+
+ folder.getContents().sort(Folder.ITEM_POS_COMPARATOR);
verifiers.forEach(verifier -> verifier.setFolderInfo(folder));
- int size = folder.contents.size();
+ int size = folder.getContents().size();
// Update ranks here to ensure there are no gaps caused by removed folder items.
// Ranks are the source of truth for folder items, so cellX and cellY can be
// ignored for now. Database will be updated once user manually modifies folder.
for (int rank = 0; rank < size; ++rank) {
- WorkspaceItemInfo info = folder.contents.get(rank);
- // rank is used differently in app pairs, so don't reset
- if (folder.itemType != ITEM_TYPE_APP_PAIR) {
- info.rank = rank;
- }
+ WorkspaceItemInfo info = folder.getContents().get(rank);
+ info.rank = rank;
if (info.usingLowResIcon() && info.itemType == Favorites.ITEM_TYPE_APPLICATION
&& verifiers.stream().anyMatch(it -> it.isItemInPreview(info.rank))) {
@@ -611,14 +620,32 @@
IntArray deletedFolderIds = mApp.getModel().getModelDbController().deleteEmptyFolders();
synchronized (mBgDataModel) {
for (int folderId : deletedFolderIds) {
- mBgDataModel.workspaceItems.remove(mBgDataModel.folders.get(folderId));
- mBgDataModel.folders.remove(folderId);
+ mBgDataModel.workspaceItems.remove(mBgDataModel.collections.get(folderId));
+ mBgDataModel.collections.remove(folderId);
mBgDataModel.itemsIdMap.remove(folderId);
}
}
}
}
+ /** Cleans up app pairs if they don't have the right number of member apps (2). */
+ private void sanitizeAppPairs() {
+ IntArray deletedAppPairIds = mApp.getModel().getModelDbController().deleteBadAppPairs();
+ IntArray deletedAppIds = mApp.getModel().getModelDbController().deleteUnparentedApps();
+
+ IntArray deleted = new IntArray();
+ deleted.addAll(deletedAppPairIds);
+ deleted.addAll(deletedAppIds);
+
+ synchronized (mBgDataModel) {
+ for (int id : deleted) {
+ mBgDataModel.workspaceItems.remove(mBgDataModel.collections.get(id));
+ mBgDataModel.collections.remove(id);
+ mBgDataModel.itemsIdMap.remove(id);
+ }
+ }
+ }
+
private void sanitizeWidgetsShortcutsAndPackages() {
Context context = mApp.getContext();
@@ -754,16 +781,16 @@
private void loadFolderNames() {
FolderNameProvider provider = FolderNameProvider.newInstance(mApp.getContext(),
- mBgAllAppsList.data, mBgDataModel.folders);
+ mBgAllAppsList.data, mBgDataModel.collections);
synchronized (mBgDataModel) {
- for (int i = 0; i < mBgDataModel.folders.size(); i++) {
+ for (int i = 0; i < mBgDataModel.collections.size(); i++) {
FolderNameInfos suggestionInfos = new FolderNameInfos();
- FolderInfo info = mBgDataModel.folders.valueAt(i);
- if (info.suggestedFolderNames == null) {
- provider.getSuggestedFolderName(mApp.getContext(), info.contents,
+ CollectionInfo info = mBgDataModel.collections.valueAt(i);
+ if (info instanceof FolderInfo fi && fi.suggestedFolderNames == null) {
+ provider.getSuggestedFolderName(mApp.getContext(), fi.getContents(),
suggestionInfos);
- info.suggestedFolderNames = suggestionInfos;
+ fi.suggestedFolderNames = suggestionInfos;
}
}
}
diff --git a/src/com/android/launcher3/model/ModelDbController.java b/src/com/android/launcher3/model/ModelDbController.java
index 8ed554a..7e1d40d 100644
--- a/src/com/android/launcher3/model/ModelDbController.java
+++ b/src/com/android/launcher3/model/ModelDbController.java
@@ -15,11 +15,15 @@
*/
package com.android.launcher3.model;
+import static android.provider.BaseColumns._ID;
import static android.util.Base64.NO_PADDING;
import static android.util.Base64.NO_WRAP;
import static com.android.launcher3.DefaultLayoutParser.RES_PARTNER_DEFAULT_LAYOUT;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE;
+import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
+import static com.android.launcher3.LauncherSettings.Favorites.TABLE_NAME;
import static com.android.launcher3.LauncherSettings.Favorites.addTableToDb;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_KEY;
import static com.android.launcher3.LauncherSettings.Settings.LAYOUT_DIGEST_LABEL;
@@ -391,6 +395,68 @@
}
}
+ /**
+ * Deletes any app pair that doesn't contain 2 member apps from the DB.
+ * @return Ids of deleted app pairs.
+ */
+ @WorkerThread
+ public IntArray deleteBadAppPairs() {
+ createDbIfNotExists();
+
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ try (SQLiteTransaction t = new SQLiteTransaction(db)) {
+ // Select all entries with ITEM_TYPE = ITEM_TYPE_APP_PAIR whose id does not appear
+ // exactly twice in the CONTAINER column.
+ String selection =
+ ITEM_TYPE + " = " + ITEM_TYPE_APP_PAIR
+ + " AND " + _ID + " NOT IN"
+ + " (SELECT " + CONTAINER + " FROM " + TABLE_NAME
+ + " GROUP BY " + CONTAINER + " HAVING COUNT(*) = 2)";
+
+ IntArray appPairIds = LauncherDbUtils.queryIntArray(false, db, TABLE_NAME,
+ _ID, selection, null, null);
+ if (!appPairIds.isEmpty()) {
+ db.delete(TABLE_NAME, Utilities.createDbSelectionQuery(
+ _ID, appPairIds), null);
+ }
+ t.commit();
+ return appPairIds;
+ } catch (SQLException ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ return new IntArray();
+ }
+ }
+
+ /**
+ * Deletes any app with a container id that doesn't exist.
+ * @return Ids of deleted apps.
+ */
+ @WorkerThread
+ public IntArray deleteUnparentedApps() {
+ createDbIfNotExists();
+
+ SQLiteDatabase db = mOpenHelper.getWritableDatabase();
+ try (SQLiteTransaction t = new SQLiteTransaction(db)) {
+ // Select all entries whose container id does not appear in the database.
+ String selection =
+ CONTAINER + " >= 0"
+ + " AND " + CONTAINER + " NOT IN"
+ + " (SELECT " + _ID + " FROM " + TABLE_NAME + ")";
+
+ IntArray appIds = LauncherDbUtils.queryIntArray(false, db, TABLE_NAME,
+ _ID, selection, null, null);
+ if (!appIds.isEmpty()) {
+ db.delete(TABLE_NAME, Utilities.createDbSelectionQuery(
+ _ID, appIds), null);
+ }
+ t.commit();
+ return appIds;
+ } catch (SQLException ex) {
+ Log.e(TAG, ex.getMessage(), ex);
+ return new IntArray();
+ }
+ }
+
private static void addModifiedTime(ContentValues values) {
values.put(LauncherSettings.Favorites.MODIFIED, System.currentTimeMillis());
}
diff --git a/src/com/android/launcher3/model/ModelWriter.java b/src/com/android/launcher3/model/ModelWriter.java
index 55093a3..b477cb1 100644
--- a/src/com/android/launcher3/model/ModelWriter.java
+++ b/src/com/android/launcher3/model/ModelWriter.java
@@ -37,7 +37,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.logging.FileLog;
import com.android.launcher3.model.BgDataModel.Callbacks;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
@@ -275,7 +275,7 @@
public void deleteItemsFromDatabase(@NonNull final Predicate<ItemInfo> matcher,
@Nullable final String reason) {
deleteItemsFromDatabase(StreamSupport.stream(mBgDataModel.itemsIdMap.spliterator(), false)
- .filter(matcher).collect(Collectors.toList()), reason);
+ .filter(matcher).collect(Collectors.toList()), reason);
}
/**
@@ -302,15 +302,15 @@
/**
* Remove the specified folder and all its contents from the database.
*/
- public void deleteFolderAndContentsFromDatabase(final FolderInfo info) {
+ public void deleteCollectionAndContentsFromDatabase(final CollectionInfo info) {
ModelVerifier verifier = new ModelVerifier();
notifyDelete(Collections.singleton(info));
enqueueDeleteRunnable(newModelTask(() -> {
mModel.getModelDbController().delete(Favorites.TABLE_NAME,
Favorites.CONTAINER + "=" + info.id, null);
- mBgDataModel.removeItem(mContext, info.contents);
- info.contents.clear();
+ mBgDataModel.removeItem(mContext, info.getContents());
+ info.getContents().clear();
mModel.getModelDbController().delete(Favorites.TABLE_NAME,
Favorites._ID + "=" + info.id, null);
@@ -458,12 +458,12 @@
if (item.container != Favorites.CONTAINER_DESKTOP &&
item.container != Favorites.CONTAINER_HOTSEAT) {
- // Item is in a folder, make sure this folder exists
- if (!mBgDataModel.folders.containsKey(item.container)) {
+ // Item is in a collection, make sure this collection exists
+ if (!mBgDataModel.collections.containsKey(item.container)) {
// An items container is being set to a that of an item which is not in
// the list of Folders.
String msg = "item: " + item + " container being set to: " +
- item.container + ", not in the list of folders";
+ item.container + ", not in the list of collections";
Log.e(TAG, msg);
}
}
diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java
index 0ba468d..ea1ae2e 100644
--- a/src/com/android/launcher3/model/PackageUpdatedTask.java
+++ b/src/com/android/launcher3/model/PackageUpdatedTask.java
@@ -361,17 +361,10 @@
}
if (!removedPackages.isEmpty() || !removedComponents.isEmpty()) {
- // This predicate is used to mark an ItemInfo for removal if its package or component
- // is marked for removal.
- Predicate<ItemInfo> removeAppMatch =
+ Predicate<ItemInfo> removeMatch =
ItemInfoMatcher.ofPackages(removedPackages, mUser)
.or(ItemInfoMatcher.ofComponents(removedComponents, mUser))
.and(ItemInfoMatcher.ofItemIds(forceKeepShortcuts).negate());
- // This predicate is used to mark an app pair for removal if it contains an app marked
- // for removal.
- Predicate<ItemInfo> removeAppPairMatch =
- ItemInfoMatcher.forAppPairMatch(removeAppMatch);
- Predicate<ItemInfo> removeMatch = removeAppMatch.or(removeAppPairMatch);
deleteAndBindComponentsRemoved(removeMatch,
"removed because the corresponding package or component is removed. "
+ "mOp=" + mOp + " removedPackages=" + removedPackages.stream().collect(
diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
index 22e5eb4..aa29290 100644
--- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
+++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt
@@ -32,6 +32,8 @@
import com.android.launcher3.Utilities
import com.android.launcher3.backuprestore.LauncherRestoreEventLogger.RestoreError
import com.android.launcher3.logging.FileLog
+import com.android.launcher3.model.data.AppPairInfo
+import com.android.launcher3.model.data.FolderInfo
import com.android.launcher3.model.data.IconRequestInfo
import com.android.launcher3.model.data.ItemInfoWithIcon
import com.android.launcher3.model.data.LauncherAppWidgetInfo
@@ -360,25 +362,40 @@
}
/**
- * Loads the folder information from the database and formats it into a FolderInfo. Some of the
- * processing for folder content items is done in LoaderTask after all the items in the
- * workspace have been loaded. The loaded FolderInfos are stored in the BgDataModel.
+ * Loads CollectionInfo information from the database and formats it. This function runs while
+ * LoaderTask is still active; some of the processing for folder content items is done after all
+ * the items in the workspace have been loaded. The loaded and formatted CollectionInfo is then
+ * stored in the BgDataModel.
*/
private fun processFolderOrAppPair() {
- val folderInfo =
- bgDataModel.findOrMakeFolder(c.id).apply {
- c.applyCommonProperties(this)
- itemType = c.itemType
- // Do not trim the folder label, as is was set by the user.
- title = c.getString(c.mTitleIndex)
- spanX = 1
- spanY = 1
- options = c.options
- }
+ var collection = bgDataModel.findOrMakeFolder(c.id)
+ // If we generated a placeholder Folder before this point, it may need to be replaced with
+ // an app pair.
+ if (c.itemType == Favorites.ITEM_TYPE_APP_PAIR && collection is FolderInfo) {
+ val folderInfo: FolderInfo = collection
+ val newAppPair = AppPairInfo()
+ // Move the placeholder's contents over to the new app pair.
+ folderInfo.contents.forEach(newAppPair::add)
+ collection = newAppPair
+ // Remove the placeholder and add the app pair into the data model.
+ bgDataModel.collections.remove(c.id)
+ bgDataModel.collections.put(c.id, collection)
+ }
- // no special handling required for restored folders
+ c.applyCommonProperties(collection)
+ // Do not trim the folder label, as is was set by the user.
+ collection.title = c.getString(c.mTitleIndex)
+ collection.spanX = 1
+ collection.spanY = 1
+ if (collection is FolderInfo) {
+ collection.options = c.options
+ } else {
+ // An app pair may be inside another folder, so it needs to preserve rank information.
+ collection.rank = c.rank
+ }
+
c.markRestored()
- c.checkAndAddItem(folderInfo, bgDataModel, memoryLogger)
+ c.checkAndAddItem(collection, bgDataModel, memoryLogger)
}
/**
diff --git a/src/com/android/launcher3/model/data/AppPairInfo.kt b/src/com/android/launcher3/model/data/AppPairInfo.kt
new file mode 100644
index 0000000..4081316
--- /dev/null
+++ b/src/com/android/launcher3/model/data/AppPairInfo.kt
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model.data
+
+import android.content.Context
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.logger.LauncherAtom
+import com.android.launcher3.views.ActivityContext
+
+/** A type of app collection that launches multiple apps into split screen. */
+class AppPairInfo() : CollectionInfo() {
+ init {
+ itemType = LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR
+ }
+
+ /** Convenience constructor, calls primary constructor and init block */
+ constructor(app1: WorkspaceItemInfo, app2: WorkspaceItemInfo) : this() {
+ add(app1)
+ add(app2)
+ }
+
+ /** Adds an element to the contents array. */
+ override fun add(item: WorkspaceItemInfo) {
+ contents.add(item)
+ }
+
+ /** Returns the first app in the pair. */
+ fun getFirstApp() = contents[0]
+
+ /** Returns the second app in the pair. */
+ fun getSecondApp() = contents[1]
+
+ /** Returns if either of the app pair members is currently disabled. */
+ override fun isDisabled() = anyMatch { it.isDisabled }
+
+ /** Checks if the app pair is launchable at the current screen size. */
+ fun isLaunchable(context: Context) =
+ (ActivityContext.lookupContext(context) as ActivityContext).getDeviceProfile().isTablet ||
+ noneMatch { it.hasStatusFlag(WorkspaceItemInfo.FLAG_NON_RESIZEABLE) }
+
+ /** Generates an ItemInfo for logging. */
+ override fun buildProto(cInfo: CollectionInfo?): LauncherAtom.ItemInfo {
+ val appPairIcon = LauncherAtom.FolderIcon.newBuilder().setCardinality(contents.size)
+ appPairIcon.setLabelInfo(title.toString())
+ return getDefaultItemInfoBuilder()
+ .setFolderIcon(appPairIcon)
+ .setRank(rank)
+ .setContainerInfo(getContainerInfo())
+ .build()
+ }
+}
diff --git a/src/com/android/launcher3/model/data/CollectionInfo.kt b/src/com/android/launcher3/model/data/CollectionInfo.kt
new file mode 100644
index 0000000..2b865a5
--- /dev/null
+++ b/src/com/android/launcher3/model/data/CollectionInfo.kt
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model.data
+
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.logger.LauncherAtom
+import com.android.launcher3.util.ContentWriter
+import java.util.function.Predicate
+
+abstract class CollectionInfo : ItemInfo() {
+ var contents: ArrayList<WorkspaceItemInfo> = ArrayList()
+
+ abstract fun add(item: WorkspaceItemInfo)
+
+ /** Convenience function. Checks contents to see if any match a given predicate. */
+ fun anyMatch(matcher: Predicate<in WorkspaceItemInfo>): Boolean {
+ return contents.stream().anyMatch(matcher)
+ }
+
+ /** Convenience function. Returns true if none of the contents match a given predicate. */
+ fun noneMatch(matcher: Predicate<in WorkspaceItemInfo>): Boolean {
+ return contents.stream().noneMatch(matcher)
+ }
+
+ override fun onAddToDatabase(writer: ContentWriter) {
+ super.onAddToDatabase(writer)
+ writer.put(LauncherSettings.Favorites.TITLE, title)
+ }
+
+ /** Returns the collection wrapped as {@link LauncherAtom.ItemInfo} for logging. */
+ override fun buildProto(): LauncherAtom.ItemInfo {
+ return buildProto(null)
+ }
+}
diff --git a/src/com/android/launcher3/model/data/FolderInfo.java b/src/com/android/launcher3/model/data/FolderInfo.java
index 83ba2b3..1bbb2fe 100644
--- a/src/com/android/launcher3/model/data/FolderInfo.java
+++ b/src/com/android/launcher3/model/data/FolderInfo.java
@@ -24,8 +24,6 @@
import static com.android.launcher3.logger.LauncherAtom.Attribute.MANUAL_LABEL;
import static com.android.launcher3.logger.LauncherAtom.Attribute.SUGGESTED_LABEL;
-import android.os.Process;
-
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -49,7 +47,7 @@
/**
* Represents a folder containing shortcuts or apps.
*/
-public class FolderInfo extends ItemInfo {
+public class FolderInfo extends CollectionInfo {
public static final int NO_FLAGS = 0x00000000;
@@ -100,27 +98,15 @@
public FolderNameInfos suggestedFolderNames;
- /**
- * The apps and shortcuts
- */
- public ArrayList<WorkspaceItemInfo> contents = new ArrayList<>();
-
private ArrayList<FolderListener> mListeners = new ArrayList<>();
public FolderInfo() {
itemType = LauncherSettings.Favorites.ITEM_TYPE_FOLDER;
- user = Process.myUserHandle();
}
- /**
- * Create an app pair, a type of app collection that launches multiple apps into split screen
- */
- public static FolderInfo createAppPair(WorkspaceItemInfo app1, WorkspaceItemInfo app2) {
- FolderInfo newAppPair = new FolderInfo();
- newAppPair.itemType = LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR;
- newAppPair.add(app1, /* animate */ false);
- newAppPair.add(app2, /* animate */ false);
- return newAppPair;
+ /** Adds a app or shortcut to the contents array without animation. */
+ public void add(@NonNull WorkspaceItemInfo item) {
+ add(item, false /* animate */);
}
/**
@@ -129,15 +115,15 @@
* @param item
*/
public void add(WorkspaceItemInfo item, boolean animate) {
- add(item, contents.size(), animate);
+ add(item, getContents().size(), animate);
}
/**
* Add an app or shortcut for a specified rank.
*/
public void add(WorkspaceItemInfo item, int rank, boolean animate) {
- rank = Utilities.boundToRange(rank, 0, contents.size());
- contents.add(rank, item);
+ rank = Utilities.boundToRange(rank, 0, getContents().size());
+ getContents().add(rank, item);
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onAdd(item, rank);
}
@@ -157,7 +143,7 @@
* Remove all matching app or shortcut. Does not change the DB.
*/
public void removeAll(List<WorkspaceItemInfo> items, boolean animate) {
- contents.removeAll(items);
+ getContents().removeAll(items);
for (int i = 0; i < mListeners.size(); i++) {
mListeners.get(i).onRemove(items);
}
@@ -167,8 +153,7 @@
@Override
public void onAddToDatabase(@NonNull ContentWriter writer) {
super.onAddToDatabase(writer);
- writer.put(LauncherSettings.Favorites.TITLE, title)
- .put(LauncherSettings.Favorites.OPTIONS, options);
+ writer.put(LauncherSettings.Favorites.OPTIONS, options);
}
public void addListener(FolderListener listener) {
@@ -219,9 +204,9 @@
@NonNull
@Override
- public LauncherAtom.ItemInfo buildProto(@Nullable FolderInfo fInfo) {
+ public LauncherAtom.ItemInfo buildProto(@Nullable CollectionInfo cInfo) {
FolderIcon.Builder folderIcon = FolderIcon.newBuilder()
- .setCardinality(contents.size());
+ .setCardinality(getContents().size());
if (LabelState.SUGGESTED.equals(getLabelState())) {
folderIcon.setLabelInfo(title.toString());
}
@@ -278,20 +263,11 @@
public ItemInfo makeShallowCopy() {
FolderInfo folderInfo = new FolderInfo();
folderInfo.copyFrom(this);
- folderInfo.contents = this.contents;
+ folderInfo.setContents(this.getContents());
return folderInfo;
}
/**
- * Returns {@link LauncherAtom.FolderIcon} wrapped as {@link LauncherAtom.ItemInfo} for logging.
- */
- @NonNull
- @Override
- public LauncherAtom.ItemInfo buildProto() {
- return buildProto(null);
- }
-
- /**
* Returns index of the accepted suggestion.
*/
public OptionalInt getAcceptedSuggestionIndex() {
@@ -371,13 +347,4 @@
}
return LauncherAtom.ToState.TO_STATE_UNSPECIFIED;
}
-
- @Override
- public boolean isDisabled() {
- if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APP_PAIR) {
- return contents.stream().anyMatch((WorkspaceItemInfo::isDisabled));
- }
-
- return super.isDisabled();
- }
}
diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java
index f7cff78..8c3efd7 100644
--- a/src/com/android/launcher3/model/data/ItemInfo.java
+++ b/src/com/android/launcher3/model/data/ItemInfo.java
@@ -349,10 +349,9 @@
/**
* Creates {@link LauncherAtom.ItemInfo} with important fields and parent container info.
- * @param fInfo
*/
@NonNull
- public LauncherAtom.ItemInfo buildProto(@Nullable final FolderInfo fInfo) {
+ public LauncherAtom.ItemInfo buildProto(@Nullable final CollectionInfo cInfo) {
LauncherAtom.ItemInfo.Builder itemBuilder = getDefaultItemInfoBuilder();
Optional<ComponentName> nullableComponent = Optional.ofNullable(getTargetComponent());
switch (itemType) {
@@ -398,21 +397,21 @@
default:
break;
}
- if (fInfo != null) {
+ if (cInfo != null) {
LauncherAtom.FolderContainer.Builder folderBuilder =
LauncherAtom.FolderContainer.newBuilder();
folderBuilder.setGridX(cellX).setGridY(cellY).setPageIndex(screenId);
- switch (fInfo.container) {
+ switch (cInfo.container) {
case CONTAINER_HOTSEAT:
case CONTAINER_HOTSEAT_PREDICTION:
folderBuilder.setHotseat(LauncherAtom.HotseatContainer.newBuilder()
- .setIndex(fInfo.screenId));
+ .setIndex(cInfo.screenId));
break;
case CONTAINER_DESKTOP:
folderBuilder.setWorkspace(LauncherAtom.WorkspaceContainer.newBuilder()
- .setPageIndex(fInfo.screenId)
- .setGridX(fInfo.cellX).setGridY(fInfo.cellY));
+ .setPageIndex(cInfo.screenId)
+ .setGridX(cInfo.cellX).setGridY(cInfo.cellY));
break;
}
itemBuilder.setContainerInfo(ContainerInfo.newBuilder().setFolder(folderBuilder));
diff --git a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
index 6fa8c54..f4dda55 100644
--- a/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
+++ b/src/com/android/launcher3/model/data/LauncherAppWidgetInfo.java
@@ -271,8 +271,8 @@
@NonNull
@Override
- public LauncherAtom.ItemInfo buildProto(@Nullable FolderInfo folderInfo) {
- LauncherAtom.ItemInfo info = super.buildProto(folderInfo);
+ public LauncherAtom.ItemInfo buildProto(@Nullable CollectionInfo collectionInfo) {
+ LauncherAtom.ItemInfo info = super.buildProto(collectionInfo);
return info.toBuilder()
.setWidget(info.getWidget().toBuilder().setWidgetFeatures(widgetFeatures))
.addItemAttributes(getAttribute(sourceContainer))
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
index 911568c..0c25e96 100644
--- a/src/com/android/launcher3/touch/ItemClickHandler.java
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -53,6 +53,7 @@
import com.android.launcher3.logging.InstanceIdSequence;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.ItemInfoWithIcon;
@@ -101,11 +102,9 @@
if (tag instanceof WorkspaceItemInfo) {
onClickAppShortcut(v, (WorkspaceItemInfo) tag, launcher);
} else if (tag instanceof FolderInfo) {
- if (v instanceof FolderIcon) {
- onClickFolderIcon(v);
- } else if (v instanceof AppPairIcon) {
- onClickAppPairIcon(v);
- }
+ onClickFolderIcon(v);
+ } else if (tag instanceof AppPairInfo) {
+ onClickAppPairIcon(v);
} else if (tag instanceof AppInfo) {
startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
} else if (tag instanceof LauncherAppWidgetInfo) {
@@ -150,7 +149,7 @@
private static void onClickAppPairIcon(View v) {
Launcher launcher = Launcher.getLauncher(v.getContext());
AppPairIcon appPairIcon = (AppPairIcon) v;
- if (!appPairIcon.isLaunchableAtScreenSize()) {
+ if (!appPairIcon.getInfo().isLaunchable(launcher)) {
// Display a message for app pairs that are disabled due to screen size
boolean isFoldable = InvariantDeviceProfile.INSTANCE.get(launcher)
.supportedProfiles.stream().anyMatch(dp -> dp.isTwoPanels);
@@ -159,8 +158,8 @@
: R.string.app_pair_unlaunchable_at_screen_size,
Toast.LENGTH_SHORT).show();
} else if (appPairIcon.getInfo().isDisabled()) {
- WorkspaceItemInfo app1 = appPairIcon.getInfo().contents.get(0);
- WorkspaceItemInfo app2 = appPairIcon.getInfo().contents.get(1);
+ WorkspaceItemInfo app1 = appPairIcon.getInfo().getFirstApp();
+ WorkspaceItemInfo app2 = appPairIcon.getInfo().getSecondApp();
// Show the user why the app pair is disabled.
if (app1.isDisabled() && !handleDisabledItemClicked(app1, launcher)) {
// If handleDisabledItemClicked() did not handle the error message, we initiate an
diff --git a/src/com/android/launcher3/util/ItemInflater.kt b/src/com/android/launcher3/util/ItemInflater.kt
index 0f8311d..ebf4656 100644
--- a/src/com/android/launcher3/util/ItemInflater.kt
+++ b/src/com/android/launcher3/util/ItemInflater.kt
@@ -29,6 +29,7 @@
import com.android.launcher3.apppairs.AppPairIcon
import com.android.launcher3.folder.FolderIcon
import com.android.launcher3.model.ModelWriter
+import com.android.launcher3.model.data.AppPairInfo
import com.android.launcher3.model.data.FolderInfo
import com.android.launcher3.model.data.ItemInfo
import com.android.launcher3.model.data.LauncherAppWidgetInfo
@@ -81,7 +82,7 @@
R.layout.app_pair_icon,
context,
parent,
- item as FolderInfo,
+ item as AppPairInfo,
BubbleTextView.DISPLAY_WORKSPACE
)
Favorites.ITEM_TYPE_APPWIDGET,
diff --git a/src/com/android/launcher3/util/ItemInfoMatcher.java b/src/com/android/launcher3/util/ItemInfoMatcher.java
index 3074111..063313a 100644
--- a/src/com/android/launcher3/util/ItemInfoMatcher.java
+++ b/src/com/android/launcher3/util/ItemInfoMatcher.java
@@ -65,20 +65,11 @@
* Returns a matcher for items within folders.
*/
public static Predicate<ItemInfo> forFolderMatch(Predicate<ItemInfo> childOperator) {
- return info -> info instanceof FolderInfo && ((FolderInfo) info).contents.stream()
+ return info -> info instanceof FolderInfo && ((FolderInfo) info).getContents().stream()
.anyMatch(childOperator);
}
/**
- * Returns a matcher for items within app pairs.
- */
- public static Predicate<ItemInfo> forAppPairMatch(Predicate<ItemInfo> childOperator) {
- Predicate<ItemInfo> isAppPair = info ->
- info instanceof FolderInfo fi && fi.itemType == Favorites.ITEM_TYPE_APP_PAIR;
- return isAppPair.and(forFolderMatch(childOperator));
- }
-
- /**
* Returns a matcher for items with provided ids
*/
public static Predicate<ItemInfo> ofItemIds(IntSet ids) {
diff --git a/src/com/android/launcher3/util/LauncherBindableItemsContainer.java b/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
index 69786bb..02779ce 100644
--- a/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
+++ b/src/com/android/launcher3/util/LauncherBindableItemsContainer.java
@@ -23,6 +23,7 @@
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.graphics.PreloadIconDrawable;
+import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
@@ -59,7 +60,7 @@
: null);
} else if (info instanceof FolderInfo && v instanceof FolderIcon) {
((FolderIcon) v).updatePreviewItems(updates::contains);
- } else if (info instanceof FolderInfo && v instanceof AppPairIcon appPairIcon) {
+ } else if (info instanceof AppPairInfo && v instanceof AppPairIcon appPairIcon) {
appPairIcon.maybeRedrawForWorkspaceUpdate(updates::contains);
}
@@ -89,7 +90,7 @@
((PendingAppWidgetHostView) v).applyState();
} else if (v instanceof FolderIcon && info instanceof FolderInfo) {
((FolderIcon) v).updatePreviewItems(updates::contains);
- } else if (info instanceof FolderInfo && v instanceof AppPairIcon appPairIcon) {
+ } else if (info instanceof AppPairInfo && v instanceof AppPairIcon appPairIcon) {
appPairIcon.maybeRedrawForWorkspaceUpdate(updates::contains);
}
// process all the shortcuts
diff --git a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
index a501960..a916252 100644
--- a/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
+++ b/src/com/android/launcher3/widget/PendingAddWidgetInfo.java
@@ -25,7 +25,7 @@
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.PendingAddItemInfo;
import com.android.launcher3.logger.LauncherAtom;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.LauncherAppWidgetInfo;
import com.android.launcher3.widget.picker.WidgetRecommendationCategory;
import com.android.launcher3.widget.util.WidgetSizes;
@@ -82,8 +82,8 @@
@NonNull
@Override
- public LauncherAtom.ItemInfo buildProto(@Nullable FolderInfo folderInfo) {
- LauncherAtom.ItemInfo info = super.buildProto(folderInfo);
+ public LauncherAtom.ItemInfo buildProto(@Nullable CollectionInfo collectionInfo) {
+ LauncherAtom.ItemInfo info = super.buildProto(collectionInfo);
return info.toBuilder()
.addItemAttributes(LauncherAppWidgetInfo.getAttribute(sourceContainer))
.build();
diff --git a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
index ba6c4cf..fcd2571 100644
--- a/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java
@@ -27,7 +27,6 @@
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Rect;
-import android.os.Build;
import android.os.Bundle;
import android.os.Parcelable;
import android.os.Process;
@@ -47,12 +46,9 @@
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;
-import android.window.BackEvent;
-import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.Px;
-import androidx.annotation.RequiresApi;
import androidx.annotation.VisibleForTesting;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.RecyclerView;
@@ -904,17 +900,6 @@
}
@Override
- @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)
- public void onBackProgressed(@NonNull BackEvent backEvent) {
- super.onBackProgressed(backEvent);
- // In two pane picker, scroll bar is always hidden.
- if (!isTwoPane()) {
- mFastScroller.setVisibility(
- backEvent.getProgress() > 0 ? View.INVISIBLE : View.VISIBLE);
- }
- }
-
- @Override
public void onBackInvoked() {
if (mIsInSearchMode) {
mSearchBar.reset();
diff --git a/tests/Android.bp b/tests/Android.bp
index c1d4180..13a1cbb 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -86,6 +86,7 @@
"mockito-target-extended-minus-junit4",
"launcher_log_protos_lite",
"truth",
+ "kotlinx_coroutines_test",
"platform-test-rules",
"testables",
"com_android_launcher3_flags_lib",
diff --git a/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
index b86333c..0c3081f 100644
--- a/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
+++ b/tests/multivalentTests/src/com/android/launcher3/celllayout/FavoriteItemsTransaction.java
@@ -26,7 +26,7 @@
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.model.ModelDbController;
-import com.android.launcher3.model.data.FolderInfo;
+import com.android.launcher3.model.data.CollectionInfo;
import com.android.launcher3.model.data.ItemInfo;
import com.android.launcher3.provider.LauncherDbUtils.SQLiteTransaction;
import com.android.launcher3.util.ContentWriter;
@@ -73,9 +73,8 @@
ContentWriter writer = new ContentWriter(mContext);
ItemInfo item = mItemsToSubmit.get(i).get();
- if (item.itemType == LauncherSettings.Favorites.ITEM_TYPE_FOLDER) {
- FolderInfo folderInfo = (FolderInfo) item;
- for (ItemInfo itemInfo : folderInfo.contents) {
+ if (item instanceof CollectionInfo ci) {
+ for (ItemInfo itemInfo : ci.getContents()) {
itemInfo.container = i;
containerItems.add(itemInfo);
}
diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
index eea4fe5..476bda5 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java
@@ -26,7 +26,7 @@
import static com.android.launcher3.util.rule.TestStabilityRule.PLATFORM_POSTSUBMIT;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.doNothing;
@@ -80,7 +80,7 @@
private PrivateProfileManager mPrivateProfileManager;
@Mock
- private ActivityAllAppsContainerView mActivityAllAppsContainerView;
+ private ActivityAllAppsContainerView mAllApps;
@Mock
private StatsLogManager mStatsLogManager;
@Mock
@@ -90,13 +90,13 @@
@Mock
private Context mContext;
@Mock
- private AllAppsStore mAllAppsStore;
+ private AllAppsStore<?> mAllAppsStore;
@Mock
private PackageManager mPackageManager;
@Mock
private LauncherApps mLauncherApps;
-
- private boolean mRunnableCalled = false;
+ @Mock
+ private AllAppsRecyclerView mAllAppsRecyclerView;
@Before
public void setUp() {
@@ -105,8 +105,9 @@
.thenReturn(Arrays.asList(MAIN_HANDLE, PRIVATE_HANDLE));
when(mUserCache.getUserInfo(Process.myUserHandle())).thenReturn(MAIN_ICON_INFO);
when(mUserCache.getUserInfo(PRIVATE_HANDLE)).thenReturn(PRIVATE_ICON_INFO);
- when(mActivityAllAppsContainerView.getContext()).thenReturn(mContext);
- when(mActivityAllAppsContainerView.getAppsStore()).thenReturn(mAllAppsStore);
+ when(mAllApps.getContext()).thenReturn(mContext);
+ when(mAllApps.getAppsStore()).thenReturn(mAllAppsStore);
+ when(mAllApps.getActiveRecyclerView()).thenReturn(mAllAppsRecyclerView);
when(mContext.getPackageManager()).thenReturn(mPackageManager);
when(mPackageManager.resolveActivity(any(), any())).thenReturn(new ResolveInfo());
when(mContext.getSystemService(LauncherApps.class)).thenReturn(mLauncherApps);
@@ -117,7 +118,7 @@
.thenReturn("com.android.launcher3.tests.privateProfileManager");
when(mLauncherApps.getPreInstalledSystemPackages(any())).thenReturn(new ArrayList<>());
mPrivateProfileManager = new PrivateProfileManager(mUserManager,
- mActivityAllAppsContainerView, mStatsLogManager, mUserCache);
+ mAllApps, mStatsLogManager, mUserCache);
}
@Test
@@ -134,7 +135,7 @@
public void unlockPrivateProfile_requestsQuietModeAsFalse() throws Exception {
when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED)).thenReturn(true);
- mPrivateProfileManager.unlockPrivateProfile(() -> {});
+ mPrivateProfileManager.unlockPrivateProfile();
awaitTasksCompleted();
Mockito.verify(mUserManager).requestQuietModeEnabled(false, PRIVATE_HANDLE);
@@ -160,20 +161,36 @@
@Test
@TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/320703862
- public void transitioningToUnlocked_resetCallsPendingRunnable() throws Exception {
+ public void transitioningToUnlocked_resetCallsPostUnlock() throws Exception {
PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
.thenReturn(false);
+ doNothing().when(privateProfileManager).expandPrivateSpace();
when(privateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
- mRunnableCalled = false;
- privateProfileManager.unlockPrivateProfile(this::testRunnable);
+ privateProfileManager.unlockPrivateProfile();
privateProfileManager.reset();
awaitTasksCompleted();
- Mockito.verify(privateProfileManager).applyUnlockRunnable();
- assertTrue("Unlock Runnable not Invoked", mRunnableCalled);
+ Mockito.verify(privateProfileManager).postUnlock();
+ }
+
+ @Test
+ @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT)
+ public void transitioningToLocked_resetCallsExecuteLock() throws Exception {
+ PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+ doNothing().when(privateProfileManager).resetPrivateSpaceDecorator(anyInt());
+ when(mAllAppsStore.hasModelFlag(FLAG_PRIVATE_PROFILE_QUIET_MODE_ENABLED))
+ .thenReturn(true);
+ doNothing().when(privateProfileManager).expandPrivateSpace();
+ when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+
+ privateProfileManager.lockPrivateProfile();
+ privateProfileManager.reset();
+
+ awaitTasksCompleted();
+ Mockito.verify(privateProfileManager).executeLock();
}
@Test
@@ -191,8 +208,4 @@
private static void awaitTasksCompleted() throws Exception {
UI_HELPER_EXECUTOR.submit(() -> null).get();
}
-
- private void testRunnable() {
- mRunnableCalled = true;
- }
}
diff --git a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
similarity index 75%
rename from tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
rename to tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
index 043461d..7ac276a 100644
--- a/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewControllerTest.java
+++ b/tests/src/com/android/launcher3/allapps/PrivateSpaceHeaderViewTest.java
@@ -28,6 +28,10 @@
import static org.junit.Assert.assertTrue;
import static org.mockito.AdditionalAnswers.answer;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doAnswer;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import android.content.ComponentName;
@@ -39,6 +43,7 @@
import android.graphics.drawable.Drawable;
import android.os.Process;
import android.os.UserHandle;
+import android.os.UserManager;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ImageButton;
@@ -51,8 +56,11 @@
import androidx.test.runner.AndroidJUnit4;
import com.android.launcher3.R;
+import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.model.data.AppInfo;
+import com.android.launcher3.pm.UserCache;
import com.android.launcher3.util.ActivityContextWrapper;
+import com.android.launcher3.util.UserIconInfo;
import org.junit.Before;
import org.junit.Test;
@@ -61,14 +69,20 @@
import org.mockito.MockitoAnnotations;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
-public class PrivateSpaceHeaderViewControllerTest {
+public class PrivateSpaceHeaderViewTest {
private static final UserHandle MAIN_HANDLE = Process.myUserHandle();
private static final UserHandle PRIVATE_HANDLE = new UserHandle(11);
+ private static final UserIconInfo MAIN_ICON_INFO =
+ new UserIconInfo(MAIN_HANDLE, UserIconInfo.TYPE_MAIN);
+ private static final UserIconInfo PRIVATE_ICON_INFO =
+ new UserIconInfo(PRIVATE_HANDLE, UserIconInfo.TYPE_PRIVATE);
+ private static final String CAMERA_PACKAGE_NAME = "com.android.launcher3.tests.camera";
private static final int CONTAINER_HEADER_ELEMENT_COUNT = 1;
private static final int LOCK_UNLOCK_BUTTON_COUNT = 1;
private static final int PS_SETTINGS_BUTTON_COUNT_VISIBLE = 1;
@@ -84,37 +98,41 @@
private static final float HEADER_PROTECTION_HEIGHT = 1F;
private Context mContext;
- private PrivateSpaceHeaderViewController mPsHeaderViewController;
private RelativeLayout mPsHeaderLayout;
private AlphabeticalAppsList<?> mAlphabeticalAppsList;
- @Mock
private PrivateProfileManager mPrivateProfileManager;
@Mock
private ActivityAllAppsContainerView mAllApps;
@Mock
private AllAppsStore<?> mAllAppsStore;
+ @Mock
+ private UserCache mUserCache;
+ @Mock
+ private UserManager mUserManager;
+ @Mock
+ private StatsLogManager mStatsLogManager;
@Before
public void setUp() {
MockitoAnnotations.initMocks(this);
mContext = new ActivityContextWrapper(getApplicationContext());
- when(mPrivateProfileManager.getItemInfoMatcher()).thenReturn(info ->
- info != null && info.user.equals(PRIVATE_HANDLE));
- mPsHeaderViewController = new PrivateSpaceHeaderViewController(mAllApps,
- mPrivateProfileManager);
+ when(mAllApps.getContext()).thenReturn(mContext);
+ when(mUserCache.getUserInfo(PRIVATE_HANDLE)).thenReturn(PRIVATE_ICON_INFO);
+ when(mUserCache.getUserProfiles())
+ .thenReturn(Arrays.asList(MAIN_HANDLE, PRIVATE_HANDLE));
+ when(mUserCache.getUserInfo(Process.myUserHandle())).thenReturn(MAIN_ICON_INFO);
+ mPrivateProfileManager = new PrivateProfileManager(mUserManager,
+ mAllApps, mStatsLogManager, mUserCache);
mPsHeaderLayout = (RelativeLayout) LayoutInflater.from(mContext).inflate(
R.layout.private_space_header, null);
- mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
- null, mPrivateProfileManager);
- mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
}
@Test
public void privateProfileDisabled_psHeaderContainsLockedView() throws Exception {
Bitmap unlockButton = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
- when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
-
- mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+ PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+ when(privateProfileManager.getCurrentState()).thenReturn(STATE_DISABLED);
+ privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
awaitTasksCompleted();
int totalContainerHeaderView = 0;
@@ -137,6 +155,7 @@
assertEquals(View.GONE, view.getVisibility());
}
}
+
assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
assertEquals(LOCK_UNLOCK_BUTTON_COUNT, totalLockUnlockButtonView);
}
@@ -145,10 +164,10 @@
public void privateProfileEnabled_psHeaderContainsUnlockedView() throws Exception {
Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
Bitmap settingsImage = getBitmap(mContext.getDrawable(R.drawable.ic_ps_settings));
- when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
- when(mPrivateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(true);
-
- mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+ PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+ when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+ when(privateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(true);
+ privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
awaitTasksCompleted();
int totalContainerHeaderView = 0;
@@ -177,6 +196,7 @@
assertEquals(View.GONE, view.getVisibility());
}
}
+
assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
assertEquals(LOCK_UNLOCK_BUTTON_COUNT, totalLockUnlockButtonView);
assertEquals(PS_SETTINGS_BUTTON_COUNT_VISIBLE, totalSettingsImageView);
@@ -186,10 +206,10 @@
public void privateProfileEnabledAndNoSettingsIntent_psHeaderContainsUnlockedView()
throws Exception {
Bitmap lockImage = getBitmap(mContext.getDrawable(R.drawable.ic_lock));
- when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
- when(mPrivateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(false);
-
- mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+ PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+ when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+ when(privateProfileManager.isPrivateSpaceSettingsAvailable()).thenReturn(false);
+ privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
awaitTasksCompleted();
int totalContainerHeaderView = 0;
@@ -216,6 +236,7 @@
assertEquals(View.GONE, view.getVisibility());
}
}
+
assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
assertEquals(LOCK_UNLOCK_BUTTON_COUNT, totalLockUnlockButtonView);
assertEquals(PS_SETTINGS_BUTTON_COUNT_INVISIBLE, totalSettingsImageView);
@@ -224,9 +245,9 @@
@Test
public void privateProfileTransitioning_psHeaderContainsTransitionView() throws Exception {
Bitmap transitionImage = getBitmap(mContext.getDrawable(R.drawable.bg_ps_transition_image));
- when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_TRANSITION);
-
- mPsHeaderViewController.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
+ PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+ when(privateProfileManager.getCurrentState()).thenReturn(STATE_TRANSITION);
+ privateProfileManager.addPrivateSpaceHeaderViewElements(mPsHeaderLayout);
awaitTasksCompleted();
int totalContainerHeaderView = 0;
@@ -248,6 +269,7 @@
assertEquals(View.GONE, view.getVisibility());
}
}
+
assertEquals(CONTAINER_HEADER_ELEMENT_COUNT, totalContainerHeaderView);
assertEquals(PS_TRANSITION_IMAGE_COUNT, totalLockUnlockButtonView);
}
@@ -255,18 +277,25 @@
@Test
public void scrollForViewToBeVisibleInContainer_withHeader() {
when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
- when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
- .thenAnswer(answer(this::addPrivateSpaceHeader));
- when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
- when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+ PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+ when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+ when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
.thenReturn(iteminfo -> iteminfo.componentName == null
|| !iteminfo.componentName.getPackageName()
- .equals("com.android.launcher3.tests.camera"));
- when(mAllApps.getContext()).thenReturn(mContext);
- mAlphabeticalAppsList.updateItemFilter(info -> info != null
- && info.user.equals(MAIN_HANDLE));
+ .equals(CAMERA_PACKAGE_NAME));
+ doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
+ doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
+ .addPrivateSpaceHeader(any());
+ doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
+ doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+ mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+ null, privateProfileManager);
+ mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
+ mAlphabeticalAppsList.updateItemFilter(info -> info != null
+ && info.user.equals(MAIN_HANDLE));
+
int rows = (int) (ALL_APPS_HEIGHT - PS_HEADER_HEIGHT - HEADER_PROTECTION_HEIGHT);
int position = rows * NUM_APP_COLS - (NUM_APP_COLS-1) + 1;
@@ -274,7 +303,7 @@
assertEquals(NUM_PRIVATE_SPACE_APPS + 1 + 1,
mAlphabeticalAppsList.getAdapterItems().size());
assertEquals(position,
- mPsHeaderViewController.scrollForViewToBeVisibleInContainer(
+ privateProfileManager.scrollForViewToBeVisibleInContainer(
new AllAppsRecyclerView(mContext),
mAlphabeticalAppsList.getAdapterItems(),
PS_HEADER_HEIGHT,
@@ -284,18 +313,25 @@
@Test
public void scrollForViewToBeVisibleInContainer_withHeaderAndLessAppRowSpace() {
when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
- when(mPrivateProfileManager.addPrivateSpaceHeader(any()))
- .thenAnswer(answer(this::addPrivateSpaceHeader));
- when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
- when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+ PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+ when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+ when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
.thenReturn(iteminfo -> iteminfo.componentName == null
|| !iteminfo.componentName.getPackageName()
- .equals("com.android.launcher3.tests.camera"));
- when(mAllApps.getContext()).thenReturn(mContext);
- mAlphabeticalAppsList.updateItemFilter(info -> info != null
- && info.user.equals(MAIN_HANDLE));
+ .equals(CAMERA_PACKAGE_NAME));
+ doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
+ doAnswer(answer(this::addPrivateSpaceHeader)).when(privateProfileManager)
+ .addPrivateSpaceHeader(any());
+ doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
+ doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+ mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+ null, privateProfileManager);
+ mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
+ mAlphabeticalAppsList.updateItemFilter(info -> info != null
+ && info.user.equals(MAIN_HANDLE));
+
int rows = (int) (ALL_APPS_HEIGHT - BIGGER_PS_HEADER_HEIGHT - HEADER_PROTECTION_HEIGHT);
int position = rows * NUM_APP_COLS - (NUM_APP_COLS-1) + 1;
@@ -303,7 +339,7 @@
assertEquals(NUM_PRIVATE_SPACE_APPS + 1 + 1,
mAlphabeticalAppsList.getAdapterItems().size());
assertEquals(position,
- mPsHeaderViewController.scrollForViewToBeVisibleInContainer(
+ privateProfileManager.scrollForViewToBeVisibleInContainer(
new AllAppsRecyclerView(mContext),
mAlphabeticalAppsList.getAdapterItems(),
BIGGER_PS_HEADER_HEIGHT,
@@ -313,21 +349,27 @@
@Test
public void scrollForViewToBeVisibleInContainer_withNoHeader() {
when(mAllAppsStore.getApps()).thenReturn(createAppInfoList());
- when(mPrivateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
- when(mPrivateProfileManager.splitIntoUserInstalledAndSystemApps())
+ PrivateProfileManager privateProfileManager = spy(mPrivateProfileManager);
+ when(privateProfileManager.getCurrentState()).thenReturn(STATE_ENABLED);
+ when(privateProfileManager.splitIntoUserInstalledAndSystemApps())
.thenReturn(iteminfo -> iteminfo.componentName == null
|| !iteminfo.componentName.getPackageName()
- .equals("com.android.launcher3.tests.camera"));
- when(mAllApps.getContext()).thenReturn(mContext);
- mAlphabeticalAppsList.updateItemFilter(info -> info != null
- && info.user.equals(MAIN_HANDLE));
+ .equals(CAMERA_PACKAGE_NAME));
+ doReturn(0).when(privateProfileManager).addPrivateSpaceHeader(any());
+ doNothing().when(privateProfileManager).addPrivateSpaceInstallAppButton(any());
+ doReturn(0).when(privateProfileManager).addSystemAppsDivider(any());
when(mAllApps.getHeight()).thenReturn(ALL_APPS_HEIGHT);
when(mAllApps.getHeaderProtectionHeight()).thenReturn(HEADER_PROTECTION_HEIGHT);
+ mAlphabeticalAppsList = new AlphabeticalAppsList<>(mContext, mAllAppsStore,
+ null, privateProfileManager);
+ mAlphabeticalAppsList.setNumAppsPerRowAllApps(NUM_APP_COLS);
+ mAlphabeticalAppsList.updateItemFilter(info -> info != null
+ && info.user.equals(MAIN_HANDLE));
// The number of adapterItems should be the private space apps + one main app.
assertEquals(NUM_PRIVATE_SPACE_APPS + 1,
mAlphabeticalAppsList.getAdapterItems().size());
- assertEquals(SCROLL_NO_WHERE, mPsHeaderViewController.scrollForViewToBeVisibleInContainer(
+ assertEquals(SCROLL_NO_WHERE, privateProfileManager.scrollForViewToBeVisibleInContainer(
new AllAppsRecyclerView(mContext),
mAlphabeticalAppsList.getAdapterItems(),
BIGGER_PS_HEADER_HEIGHT,
@@ -376,7 +418,7 @@
AppInfo(gmailComponentName, "Gmail", MAIN_HANDLE, new Intent());
appInfos.add(gmailAppInfo);
ComponentName privateCameraComponentName = new ComponentName(
- "com.android.launcher3.tests.camera", "CameraActivity");
+ CAMERA_PACKAGE_NAME, "CameraActivity");
for (int i = 0; i < NUM_PRIVATE_SPACE_APPS; i++) {
AppInfo privateCameraAppInfo = new AppInfo(privateCameraComponentName,
"Private Camera " + i, PRIVATE_HANDLE, new Intent());
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt b/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
index c5dbce4..ff46987 100644
--- a/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
+++ b/tests/src/com/android/launcher3/celllayout/testgenerator/RandomBoardGenerator.kt
@@ -21,6 +21,13 @@
/** Generates a random CellLayoutBoard. */
open class RandomBoardGenerator(generator: Random) : DeterministicRandomGenerator(generator) {
+
+ companion object {
+ // This is the max number of widgets because we encode the widgets as letters A-Z and we
+ // already have some of those letter used by other things so 22 is a safe number
+ val MAX_NUMBER_OF_WIDGETS = 22
+ }
+
/**
* @param remainingEmptySpaces the maximum number of spaces we will fill with icons and widgets
* meaning that if the number is 100 we will try to fill the board with at most 100 spaces
@@ -33,9 +40,9 @@
}
protected fun fillBoard(
- board: CellLayoutBoard,
- area: Rect,
- remainingEmptySpacesArg: Int
+ board: CellLayoutBoard,
+ area: Rect,
+ remainingEmptySpacesArg: Int
): CellLayoutBoard {
var remainingEmptySpaces = remainingEmptySpacesArg
if (area.height() * area.width() <= 0) return board
@@ -45,11 +52,18 @@
val y = area.top + getRandom(0, area.height() - height)
if (remainingEmptySpaces > 0) {
remainingEmptySpaces -= width * height
- } else if (board.widgets.size <= 22 && width * height > 1) {
+ }
+
+ if (board.widgets.size <= MAX_NUMBER_OF_WIDGETS && width * height > 1) {
board.addWidget(x, y, width, height)
} else {
board.addIcon(x, y)
}
+
+ if (remainingEmptySpaces < 0) {
+ // optimization, no need to keep going
+ return board
+ }
fillBoard(board, Rect(area.left, area.top, area.right, y), remainingEmptySpaces)
fillBoard(board, Rect(area.left, y, x, area.bottom), remainingEmptySpaces)
fillBoard(board, Rect(x, y + height, area.right, area.bottom), remainingEmptySpaces)
diff --git a/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt b/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
new file mode 100644
index 0000000..e773a86
--- /dev/null
+++ b/tests/src/com/android/launcher3/celllayout/testgenerator/ValidGridMigrationTestCaseGenerator.kt
@@ -0,0 +1,160 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.celllayout.testgenerator
+
+import android.graphics.Point
+import com.android.launcher3.LauncherSettings
+import com.android.launcher3.celllayout.board.CellLayoutBoard
+import com.android.launcher3.model.data.LauncherAppWidgetInfo
+import com.android.launcher3.model.gridmigration.WorkspaceItem
+import java.util.Random
+import java.util.concurrent.atomic.AtomicInteger
+
+/**
+ * Generate a list of WorkspaceItem's for the given test case.
+ *
+ * @param repeatAfter a number after which we would repeat the same number of icons and widgets to
+ * account for cases where the user have the same item multiple times.
+ */
+fun generateItemsForTest(
+ testCase: GridMigrationUnitTestCase,
+ repeatAfter: Int
+): List<WorkspaceItem> {
+ val id = AtomicInteger(0)
+ val widgetId = AtomicInteger(LauncherAppWidgetInfo.CUSTOM_WIDGET_ID - 1)
+ val boards = testCase.boards
+ // Repeat the same appWidgetProvider and intent to have repeating widgets and icons and test
+ // that case too
+ val getIntent = { i: Int -> "Intent ${i % repeatAfter}" }
+ val getProvider = { i: Int -> "com.test/test.Provider${i % repeatAfter}" }
+ val hotseatEntries =
+ (0 until boards[0].width).map {
+ WorkspaceItem(
+ x = it,
+ y = 0,
+ spanX = 1,
+ spanY = 1,
+ id = id.getAndAdd(1),
+ screenId = it,
+ title = "Hotseat ${id.get()}",
+ appWidgetId = -1,
+ appWidgetProvider = "Hotseat icons don't have a provider",
+ intent = getIntent(id.get()),
+ type = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION,
+ container = LauncherSettings.Favorites.CONTAINER_HOTSEAT
+ )
+ }
+ var widgetEntries =
+ boards
+ .flatMapIndexed { i, board -> board.widgets.map { Pair(i, it) } }
+ .map {
+ WorkspaceItem(
+ x = it.second.cellX,
+ y = it.second.cellY,
+ spanX = it.second.spanX,
+ spanY = it.second.spanY,
+ id = id.getAndAdd(1),
+ screenId = it.first,
+ title = "Title Widget ${id.get()}",
+ appWidgetId = widgetId.getAndAdd(-1),
+ appWidgetProvider = getProvider(id.get()),
+ intent = "Widgets don't have intent",
+ type = LauncherSettings.Favorites.ITEM_TYPE_APPWIDGET,
+ container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+ )
+ }
+ widgetEntries = widgetEntries.filter { it.appWidgetProvider.contains("Provider4") }
+ val iconEntries =
+ boards
+ .flatMapIndexed { i, board -> board.icons.map { Pair(i, it) } }
+ .map {
+ WorkspaceItem(
+ x = it.second.coord.x,
+ y = it.second.coord.y,
+ spanX = 1,
+ spanY = 1,
+ id = id.getAndAdd(1),
+ screenId = it.first,
+ title = "Title Icon ${id.get()}",
+ appWidgetId = -1,
+ appWidgetProvider = "Icons don't have providers",
+ intent = getIntent(id.get()),
+ type = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION,
+ container = LauncherSettings.Favorites.CONTAINER_DESKTOP
+ )
+ }
+ return widgetEntries + hotseatEntries // + iconEntries
+}
+
+data class GridMigrationUnitTestCase(
+ val boards: List<CellLayoutBoard>,
+ val srcSize: Point,
+ val targetSize: Point,
+ val seed: Long
+)
+
+class ValidGridMigrationTestCaseGenerator(private val generator: Random) :
+ DeterministicRandomGenerator(generator) {
+
+ companion object {
+ const val MAX_BOARD_SIZE = 12
+ const val MAX_BOARD_COUNT = 10
+ const val SEED = 10342
+ }
+
+ private fun generateBoards(
+ boardGenerator: RandomBoardGenerator,
+ width: Int,
+ height: Int,
+ boardCount: Int
+ ): List<CellLayoutBoard> {
+ val boards = mutableListOf<CellLayoutBoard>()
+ for (i in 0 until boardCount) {
+ boards.add(
+ boardGenerator.generateBoard(
+ width,
+ height,
+ boardGenerator.getRandom(0, width * height)
+ )
+ )
+ }
+ return boards
+ }
+
+ fun generateTestCase(): GridMigrationUnitTestCase {
+ var seed = generator.nextLong()
+ val randomBoardGenerator = RandomBoardGenerator(Random(seed))
+ val width = randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
+ val height = randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
+ return GridMigrationUnitTestCase(
+ boards =
+ generateBoards(
+ boardGenerator = randomBoardGenerator,
+ width = width,
+ height = height,
+ boardCount = randomBoardGenerator.getRandom(3, MAX_BOARD_COUNT)
+ ),
+ srcSize = Point(width, height),
+ targetSize =
+ Point(
+ randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE),
+ randomBoardGenerator.getRandom(3, MAX_BOARD_SIZE)
+ ),
+ seed = seed
+ )
+ }
+}
diff --git a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
index 4ec5b0e..3a1883c 100644
--- a/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
+++ b/tests/src/com/android/launcher3/folder/PreviewItemManagerTest.kt
@@ -28,6 +28,7 @@
import com.android.launcher3.icons.BaseIconFactory
import com.android.launcher3.icons.FastBitmapDrawable
import com.android.launcher3.icons.UserBadgeDrawable
+import com.android.launcher3.model.data.FolderInfo
import com.android.launcher3.model.data.WorkspaceItemInfo
import com.android.launcher3.util.ActivityContextWrapper
import com.android.launcher3.util.FlagOp
@@ -71,8 +72,8 @@
.build()
)
.loadModelSync()
- folderItems = modelHelper.bgDataModel.folders.valueAt(0).contents
- folderIcon.mInfo = modelHelper.bgDataModel.folders.valueAt(0)
+ folderItems = modelHelper.bgDataModel.collections.valueAt(0).contents
+ folderIcon.mInfo = modelHelper.bgDataModel.collections.valueAt(0) as FolderInfo
folderIcon.mInfo.contents = folderItems
// Set first icon to be themed.
diff --git a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
index 7a0b60a..abb0c39 100644
--- a/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
+++ b/tests/src/com/android/launcher3/model/CacheDataUpdatedTaskTest.java
@@ -160,6 +160,6 @@
}
private List<WorkspaceItemInfo> allItems() {
- return ((FolderInfo) mModelHelper.getBgDataModel().itemsIdMap.get(1)).contents;
+ return ((FolderInfo) mModelHelper.getBgDataModel().itemsIdMap.get(1)).getContents();
}
}
diff --git a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java b/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
index 2b89321..10785f7 100644
--- a/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
+++ b/tests/src/com/android/launcher3/model/DefaultLayoutProviderTest.java
@@ -87,7 +87,7 @@
assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
ItemInfo info = mModelHelper.getBgDataModel().workspaceItems.get(0);
assertEquals(LauncherSettings.Favorites.ITEM_TYPE_FOLDER, info.itemType);
- assertEquals(3, ((FolderInfo) info).contents.size());
+ assertEquals(3, ((FolderInfo) info).getContents().size());
}
@Test
@@ -102,7 +102,7 @@
assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
ItemInfo info = mModelHelper.getBgDataModel().workspaceItems.get(0);
assertEquals(LauncherSettings.Favorites.ITEM_TYPE_FOLDER, info.itemType);
- assertEquals(3, ((FolderInfo) info).contents.size());
+ assertEquals(3, ((FolderInfo) info).getContents().size());
assertEquals("CustomFolder", info.title.toString());
}
@@ -154,11 +154,11 @@
// Verify folder
assertEquals(1, mModelHelper.getBgDataModel().workspaceItems.size());
FolderInfo info = (FolderInfo) mModelHelper.getBgDataModel().workspaceItems.get(0);
- assertEquals(3, info.contents.size());
+ assertEquals(3, info.getContents().size());
// Verify last icon
assertEquals(LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT,
- info.contents.get(info.contents.size() - 1).itemType);
+ info.getContents().get(info.getContents().size() - 1).itemType);
}
private void writeLayoutAndLoad(LauncherLayoutBuilder builder) throws Exception {
diff --git a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
index 2118ed6..ed587a1 100644
--- a/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
+++ b/tests/src/com/android/launcher3/model/FolderIconLoadTest.kt
@@ -165,11 +165,11 @@
// Reload again with correct icon state
app.model.forceReload()
modelHelper.loadModelSync()
- val folders = modelHelper.getBgDataModel().folders
+ val collections = modelHelper.getBgDataModel().collections
- assertThat(folders.size()).isEqualTo(1)
- assertThat(folders.valueAt(0).contents.size).isEqualTo(itemCount)
- return folders.valueAt(0).contents
+ assertThat(collections.size()).isEqualTo(1)
+ assertThat(collections.valueAt(0).contents.size).isEqualTo(itemCount)
+ return collections.valueAt(0).contents
}
private fun verifyHighRes(items: ArrayList<WorkspaceItemInfo>, vararg indices: Int) {
diff --git a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
index 04735f2..761f06d 100644
--- a/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
+++ b/tests/src/com/android/launcher3/model/GridSizeMigrationUtilTest.kt
@@ -28,7 +28,6 @@
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.LauncherPrefs.Companion.WORKSPACE_SIZE
import com.android.launcher3.LauncherSettings.Favorites.*
-import com.android.launcher3.config.FeatureFlags
import com.android.launcher3.model.GridSizeMigrationUtil.DbReader
import com.android.launcher3.pm.UserCache
import com.android.launcher3.provider.LauncherDbUtils
@@ -98,10 +97,7 @@
modelHelper.destroy()
}
- /**
- * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
- * needed anymore
- */
+ /** Old migration logic, should be modified once is not needed anymore */
@Test
@Throws(Exception::class)
fun testMigration() {
@@ -208,10 +204,7 @@
assertThat(locMap[testPackage9]).isEqualTo(Point(0, 2))
}
- /**
- * Old migration logic, should be modified once [FeatureFlags.ENABLE_NEW_MIGRATION_LOGIC] is not
- * needed anymore
- */
+ /** Old migration logic, should be modified once is not needed anymore */
@Test
@Throws(Exception::class)
fun testMigrationBackAndForth() {
@@ -606,68 +599,6 @@
}
/**
- * Migrating from a smaller grid to a large one should keep the pages if the column difference
- * is less than 2
- */
- @Test
- @Throws(Exception::class)
- fun migrateFromSmallerGridSmallDifference() {
- enableNewMigrationLogic("4,4")
-
- // Setup src grid
- addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 2, testPackage1, 5, TMP_TABLE)
- addItem(ITEM_TYPE_APPLICATION, 0, CONTAINER_DESKTOP, 2, 3, testPackage2, 6, TMP_TABLE)
- addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 1, testPackage3, 7, TMP_TABLE)
- addItem(ITEM_TYPE_APPLICATION, 1, CONTAINER_DESKTOP, 3, 2, testPackage4, 8, TMP_TABLE)
- addItem(ITEM_TYPE_APPLICATION, 2, CONTAINER_DESKTOP, 3, 3, testPackage5, 9, TMP_TABLE)
-
- idp.numDatabaseHotseatIcons = 4
- idp.numColumns = 6
- idp.numRows = 5
-
- val srcReader = DbReader(db, TMP_TABLE, context, validPackages)
- val destReader = DbReader(db, TABLE_NAME, context, validPackages)
- GridSizeMigrationUtil.migrate(
- dbHelper,
- srcReader,
- destReader,
- idp.numDatabaseHotseatIcons,
- Point(idp.numColumns, idp.numRows),
- DeviceGridState(context),
- DeviceGridState(idp)
- )
-
- // Get workspace items
- val c =
- db.query(
- TABLE_NAME,
- arrayOf(INTENT, SCREEN),
- "container=$CONTAINER_DESKTOP",
- null,
- null,
- null,
- null
- )
- ?: throw IllegalStateException()
- val intentIndex = c.getColumnIndex(INTENT)
- val screenIndex = c.getColumnIndex(SCREEN)
-
- // Get in which screen the icon is
- val locMap = HashMap<String?, Int>()
- while (c.moveToNext()) {
- locMap[Intent.parseUri(c.getString(intentIndex), 0).getPackage()] =
- c.getInt(screenIndex)
- }
- c.close()
- assertThat(locMap.size).isEqualTo(5)
- assertThat(locMap[testPackage1]).isEqualTo(0)
- assertThat(locMap[testPackage2]).isEqualTo(0)
- assertThat(locMap[testPackage3]).isEqualTo(1)
- assertThat(locMap[testPackage4]).isEqualTo(1)
- assertThat(locMap[testPackage5]).isEqualTo(2)
- }
-
- /**
* Migrating from a smaller grid to a large one should reflow the pages if the column difference
* is more than 2
*/
diff --git a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
index bbe8265..5731e2a 100644
--- a/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
+++ b/tests/src/com/android/launcher3/model/LoaderTaskTest.kt
@@ -103,7 +103,7 @@
.runSyncOnBackgroundThread()
Truth.assertThat(workspaceItems.size).isAtLeast(25)
Truth.assertThat(appWidgets.size).isAtLeast(7)
- Truth.assertThat(folders.size()).isAtLeast(8)
+ Truth.assertThat(collections.size()).isAtLeast(8)
Truth.assertThat(itemsIdMap.size()).isAtLeast(40)
}
diff --git a/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt b/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.kt
new file mode 100644
index 0000000..cc8e61d
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/gridmigration/GridMigrationUtils.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.launcher3.model.gridmigration
+
+import android.content.ContentValues
+import android.database.sqlite.SQLiteDatabase
+import android.graphics.Point
+import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.celllayout.board.CellLayoutBoard
+
+class MockSet(override val size: Int) : Set<String> {
+ override fun contains(element: String): Boolean = true
+ override fun containsAll(elements: Collection<String>): Boolean = true
+ override fun isEmpty(): Boolean = false
+ override fun iterator(): Iterator<String> = listOf<String>().iterator()
+}
+
+fun itemListToBoard(itemsArg: List<WorkspaceItem>, boardSize: Point): List<CellLayoutBoard> {
+ val items = itemsArg.filter { it.container != Favorites.CONTAINER_HOTSEAT }
+ val boardList =
+ List(items.maxOf { it.screenId + 1 }) { CellLayoutBoard(boardSize.x, boardSize.y) }
+ items.forEach {
+ when (it.type) {
+ Favorites.ITEM_TYPE_FOLDER,
+ Favorites.ITEM_TYPE_APP_PAIR -> throw Exception("Not implemented")
+ Favorites.ITEM_TYPE_APPWIDGET ->
+ boardList[it.screenId].addWidget(it.x, it.y, it.spanX, it.spanY)
+ Favorites.ITEM_TYPE_APPLICATION -> boardList[it.screenId].addIcon(it.x, it.y)
+ }
+ }
+ return boardList
+}
+
+fun insertIntoDb(tableName: String, entry: WorkspaceItem, db: SQLiteDatabase) {
+ val values = ContentValues()
+ values.put(Favorites.SCREEN, entry.screenId)
+ values.put(Favorites.CELLX, entry.x)
+ values.put(Favorites.CELLY, entry.y)
+ values.put(Favorites.SPANX, entry.spanX)
+ values.put(Favorites.SPANY, entry.spanY)
+ values.put(Favorites.TITLE, entry.title)
+ values.put(Favorites.INTENT, entry.intent)
+ values.put(Favorites.APPWIDGET_PROVIDER, entry.appWidgetProvider)
+ values.put(Favorites.APPWIDGET_ID, entry.appWidgetId)
+ values.put(Favorites.CONTAINER, entry.container)
+ values.put(Favorites.ITEM_TYPE, entry.type)
+ values.put(Favorites._ID, entry.id)
+ db.insert(tableName, null, values)
+}
+
+fun readDb(tableName: String, db: SQLiteDatabase): List<WorkspaceItem> {
+ val result = mutableListOf<WorkspaceItem>()
+ val cursor = db.query(tableName, null, null, null, null, null, null)
+ val indexCellX: Int = cursor.getColumnIndexOrThrow(Favorites.CELLX)
+ val indexCellY: Int = cursor.getColumnIndexOrThrow(Favorites.CELLY)
+ val indexSpanX: Int = cursor.getColumnIndexOrThrow(Favorites.SPANX)
+ val indexSpanY: Int = cursor.getColumnIndexOrThrow(Favorites.SPANY)
+ val indexId: Int = cursor.getColumnIndexOrThrow(Favorites._ID)
+ val indexScreen: Int = cursor.getColumnIndexOrThrow(Favorites.SCREEN)
+ val indexTitle: Int = cursor.getColumnIndexOrThrow(Favorites.TITLE)
+ val indexAppWidgetId: Int = cursor.getColumnIndexOrThrow(Favorites.APPWIDGET_ID)
+ val indexWidgetProvider: Int = cursor.getColumnIndexOrThrow(Favorites.APPWIDGET_PROVIDER)
+ val indexIntent: Int = cursor.getColumnIndexOrThrow(Favorites.INTENT)
+ val indexItemType: Int = cursor.getColumnIndexOrThrow(Favorites.ITEM_TYPE)
+ val container: Int = cursor.getColumnIndexOrThrow(Favorites.CONTAINER)
+ while (cursor.moveToNext()) {
+ result.add(
+ WorkspaceItem(
+ x = cursor.getInt(indexCellX),
+ y = cursor.getInt(indexCellY),
+ spanX = cursor.getInt(indexSpanX),
+ spanY = cursor.getInt(indexSpanY),
+ id = cursor.getInt(indexId),
+ screenId = cursor.getInt(indexScreen),
+ title = cursor.getString(indexTitle),
+ appWidgetId = cursor.getInt(indexAppWidgetId),
+ appWidgetProvider = cursor.getString(indexWidgetProvider),
+ intent = cursor.getString(indexIntent),
+ type = cursor.getInt(indexItemType),
+ container = cursor.getInt(container)
+ )
+ )
+ }
+ return result
+}
+
+data class WorkspaceItem(
+ val x: Int,
+ val y: Int,
+ val spanX: Int,
+ val spanY: Int,
+ val id: Int,
+ val screenId: Int,
+ val title: String,
+ val appWidgetId: Int,
+ val appWidgetProvider: String,
+ val intent: String,
+ val type: Int,
+ val container: Int,
+)
diff --git a/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt b/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
new file mode 100644
index 0000000..1002976
--- /dev/null
+++ b/tests/src/com/android/launcher3/model/gridmigration/ValidGridMigrationUnitTest.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.launcher3.model.gridmigration
+
+import android.content.Context
+import android.database.sqlite.SQLiteDatabase
+import android.graphics.Point
+import android.os.Process
+import android.util.Log
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.InvariantDeviceProfile
+import com.android.launcher3.LauncherSettings.Favorites
+import com.android.launcher3.celllayout.testgenerator.ValidGridMigrationTestCaseGenerator
+import com.android.launcher3.celllayout.testgenerator.generateItemsForTest
+import com.android.launcher3.model.DatabaseHelper
+import com.android.launcher3.model.DeviceGridState
+import com.android.launcher3.model.GridSizeMigrationUtil
+import com.android.launcher3.pm.UserCache
+import com.android.launcher3.provider.LauncherDbUtils
+import com.android.launcher3.util.rule.TestStabilityRule
+import com.android.launcher3.util.rule.TestStabilityRule.Stability
+import java.util.Random
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ValidGridMigrationUnitTest {
+
+ companion object {
+ const val SEED = 1044542
+ const val REPEAT_AFTER = 10
+ const val TAG = "ValidGridMigrationUnitTest"
+ }
+
+ private lateinit var context: Context
+
+ @Before
+ fun setUp() {
+ context = InstrumentationRegistry.getInstrumentation().targetContext
+ }
+
+ private fun validate(
+ srcItems: List<WorkspaceItem>,
+ dstItems: List<WorkspaceItem>,
+ destinationSize: Point
+ ) {
+ // This returns a map with the number of repeated elements
+ // ex { calculatorIcon : 6, weatherWidget : 2 }
+ val itemsToSet = { it: List<WorkspaceItem> ->
+ it.filter { it.container != Favorites.CONTAINER_HOTSEAT }
+ .groupingBy {
+ when (it.type) {
+ Favorites.ITEM_TYPE_FOLDER,
+ Favorites.ITEM_TYPE_APP_PAIR -> throw Exception("Not implemented")
+ Favorites.ITEM_TYPE_APPWIDGET -> it.appWidgetProvider
+ Favorites.ITEM_TYPE_APPLICATION -> it.intent
+ else -> it.title
+ }
+ }
+ .eachCount()
+ }
+ for (it in dstItems) {
+ assert((it.x in 0..destinationSize.x) && (it.y in 0..destinationSize.y)) {
+ "Item outside of the board size. Size = $destinationSize Item = $it"
+ }
+ assert(
+ (it.x + it.spanX in 0..destinationSize.x) &&
+ (it.y + it.spanY in 0..destinationSize.y)
+ ) {
+ "Item doesn't fit in the grid. Size = $destinationSize Item = $it"
+ }
+ }
+
+ assert(itemsToSet(srcItems) == itemsToSet(dstItems)) {
+ "The srcItems do not match the dstItems src = $srcItems dst = $dstItems"
+ }
+ }
+
+ private fun addItemsToDb(db: SQLiteDatabase, tableName: String, items: List<WorkspaceItem>) {
+ LauncherDbUtils.SQLiteTransaction(db).use { transaction ->
+ items.forEach { insertIntoDb(tableName, it, transaction.db) }
+ transaction.commit()
+ }
+ }
+
+ private fun migrate(
+ srcItems: List<WorkspaceItem>,
+ srcSize: Point,
+ targetSize: Point
+ ): List<WorkspaceItem> {
+ val userSerial = UserCache.INSTANCE[context].getSerialNumberForUser(Process.myUserHandle())
+ val dbHelper =
+ DatabaseHelper(
+ context,
+ null,
+ { UserCache.INSTANCE.get(context).getSerialNumberForUser(it) },
+ {}
+ )
+ val srcTableName = Favorites.TMP_TABLE
+ val dstTableName = Favorites.TABLE_NAME
+ Favorites.addTableToDb(dbHelper.writableDatabase, userSerial, false, srcTableName)
+ addItemsToDb(dbHelper.writableDatabase, srcTableName, srcItems)
+ LauncherDbUtils.SQLiteTransaction(dbHelper.writableDatabase).use {
+ GridSizeMigrationUtil.migrate(
+ dbHelper,
+ GridSizeMigrationUtil.DbReader(it.db, srcTableName, context, MockSet(1)),
+ GridSizeMigrationUtil.DbReader(it.db, dstTableName, context, MockSet(1)),
+ targetSize.x,
+ targetSize,
+ DeviceGridState(
+ srcSize.x,
+ srcSize.y,
+ srcSize.x,
+ InvariantDeviceProfile.TYPE_PHONE,
+ srcTableName
+ ),
+ DeviceGridState(
+ targetSize.x,
+ targetSize.y,
+ targetSize.x,
+ InvariantDeviceProfile.TYPE_PHONE,
+ dstTableName
+ )
+ )
+ it.commit()
+ }
+ return readDb(dstTableName, dbHelper.readableDatabase)
+ }
+
+ @Test
+ fun runTestCase() {
+ val caseGenerator = ValidGridMigrationTestCaseGenerator(Random(SEED.toLong()))
+ for (i in 0..50) {
+ val testCase = caseGenerator.generateTestCase()
+ Log.d(TAG, "Test case = $testCase")
+ val srcItemList = generateItemsForTest(testCase, REPEAT_AFTER)
+ val dstItemList = migrate(srcItemList, testCase.srcSize, testCase.targetSize)
+ validate(srcItemList, dstItemList, testCase.targetSize)
+ }
+ }
+
+ // This test takes about 4 minutes, there is no need to run it in presubmit.
+ @Stability(flavors = TestStabilityRule.LOCAL or TestStabilityRule.PLATFORM_POSTSUBMIT)
+ @Test
+ fun runExtensiveTestCases() {
+ val caseGenerator = ValidGridMigrationTestCaseGenerator(Random(SEED.toLong()))
+ for (i in 0..1000) {
+ val testCase = caseGenerator.generateTestCase()
+ Log.d(TAG, "Test case = $testCase")
+ val srcItemList = generateItemsForTest(testCase, REPEAT_AFTER)
+ val dstItemList = migrate(srcItemList, testCase.srcSize, testCase.targetSize)
+ validate(srcItemList, dstItemList, testCase.targetSize)
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/ItemInflaterTest.kt b/tests/src/com/android/launcher3/util/ItemInflaterTest.kt
index efad899..0065527 100644
--- a/tests/src/com/android/launcher3/util/ItemInflaterTest.kt
+++ b/tests/src/com/android/launcher3/util/ItemInflaterTest.kt
@@ -36,6 +36,7 @@
import com.android.launcher3.folder.FolderIcon
import com.android.launcher3.model.ModelWriter
import com.android.launcher3.model.data.AppInfo
+import com.android.launcher3.model.data.AppPairInfo
import com.android.launcher3.model.data.FolderInfo
import com.android.launcher3.model.data.LauncherAppWidgetInfo
import com.android.launcher3.model.data.LauncherAppWidgetInfo.FLAG_ID_NOT_VALID
@@ -170,7 +171,7 @@
@Test
fun test_app_pair_inflated_on_UI() {
- val itemInfo = FolderInfo()
+ val itemInfo = AppPairInfo()
itemInfo.itemType = ITEM_TYPE_APP_PAIR
itemInfo.contents.add(workspaceItemInfo())
itemInfo.contents.add(workspaceItemInfo())
@@ -186,7 +187,7 @@
fun test_app_pair_inflated_on_BG() {
setFlagsRule.enableFlags(Flags.FLAG_ENABLE_WORKSPACE_INFLATION)
- val itemInfo = FolderInfo()
+ val itemInfo = AppPairInfo()
itemInfo.itemType = ITEM_TYPE_APP_PAIR
itemInfo.contents.add(workspaceItemInfo())
itemInfo.contents.add(workspaceItemInfo())
diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
index c7d3754..0a52955 100644
--- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
+++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java
@@ -24,6 +24,7 @@
import static android.view.MotionEvent.ACTION_SCROLL;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.AXIS_GESTURE_SWIPE_FINGER_COUNT;
+import static android.view.Surface.ROTATION_90;
import static com.android.launcher3.tapl.Folder.FOLDER_CONTENT_RES_ID;
import static com.android.launcher3.tapl.TestHelpers.getOverviewPackageName;
@@ -474,12 +475,25 @@
logShellCommand(cmd);
}
+ /**
+ * Retrieves a resource value from context that defines if nav bar can change position or if it
+ * is fixed position regardless of device orientation.
+ */
+ private boolean getNavBarCanMove() {
+ final Context baseContext = mInstrumentation.getTargetContext();
+ try {
+ final Context ctx = getLauncherContext(baseContext);
+ return getNavBarCanMove(ctx);
+ } catch (Exception e) {
+ fail(e.toString());
+ }
+ return false;
+ }
+
public NavigationModel getNavigationModel() {
final Context baseContext = mInstrumentation.getTargetContext();
try {
- // Workaround, use constructed context because both the instrumentation context and the
- // app context are not constructed with resources that take overlays into account
- final Context ctx = baseContext.createPackageContext(getLauncherPackageName(), 0);
+ final Context ctx = getLauncherContext(baseContext);
for (int i = 0; i < 100; ++i) {
final int currentInteractionMode = getCurrentInteractionMode(ctx);
final NavigationModel model = getNavigationModel(currentInteractionMode);
@@ -1101,19 +1115,31 @@
/**
* Goes to home from immersive fullscreen app by first swiping up to bring navbar, and then
* performing {@code goHome()} action.
- * Currently only supports gesture navigation mode.
*
* @return the Workspace object.
*/
public Workspace goHomeFromImmersiveFullscreenApp() {
- assertTrue("expected gesture navigation mode",
- getNavigationModel() == NavigationModel.ZERO_BUTTON);
- final Point displaySize = getRealDisplaySize();
- linearGesture(
- displaySize.x / 2, displaySize.y - 1,
- displaySize.x / 2, 0,
- ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
- false, GestureScope.EXPECT_PILFER);
+ final boolean navBarCanMove = getNavBarCanMove();
+ if (getNavigationModel() == NavigationModel.ZERO_BUTTON || !navBarCanMove) {
+ // in gesture nav we can swipe up at the bottom to bring the navbar handle
+ final Point displaySize = getRealDisplaySize();
+ linearGesture(
+ displaySize.x / 2, displaySize.y - 1,
+ displaySize.x / 2, 0,
+ ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
+ false, GestureScope.EXPECT_PILFER);
+ } else {
+ // in 3 button nav we swipe up on the side edge of the screen to bring the navbar
+ final boolean rotated90degrees = mDevice.getDisplayRotation() == ROTATION_90;
+ final Point displaySize = getRealDisplaySize();
+ final int startX = rotated90degrees ? displaySize.x : 0;
+ final int endX = rotated90degrees ? 0 : displaySize.x;
+ linearGesture(
+ startX, displaySize.y / 2,
+ endX, displaySize.y / 2,
+ ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME,
+ false, GestureScope.EXPECT_PILFER);
+ }
return goHome();
}
@@ -2126,6 +2152,13 @@
return getSystemIntegerRes(context, "config_navBarInteractionMode");
}
+ /**
+ * Retrieve the resource value that defines if nav bar can moved or if it is fixed position.
+ */
+ private static boolean getNavBarCanMove(Context context) {
+ return getSystemBooleanRes(context, "config_navBarCanMove");
+ }
+
@NonNull
UiObject2 clickAndGet(
@NonNull final UiObject2 target, @NonNull String resName, Pattern longClickEvent) {
@@ -2166,6 +2199,18 @@
}
}
+ private static boolean getSystemBooleanRes(Context context, String resName) {
+ Resources res = context.getResources();
+ int resId = res.getIdentifier(resName, "bool", "android");
+
+ if (resId != 0) {
+ return res.getBoolean(resId);
+ } else {
+ Log.e(TAG, "Failed to get system resource ID. Incompatible framework version?");
+ return false;
+ }
+ }
+
private static int getSystemIntegerRes(Context context, String resName) {
Resources res = context.getResources();
int resId = res.getIdentifier(resName, "integer", "android");
@@ -2431,6 +2476,13 @@
return Math.max(topRadius, bottomRadius) + tmpBuffer;
}
+ private Context getLauncherContext(Context baseContext)
+ throws PackageManager.NameNotFoundException {
+ // Workaround, use constructed context because both the instrumentation context and the
+ // app context are not constructed with resources that take overlays into account
+ return baseContext.createPackageContext(getLauncherPackageName(), 0);
+ }
+
private static boolean supportsRoundedCornersOnWindows(Resources resources) {
return ResourceUtils.getBoolByName(
"config_supportsRoundedCornersOnWindows", resources, false);